[svn] GpgOL - r178 - trunk/src

svn author wk cvs at cvs.gnupg.org
Fri Sep 14 17:21:51 CEST 2007


Author: wk
Date: 2007-09-14 17:21:50 +0200 (Fri, 14 Sep 2007)
New Revision: 178

Modified:
   trunk/src/ChangeLog
   trunk/src/common.h
   trunk/src/engine-gpgme.c
   trunk/src/engine.c
   trunk/src/engine.h
   trunk/src/message-events.cpp
   trunk/src/message.cpp
   trunk/src/message.h
   trunk/src/mimemaker.c
   trunk/src/mimemaker.h
   trunk/src/mimeparser.c
   trunk/src/mimeparser.h
Log:
A lot of cleanups.  removed unused all gpgme stuff.
There is still a race condition soemwhere, but the basic
functionality is now again complete - when using the gpgme backend.


Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/ChangeLog	2007-09-14 15:21:50 UTC (rev 178)
@@ -1,3 +1,7 @@
+2007-09-14  Werner Koch  <wk at g10code.com>
+
+	* engine-gpgme.c: Rewrote most of it.
+
 2007-09-13  Werner Koch  <wk at g10code.com>
 
 	* common.c (xrealloc): New.

Modified: trunk/src/common.h
===================================================================
--- trunk/src/common.h	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/common.h	2007-09-14 15:21:50 UTC (rev 178)
@@ -34,12 +34,14 @@
 #endif
 #endif
 
-/* Identifiers for the protocol.  */
+/* Identifiers for the protocol.  We use different one than those use
+   by gpgme.  FIXME: We might want to define an unknown protocol to
+   non-null and define such a value also in gpgme. */
 typedef enum
   {
     PROTOCOL_UNKNOWN = 0,
-    PROTOCOL_OPENPGP,
-    PROTOCOL_SMIME
+    PROTOCOL_OPENPGP = 1000,
+    PROTOCOL_SMIME   = 1001
   }
 protocol_t;
 

Modified: trunk/src/engine-gpgme.c
===================================================================
--- trunk/src/engine-gpgme.c	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/engine-gpgme.c	2007-09-14 15:21:50 UTC (rev 178)
@@ -19,9 +19,6 @@
  * 02110-1301, USA.
  */
 
-/* Please note that we assume UTF-8 strings everywhere except when
-   noted. */
-   
 
 #include <config.h>
 
@@ -30,10 +27,9 @@
 #include <string.h>
 #include <time.h>
 #include <errno.h>
-
-#define COBJMACROS
+#include <assert.h>
+#define WIN32_LEAN_AND_MEAN 
 #include <windows.h>
-#include <objidl.h> /* For IStream. */
 
 #include "common.h"
 #include "passcache.h"
@@ -45,49 +41,44 @@
                         } while (0)
 
 
-static char *debug_file = NULL;
+/* Because we are using asynchronous gpgme commands, we need to have a
+   closure to cleanup allocated resources and run the code required
+   adfter gpgme finished the command (e.g. getting the signature
+   verification result.  Thus all functions need to implement a
+   closure function and pass it using a closure_data_t object via the
+   gpgme_progress_cb hack.  */
+struct closure_data_s;
+typedef struct closure_data_s *closure_data_t;
+struct closure_data_s
+{
+  void (*closure)(closure_data_t, gpgme_ctx_t, gpg_error_t);
+  engine_filter_t filter;
+  struct passphrase_cb_s pw_cb;  /* Passphrase callback info.  */
+  int with_verify;
+  gpgme_data_t sigobj;
+};
+
+
 static int init_done = 0;
 
 
 static DWORD WINAPI waiter_thread (void *dummy);
 static void update_passphrase_cache (int err, 
                                      struct passphrase_cb_s *pass_cb_value);
-static void add_verify_attestation (gpgme_data_t at, 
-                                    gpgme_ctx_t ctx, 
-                                    gpgme_verify_result_t res,
-                                    const char *filename);
+/* static void add_verify_attestation (gpgme_data_t at,  */
+/*                                     gpgme_ctx_t ctx,  */
+/*                                     gpgme_verify_result_t res, */
+/*                                     const char *filename); */
 
 
 
 static void
 cleanup (void)
 {
-  if (debug_file)
-    {
-      xfree (debug_file);
-      debug_file = NULL;
-    }
+  /* Fixme: We should stop the thread.  */
 }
 
 
-/* Enable or disable GPGME debug mode. */
-void
-op_gpgme_set_debug_mode (int val, const char *file)
-{
-  const char *s= "GPGME_DEBUG";
-
-  cleanup ();
-  if (val > 0) 
-    {
-      debug_file = (char *)xcalloc (1, strlen (file) + strlen (s) + 2);
-      sprintf (debug_file, "%s=%d;%s", s, val, file);
-      putenv (debug_file);
-    }
-  else
-    putenv ("GPGME_DEBUG=");
-}
-
-
 /* Cleanup static resources. */
 void
 op_gpgme_deinit (void)
@@ -132,7 +123,7 @@
     HANDLE th;
     DWORD tid;
 
-    th = CreateThread (NULL, 64*1024, waiter_thread, NULL, 0, &tid);
+    th = CreateThread (NULL, 128*1024, waiter_thread, NULL, 0, &tid);
     if (th == INVALID_HANDLE_VALUE)
       log_error ("failed to start the gpgme waiter thread\n");
     else
@@ -144,20 +135,21 @@
 }
 
 
+/* The worker for the asynchronous commands.  */
 static DWORD WINAPI
 waiter_thread (void *dummy)
 {
   gpgme_ctx_t ctx;
   gpg_error_t err;
-  void *filter;
-  void *pass_cb;
+  void *a_voidptr;
+  closure_data_t closure_data;
 
   (void)dummy;
 
   TRACEPOINT ();
   for (;;)
     {
-      /*  Note: We don't use hang becuase this will end up in a tight
+      /*  Note: We don't use hang because this will end up in a tight
           loop and does not do a voluntary context switch.  Thus we do
           this by ourself.  Actually it would be better to start
           gpgme-Wait only if we really have something to do but that
@@ -165,12 +157,12 @@
       ctx = gpgme_wait (NULL, &err, 0);
       if (ctx)
         {
-          gpgme_get_progress_cb (ctx, NULL, &filter);
-          engine_gpgme_finished (filter, err);
-          gpgme_get_passphrase_cb (ctx, NULL, &pass_cb);
-          if (pass_cb)
-            update_passphrase_cache (err, (struct passphrase_cb_s *)pass_cb);
-          xfree (pass_cb);
+          gpgme_get_progress_cb (ctx, NULL, &a_voidptr);
+          closure_data = a_voidptr;
+          assert (closure_data);
+          assert (closure_data->closure);
+          closure_data->closure (closure_data, ctx, err);
+          xfree (closure_data);
           gpgme_release (ctx);
         }
       else if (err)
@@ -182,53 +174,6 @@
 }
 
 
-
-/* The read callback used by GPGME to read data from an IStream object. */
-static ssize_t
-stream_read_cb (void *handle, void *buffer, size_t size)
-{
-  LPSTREAM stream = handle;
-  HRESULT hr;
-  ULONG nread;
-
-  /* For EOF detection we assume that Read returns no error and thus
-     nread will be 0.  The specs say that "Depending on the
-     implementation, either S_FALSE or an error code could be returned
-     when reading past the end of the stream"; thus we are not really
-     sure whether our assumption is correct.  OTOH, at another place
-     the docuemntation says that the implementation used by
-     ISequentialStream exhibits the same EOF behaviour has found on
-     the MSDOS FAT file system.  So we seem to have good karma. */
-  hr = IStream_Read (stream, buffer, size, &nread);
-  if (hr != S_OK)
-    {
-      log_debug ("%s:%s: Read failed: hr=%#lx", SRCNAME, __func__, hr);
-      errno = EIO;
-      return -1;
-    }
-  return nread;
-}
-
-
-/* The write callback used by GPGME to write data to an IStream object. */
-static ssize_t
-stream_write_cb (void *handle, const void *buffer, size_t size)
-{
-  LPSTREAM stream = handle;
-  HRESULT hr;
-  ULONG nwritten;
-
-  hr = IStream_Write (stream, buffer, size, &nwritten);
-  if (hr != S_OK)
-    {
-      log_debug ("%s:%s: Write failed: hr=%#lx", SRCNAME, __func__, hr);
-      errno = EIO;
-      return -1;
-    }
-  return nwritten;
-}
-
-
 /* This routine should be called immediately after an operation to
    make sure that the passphrase cache gets updated. ERR is expected
    to be the error code from the gpgme operation and PASS_CB_VALUE the
@@ -242,7 +187,9 @@
 static void
 update_passphrase_cache (int err, struct passphrase_cb_s *pass_cb_value)
 {
-  if (*pass_cb_value->keyid)
+  if (!pass_cb_value)
+    return;
+  if (pass_cb_value->keyid && *pass_cb_value->keyid)
     {
       if (err)
         passcache_put (pass_cb_value->keyid, NULL, 0);
@@ -272,151 +219,13 @@
   res = gpgme_op_encrypt_result (ctx);
   if (!res)
     return err;
-  if (res->invalid_recipients != NULL)
+  if (res->invalid_recipients)
     return gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
   /* XXX: we need to do more here! */
   return err;
 }
 
 
-/* Encrypt the data in INBUF into a newly malloced buffer stored on
-   success at OUTBUF.  The caller should release this buffer using
-   gpgme_free.  The recipients are expected in the NULL terminated
-   array KEYS. If SIGN_KEY is not NULl, the data will also be signed
-   using this key.  TTL is the time the passphrase should be
-   cached. */
-int
-op_encrypt (const char *inbuf, char **outbuf, gpgme_key_t *keys,
-            gpgme_key_t sign_key, int ttl)
-{
-  struct passphrase_cb_s cb;
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;
-  gpgme_error_t err;
-  gpgme_ctx_t ctx = NULL;
-    
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 0;
-
-  *outbuf = NULL;
-
-  op_gpgme_init ();
-  err = gpgme_new (&ctx);
-  if (err)
-    goto leave;
-
-  err = gpgme_data_new_from_mem (&in, inbuf, strlen (inbuf), 1);
-  if (err)
-    goto leave;
-
-  err = gpgme_data_new (&out);
-  if (err)
-    goto leave;
-
-  gpgme_set_textmode (ctx, 1);
-  gpgme_set_armor (ctx, 1);
-  if (sign_key)
-    {
-      gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cb);
-      cb.ctx = ctx;
-      err = gpgme_signers_add (ctx, sign_key);
-      if (!err)
-        err = gpgme_op_encrypt_sign (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST,
-                                     in, out);
-      cb.ctx = NULL;
-      update_passphrase_cache (err, &cb);
-    }
-  else
-    err = gpgme_op_encrypt (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
-  if (err)
-    err = check_encrypt_result (ctx, err);
-  else
-    {
-      /* Return the buffer but first make sure it is a string. */
-      if (gpgme_data_write (out, "", 1) == 1)
-        {
-          *outbuf = gpgme_data_release_and_get_mem (out, NULL);
-          out = NULL; 
-        }
-    }
-
-
- leave:
-  if (ctx)
-    gpgme_release (ctx);
-  if (in)
-    gpgme_data_release (in);
-  if (out)
-    gpgme_data_release (out);
-  return err;
-}
-
-
-
-/* Encrypt the stream INSTREAM to the OUTSTREAM for all recpients
-   given in the NULL terminated array KEYS.  If SIGN_KEY is not NULL
-   the message will also be signed. */
-int
-op_encrypt_stream (LPSTREAM instream, LPSTREAM outstream, gpgme_key_t *keys,
-                   gpgme_key_t sign_key, int ttl)
-{
-  struct passphrase_cb_s cb;
-  struct gpgme_data_cbs cbs;
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;
-  gpgme_ctx_t ctx = NULL;
-  gpgme_error_t err;
-
-  memset (&cbs, 0, sizeof cbs);
-  cbs.read = stream_read_cb;
-  cbs.write = stream_write_cb;
-
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 0;
-
-  err = gpgme_data_new_from_cbs (&in, &cbs, instream);
-  if (err)
-    goto fail;
-
-  err = gpgme_data_new_from_cbs (&out, &cbs, outstream);
-  if (err)
-    goto fail;
-
-  err = gpgme_new (&ctx);
-  if (err)
-    goto fail;
-
-  gpgme_set_armor (ctx, 1);
-  /* FIXME:  We should not hardcode always trust. */
-  if (sign_key)
-    {
-      gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cb);
-      cb.ctx = ctx;
-      err = gpgme_signers_add (ctx, sign_key);
-      if (!err)
-        err = gpgme_op_encrypt_sign (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST,
-                                     in, out);
-      cb.ctx = NULL;
-      update_passphrase_cache (err, &cb);
-    }
-  else
-    err = gpgme_op_encrypt (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
-  if (err)
-    err = check_encrypt_result (ctx, err);
-
- fail:
-  if (ctx)
-    gpgme_release (ctx);
-  if (in)
-    gpgme_data_release (in);
-  if (out)
-    gpgme_data_release (out);
-  return err;
-}
-
-
 /* Release an array of GPGME keys. */
 static void 
 release_key_array (gpgme_key_t *keys)
@@ -546,6 +355,22 @@
 }
 
 
+/* Not that this closure is called in the context of the
+   waiter_thread.  */
+static void
+encrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
+{
+  if (cld->pw_cb.ctx)
+    {
+      /* Signing was also request; thus update the passphrase cache.  */ 
+      update_passphrase_cache (err, &cld->pw_cb);
+    }
+  if (err)
+    err = check_encrypt_result (ctx, err);
+  engine_gpgme_finished (cld->filter, err);
+}
+
+
 /* Encrypt the data from INDATA to the OUTDATA object for all
    recpients given in the NULL terminated array KEYS.  If SIGN_KEY is
    not NULL the message will also be signed.  On termination of the
@@ -556,19 +381,19 @@
    just for this notification.  We abuse the gpgme_set_progress_cb
    value for storing the pointer with the gpgme context.  */
 int
-op_gpgme_encrypt_data (protocol_t protocol, 
-                       gpgme_data_t indata, gpgme_data_t outdata,
-                       void *notify_data, /* FIXME: Add hwnd */
-                       char **recipients, gpgme_key_t sign_key, int ttl)
+op_gpgme_encrypt (protocol_t protocol, 
+                  gpgme_data_t indata, gpgme_data_t outdata,
+                  void *notify_data, /* FIXME: Add hwnd */
+                  char **recipients, gpgme_key_t sign_key, int ttl)
 {
   gpg_error_t err;
-  struct passphrase_cb_s cb;
+  closure_data_t cld;
   gpgme_ctx_t ctx = NULL;
   gpgme_key_t *keys = NULL;
 
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 0;
+  cld = xcalloc (1, sizeof *cld);
+  cld->closure = encrypt_closure;
+  cld->filter = notify_data;
 
   err = prepare_recipient_keys (&keys, recipients, NULL);
   if (err)
@@ -577,52 +402,72 @@
   err = gpgme_new (&ctx);
   if (err)
     goto leave;
-  if (protocol == PROTOCOL_SMIME)
+  gpgme_set_progress_cb (ctx, NULL, cld);
+  switch (protocol)
     {
+    case PROTOCOL_OPENPGP:  /* Gpgme's default.  */
+      break;
+    case PROTOCOL_SMIME:
       err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
-      if (err)
-        goto leave;
+      break;
+    default:
+      err = gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+      break;
     }
-  gpgme_set_progress_cb (ctx, NULL, notify_data);
+  if (err)
+    goto leave;
 
+
   gpgme_set_armor (ctx, 1);
   /* FIXME:  We should not hardcode always trust. */
   if (sign_key)
     {
-      gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cb);
-      cb.ctx = ctx;
+      gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cld->pw_cb);
+      cld->pw_cb.ctx = ctx;
+      cld->pw_cb.ttl = ttl;
       err = gpgme_signers_add (ctx, sign_key);
       if (!err)
         err = gpgme_op_encrypt_sign_start (ctx, keys,
                                            GPGME_ENCRYPT_ALWAYS_TRUST,
                                            indata, outdata);
-      cb.ctx = NULL;
-      update_passphrase_cache (err, &cb);
     }
   else
     err = gpgme_op_encrypt_start (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, 
                                   indata, outdata);
-/*   if (err) */
-/*     err = check_encrypt_result (ctx, err); */
 
  leave:
-  if (ctx && err)
-    gpgme_release (ctx);
+  if (err)
+    {
+      xfree (cld);
+      gpgme_release (ctx);
+    }
   release_key_array (keys);
   return err;
 }
 
 
+
+
+/* Not that this closure is called in the context of the
+   waiter_thread.  */
+static void
+sign_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
+{
+  update_passphrase_cache (err, &cld->pw_cb);
+  engine_gpgme_finished (cld->filter, err);
+}
+
+
 /* Created a detached signature for INDATA and write it to OUTDATA.
    On termination of the signing command engine_gpgme_finished() is
    called with NOTIFY_DATA as the first argument.  */
 int
-op_gpgme_sign_data (protocol_t protocol, 
-                    gpgme_data_t indata, gpgme_data_t outdata,
-                    void *notify_data /* FIXME: Add hwnd */)
+op_gpgme_sign (protocol_t protocol, 
+               gpgme_data_t indata, gpgme_data_t outdata,
+               void *notify_data /* FIXME: Add hwnd */)
 {
   gpg_error_t err;
-  struct passphrase_cb_s *cb;
+  closure_data_t cld;
   gpgme_ctx_t ctx = NULL;
   gpgme_key_t sign_key = NULL;
 
@@ -632,32 +477,39 @@
       return gpg_error (GPG_ERR_CANCELED);  
     }
 
-  cb = xcalloc (1, sizeof *cb);
-  cb->ttl = 0 /*FIXME: ttl*/;
+  cld = xcalloc (1, sizeof *cld);
+  cld->closure = sign_closure;
+  cld->filter = notify_data;
 
   err = gpgme_new (&ctx);
   if (err)
     goto leave;
-  if (protocol == PROTOCOL_SMIME)
+  gpgme_set_progress_cb (ctx, NULL, cld);
+  switch (protocol)
     {
+    case PROTOCOL_OPENPGP:  /* Gpgme's default.  */
+      break;
+    case PROTOCOL_SMIME:
       err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
-      if (err)
-        goto leave;
+      break;
+    default:
+      err = gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+      break;
     }
+  if (err)
+    goto leave;
 
-  gpgme_set_progress_cb (ctx, NULL, notify_data);
-
   gpgme_set_armor (ctx, 1);
-  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, cb);
-  cb->ctx = ctx;
+  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cld->pw_cb);
+  cld->pw_cb.ctx = ctx;
   err = gpgme_signers_add (ctx, sign_key);
   if (!err)
     err = gpgme_op_sign_start (ctx, indata, outdata, GPGME_SIG_MODE_DETACH);
 
  leave:
-  if (ctx && err)
+  if (err)
     {
-      xfree (cb);
+      xfree (cld);
       gpgme_release (ctx);
     }
   gpgme_key_unref (sign_key);
@@ -665,629 +517,186 @@
 }
 
 
-
-
-
 
-/* Sign and encrypt the data in INBUF into a newly allocated buffer at
-   OUTBUF. Caller needs to free the returned buffer using gpgme_free. */
-int
-op_sign (const char *inbuf, char **outbuf, int mode,
-         gpgme_key_t sign_key, int ttl)
+/* Not that this closure is called in the context of the
+   waiter_thread.  */
+static void
+decrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
 {
-  struct passphrase_cb_s cb;
-  gpgme_error_t err;
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;
-  gpgme_ctx_t ctx = NULL;
+  update_passphrase_cache (err, &cld->pw_cb);
 
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 0;
-
-  *outbuf = NULL;
-  op_gpgme_init ();
-  
-  err = gpgme_new (&ctx);
-  if (err) 
-    goto leave;
-
-  err = gpgme_data_new_from_mem (&in, inbuf, strlen (inbuf), 1);
-  if (err)
-    goto leave;
-
-  err = gpgme_data_new (&out);
-  if (err)
-    goto leave;
-
-  if (sign_key)
-    gpgme_signers_add (ctx, sign_key);
-
-  if (mode == GPGME_SIG_MODE_CLEAR)
-    gpgme_set_textmode (ctx, 1);
-  gpgme_set_armor (ctx, 1);
-
-  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cb);
-  cb.ctx = ctx;
-  err = gpgme_op_sign (ctx, in, out, mode);
-  cb.ctx = NULL;
-  update_passphrase_cache (err, &cb);
-
-  if (!err)
-    {
-      /* Return the buffer but first make sure it is a string. */
-      if (gpgme_data_write (out, "", 1) == 1)
-        {
-          *outbuf = gpgme_data_release_and_get_mem (out, NULL);
-          out = NULL; 
-        }
-    }
-
- leave:
-  if (ctx)
-    gpgme_release (ctx);
-  if (in)
-    gpgme_data_release (in);
-  if (out)
-    gpgme_data_release (out);
-  return err;
-}
-
-
-/* Create a signature from INSTREAM and write it to OUTSTREAM.  Use
-   signature mode MODE and a passphrase caching time of TTL. */
-int
-op_sign_stream (LPSTREAM instream, LPSTREAM outstream, int mode,
-                gpgme_key_t sign_key, int ttl)
-{
-  struct gpgme_data_cbs cbs;
-  struct passphrase_cb_s cb;
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;
-  gpgme_ctx_t ctx = NULL;
-  gpgme_error_t err;
-  
-  memset (&cbs, 0, sizeof cbs);
-  cbs.read = stream_read_cb;
-  cbs.write = stream_write_cb;
-
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 0;
-
-  err = gpgme_data_new_from_cbs (&in, &cbs, instream);
-  if (err)
-    goto fail;
-
-  err = gpgme_data_new_from_cbs (&out, &cbs, outstream);
-  if (err)
-    goto fail;
-
-  err = gpgme_new (&ctx);
-  if (err)
-    goto fail;
-  
-  if (sign_key)
-    gpgme_signers_add (ctx, sign_key);
-
-  if (mode == GPGME_SIG_MODE_CLEAR)
-    gpgme_set_textmode (ctx, 1);
-  gpgme_set_armor (ctx, 1);
-
-  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cb);
-  cb.ctx = ctx;
-  err = gpgme_op_sign (ctx, in, out, mode);
-  cb.ctx = NULL;
-  update_passphrase_cache (err, &cb);
-  
- fail:
-  if (in)
-    gpgme_data_release (in);
-  if (out)
-    gpgme_data_release (out);
-  if (ctx)
-    gpgme_release (ctx);    
-  return err;
-}
-
-
-
-/* Run the decryption.  Decrypts INBUF to OUTBUF; caller needs to free
-   the returned result at OUTBUF using gpgme_free.  the result at
-   OUTBUF.  TTL is the time in seconds to cache a passphrase.  If
-   FILENAME is not NULL it will be displayed along with status
-   outputs. If ATTESTATION is not NULL a text with the result of the
-   signature verification will get printed to it. */
-int 
-op_decrypt (const char *inbuf, char **outbuf, int ttl, const char *filename,
-            gpgme_data_t attestation, int preview_mode)
-{
-  struct passphrase_cb_s cb;
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;
-  gpgme_ctx_t ctx;
-  gpgme_error_t err;
-  
-  *outbuf = NULL;
-  op_gpgme_init ();
-
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 1;
-
-  err = gpgme_new (&ctx);
-  if (err)
-    return err;
-
-  err = gpgme_data_new_from_mem (&in, inbuf, strlen (inbuf), 1);
-  if (err)
-    goto leave;
-  err = gpgme_data_new (&out);
-  if (err)
-    goto leave;
-
-  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cb);
-  cb.ctx = ctx;
-  if (preview_mode)
-    err = gpgme_op_decrypt (ctx, in, out);
-  else
-    err = gpgme_op_decrypt_verify (ctx, in, out);
-  cb.ctx = NULL;
-  update_passphrase_cache (err, &cb);
-
-  /* Act upon the result of the decryption operation. */
-  if (!err && preview_mode) 
+  if (!err && !cld->with_verify) 
     ;
   else if (!err) 
     {
-      /* Decryption succeeded.  Store the result at OUTBUF. */
       gpgme_verify_result_t res;
 
-      /* Return the buffer but first make sure it is a string. */
-      if (gpgme_data_write (out, "", 1) == 1)
-        {
-          *outbuf = gpgme_data_release_and_get_mem (out, NULL);
-          out = NULL; 
-        }
-
-      /* Now check the state of any signature. */
+      /* Decryption succeeded.  Now check the state of the signatures. */
       res = gpgme_op_verify_result (ctx);
       if (res && res->signatures)
-        verify_dialog_box (gpgme_get_protocol (ctx), res, filename);
-      if (res && res->signatures && attestation)
-        add_verify_attestation (attestation, ctx, res, filename);
+        verify_dialog_box (gpgme_get_protocol (ctx), res, NULL);
     }
-  else if (gpgme_err_code (err) == GPG_ERR_DECRYPT_FAILED)
+  else if (gpg_err_code (err) == GPG_ERR_DECRYPT_FAILED)
     {
-      /* The decryption failed.  See whether we can determine the real
-         problem. */
+      /* The decryption failed.  See whether we can figure out a more
+         suitable error code.  */
       gpgme_decrypt_result_t res;
+
       res = gpgme_op_decrypt_result (ctx);
-      if (res != NULL && res->recipients != NULL &&
-          gpgme_err_code (res->recipients->status) == GPG_ERR_NO_SECKEY)
-        err = GPG_ERR_NO_SECKEY;
-      /* XXX: return the keyids */
+      if (res && res->recipients 
+          && gpgme_err_code (res->recipients->status) == GPG_ERR_NO_SECKEY)
+        err = gpg_error (GPG_ERR_NO_SECKEY);
+      /* Fixme: return the keyids */
     }
   else
     {
       /* Decryption failed for other reasons. */
     }
 
-
-  /* If the callback indicated a cancel operation, set the error
-     accordingly. */
-  if (err && (cb.opts & OPT_FLAG_CANCEL))
+  /* If the passphrase callback indicated a cancel operation, change
+     the the error code accordingly. */
+  if (err && (cld->pw_cb.opts & OPT_FLAG_CANCEL))
     err = gpg_error (GPG_ERR_CANCELED);
-  
-leave:    
-  if (ctx)
-    gpgme_release (ctx);
-  if (in)
-    gpgme_data_release (in);
-  if (out)
-    gpgme_data_release (out);
-  return err;
+
+  engine_gpgme_finished (cld->filter, err);
 }
 
 
-/* Decrypt the GPGME data object IN into the data object OUT.  Returns
-   0 on success or an gpgme error code on failure.  If FILENAME is not
-   NULL it will be displayed along with status outputs. If ATTESTATION
-   is not NULL a text with the result of the signature verification
-   will get printed to it. */
-static int
-decrypt_stream (gpgme_protocol_t protocol,
-                gpgme_data_t in, gpgme_data_t out, int ttl,
-                const char *filename, gpgme_data_t attestation, 
-                int preview_mode)
-{    
-  struct passphrase_cb_s cb;
-  gpgme_ctx_t ctx = NULL;
+/* Decrypt data from INDATA to OUTDATE.  If WITH_VERIFY is set, a
+   signature of PGP/MIME combined message is also verified the same
+   way as with op_gpgme_verify.  */
+int
+op_gpgme_decrypt (protocol_t protocol,
+                  gpgme_data_t indata, gpgme_data_t outdata, 
+                  void *notify_data,
+                  int with_verify)
+{
   gpgme_error_t err;
+  closure_data_t cld;
+  gpgme_ctx_t ctx = NULL;
   
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 1;
+  cld = xcalloc (1, sizeof *cld);
+  cld->closure = decrypt_closure;
+  cld->filter = notify_data;
+  cld->with_verify = with_verify;
 
   err = gpgme_new (&ctx);
   if (err)
-    goto fail;
-
-  err = gpgme_set_protocol (ctx, protocol);
+    goto leave;
+  gpgme_set_progress_cb (ctx, NULL, cld);
+  switch (protocol)
+    {
+    case PROTOCOL_OPENPGP:  /* Gpgme's default.  */
+      break;
+    case PROTOCOL_SMIME:
+      err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
+      break;
+    default:
+      err = gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+      break;
+    }
   if (err)
-    goto fail;
+    goto leave;
 
-  /* GPGME does not support a command handler for gpgsm.  Thus we
-     can't set the passphrase callback.  */
-  if (protocol != GPGME_PROTOCOL_CMS)
-    gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cb);
+  /* Note: We do no error checking for the next call because some
+     backends may not implement a command hanler at all.  */
+  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cld->pw_cb);
+  cld->pw_cb.ctx = ctx;
 
-  cb.ctx = ctx;
-  if (preview_mode)
-    err = gpgme_op_decrypt (ctx, in, out);
+  if (with_verify) 
+    err = gpgme_op_decrypt_verify_start (ctx, indata, outdata);
   else
-    err = gpgme_op_decrypt_verify (ctx, in, out);
-  cb.ctx = NULL;
-  update_passphrase_cache (err, &cb);
-  /* Act upon the result of the decryption operation. */
-  if (!err && preview_mode) 
-    ;
-  else if (!err) 
-    {
-      gpgme_verify_result_t res;
+    err = gpgme_op_decrypt_start (ctx, indata, outdata);
 
-      /* Decryption succeeded.  Now check the state of the signatures. */
-      res = gpgme_op_verify_result (ctx);
-      if (res && res->signatures)
-        verify_dialog_box (gpgme_get_protocol (ctx), res, filename);
-      if (res && res->signatures && attestation)
-        add_verify_attestation (attestation, ctx, res, filename);
-    }
-  else if (gpgme_err_code (err) == GPG_ERR_DECRYPT_FAILED)
-    {
-      /* The decryption failed.  See whether we can determine the real
-         problem. */
-      gpgme_decrypt_result_t res;
-      res = gpgme_op_decrypt_result (ctx);
-      if (res != NULL && res->recipients != NULL &&
-          gpgme_err_code (res->recipients->status) == GPG_ERR_NO_SECKEY)
-        err = GPG_ERR_NO_SECKEY;
-      /* XXX: return the keyids */
-    }
-  else
-    {
-      /* Decryption failed for other reasons. */
-    }
 
-
-  /* If the callback indicated a cancel operation, set the error
-     accordingly. */
-  if (err && (cb.opts & OPT_FLAG_CANCEL))
-    err = gpg_error (GPG_ERR_CANCELED);
-
- fail:
-  if (ctx)
-    gpgme_release (ctx);
-  return err;
-}
-
-/* Decrypt the stream INSTREAM directly to the stream OUTSTREAM.
-   Returns 0 on success or an gpgme error code on failure.  If
-   FILENAME is not NULL it will be displayed along with status
-   outputs. */
-int
-op_decrypt_stream (LPSTREAM instream, LPSTREAM outstream, int ttl,
-                   const char *filename, gpgme_data_t attestation)
-{
-  struct gpgme_data_cbs cbs;
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;    
-  gpgme_error_t err;
-  
-  memset (&cbs, 0, sizeof cbs);
-  cbs.read = stream_read_cb;
-  cbs.write = stream_write_cb;
-
-  err = gpgme_data_new_from_cbs (&in, &cbs, instream);
-  if (!err)
-    err = gpgme_data_new_from_cbs (&out, &cbs, outstream);
-  if (!err)
-    err = decrypt_stream (GPGME_PROTOCOL_OpenPGP,
-                          in, out, ttl, filename, attestation, 0);
-
-  if (in)
-    gpgme_data_release (in);
-  if (out)
-    gpgme_data_release (out);
-  return err;
-}
-
-
-/* Decrypt the stream INSTREAM directly to the newly allocated buffer
-   OUTBUF.  Caller needs to free the returned buffer using gpgme_free.
-   Returns 0 on success or an gpgme error code on failure.  If
-   FILENAME is not NULL it will be displayed along with status
-   outputs. */
-int
-op_decrypt_stream_to_buffer (LPSTREAM instream, char **outbuf, int ttl,
-                             const char *filename, gpgme_data_t attestation)
-{    
-  struct gpgme_data_cbs cbs;
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;    
-  gpgme_error_t err;
-  
-  *outbuf = NULL;
-
-  memset (&cbs, 0, sizeof cbs);
-  cbs.read = stream_read_cb;
-
-  err = gpgme_data_new_from_cbs (&in, &cbs, instream);
-  if (!err)
-    err = gpgme_data_new (&out);
-  if (!err)
-    err = decrypt_stream (GPGME_PROTOCOL_OpenPGP,
-                          in, out, ttl, filename, attestation, 0);
-  if (!err)
+ leave:
+  if (err)
     {
-      /* Return the buffer but first make sure it is a string. */
-      if (gpgme_data_write (out, "", 1) == 1)
-        {
-          *outbuf = gpgme_data_release_and_get_mem (out, NULL);
-          out = NULL; 
-        }
+      xfree (cld);
+      gpgme_release (ctx);
     }
-
-  if (in)
-    gpgme_data_release (in);
-  if (out)
-    gpgme_data_release (out);
   return err;
 }
 
 
-/* Decrypt the stream INSTREAM directly to the GPGME data object OUT.
-   Returns 0 on success or an gpgme error code on failure.  If
-   FILENAME is not NULL it will be displayed along with status
-   outputs. */
-int
-op_decrypt_stream_to_gpgme (gpgme_protocol_t protocol,
-                            LPSTREAM instream, gpgme_data_t out, int ttl,
-                            const char *filename, gpgme_data_t attestation,
-                            int preview_mode)
-{
-  struct gpgme_data_cbs cbs;
-  gpgme_data_t in = NULL;
-  gpgme_error_t err;
-  
-  memset (&cbs, 0, sizeof cbs);
-  cbs.read = stream_read_cb;
 
-  err = gpgme_data_new_from_cbs (&in, &cbs, instream);
-  if (!err)
-    err = decrypt_stream (protocol, 
-                          in, out, ttl, filename, attestation, preview_mode);
-
-  if (in)
-    gpgme_data_release (in);
-  return err;
-}
-
-
 
-/* Verify a message in INBUF and return the new message (i.e. the one
-   with stripped off dash escaping) in a newly allocated buffer
-   OUTBUF. If OUTBUF is NULL only the verification result will be
-   displayed (this is suitable for PGP/MIME messages).  A dialog box
-   will show the result of the verification.  If FILENAME is not NULL
-   it will be displayed along with status outputs.  If ATTESTATION is
-   not NULL a text with the result of the signature verification will
-   get printed to it. Caller needs to free the returned buffer at
-   OUTBUF using gpgme_free. */
-int
-op_verify (const char *inbuf, char **outbuf, const char *filename,
-           gpgme_data_t attestation)
+/* Not that this closure is called in the context of the
+   waiter_thread.  */
+static void
+verify_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
 {
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;
-  gpgme_ctx_t ctx = NULL;
-  gpgme_error_t err;
-  gpgme_verify_result_t res = NULL;
-
-  if (outbuf)
-    *outbuf = NULL;
-
-  op_gpgme_init ();
-
-  err = gpgme_new (&ctx);
-  if (err)
-    goto leave;
-
-  err = gpgme_data_new_from_mem (&in, inbuf, strlen (inbuf), 1);
-  if (err)
-    goto leave;
-
-  err = gpgme_data_new (&out);
-  if (err)
-    goto leave;
-
-  err = gpgme_op_verify (ctx, in, NULL, out);
   if (!err)
     {
-      if (outbuf) 
-        {
-          /* Return the buffer but first make sure it is a string. */
-          if (gpgme_data_write (out, "", 1) == 1)
-            {
-              *outbuf = gpgme_data_release_and_get_mem (out, NULL);
-              out = NULL; 
-            }
-	}
+      gpgme_verify_result_t res;
+
       res = gpgme_op_verify_result (ctx);
+      if (res) 
+        verify_dialog_box (gpgme_get_protocol (ctx), res, NULL);
     }
-  if (res) 
-    verify_dialog_box (gpgme_get_protocol (ctx), res, filename);
-  if (res && attestation)
-    add_verify_attestation (attestation, ctx, res, filename);
-
- leave:
-  if (out)
-    gpgme_data_release (out);
-  if (in)
-    gpgme_data_release (in);
-  if (ctx)
-    gpgme_release (ctx);
-  return err;
+  gpgme_data_release (cld->sigobj);
+  engine_gpgme_finished (cld->filter, err);
 }
 
-/* Verify a detached message where the data is to be read from the
-   DATA_STREAM and the signature itself is expected to be the string
-   SIG_STRING.  FILENAME will be shown by the verification status
-   dialog box.  If ATTESTATION is not NULL a text with the result of
-   the signature verification will get printed to it.  */ 
+
+/* Verify a detached message where the data is in the gpgme object
+   DATA and the signature given as the string SIGNATUEE. */
 int
-op_verify_detached_sig (LPSTREAM data_stream,
-                        const char *sig_string, const char *filename,
-                        gpgme_data_t attestation)
+op_gpgme_verify (gpgme_protocol_t protocol, 
+                 gpgme_data_t data, const char *signature,
+                 void *notify_data )
 {
-  struct gpgme_data_cbs cbs;
-  gpgme_data_t data = NULL;
-  gpgme_data_t sig = NULL;
-  gpgme_ctx_t ctx = NULL;
   gpgme_error_t err;
-  gpgme_verify_result_t res = NULL;
+  closure_data_t cld;
+  gpgme_ctx_t ctx = NULL;
+  gpgme_data_t sigobj = NULL;
 
-  memset (&cbs, 0, sizeof cbs);
-  cbs.read = stream_read_cb;
-  cbs.write = stream_write_cb;
+  cld = xcalloc (1, sizeof *cld);
+  cld->closure = verify_closure;
+  cld->filter = notify_data;
 
-  op_gpgme_init ();
-
   err = gpgme_new (&ctx);
   if (err)
     goto leave;
 
-  err = gpgme_data_new_from_cbs (&data, &cbs, data_stream);
-  if (err)
-    goto leave;
-
-  err = gpgme_data_new_from_mem (&sig, sig_string, strlen (sig_string), 0);
-  if (err)
-    goto leave;
-
-  err = gpgme_op_verify (ctx, sig, data, NULL);
-  if (!err)
+  gpgme_set_progress_cb (ctx, NULL, cld);
+  switch (protocol)
     {
-      res = gpgme_op_verify_result (ctx);
-      if (res) 
-        verify_dialog_box (gpgme_get_protocol (ctx), res, filename);
-      if (res && attestation)
-        add_verify_attestation (attestation, ctx, res, filename);
+    case PROTOCOL_OPENPGP:  /* Gpgme's default.  */
+      break;
+    case PROTOCOL_SMIME:
+      err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
+      break;
+    default:
+      err = gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+      break;
     }
-
- leave:
-  if (data)
-    gpgme_data_release (data);
-  if (sig)
-    gpgme_data_release (sig);
-  if (ctx)
-    gpgme_release (ctx);
-  return err;
-}
-
-/* Verify a detached message where the data is in the string
-   DATA_STRING and the signature itself is expected to be the string
-   SIG_STRING.  FILENAME will be shown by the verification status
-   dialog box.  If ATTESTATION is not NULL a text with the result of
-   the signature verification will get printed to it.  */ 
-int
-op_verify_detached_sig_mem (const char *data_string,
-                            const char *sig_string, const char *filename,
-                            gpgme_data_t attestation)
-{
-  gpgme_data_t data = NULL;
-  gpgme_data_t sig = NULL;
-  gpgme_ctx_t ctx = NULL;
-  gpgme_error_t err;
-  gpgme_verify_result_t res = NULL;
-
-  op_gpgme_init ();
-
-  err = gpgme_new (&ctx);
   if (err)
     goto leave;
 
-  err = gpgme_data_new_from_mem (&data, data_string, strlen (data_string), 0);
+  err = gpgme_data_new_from_mem (&sigobj, signature, strlen (signature), 0);
   if (err)
     goto leave;
+  cld->sigobj = sigobj;
 
-  err = gpgme_data_new_from_mem (&sig, sig_string, strlen (sig_string), 0);
-  if (err)
-    goto leave;
+  err = gpgme_op_verify_start (ctx, sigobj, data, NULL);
 
-  err = gpgme_op_verify (ctx, sig, data, NULL);
-  if (!err)
+ leave:
+  if (err)
     {
-      res = gpgme_op_verify_result (ctx);
-      if (res) 
-        verify_dialog_box (gpgme_get_protocol (ctx), res, filename);
-      if (res && attestation)
-        add_verify_attestation (attestation, ctx, res, filename);
+      gpgme_data_release (sigobj);
+      xfree (cld);
+      gpgme_release (ctx);
     }
-
- leave:
-  if (data)
-    gpgme_data_release (data);
-  if (sig)
-    gpgme_data_release (sig);
-  if (ctx)
-    gpgme_release (ctx);
   return err;
 }
 
 
-/* Verify a detached message where the data is in the gpgme object
-   DATA and the signature is the gpgme object SIG.  FILENAME will be
-   shown by the verification status dialog box.  If ATTESTATION is not
-   NULL a text with the result of the signature verification will get
-   printed to it.  */ 
-int
-op_verify_detached_sig_gpgme (gpgme_protocol_t protocol, 
-                              gpgme_data_t data, gpgme_data_t sig,
-                              const char *filename, gpgme_data_t attestation)
-{
-  gpgme_ctx_t ctx = NULL;
-  gpgme_error_t err;
-  gpgme_verify_result_t res = NULL;
 
-  op_gpgme_init ();
 
-  err = gpgme_new (&ctx);
-  if (err)
-    goto leave;
 
-  err = gpgme_set_protocol (ctx, protocol);
-  if (err)
-    goto leave;
-
-  err = gpgme_op_verify (ctx, sig, data, NULL);
-  if (!err)
-    {
-      res = gpgme_op_verify_result (ctx);
-      if (res) 
-        verify_dialog_box (gpgme_get_protocol (ctx), res, filename);
-      if (res && attestation)
-        add_verify_attestation (attestation, ctx, res, filename);
-    }
-
- leave:
-  if (ctx)
-    gpgme_release (ctx);
-  return err;
-}
-
-
 
+#if 0
 static void
 at_puts (gpgme_data_t a, const char *s)
 {
@@ -1613,9 +1022,9 @@
     }
   at_puts (a, "\n");
 }
+#endif
 
 
-
 
 /* Try to find a key for each item in array NAMES. Items not found are
    stored as malloced strings in the newly allocated array UNKNOWN.
@@ -1798,18 +1207,3 @@
     return "????????";
 }
 
-
-const char*
-op_strerror (int err)
-{
-  return gpgme_strerror (err);
-}
-
-
-const char*
-op_strsource (int err)
-{
-  return gpgme_strsource (err);
-}
-
-

Modified: trunk/src/engine.c
===================================================================
--- trunk/src/engine.c	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/engine.c	2007-09-14 15:21:50 UTC (rev 178)
@@ -27,9 +27,8 @@
 #include <time.h>
 #include <errno.h>
 #include <assert.h>
-/*#define WIN32_LEAN_AND_MEAN  uncomment it after remove LPSTREAM*/
+#define WIN32_LEAN_AND_MEAN 
 #include <windows.h>
-#include <objidl.h> /* For LPSTREAM in engine-gpgme.h   FIXME: Remove it.  */
 
 #include "common.h"
 #include "engine.h"
@@ -233,7 +232,7 @@
 }
 
 /* This function is called by the gpgme backend to notify a filter
-   object about the final status of an operation.  It may not be
+   object about the final status of an operation.  It may only be
    called by the engine-gpgme.c module. */
 void
 engine_gpgme_finished (engine_filter_t filter, gpg_error_t status)
@@ -295,7 +294,7 @@
 engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
 {
   gpg_error_t err;
-  size_t nbytes;
+  int nbytes;
 
   log_debug ("%s:%s: enter; filter=%p\n", SRCNAME, __func__, filter); 
   /* Our implementation is for now straightforward without any
@@ -326,11 +325,11 @@
               LeaveCriticalSection (&filter->out.lock);
               return gpg_error (GPG_ERR_EIO);
             }
-          assert (nbytes < filter->out.length && nbytes >= 0);
+          assert (nbytes <= filter->out.length && nbytes >= 0);
           if (nbytes < filter->out.length)
             memmove (filter->out.buffer, filter->out.buffer + nbytes,
                      filter->out.length - nbytes); 
-          filter->out.length =- nbytes;
+          filter->out.length -= nbytes;
         }
       if (!PulseEvent (filter->out.condvar))
         log_error_w32 (-1, "%s:%s: PulseEvent(out) failed", SRCNAME, __func__);
@@ -383,6 +382,17 @@
 }
 
 
+/* Dummy data sink used if caller does not need an output
+   function.  */
+static int
+dummy_outfnc (void *opaque, const void *data, size_t datalen)
+{
+  (void)opaque;
+  (void)data;
+  return (int)datalen;
+}
+
+
 /* Create a new filter object which uses OUTFNC as its data sink.  If
    OUTFNC is called with NULL/0 for the data to be written, the
    function should do a flush.  OUTFNC is expected to return the
@@ -402,7 +412,7 @@
   filter = create_filter ();
   filter->cb_inbound.read = filter_gpgme_read_cb;
   filter->cb_outbound.write = filter_gpgme_write_cb;
-  filter->outfnc = outfnc;
+  filter->outfnc = outfnc? outfnc : dummy_outfnc;
   filter->outfncdata = outfncdata;
 
   err = gpgme_data_new_from_cbs (&filter->indata, 
@@ -449,20 +459,21 @@
       while (filter->out.length)
         {
           int nbytes; 
-          TRACEPOINT ();
+
           nbytes = filter->outfnc (filter->outfncdata, 
                                    filter->out.buffer, filter->out.length);
           if (nbytes == -1)
             {
               log_debug ("%s:%s: error writing data\n", SRCNAME, __func__);
               LeaveCriticalSection (&filter->out.lock);
-              break;
+              return gpg_error (GPG_ERR_EIO);
             }
-          assert (nbytes < filter->out.length && nbytes >= 0);
+          
+          assert (nbytes <= filter->out.length && nbytes >= 0);
           if (nbytes < filter->out.length)
             memmove (filter->out.buffer, filter->out.buffer + nbytes,
                      filter->out.length - nbytes); 
-          filter->out.length =- nbytes;
+          filter->out.length -= nbytes;
         }
       if (!PulseEvent (filter->out.condvar))
         log_error_w32 (-1, "%s:%s: PulseEvent(out) failed", SRCNAME, __func__);
@@ -471,10 +482,10 @@
       more = !filter->in.ready;
       LeaveCriticalSection (&filter->in.lock);
       if (more)
-        Sleep (0);
+        Sleep (100);
     }
   while (more);
-  
+
   if (WaitForSingleObject (filter->in.ready_event, INFINITE) != WAIT_OBJECT_0)
     {
       log_error_w32 (-1, "%s:%s: WFSO failed", SRCNAME, __func__);
@@ -520,30 +531,72 @@
 {
   gpg_error_t err;
 
-  err = op_gpgme_encrypt_data (protocol, filter->indata, filter->outdata,
-                               filter, recipients, NULL, 0);
+  err = op_gpgme_encrypt (protocol, filter->indata, filter->outdata,
+                          filter, recipients, NULL, 0);
   return err;
 }
 
 
-/* Start an detached signing operation.
-   FILTER
-   is an object created by engine_create_filter.  The caller needs to
-   call engine_wait to finish the operation.  A filter object may not
-   be reused after having been used through this function.  However,
-   the lifetime of the filter object lasts until the final engine_wait
-   or engine_cancel.  */
+/* Start an detached signing operation.  FILTER is an object created
+   by engine_create_filter.  The caller needs to call engine_wait to
+   finish the operation.  A filter object may not be reused after
+   having been used through this function.  However, the lifetime of
+   the filter object lasts until the final engine_wait or
+   engine_cancel.  */
 int
 engine_sign_start (engine_filter_t filter, protocol_t protocol)
 {
   gpg_error_t err;
 
-  err = op_gpgme_sign_data (protocol, filter->indata, filter->outdata,
-                            filter);
+  err = op_gpgme_sign (protocol, filter->indata, filter->outdata,
+                       filter);
   return err;
 }
 
 
+/* Start an decrypt operation.  FILTER is an object created by
+   engine_create_filter.  The caller needs to call engine_wait to
+   finish the operation.  A filter object may not be reused after
+   having been used through this function.  However, the lifetime of
+   the filter object lasts until the final engine_wait or
+   engine_cancel.  */
+int
+engine_decrypt_start (engine_filter_t filter, protocol_t protocol,
+                      int with_verify)
+{
+  gpg_error_t err;
 
+  err = op_gpgme_decrypt (protocol, filter->indata, filter->outdata,
+                          filter, with_verify);
+  return err;
+}
 
 
+/* Start a verify operation.  FILTER is an object created by
+   engine_create_filter; an output function is not required. SIGNATURE
+   is the detached signature or NULL if FILTER delivers an opaque
+   signature.  The caller needs to call engine_wait to finish the
+   operation.  A filter object may not be reused after having been
+   used through this function.  However, the lifetime of the filter
+   object lasts until the final engine_wait or engine_cancel.  */
+int
+engine_verify_start (engine_filter_t filter, const char *signature,
+                     protocol_t protocol)
+{
+  gpg_error_t err;
+
+  if (!signature)
+    {
+      log_error ("%s:%s: opaque signature are not yet supported\n",
+                 SRCNAME, __func__);
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
+
+  err = op_gpgme_verify (protocol, filter->indata, signature, filter);
+  return err;
+}
+
+
+
+
+

Modified: trunk/src/engine.h
===================================================================
--- trunk/src/engine.h	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/engine.h	2007-09-14 15:21:50 UTC (rev 178)
@@ -67,6 +67,10 @@
 int engine_encrypt_start (engine_filter_t filter, 
                           protocol_t protocol, char **recipients);
 int engine_sign_start (engine_filter_t filter, protocol_t protocol);
+int engine_decrypt_start (engine_filter_t filter, protocol_t protocol,
+                          int with_verify);
+int engine_verify_start (engine_filter_t filter, const char *signature,
+                         protocol_t protocol);
 
 
 

Modified: trunk/src/message-events.cpp
===================================================================
--- trunk/src/message-events.cpp	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/message-events.cpp	2007-09-14 15:21:50 UTC (rev 178)
@@ -349,11 +349,11 @@
   if (SUCCEEDED (hr))
     {
       if (m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
-        rc = mime_sign_encrypt (msg, PROTOCOL_OPENPGP);
+        rc = message_sign_encrypt (msg, hWnd);
       else if (m_pExchExt->m_gpgEncrypt && !m_pExchExt->m_gpgSign)
         rc = message_encrypt (msg, hWnd);
       else if (!m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
-        rc = mime_sign (msg, PROTOCOL_OPENPGP);
+        rc = message_sign (msg, hWnd);
       else
         rc = 0;
       

Modified: trunk/src/message.cpp
===================================================================
--- trunk/src/message.cpp	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/message.cpp	2007-09-14 15:21:50 UTC (rev 178)
@@ -229,6 +229,7 @@
   int i;
   char *inbuf;
   size_t inbuflen;
+  protocol_t protocol = PROTOCOL_UNKNOWN;
   int err;
 
   switch (msgtype)
@@ -271,6 +272,7 @@
       rawstream->Release ();
       if (!inbuf)
         return -1;
+      protocol = PROTOCOL_OPENPGP;
     }
   else
     {
@@ -311,8 +313,7 @@
         }
     }
 
-  err = mime_verify (inbuf, inbuflen, message, 0, 
-                     opt.passwd_ttl, NULL, NULL, 0);
+  err = mime_verify (protocol, inbuf, inbuflen, message, 0, 0);
   log_debug ("mime_verify returned %d", err);
   if (err)
     {
@@ -347,7 +348,7 @@
   LPSTREAM cipherstream;
   gpg_error_t err;
   int is_opaque = 0;
-  int is_smime = 0;
+  protocol_t protocol;
 
   switch (msgtype)
     {
@@ -373,6 +374,7 @@
       cipherstream = mapi_get_body_as_stream (message);
       if (!cipherstream)
         goto leave;
+      protocol = PROTOCOL_OPENPGP;
     }
   else
     {
@@ -420,7 +422,7 @@
                          SRCNAME, __func__);
               goto leave;
             }
-          is_smime = 1;
+          protocol = PROTOCOL_SMIME;
         }
       else 
         {
@@ -472,6 +474,7 @@
                          SRCNAME, __func__);
               goto leave;
             }
+          protocol = PROTOCOL_OPENPGP;
         }
       
       cipherstream = mapi_get_attach_as_stream (message, table+part2_idx);
@@ -479,8 +482,7 @@
         goto leave; /* Problem getting the attachment.  */
     }
 
-  err = mime_decrypt (cipherstream, message, is_smime, opt.passwd_ttl,
-                      NULL, NULL, 0);
+  err = mime_decrypt (protocol, cipherstream, message, 0, 0);
   log_debug ("mime_decrypt returned %d (%s)", err, gpg_strerror (err));
   if (err)
     {
@@ -595,183 +597,74 @@
 
 
 
-
-
-
-#if 0
-/* Sign the current message. Returns 0 on success. */
-int
-message_sign (LPMESSAGE message, HWND hwnd, int want_html)
+static int
+sign_encrypt (LPMESSAGE message, HWND hwnd, int signflag)
 {
-  HRESULT hr;
-  STATSTG statinfo;
-  LPSTREAM plaintext;
-  size_t plaintextlen;
-  char *signedtext = NULL;
-  int err = 0;
-  gpgme_key_t sign_key = NULL;
-  SPropValue prop;
-  int have_html_attach = 0;
+  gpg_error_t err;
+  char **recipients;
 
-  log_debug ("%s:%s: enter message=%p\n", SRCNAME, __func__, message);
-  
-  /* We don't sign an empty body - a signature on a zero length string
-     is pretty much useless.  We assume that a HTML message always
-     comes with a text/plain alternative. */
-  plaintext = mapi_get_body_as_stream (message);
-  if (!plaintext)
-    plaintextlen = 0;
-  else
+  recipients = get_recipients (message);
+  if (!recipients || !recipients[0])
     {
-      hr = input->Stat (&statinfo, STATFLAG_NONAME);
-      if (hr)
-        {
-          log_debug ("%s:%s: Stat failed: hr=%#lx", SRCNAME, __func__, hr);
-          plaintext->Release ();
-          return gpg_error (GPG_ERR_GENERAL);
-        }
-      plaintextlen = (size_t)statinfo.cbSize.QuadPart;
-    }
+      MessageBox (hwnd, _("No recipients to encrypt to are given"),
+                  "GpgOL", MB_ICONERROR|MB_OK);
 
-  if ( !plaintextlen && !has_attachments (message)) 
-    {
-      log_debug ("%s:%s: leave (empty)", SRCNAME, __func__);
-      plaintext->Release ();
-      return 0; 
+      err = gpg_error (GPG_ERR_GENERAL);
     }
-
-  /* Pop up a dialog box to ask for the signer of the message. */
-  if (signer_dialog_box (&sign_key, NULL, 0) == -1)
+  else
     {
-      log_debug ("%s.%s: leave (dialog failed)\n", SRCNAME, __func__);
-      plaintext->Release ();
-      return gpg_error (GPG_ERR_CANCELED);  
-    }
-
-  /* Sign the plaintext */
-  if (plaintextlen)
-    {
-      err = op_sign (plaintext, &signedtext, 
-                     OP_SIG_CLEAR, sign_key, opt.passwd_ttl);
+      if (signflag)
+        err = mime_sign_encrypt (message, PROTOCOL_OPENPGP, recipients);
+      else
+        err = mime_encrypt (message, PROTOCOL_OPENPGP, recipients);
       if (err)
         {
-          MessageBox (hwnd, op_strerror (err),
-                      _("Signing Failure"), MB_ICONERROR|MB_OK);
-          plaintext->Release ();
-          return gpg_error (GPG_ERR_GENERAL);
+          char buf[200];
+          
+          snprintf (buf, sizeof buf,
+                    _("Encryption failed (%s)"), gpg_strerror (err));
+          MessageBox (hwnd, buf, "GpgOL", MB_ICONERROR|MB_OK);
         }
     }
+  release_recipient_array (recipients);
+  return err;
+}
 
-  
-  /* If those brain dead html mails are requested we now figure out
-     whether a HTML body is actually available and move it to an
-     attachment so that the code below will sign it as a regular
-     attachments.  */
-  if (want_html)
-    {
-      log_debug ("Signing HTML is not yet supported\n");
-//       char *htmltext = loadBody (true);
-      
-//       if (htmltext && *htmltext)
-//         {
-//           if (!createHtmlAttachment (htmltext))
-//             have_html_attach = 1;
-//         }
-//       xfree (htmltext);
 
-      /* If we got a new attachment we need to release the loaded
-         attachment info so that the next getAttachment call will read
-         fresh info. */
-//       if (have_html_attach)
-//         free_attach_info ();
-    }
+/* Sign the MESSAGE.  */
+int 
+message_sign (LPMESSAGE message, HWND hwnd)
+{
+  gpg_error_t err;
 
-
-  /* Note, there is a side-effect when we have HTML mails: The
-     auto-sign-attch option is ignored.  I regard auto-sign-attach as a
-     silly option anyway. */
-  if ((opt.auto_sign_attach || have_html_attach) && has_attachments ())
+  err = mime_sign (message, PROTOCOL_OPENPGP);
+  if (err)
     {
-      unsigned int n;
+      char buf[200];
       
-      n = getAttachments ();
-      log_debug ("%s:%s: message has %u attachments\n", SRCNAME, __func__, n);
-      for (unsigned int i=0; i < n; i++) 
-        signAttachment (hwnd, i, sign_key, opt.passwd_ttl);
-      /* FIXME: we should throw an error if signing of any attachment
-         failed. */
+      snprintf (buf, sizeof buf,
+                _("Signing failed (%s)"), gpg_strerror (err));
+      MessageBox (hwnd, buf, "GpgOL", MB_ICONERROR|MB_OK);
     }
-
-  set_x_header (message, "GPGOL-VERSION", PACKAGE_VERSION);
-
-  /* Now that we successfully processed the attachments, we can save
-     the changes to the body.  */
-  if (plaintextlen)
-    {
-      err = set_message_body (message, signedtext, 0);
-      if (err)
-        goto leave;
-
-      /* In case we don't have attachments, Outlook will really insert
-         the following content type into the header.  We use this to
-         declare that the encrypted content of the message is utf-8
-         encoded.  If we have atatchments, OUtlook has its own idea of
-         the content type to use.  */
-      prop.ulPropTag=PR_CONTENT_TYPE_A;
-      prop.Value.lpszA="text/plain; charset=utf-8"; 
-      hr = HrSetOneProp (message, &prop);
-      if (hr)
-        log_error ("%s:%s: can't set content type: hr=%#lx\n",
-                   SRCNAME, __func__, hr);
-    }
-  
-  hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
-  if (hr)
-    {
-      log_error ("%s:%s: SaveChanges(message) failed: hr=%#lx\n",
-                 SRCNAME, __func__, hr); 
-      err = gpg_error (GPG_ERR_GENERAL);
-      goto leave;
-    }
-
- leave:
-  xfree (signedtext);
-  gpgme_key_release (sign_key);
-  xfree (plaintext);
-  log_debug ("%s:%s: leave (err=%s)\n", SRCNAME, __func__, op_strerror (err));
   return err;
 }
 
-#endif
 
 
 /* Encrypt the MESSAGE.  */
 int 
 message_encrypt (LPMESSAGE message, HWND hwnd)
 {
-  gpg_error_t err;
-  char **recipients;
+  return sign_encrypt (message, hwnd, 0);
+}
 
-  recipients = get_recipients (message);
-  if (!recipients || !recipients[0])
-    {
-      MessageBox (hwnd, _("No recipients for encrypted message given"),
-                  "GpgOL", MB_ICONERROR|MB_OK);
 
-      err = gpg_error (GPG_ERR_GENERAL);
-    }
-  else
-    {
-      err = mime_encrypt (message, PROTOCOL_OPENPGP, recipients);
-      if (err)
-        {
-          char buf[200];
-          
-          snprintf (buf, sizeof buf,
-                    _("Encryption failed (%s)"), gpg_strerror (err));
-          MessageBox (hwnd, buf, "GpgOL", MB_ICONERROR|MB_OK);
-        }
-    }
-  release_recipient_array (recipients);
-  return err;
+/* Sign+Encrypt the MESSAGE.  */
+int 
+message_sign_encrypt (LPMESSAGE message, HWND hwnd)
+{
+  return sign_encrypt (message, hwnd, 1);
 }
+
+
+

Modified: trunk/src/message.h
===================================================================
--- trunk/src/message.h	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/message.h	2007-09-14 15:21:50 UTC (rev 178)
@@ -26,7 +26,9 @@
 int message_verify (LPMESSAGE message, msgtype_t msgtype, int force);
 int message_decrypt (LPMESSAGE message, msgtype_t msgtype, int force);
 
+int message_sign (LPMESSAGE message, HWND hwnd);
 int message_encrypt (LPMESSAGE message, HWND hwnd);
+int message_sign_encrypt (LPMESSAGE message, HWND hwnd);
 
 
 #endif /*MESSAGE_H*/

Modified: trunk/src/mimemaker.c
===================================================================
--- trunk/src/mimemaker.c	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/mimemaker.c	2007-09-14 15:21:50 UTC (rev 178)
@@ -1484,7 +1484,7 @@
 
 
 int 
-mime_sign_encrypt (LPMESSAGE message, protocol_t protocol)
+mime_sign_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients)
 {
   return -1;
 }

Modified: trunk/src/mimemaker.h
===================================================================
--- trunk/src/mimemaker.h	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/mimemaker.h	2007-09-14 15:21:50 UTC (rev 178)
@@ -30,7 +30,8 @@
 
 int mime_sign (LPMESSAGE message, protocol_t protocol);
 int mime_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients);
-int mime_sign_encrypt (LPMESSAGE message, protocol_t protocol);
+int mime_sign_encrypt (LPMESSAGE message, protocol_t protocol, 
+                       char **recipients);
 
 
 #ifdef __cplusplus

Modified: trunk/src/mimeparser.c
===================================================================
--- trunk/src/mimeparser.c	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/mimeparser.c	2007-09-14 15:21:50 UTC (rev 178)
@@ -761,7 +761,7 @@
 
 
 /* This handler is called by GPGME with the decrypted plaintext. */
-static ssize_t
+static int
 plaintext_handler (void *handle, const void *buffer, size_t size)
 {
   mime_context_t ctx = handle;
@@ -895,20 +895,27 @@
 
 
 
+
 int
-mime_verify (const char *message, size_t messagelen, 
-             LPMESSAGE mapi_message, int is_smime,
-             int ttl, gpgme_data_t attestation, HWND hwnd, int preview_mode)
+mime_verify (protocol_t protocol, const char *message, size_t messagelen, 
+             LPMESSAGE mapi_message, HWND hwnd, int preview_mode)
 {
   gpg_error_t err = 0;
   mime_context_t ctx;
   const char *s;
   size_t len;
+  char *signature = NULL;
+  engine_filter_t filter = NULL;
 
-  (void)is_smime;  /* Not yet used.  */
-
-  log_debug ("%s:%s: enter", SRCNAME, __func__);
-
+  /* Note: PROTOCOL is not used here but figured out directly while
+     collecting the message.  Eventually it might help use setup a
+     proper verification context right at startup to avoid collecting
+     all the stuff.  However there are a couple of problems with that
+     - for example we don't know whether gpgsm behaves correctly by
+     first reading all the data and only the reading the signature.  I
+     guess it is the case but that needs to be checked first.  It is
+     just a performance issue.  */
+ 
   ctx = xcalloc (1, sizeof *ctx + LINEBUFSIZE);
   ctx->linebufsize = LINEBUFSIZE;
   ctx->hwnd = hwnd;
@@ -943,54 +950,67 @@
     }
   /* Note: the last character should be a LF, if not we ignore such an
      incomplete last line.  */
+  if (ctx->sig_data && gpgme_data_write (ctx->sig_data, "", 1) == 1)
+    {
+      signature = gpgme_data_release_and_get_mem (ctx->sig_data, NULL);
+      ctx->sig_data = NULL; 
+    }
 
-
   /* Now actually verify the signature. */
-  if (!err && ctx->signed_data && ctx->sig_data)
+  if (!err && ctx->signed_data && signature)
     {
-      char *tmp;
-      gpgme_protocol_t xprot;
-      int inv_prot = 0;
+      gpgme_data_seek (ctx->signed_data, 0, SEEK_SET);
+      
+      if ((err=engine_create_filter (&filter, NULL, NULL)))
+        goto leave;
+      if ((err=engine_verify_start (filter, signature, ctx->protocol)))
+        goto leave;
 
-      gpgme_data_seek (ctx->signed_data, 0, SEEK_SET);
-      gpgme_data_seek (ctx->sig_data, 0, SEEK_SET);
-      if (ctx->protocol == PROTOCOL_OPENPGP)
+      /* Filter the data.  */
+      do
         {
-          tmp = native_to_utf8 (_("[OpenPGP signature]"));
-          xprot = GPGME_PROTOCOL_OpenPGP;
+          int nread;
+          char buffer[4096];
+          
+          nread = gpgme_data_read (ctx->signed_data, buffer, sizeof buffer);
+          if (nread < 0)
+            {
+              err = gpg_error_from_syserror ();
+              log_error ("%s:%s: gpgme_data_read failed: %s", 
+                         SRCNAME, __func__, gpg_strerror (err));
+            }
+          else if (nread)
+            {
+              TRACEPOINT();
+              err = engine_filter (filter, buffer, nread);
+            }
+          else
+            break; /* EOF */
         }
-      else if (ctx->protocol == PROTOCOL_SMIME)
-        {
-          tmp = native_to_utf8 (_("[S/MIME signature]"));
-          xprot = GPGME_PROTOCOL_CMS;
-        }
-      else
-        {
-          tmp = native_to_utf8 (_("[Unknown signature protocol]"));
-          inv_prot = 1;
-        }
-
-      err = (inv_prot
-             ? gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL)
-             : op_verify_detached_sig_gpgme (xprot,
-                                             ctx->signed_data, ctx->sig_data,
-                                             tmp, attestation));
-      log_debug ("%s:%s: checked signature: %s <%s>", 
-                 SRCNAME, __func__, gpg_strerror (err), op_strsource (err));
-      xfree (tmp);
+      while (!err);
+      if (err)
+        goto leave;
+      
+      /* Wait for the engine to finish.  */
+      if ((err = engine_filter (filter, NULL, 0)))
+        goto leave;
+      if ((err = engine_wait (filter)))
+        goto leave;
+      filter = NULL;
     }
 
 
  leave:
+  TRACEPOINT();
+  gpgme_free (signature);
+  engine_cancel (filter);
   if (ctx)
     {
       /* Cancel any left open attachment.  */
       finish_attachment (ctx, 1); 
       rfc822parse_close (ctx->msg);
-      if (ctx->signed_data)
-        gpgme_data_release (ctx->signed_data);
-      if (ctx->sig_data)
-        gpgme_data_release (ctx->sig_data);
+      gpgme_data_release (ctx->signed_data);
+      gpgme_data_release (ctx->sig_data);
       show_mimestruct (ctx->mimestruct);
       while (ctx->mimestruct)
         {
@@ -1008,27 +1028,20 @@
 
 
 
-/* Decrypt the PGP or S/MIME message taken from INSTREAM.  If
-   ATTESTATION is not NULL a text with the result of the signature
-   verification will get printed to it.  HWND is the window to be used
-   for message box and such.  In PREVIEW_MODE no verification will be
-   done, no messages saved and no messages boxes will pop up. */
+/* Decrypt the PGP or S/MIME message taken from INSTREAM.  HWND is the
+   window to be used for message box and such.  In PREVIEW_MODE no
+   verification will be done, no messages saved and no messages boxes
+   will pop up. */
 int
-mime_decrypt (LPSTREAM instream, LPMESSAGE mapi_message, int is_smime,
-              int ttl, gpgme_data_t attestation, HWND hwnd, int preview_mode)
+mime_decrypt (protocol_t protocol, LPSTREAM instream, LPMESSAGE mapi_message,
+              HWND hwnd, int preview_mode)
 {
   gpg_error_t err;
-  struct gpgme_data_cbs cbs;
-  gpgme_data_t plaintext;
   mime_context_t ctx;
-  char *title;
-  gpgme_protocol_t proto;
+  engine_filter_t filter = NULL;
 
-  log_debug ("%s:%s: enter", SRCNAME, __func__);
+  log_debug ("%s:%s: enter (protocol=%d)", SRCNAME, __func__, protocol);
 
-  memset (&cbs, 0, sizeof cbs);
-  cbs.write = plaintext_handler;
-
   ctx = xcalloc (1, sizeof *ctx + LINEBUFSIZE);
   ctx->linebufsize = LINEBUFSIZE;
   ctx->protect_mode = 1; 
@@ -1046,30 +1059,61 @@
       goto leave;
     }
 
-  err = gpgme_data_new_from_cbs (&plaintext, &cbs, ctx);
-  if (err)
+  /* Prepare the decryption.  */
+/*       title = native_to_utf8 (_("[Encrypted S/MIME message]")); */
+/*       title = native_to_utf8 (_("[Encrypted PGP/MIME message]")); */
+  if ((err=engine_create_filter (&filter, plaintext_handler, ctx)))
     goto leave;
+  if ((err=engine_decrypt_start (filter, protocol, !preview_mode)))
+    goto leave;
 
-  if (is_smime)
+  
+  /* Filter the stream.  */
+  do
     {
-      proto = GPGME_PROTOCOL_CMS;
-      title = native_to_utf8 (_("[Encrypted S/MIME message]"));
+      HRESULT hr;
+      ULONG nread;
+      char buffer[4096];
+      
+      /* For EOF detection we assume that Read returns no error and
+         thus nread will be 0.  The specs say that "Depending on the
+         implementation, either S_FALSE or an error code could be
+         returned when reading past the end of the stream"; thus we
+         are not really sure whether our assumption is correct.  At
+         another place the documentation says that the implementation
+         used by ISequentialStream exhibits the same EOF behaviour has
+         found on the MSDOS FAT file system.  So we seem to have good
+         karma. */
+      hr = IStream_Read (instream, buffer, sizeof buffer, &nread);
+      if (hr)
+        {
+          log_error ("%s:%s: IStream::Read failed: hr=%#lx", 
+                     SRCNAME, __func__, hr);
+          err = gpg_error (GPG_ERR_EIO);
+        }
+      else if (nread)
+        {
+          err = engine_filter (filter, buffer, nread);
+        }
+      else
+        break; /* EOF */
     }
-  else
-    {
-      proto = GPGME_PROTOCOL_OpenPGP;
-      title = native_to_utf8 (_("[Encrypted PGP/MIME message]"));
-    }
-  err = op_decrypt_stream_to_gpgme (proto, instream, plaintext, ttl, title,
-                                    attestation, preview_mode);
-  xfree (title);
-  if (!err && (ctx->parser_error || ctx->line_too_long))
+  while (!err);
+  if (err)
+    goto leave;
+
+  /* Wait for the engine to finish.  */
+  if ((err = engine_filter (filter, NULL, 0)))
+    goto leave;
+  if ((err = engine_wait (filter)))
+    goto leave;
+  filter = NULL;
+
+  if (ctx->parser_error || ctx->line_too_long)
     err = gpg_error (GPG_ERR_GENERAL);
 
-
  leave:
-  if (plaintext)
-    gpgme_data_release (plaintext);
+  engine_cancel (filter);
   if (ctx)
     {
       /* Cancel any left over attachment which means that the MIME

Modified: trunk/src/mimeparser.h
===================================================================
--- trunk/src/mimeparser.h	2007-09-13 11:53:15 UTC (rev 177)
+++ trunk/src/mimeparser.h	2007-09-14 15:21:50 UTC (rev 178)
@@ -29,13 +29,12 @@
 #endif
 
 
-int mime_verify (const char *message, size_t messagelen, 
-                 LPMESSAGE mapi_message, int is_smime,
-                 int ttl, 
-                 gpgme_data_t attestation, HWND hwnd, int preview_mode);
-int mime_decrypt (LPSTREAM instream, LPMESSAGE mapi_message, int is_smime,
-                  int ttl,
-                  gpgme_data_t attestation, HWND hwnd, int preview_mode);
+int mime_verify (protocol_t protocol, const char *message, size_t messagelen, 
+                 LPMESSAGE mapi_message, 
+                 HWND hwnd, int preview_mode);
+int mime_decrypt (protocol_t protocol, 
+                  LPSTREAM instream, LPMESSAGE mapi_message,
+                  HWND hwnd, int preview_mode);
 
 
 #ifdef __cplusplus




More information about the Gnupg-commits mailing list