2002-07-28 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / encrypt.c
index e4bb38e..57ec978 100644 (file)
@@ -1,5 +1,6 @@
 /* encrypt.c -  encrypt functions
  *     Copyright (C) 2000 Werner Koch (dd9jn)
+ *      Copyright (C) 2001, 2002 g10 Code GmbH
  *
  * This file is part of GPGME.
  *
 #include "util.h"
 #include "context.h"
 #include "ops.h"
+#include "wait.h"
 
+#define SKIP_TOKEN_OR_RETURN(a) do { \
+    while (*(a) && *(a) != ' ') (a)++; \
+    while (*(a) == ' ') (a)++; \
+    if (!*(a)) \
+        return; /* oops */ \
+} while (0)
+
+struct encrypt_result_s
+{
+  int no_valid_recipients;
+  int invalid_recipients;
+  GpgmeData xmlinfo;
+};
+
+void
+_gpgme_release_encrypt_result (EncryptResult result)
+{
+  if (!result)
+    return;
+  gpgme_data_release (result->xmlinfo);
+  xfree (result);
+}
+
+/* 
+ * Parse the args and save the information 
+ * in an XML structure.
+ * With args of NULL the xml structure is closed.
+ */
 static void
-encrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
+append_xml_encinfo (GpgmeData *rdh, char *args)
 {
-    DEBUG2 ("encrypt_status: code=%d args=`%s'\n", code, args );
+  GpgmeData dh;
+  char helpbuf[100];
+
+  if (!*rdh)
+    {
+      if (gpgme_data_new (rdh))
+       return; /* FIXME: We are ignoring out-of-core.  */
+      dh = *rdh;
+      _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
+    }
+  else
+    {
+      dh = *rdh;
+      _gpgme_data_append_string (dh, "  </encryption>\n");
+    }
+
+  if (!args)
+    {
+      /* Just close the XML containter.  */
+      _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
+      return;
+    }
 
+  _gpgme_data_append_string (dh, "  <encryption>\n"
+                            "    <error>\n"
+                            "      <invalidRecipient/>\n");
+    
+  sprintf (helpbuf, "      <reason>%d</reason>\n", atoi (args));
+  _gpgme_data_append_string (dh, helpbuf);
+  SKIP_TOKEN_OR_RETURN (args);
+
+  _gpgme_data_append_string (dh, "      <name>");
+  _gpgme_data_append_percentstring_for_xml (dh, args);
+  _gpgme_data_append_string (dh, "</name>\n"
+                            "    </error>\n");
 }
 
 
+void
+_gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
+{
+  if (ctx->error)
+    return;
+  test_and_allocate_result (ctx, encrypt);
+
+  switch (code)
+    {
+    case GPGME_STATUS_EOF:
+      if (ctx->result.encrypt->xmlinfo)
+       {
+         append_xml_encinfo (&ctx->result.encrypt->xmlinfo, NULL);
+         _gpgme_set_op_info (ctx, ctx->result.encrypt->xmlinfo);
+         ctx->result.encrypt->xmlinfo = NULL;
+        }
+      if (ctx->result.encrypt->no_valid_recipients) 
+       ctx->error = mk_error (No_Recipients);
+      else if (ctx->result.encrypt->invalid_recipients) 
+       ctx->error = mk_error (Invalid_Recipients);
+      break;
+
+    case GPGME_STATUS_INV_RECP:
+      ctx->result.encrypt->invalid_recipients++;
+      append_xml_encinfo (&ctx->result.encrypt->xmlinfo, args);
+      break;
+
+    case GPGME_STATUS_NO_RECP:
+      ctx->result.encrypt->no_valid_recipients = 1;
+      break;
+
+    default:
+      break;
+    }
+}
+
 
-GpgmeError
-gpgme_op_encrypt_start ( GpgmeCtx c, GpgmeRecipients recp,
-                         GpgmeData plain, GpgmeData ciph )
+void
+_gpgme_encrypt_sym_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
 {
-    int rc = 0;
-    int i;
-
-    fail_on_pending_request( c );
-    c->pending = 1;
-
-    /* do some checks */
-    assert ( !c->gpg );
-    if ( !gpgme_recipients_count ( recp ) ) {
-        /* Fixme: In this case we should do symmentric encryption */
-        rc = mk_error (No_Recipients);
-        goto leave;
+  _gpgme_passphrase_status_handler (ctx, code, args);
+}
+
+
+static GpgmeError
+_gpgme_op_encrypt_start (GpgmeCtx ctx, int synchronous,
+                        GpgmeRecipients recp, GpgmeData plain, GpgmeData ciph)
+{
+  GpgmeError err = 0;
+  int symmetric = 0;
+
+  /* Do some checks.  */
+  if (!recp)
+    symmetric = 1;
+  else if (!gpgme_recipients_count (recp))
+    {
+      err = mk_error (No_Recipients);
+      goto leave;
+    }
+
+  err = _gpgme_op_reset (ctx, synchronous);
+  if (err)
+    goto leave;
+
+  if (symmetric)
+    {
+      err = _gpgme_passphrase_start (ctx);
+      if (err)
+       goto leave;
     }
-        
-    /* create a process object */
-    _gpgme_gpg_release (c->gpg); c->gpg = NULL;
-    rc = _gpgme_gpg_new ( &c->gpg );
-    if (rc)
-        goto leave;
-
-    _gpgme_gpg_set_status_handler ( c->gpg, encrypt_status_handler, c );
-
-    /* build the commandline */
-    _gpgme_gpg_add_arg ( c->gpg, "--encrypt" );
-    if ( c->use_armor )
-        _gpgme_gpg_add_arg ( c->gpg, "--armor" );
-    for ( i=0; i < c->verbosity; i++ )
-        _gpgme_gpg_add_arg ( c->gpg, "--verbose" );
-    /* If we know that all recipients are valid (full or ultimate trust)
-     * we can pass suppress further checks */
-    if ( _gpgme_recipients_all_valid (recp) )
-        _gpgme_gpg_add_arg ( c->gpg, "--always-trust" );
-    
-    _gpgme_append_gpg_args_from_recipients ( recp, c->gpg );
 
-    /* Check the supplied data */
-    if ( gpgme_data_get_type (plain) == GPGME_DATA_TYPE_NONE ) {
-        rc = mk_error (No_Data);
-        goto leave;
+  _gpgme_engine_set_status_handler (ctx->engine,
+                                   symmetric
+                                   ? _gpgme_encrypt_sym_status_handler
+                                   : _gpgme_encrypt_status_handler,
+                                   ctx);
+  _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
+
+  /* Check the supplied data */
+  if (gpgme_data_get_type (plain) == GPGME_DATA_TYPE_NONE)
+    {
+      err = mk_error (No_Data);
+      goto leave;
     }
-    _gpgme_data_set_mode (plain, GPGME_DATA_MODE_OUT );
-    if ( !ciph || gpgme_data_get_type (ciph) != GPGME_DATA_TYPE_NONE ) {
-        rc = mk_error (Invalid_Value);
-        goto leave;
+  _gpgme_data_set_mode (plain, GPGME_DATA_MODE_OUT);
+  if (!ciph || gpgme_data_get_type (ciph) != GPGME_DATA_TYPE_NONE)
+    {
+      err = mk_error (Invalid_Value);
+      goto leave;
     }
-    _gpgme_data_set_mode (ciph, GPGME_DATA_MODE_IN );
-    /* Tell the gpg object about the data */
-    _gpgme_gpg_add_arg ( c->gpg, "--output" );
-    _gpgme_gpg_add_arg ( c->gpg, "-" );
-    _gpgme_gpg_add_data ( c->gpg, ciph, 1 );
-    _gpgme_gpg_add_arg ( c->gpg, "--" );
-    _gpgme_gpg_add_data ( c->gpg, plain, 0 );
+  _gpgme_data_set_mode (ciph, GPGME_DATA_MODE_IN);
 
-    /* and kick off the process */
-    rc = _gpgme_gpg_spawn ( c->gpg, c );
+  err = _gpgme_engine_op_encrypt (ctx->engine, recp, plain, ciph, ctx->use_armor);
+
+
+  if (!err)    /* And kick off the process.  */
+    err = _gpgme_engine_start (ctx->engine, ctx);
 
  leave:
-    if (rc) {
-        c->pending = 0; 
-        _gpgme_gpg_release ( c->gpg ); c->gpg = NULL;
+  if (err)
+    {
+      ctx->pending = 0; 
+      _gpgme_engine_release (ctx->engine);
+      ctx->engine = NULL;
     }
-    return rc;
+  return err;
+}
+
+
+GpgmeError
+gpgme_op_encrypt_start (GpgmeCtx ctx, GpgmeRecipients recp, GpgmeData plain,
+                       GpgmeData ciph)
+{
+  return _gpgme_op_encrypt_start (ctx, 0, recp, plain, ciph);
 }
 
 
@@ -120,20 +230,20 @@ gpgme_op_encrypt_start ( GpgmeCtx c, GpgmeRecipients recp,
  * Return value:  0 on success or an errorcode. 
  **/
 GpgmeError
-gpgme_op_encrypt ( GpgmeCtx c, GpgmeRecipients recp,
-                   GpgmeData in, GpgmeData out )
+gpgme_op_encrypt (GpgmeCtx ctx, GpgmeRecipients recp,
+                 GpgmeData plain, GpgmeData cipher)
 {
-    int rc = gpgme_op_encrypt_start ( c, recp, in, out );
-    if ( !rc ) {
-        gpgme_wait (c, 1);
-        c->pending = 0;
+  int err = _gpgme_op_encrypt_start (ctx, 1, recp, plain, cipher);
+  if (!err)
+    {
+      err = _gpgme_wait_one (ctx);
+      /* Old gpg versions don't return status info for invalid
+        recipients, so we simply check whether we got any output at
+        all, and if not we assume that we don't have valid
+        recipients.  */
+      if (!ctx->error && gpgme_data_get_type (cipher) == GPGME_DATA_TYPE_NONE)
+       ctx->error = mk_error (No_Recipients);
+      err = ctx->error;
     }
-    return rc;
+  return err;
 }
-
-
-
-
-
-
-