More polishing.
authorWerner Koch <wk@gnupg.org>
Thu, 20 Sep 2007 13:37:50 +0000 (13:37 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 20 Sep 2007 13:37:50 +0000 (13:37 +0000)
21 files changed:
src/ChangeLog
src/Makefile.am
src/engine-assuan.c
src/engine-assuan.h
src/engine-gpgme.c
src/engine.c
src/engine.h
src/ext-commands.cpp
src/item-events.cpp
src/mapihelp.cpp
src/mapihelp.h
src/message-events.cpp
src/message.cpp
src/mimemaker.c
src/mimeparser.c
src/mymapi.h
src/olflange-def.h
src/olflange.cpp
src/olflange.h
src/user-events.cpp [new file with mode: 0644]
src/user-events.h [new file with mode: 0644]

index 6968dbe..542109b 100644 (file)
@@ -1,3 +1,32 @@
+2007-09-20  Werner Koch  <wk@g10code.com>
+
+       * user-events.cpp, user-events.h:  New.
+       * olflange.h (class GpgolExt): Add member for it.
+       * olflange.cpp (QueryInterface): Hook it in.
+
+2007-09-19  Werner Koch  <wk@g10code.com>
+
+       * mapihelp.cpp (mapi_has_sig_status): Return true if any sig
+       status is present.
+       (mapi_test_sig_status): New. Take semantics of the former
+       mapi_has_sig_status.  Changed all callers.
+       (mapi_change_message_class): Set sign status to n/a for other
+       message classed.
+       * mimemaker.c (finalize_message): Mark created messages.
+       (write_buffer_for_cb): Rename from write_buffer_voidarg and return
+       number of bytes written.
+       (collect_signature): Return number of bytes written.
+       
+       * mapihelp.h (struct mapi_attach_item_s): New member
+       PRIVATE_MAPITABLE.
+       * mapihelp.cpp (mapi_create_attach_table) 
+       (mapi_release_attach_table): Keep the mapi table oben and put
+       PR_ATATCH_NUM into the MAPIPOS member.
+       (mapi_get_gpgol_body_attachment): Use PR_ATATCH_NUM.
+
+       * mimeparser.c (finish_message): New.
+       (mime_decrypt, mime_verify): Call it.
+
 2007-09-17  Werner Koch  <wk@g10code.com>
 
        * olflange.cpp: Print gpgme version.
index 25fcd34..0eac801 100644 (file)
@@ -50,6 +50,7 @@ gpgol_SOURCES = \
        serpent.c serpent.h         \
         vasprintf.c                 \
        ext-commands.cpp ext-commands.h       \
+       user-events.cpp     user-events.h     \
        session-events.cpp  session-events.h  \
        message-events.cpp  message-events.h  \
        attached-file-events.cpp attached-file-events.h \
index 6228124..7840ecf 100644 (file)
@@ -1,5 +1,5 @@
-/* engine-assuan.c - Crypto engine suing an Assuan server
- *     Copyright (C) 2005, 2006, 1007 g10 Code GmbH
+/* engine-assuan.c - Crypto engine using an Assuan server
+ *     Copyright (C) 2007 g10 Code GmbH
  *
  * This file is part of GpgOL.
  *
  * 02110-1301, USA.
  */
 
-/* Please note that we assume UTF-8 strings everywhere except when
-   noted. */
-   
-#if 0
 #include <config.h>
 
 #include <stdio.h>
 #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"
 #include "engine.h"
+#include "engine-assuan.h"
+
 
 #define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
                                        SRCNAME, __func__, __LINE__); \
                         } while (0)
 
 
-static char *debug_file = NULL;
-static int init_done = 0;
+/* 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.  */
+};
+
 
+static int init_done = 0;
 
-static void add_verify_attestation (gpgme_data_t at, 
-                                    gpgme_ctx_t ctx, 
-                                    gpgme_verify_result_t res,
-                                    const char *filename);
 
+static DWORD WINAPI pipe_worker_thread (void *dummy);
 
 
 static void
 cleanup (void)
 {
-  if (debug_file)
-    {
-      xfree (debug_file);
-      debug_file = NULL;
-    }
-}
-
-
-/* Enable or disable the debug mode. */
-void
-op_set_debug_mode (int val, const char *file)
-{
-  cleanup ();
-  /* FIXME: Enable assuan debugging. */
+  /* Fixme: We should stop the thread.  */
 }
 
 
 /* Cleanup static resources. */
 void
-op_deinit (void)
+op_assuan_deinit (void)
 {
   cleanup ();
 }
 
 
-/* Initialize this operation subsystem. */
-int
-op_init (void)
-{
-  if (init_done == 1)
-    return 0;
-
-  /*FIXME*/
-
-
-  init_done = 1;
-  return 0;
-}
-
-
-/* The read callback used by Assuan 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 Assuan 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;
-}
-
-
-
-\f
-/* Try to figure out why the encryption failed and provide a more
-   suitable error code than the one returned by the encryption
-   routine. */
-static gpgme_error_t
-check_encrypt_result (gpgme_ctx_t ctx, gpgme_error_t err)
-{
-  gpgme_encrypt_result_t res;
-
-  res = 0 /*gpgme_op_encrypt_result (ctx)*/;
-  if (!res)
-    return err;
-  if (res->invalid_recipients != NULL)
-    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. */
+/* Initialize this system. */
 int
-op_encrypt (const char *inbuf, char **outbuf, gpgme_key_t *keys,
-            gpgme_key_t sign_key, int ttl)
+op_assuan_init (void)
 {
-  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_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;
-}
-
-\f
-/* 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)
-{
-  struct passphrase_cb_s cb;
-  gpgme_error_t err;
-  gpgme_data_t in = NULL;
-  gpgme_data_t out = NULL;
-  gpgme_ctx_t ctx = NULL;
-
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 0;
-
-  *outbuf = NULL;
-  op_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;
+  if (init_done)
+    return 0;
 
-  err = gpgme_data_new_from_cbs (&in, &cbs, instream);
-  if (err)
-    goto fail;
+  /* FIXME: Connect to the server and return failure if it is not
+     possible.  */
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
-  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);
+  /* Fire up the pipe worker thread. */
+  {
+    HANDLE th;
+    DWORD tid;
 
-  if (mode == GPGME_SIG_MODE_CLEAR)
-    gpgme_set_textmode (ctx, 1);
-  gpgme_set_armor (ctx, 1);
+    th = CreateThread (NULL, 128*1024, pipe_worker_thread, NULL, 0, &tid);
+    if (th == INVALID_HANDLE_VALUE)
+      log_error ("failed to start the piper worker thread\n");
+    else
+      CloseHandle (th);
+  }
 
-  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;
+  init_done = 1; 
+  return 0;
 }
 
 
-\f
-/* 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)
+/* The worker thread which feeds the pipes.  */
+static DWORD WINAPI
+pipe_worker_thread (void *dummy)
 {
-  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_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) 
-    ;
-  else if (!err) 
-    {
-      /* Decryption succeeded.  Store the result at OUTBUF. */
-      gpgme_verify_result_t res;
+  gpg_error_t err;
+  void *a_voidptr;
+  closure_data_t closure_data;
 
-      /* 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; 
-        }
+  (void)dummy;
 
-      /* Now check the state of any signature. */
-      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
+  for (;;)
     {
-      /* Decryption failed for other reasons. */
+      Sleep (1000);
     }
-
-
-  /* If the callback indicated a cancel operation, set the error
-     accordingly. */
-  if (err && (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;
 }
 
 
-/* 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;
-  gpgme_error_t err;
-  
-  memset (&cb, 0, sizeof cb);
-  cb.ttl = ttl;
-  cb.decrypt_cmd = 1;
-
-  err = gpgme_new (&ctx);
-  if (err)
-    goto fail;
-
-  err = gpgme_set_protocol (ctx, protocol);
-  if (err)
-    goto fail;
-
-  /* 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);
 
-  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) 
-    ;
-  else if (!err) 
-    {
-      gpgme_verify_result_t res;
 
-      /* 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)
+/* Not that this closure is called in the context of the
+   waiter_thread.  */
+static void
+encrypt_closure (closure_data_t cld, gpg_error_t err)
 {
-  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;
+  engine_private_finished (cld->filter, 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;
+/* 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
+   encryption command engine_gpgme_finished() is called with
+   NOTIFY_DATA as the first argument.  
 
-  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)
-    {
-      /* 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; 
-        }
-    }
-
-  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;
-}
-
-
-\f
-/* 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. */
+   This global function is used to avoid allocating an extra context
+   just for this notification.  We abuse the gpgme_set_progress_cb
+   value for storing the pointer with the gpgme context.  */
 int
-op_verify (const char *inbuf, char **outbuf, const char *filename,
-           gpgme_data_t attestation)
+op_assuan_encrypt (protocol_t protocol, 
+                   gpgme_data_t indata, gpgme_data_t outdata,
+                   void *notify_data, /* FIXME: Add hwnd */
+                   char **recipients)
 {
-  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;
+  gpg_error_t err;
+  closure_data_t cld;
 
-  op_init ();
+  cld = xcalloc (1, sizeof *cld);
+  cld->closure = encrypt_closure;
+  cld->filter = notify_data;
 
-  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; 
-            }
-       }
-      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 (out)
-    gpgme_data_release (out);
-  if (in)
-    gpgme_data_release (in);
-  if (ctx)
-    gpgme_release (ctx);
-  return 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.  */ 
-int
-op_verify_detached_sig (LPSTREAM data_stream,
-                        const char *sig_string, const char *filename,
-                        gpgme_data_t attestation)
-{
-  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;
-
-  memset (&cbs, 0, sizeof cbs);
-  cbs.read = stream_read_cb;
-  cbs.write = stream_write_cb;
-
-  op_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)
-    {
-      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 (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_init ();
-
-  err = gpgme_new (&ctx);
-  if (err)
-    goto leave;
-
-  err = gpgme_data_new_from_mem (&data, data_string, strlen (data_string), 0);
-  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)
-    {
-      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);
-    }
+  /* FIXME:  We should not hardcode always trust. */
+/*   if (sign_key) */
+/*     { */
+/*       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); */
+/*     } */
+/*   else */
+/*     err = gpgme_op_encrypt_start (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST,  */
+/*                                   indata, outdata); */
+
+  err = -1;
 
  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_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);
+      xfree (cld);
     }
-
- leave:
-  if (ctx)
-    gpgme_release (ctx);
   return err;
 }
 
 
-\f
-static void
-at_puts (gpgme_data_t a, const char *s)
-{
-  gpgme_data_write (a, s, strlen (s));
-}
-
-static void 
-at_print_time (gpgme_data_t a, time_t t)
-{
-  char buf[200];
-
-  strftime (buf, sizeof (buf)-1, "%c", localtime (&t));
-  at_puts (a, buf);
-}
-
-static void 
-at_fingerprint (gpgme_data_t a, gpgme_key_t key)
-{
-  const char *s;
-  int i, is_pgp;
-  char *buf, *p;
-  const char *prefix = _("Fingerprint: ");
-
-  if (!key)
-    return;
-  s = key->subkeys ? key->subkeys->fpr : NULL;
-  if (!s)
-    return;
-  is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
-
-  buf = xmalloc ( strlen (prefix) + strlen(s) * 4 + 2 );
-  p = stpcpy (buf, prefix);
-  if (is_pgp && strlen (s) == 40)
-    { 
-      /* v4 style formatted. */
-      for (i=0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
-        {
-          *p++ = s[0];
-          *p++ = s[1];
-          *p++ = s[2];
-          *p++ = s[3];
-          *p++ = ' ';
-          if (i == 4)
-            *p++ = ' ';
-        }
-    }
-  else
-    { 
-      /* v3 style or X.509 formatted. */
-      for (i=0; *s && s[1] && s[2]; s += 2, i++)
-        {
-          *p++ = s[0];
-          *p++ = s[1];
-          *p++ = is_pgp? ' ':':';
-          if (is_pgp && i == 7)
-            *p++ = ' ';
-        }
-    }
-
-  /* Just in case print remaining odd digits */
-  for (; *s; s++)
-    *p++ = *s;
-  *p++ = '\n';
-  *p = 0;
-  at_puts (a, buf);
-  xfree (buf);
-}
-
-
-/* Print common attributes of the signature summary SUM.  Returns
-   true if a severe warning has been encountered. */
-static int 
-at_sig_summary (gpgme_data_t a,  
-                unsigned long sum, gpgme_signature_t sig, gpgme_key_t key)
-{
-  int severe = 0;
-
-  if ((sum & GPGME_SIGSUM_VALID))
-    at_puts (a, _("This signature is valid\n"));
-  if ((sum & GPGME_SIGSUM_GREEN))
-    at_puts (a, _("signature state is \"green\"\n"));
-  if ((sum & GPGME_SIGSUM_RED))
-    at_puts (a, _("signature state is \"red\"\n"));
-
-  if ((sum & GPGME_SIGSUM_KEY_REVOKED))
-    {
-      at_puts (a, _("Warning: One of the keys has been revoked\n"));
-      severe = 1;
-    }
-  
-  if ((sum & GPGME_SIGSUM_KEY_EXPIRED))
-    {
-      time_t t = key->subkeys->expires ? key->subkeys->expires : 0;
-
-      if (t)
-        {
-          at_puts (a, _("Warning: The key used to create the "
-                        "signature expired at: "));
-          at_print_time (a, t);
-          at_puts (a, "\n");
-        }
-      else
-        at_puts (a, _("Warning: At least one certification key "
-                      "has expired\n"));
-    }
-
-  if ((sum & GPGME_SIGSUM_SIG_EXPIRED))
-    {
-      at_puts (a, _("Warning: The signature expired at: "));
-      at_print_time (a, sig ? sig->exp_timestamp : 0);
-      at_puts (a, "\n");
-    }
-
-  if ((sum & GPGME_SIGSUM_KEY_MISSING))
-    at_puts (a, _("Can't verify due to a missing key or certificate\n"));
-
-  if ((sum & GPGME_SIGSUM_CRL_MISSING))
-    {
-      at_puts (a, _("The CRL is not available\n"));
-      severe = 1;
-    }
-
-  if ((sum & GPGME_SIGSUM_CRL_TOO_OLD))
-    {
-      at_puts (a, _("Available CRL is too old\n"));
-      severe = 1;
-    }
-
-  if ((sum & GPGME_SIGSUM_BAD_POLICY))
-    at_puts (a, _("A policy requirement was not met\n"));
-
-  if ((sum & GPGME_SIGSUM_SYS_ERROR))
-    {
-      const char *t0 = NULL, *t1 = NULL;
-
-      at_puts (a, _("A system error occured"));
-
-      /* Try to figure out some more detailed system error information. */
-      if (sig)
-       {
-         t0 = "";
-         t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
-       }
-
-      if (t0 || t1)
-        {
-          at_puts (a, ": ");
-          if (t0)
-            at_puts (a, t0);
-          if (t1 && !(t0 && !strcmp (t0, t1)))
-            {
-              if (t0)
-                at_puts (a, ",");
-              at_puts (a, t1);
-            }
-        }
-      at_puts (a, "\n");
-    }
-
-  return severe;
-}
-
-
-/* Print the validity of a key used for one signature. */
-static void 
-at_sig_validity (gpgme_data_t a, gpgme_signature_t sig)
-{
-  const char *txt = NULL;
-
-  switch (sig ? sig->validity : 0)
-    {
-    case GPGME_VALIDITY_UNKNOWN:
-      txt = _("WARNING: We have NO indication whether "
-              "the key belongs to the person named "
-              "as shown above\n");
-      break;
-    case GPGME_VALIDITY_UNDEFINED:
-      break;
-    case GPGME_VALIDITY_NEVER:
-      txt = _("WARNING: The key does NOT BELONG to "
-              "the person named as shown above\n");
-      break;
-    case GPGME_VALIDITY_MARGINAL:
-      txt = _("WARNING: It is NOT certain that the key "
-              "belongs to the person named as shown above\n");
-      break;
-    case GPGME_VALIDITY_FULL:
-    case GPGME_VALIDITY_ULTIMATE:
-      txt = NULL;
-      break;
-    }
-
-  if (txt)
-    at_puts (a, txt);
-}
-
-
-/* Print a text with the attestation of the signature verification
-   (which is in RES) to A.  FILENAME may also be used in the
-   attestation. */
-static void
-add_verify_attestation (gpgme_data_t a, gpgme_ctx_t ctx,
-                        gpgme_verify_result_t res, const char *filename)
-{
-  time_t created;
-  const char *fpr, *uid;
-  gpgme_key_t key = NULL;
-  int i, anybad = 0, anywarn = 0;
-  unsigned int sum;
-  gpgme_user_id_t uids = NULL;
-  gpgme_signature_t sig;
-  gpgme_error_t err;
-
-  if (!gpgme_data_seek (a, 0, SEEK_CUR))
-    {
-      /* Nothing yet written to the stream.  Insert the current time. */
-      at_puts (a, _("Verification started at: "));
-      at_print_time (a, time (NULL));
-      at_puts (a, "\n\n");
-    }
-
-  at_puts (a, _("Verification result for: "));
-  at_puts (a, filename ? filename : _("[unnamed part]"));
-  at_puts (a, "\n");
-  if (res)
-    {
-      for (sig = res->signatures; sig; sig = sig->next)
-        {
-          created = sig->timestamp;
-          fpr = sig->fpr;
-          sum = sig->summary;
-
-          if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
-            anybad = 1;
-
-          err = gpgme_get_key (ctx, fpr, &key, 0);
-          uid = !err && key->uids && key->uids->uid ? key->uids->uid : "[?]";
-
-          if ((sum & GPGME_SIGSUM_GREEN))
-            {
-              at_puts (a, _("Good signature from: "));
-              at_puts (a, uid);
-              at_puts (a, "\n");
-              for (i = 1, uids = key->uids; uids; i++, uids = uids->next)
-                {
-                  if (uids->revoked)
-                    continue;
-                  at_puts (a, _("                aka: "));
-                  at_puts (a, uids->uid);
-                  at_puts (a, "\n");
-                }
-              at_puts (a, _("            created: "));
-              at_print_time (a, created);
-              at_puts (a, "\n");
-              if (at_sig_summary (a, sum, sig, key))
-                anywarn = 1;
-              at_sig_validity (a, sig);
-            }
-          else if ((sum & GPGME_SIGSUM_RED))
-            {
-              at_puts (a, _("*BAD* signature claimed to be from: "));
-              at_puts (a, uid);
-              at_puts (a, "\n");
-              at_sig_summary (a, sum, sig, key);
-            }
-          else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
-            { /* We can't decide (yellow) but this is a PGP key with a
-                 good signature, so we display what a PGP user
-                 expects: The name, fingerprint and the key validity
-                 (which is neither fully or ultimate). */
-              at_puts (a, _("Good signature from: "));
-              at_puts (a, uid);
-              at_puts (a, "\n");
-              at_puts (a, _("            created: "));
-              at_print_time (a, created);
-              at_puts (a, "\n");
-              at_sig_validity (a, sig);
-              at_fingerprint (a, key);
-              if (at_sig_summary (a, sum, sig, key))
-                anywarn = 1;
-            }
-          else /* can't decide (yellow) */
-            {
-              at_puts (a, _("Error checking signature"));
-              at_puts (a, "\n");
-              at_sig_summary (a, sum, sig, key);
-            }
-          
-          gpgme_key_release (key);
-        }
-
-      if (!anybad )
-        {
-          gpgme_sig_notation_t notation;
-          
-          for (sig = res->signatures; sig; sig = sig->next)
-            {
-              if (!sig->notations)
-                continue;
-              at_puts (a, _("*** Begin Notation (signature by: "));
-              at_puts (a, sig->fpr);
-              at_puts (a, ") ***\n");
-              for (notation = sig->notations; notation;
-                   notation = notation->next)
-                {
-                  if (notation->name)
-                    {
-                      at_puts (a, notation->name);
-                      at_puts (a, "=");
-                    }
-                  if (notation->value)
-                    {
-                      at_puts (a, notation->value);
-                      if (!(*notation->value
-                            && (notation->value[strlen (notation->value)-1]
-                                =='\n')))
-                        at_puts (a, "\n");
-                    }
-                }
-              at_puts (a, _("*** End Notation ***\n"));
-            }
-       }
-    }
-  at_puts (a, "\n");
-}
-
-
-
-\f
-/* 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.
-   Found keys are stored in the newly allocated array KEYS.  Both
-   arrays are terminated by a NULL entry.  Caller needs to release
-   KEYS and UNKNOWN.
-
-   Returns: 0 on success. However success may also be that one or all
-   keys are unknown.
-*/
-int 
-op_lookup_keys (char **names, gpgme_key_t **keys, char ***unknown)
-{
-  gpgme_error_t err;
-  gpgme_ctx_t ctx;
-  size_t n;
-  int i, kpos, upos;
-  gpgme_key_t k, k2;
-
-  *keys = NULL;
-  *unknown = NULL;
-
-  err = gpgme_new (&ctx);
-  if (err)
-    return -1; /* Error. */
-
-  for (n=0; names[n]; n++)
-    ;
-
-  *keys =  xcalloc (n+1, sizeof *keys);
-  *unknown = xcalloc (n+1, sizeof *unknown);
-
-  for (i=kpos=upos=0; names[i]; i++)
-    {
-      k = NULL;
-      err = gpgme_op_keylist_start (ctx, names[i], 0);
-      if (!err)
-        {
-          err = gpgme_op_keylist_next (ctx, &k);
-          if (!err && !gpgme_op_keylist_next (ctx, &k2))
-            {
-              /* More than one matching key available.  Take this one
-                 as unknown. */
-              gpgme_key_release (k);
-              gpgme_key_release (k2);
-              k = k2 = NULL;
-            }
-        }
-      gpgme_op_keylist_end (ctx);
-
-      
-      /* only useable keys will be added otherwise they will be stored
-         in unknown (marked with their status). */
-      if (k && !k->revoked && !k->disabled && !k->expired)
-        (*keys)[kpos++] = k;
-      else if (k)
-       {
-         char *p, *fmt = "%s (%s)";
-         char *warn = k->revoked? "revoked" : k->expired? "expired" : "disabled";
-         
-         p = xcalloc (1, strlen (names[i]) + strlen (warn) + strlen (fmt) +1);
-         sprintf (p, fmt, names[i], warn);
-         (*unknown)[upos++] = p;
-         gpgme_key_release (k);
-       }
-      else if (!k)
-        (*unknown)[upos++] = xstrdup (names[i]);
-    }
-
-  gpgme_release (ctx);
-  return 0;
-}
-
-
-/* Return a GPGME key object matching PATTERN.  If no key matches or
-   the match is ambiguous, return NULL. */
-gpgme_key_t 
-op_get_one_key (char *pattern)
-{
-  gpgme_error_t err;
-  gpgme_ctx_t ctx;
-  gpgme_key_t k, k2;
-
-  err = gpgme_new (&ctx);
-  if (err)
-    return NULL; /* Error. */
-  err = gpgme_op_keylist_start (ctx, pattern, 0);
-  if (!err)
-    {
-      err = gpgme_op_keylist_next (ctx, &k);
-      if (!err && !gpgme_op_keylist_next (ctx, &k2))
-        {
-          /* More than one matching key available.  Return an error
-             instead. */
-          gpgme_key_release (k);
-          gpgme_key_release (k2);
-          k = k2 = NULL;
-        }
-    }
-  gpgme_op_keylist_end (ctx);
-  gpgme_release (ctx);
-  return k;
-}
-
-
-/* Copy the data from the GPGME object DAT to a newly created file
-   with name OUTFILE.  Returns 0 on success. */
-static gpgme_error_t
-data_to_file (gpgme_data_t *dat, const char *outfile)
-{
-  FILE *out;
-  char *buf;
-  size_t n=0;
-
-  out = fopen (outfile, "wb");
-  if (!out)
-    return GPG_ERR_UNKNOWN_ERRNO; /* FIXME: We need to check why we
-                                     can't use errno here. */
-  /* FIXME: Why at all are we using an in memory object wqhen we are
-     later going to write to a file anyway. */
-  buf = gpgme_data_release_and_get_mem (*dat, &n);
-  *dat = NULL;
-  if (!n)
-    {
-      fclose (out);
-      return GPG_ERR_EOF; /* FIXME:  wrap this into a gpgme_error() */
-    }
-  fwrite (buf, 1, n, out);
-  fclose (out);
-  /* FIXME: We have no error checking above. */
-  gpgme_free (buf);
-  return 0;
-}
-
-
-int
-op_export_keys (const char *pattern[], const char *outfile)
-{      
-    /* @untested@ */
-    gpgme_ctx_t ctx=NULL;
-    gpgme_data_t  out=NULL;    
-    gpgme_error_t err;
-
-    err = gpgme_new (&ctx);
-    if (err)
-       return err;
-    err = gpgme_data_new (&out);
-    if (err) {
-       gpgme_release (ctx);
-       return err;
-    }
-
-    gpgme_set_armor (ctx, 1);
-    err = gpgme_op_export_ext (ctx, pattern, 0, out);
-    if (!err)
-       data_to_file (&out, outfile);
-
-    gpgme_data_release (out);  
-    gpgme_release (ctx);  
-    return err;
-}
-
-
-const char *
-userid_from_key (gpgme_key_t k)
-{
-  if (k && k->uids && k->uids->uid)
-    return k->uids->uid;
-  else
-    return "?";
-}
-
-const char *
-keyid_from_key (gpgme_key_t k)
-{
-  
-  if (k && k->subkeys && k->subkeys->keyid)
-    return k->subkeys->keyid;
-  else
-    return "????????";
-}
-
-
-const char*
-op_strerror (int err)
-{
-  return gpgme_strerror (err);
-}
-
-
-const char*
-op_strsource (int err)
-{
-  return gpgme_strsource (err);
-}
-
 
-#endif
index 7c5831a..4a17189 100644 (file)
@@ -29,9 +29,19 @@ extern "C" {
 #endif
 #endif
 
+#include <gpgme.h>  /* We need it for gpgme_data_t.  */
 
 
 
+int  op_assuan_init (void);
+void op_assuan_deinit (void);
+
+int op_assuan_encrypt (protocol_t protocol, 
+                       gpgme_data_t indata, gpgme_data_t outdata,
+                       void *notify_data, /* FIXME: Add hwnd */
+                       char **recipients);
+
+
 
 
 
index 3eedb1c..873d17f 100644 (file)
@@ -59,10 +59,12 @@ struct closure_data_s
 };
 
 
+static int basic_init_done = 0;
 static int init_done = 0;
 
 
 static DWORD WINAPI waiter_thread (void *dummy);
+static CRITICAL_SECTION waiter_thread_lock;
 static void update_passphrase_cache (int err, 
                                      struct passphrase_cb_s *pass_cb_value);
 /* static void add_verify_attestation (gpgme_data_t at,  */
@@ -87,22 +89,38 @@ op_gpgme_deinit (void)
 }
 
 
-/* Initialize the operation system. */
+/* First part of the gpgme initialization.  This is sufficient if we
+   only use the gpgme_data_t stuff.  */
 int
-op_gpgme_init (void)
+op_gpgme_basic_init (void)
 {
-  gpgme_error_t err;
-
-  if (init_done == 1)
+  if (basic_init_done)
     return 0;
 
   if (!gpgme_check_version (NEED_GPGME_VERSION)) 
     {
       log_debug ("gpgme is too old (need %s, have %s)\n",
                  NEED_GPGME_VERSION, gpgme_check_version (NULL) );
-      return -1;
+      return gpg_error (GPG_ERR_GENERAL);
     }
 
+  basic_init_done = 1;
+  return 0;
+}
+
+
+int
+op_gpgme_init (void)
+{
+  gpgme_error_t err;
+
+  if (init_done)
+    return 0;
+
+  err = op_gpgme_basic_init ();
+  if (err)
+    return err;
+
   err = gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP);
   if (err)
     {
@@ -123,6 +141,7 @@ op_gpgme_init (void)
     HANDLE th;
     DWORD tid;
 
+    InitializeCriticalSection (&waiter_thread_lock);
     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");
@@ -146,15 +165,16 @@ waiter_thread (void *dummy)
 
   (void)dummy;
 
-  TRACEPOINT ();
   for (;;)
     {
       /*  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
-          is more complicated.  */
+          gpgme_wait only if we really have something to do but that
+          is a bit more complicated.  */
+      EnterCriticalSection (&waiter_thread_lock);
       ctx = gpgme_wait (NULL, &err, 0);
+      LeaveCriticalSection (&waiter_thread_lock);
       if (ctx)
         {
           gpgme_get_progress_cb (ctx, NULL, &a_voidptr);
@@ -174,6 +194,24 @@ waiter_thread (void *dummy)
 }
 
 
+void
+engine_gpgme_cancel (void *cancel_data)
+{
+  gpg_error_t err;
+  gpgme_ctx_t ctx = cancel_data;
+
+  if (ctx)
+    {
+      EnterCriticalSection (&waiter_thread_lock);
+      err = gpgme_cancel (ctx);
+      LeaveCriticalSection (&waiter_thread_lock);
+      if (err)
+        log_debug ("%s:%s: gpgme_cancel failed: %s\n", 
+                   SRCNAME, __func__,  gpg_strerror (err));
+    }
+}
+
+
 /* 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
@@ -367,15 +405,15 @@ encrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
     }
   if (err)
     err = check_encrypt_result (ctx, err);
-  engine_gpgme_finished (cld->filter, err);
+  engine_private_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
-   encryption command engine_gpgme_finished() is called with
-   NOTIFY_DATA as the first argument.  
+   encryption command engine_private_finished() is called with
+   FILTER as the first argument.  
 
    This global function is used to avoid allocating an extra context
    just for this notification.  We abuse the gpgme_set_progress_cb
@@ -383,8 +421,8 @@ encrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
 int
 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)
+                  engine_filter_t filter, void *hwnd,
+                  char **recipients)
 {
   gpg_error_t err;
   closure_data_t cld;
@@ -393,7 +431,7 @@ op_gpgme_encrypt (protocol_t protocol,
 
   cld = xcalloc (1, sizeof *cld);
   cld->closure = encrypt_closure;
-  cld->filter = notify_data;
+  cld->filter = filter;
 
   err = prepare_recipient_keys (&keys, recipients, NULL);
   if (err)
@@ -420,18 +458,18 @@ op_gpgme_encrypt (protocol_t protocol,
 
   gpgme_set_armor (ctx, 1);
   /* FIXME:  We should not hardcode always trust. */
-  if (sign_key)
-    {
-      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);
-    }
-  else
+/*   if (sign_key) */
+/*     { */
+/*       gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cld->pw_cb); */
+/*       cld->pw_cb.ctx = ctx; */
+/*       cld->pw_cb.ttl = opt.passwd_ttl; */
+/*       err = gpgme_signers_add (ctx, sign_key); */
+/*       if (!err) */
+/*         err = gpgme_op_encrypt_sign_start (ctx, keys, */
+/*                                            GPGME_ENCRYPT_ALWAYS_TRUST, */
+/*                                            indata, outdata); */
+/*     } */
+/*   else */
     err = gpgme_op_encrypt_start (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, 
                                   indata, outdata);
 
@@ -441,6 +479,8 @@ op_gpgme_encrypt (protocol_t protocol,
       xfree (cld);
       gpgme_release (ctx);
     }
+  else
+    engine_private_set_cancel (filter, ctx);
   release_key_array (keys);
   return err;
 }
@@ -454,17 +494,17 @@ 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);
+  engine_private_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.  */
+   On termination of the signing command engine_private_finished() is
+   called with FILTER as the first argument.  */
 int
 op_gpgme_sign (protocol_t protocol, 
                gpgme_data_t indata, gpgme_data_t outdata,
-               void *notify_data /* FIXME: Add hwnd */)
+               engine_filter_t filter, void *hwnd)
 {
   gpg_error_t err;
   closure_data_t cld;
@@ -479,7 +519,7 @@ op_gpgme_sign (protocol_t protocol,
 
   cld = xcalloc (1, sizeof *cld);
   cld->closure = sign_closure;
-  cld->filter = notify_data;
+  cld->filter = filter;
 
   err = gpgme_new (&ctx);
   if (err)
@@ -502,6 +542,7 @@ op_gpgme_sign (protocol_t protocol,
   gpgme_set_armor (ctx, 1);
   gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &cld->pw_cb);
   cld->pw_cb.ctx = ctx;
+  cld->pw_cb.ttl = opt.passwd_ttl;
   err = gpgme_signers_add (ctx, sign_key);
   if (!err)
     err = gpgme_op_sign_start (ctx, indata, outdata, GPGME_SIG_MODE_DETACH);
@@ -512,6 +553,8 @@ op_gpgme_sign (protocol_t protocol,
       xfree (cld);
       gpgme_release (ctx);
     }
+  else
+    engine_private_set_cancel (filter, ctx);
   gpgme_key_unref (sign_key);
   return err;
 }
@@ -558,7 +601,7 @@ decrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
   if (err && (cld->pw_cb.opts & OPT_FLAG_CANCEL))
     err = gpg_error (GPG_ERR_CANCELED);
 
-  engine_gpgme_finished (cld->filter, err);
+  engine_private_finished (cld->filter, err);
 }
 
 
@@ -568,7 +611,7 @@ decrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
 int
 op_gpgme_decrypt (protocol_t protocol,
                   gpgme_data_t indata, gpgme_data_t outdata, 
-                  void *notify_data,
+                  engine_filter_t filter, void *hwnd,
                   int with_verify)
 {
   gpgme_error_t err;
@@ -577,7 +620,7 @@ op_gpgme_decrypt (protocol_t protocol,
   
   cld = xcalloc (1, sizeof *cld);
   cld->closure = decrypt_closure;
-  cld->filter = notify_data;
+  cld->filter = filter;
   cld->with_verify = with_verify;
 
   err = gpgme_new (&ctx);
@@ -615,6 +658,8 @@ op_gpgme_decrypt (protocol_t protocol,
       xfree (cld);
       gpgme_release (ctx);
     }
+  else
+    engine_private_set_cancel (filter, ctx);
   return err;
 }
 
@@ -635,7 +680,7 @@ verify_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
         verify_dialog_box (gpgme_get_protocol (ctx), res, NULL);
     }
   gpgme_data_release (cld->sigobj);
-  engine_gpgme_finished (cld->filter, err);
+  engine_private_finished (cld->filter, err);
 }
 
 
@@ -644,7 +689,7 @@ verify_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
 int
 op_gpgme_verify (gpgme_protocol_t protocol, 
                  gpgme_data_t data, const char *signature,
-                 void *notify_data )
+                 engine_filter_t filter, void *hwnd)
 {
   gpgme_error_t err;
   closure_data_t cld;
@@ -653,7 +698,7 @@ op_gpgme_verify (gpgme_protocol_t protocol,
 
   cld = xcalloc (1, sizeof *cld);
   cld->closure = verify_closure;
-  cld->filter = notify_data;
+  cld->filter = filter;
 
   err = gpgme_new (&ctx);
   if (err)
@@ -688,6 +733,8 @@ op_gpgme_verify (gpgme_protocol_t protocol,
       xfree (cld);
       gpgme_release (ctx);
     }
+  else
+    engine_private_set_cancel (filter, ctx);
   return err;
 }
 
index f1719cd..34e4173 100644 (file)
@@ -35,6 +35,7 @@
 #include "engine-gpgme.h"
 #include "engine-assuan.h"
 
+
 #define FILTER_BUFFER_SIZE 128  /* FIXME: Increase it after testing  */
 
 
@@ -42,6 +43,8 @@
                                        SRCNAME, __func__, __LINE__); \
                         } while (0)
 
+static int debug_filter = 0;
+
 
 /* Definition of the key object.  */
 struct engine_keyinfo_s
@@ -88,9 +91,44 @@ struct engine_filter_s
   struct gpgme_data_cbs cb_outbound; /* Ditto.  */
   gpgme_data_t indata;               /* Input data.  */
   gpgme_data_t outdata;              /* Output data.  */
+  void *cancel_data;                 /* Used by engine_cancel.  */
 };
 
 
+static void
+take_in_lock (engine_filter_t filter, const char *func)
+{
+  EnterCriticalSection (&filter->in.lock);
+  if (debug_filter > 1)
+    log_debug ("%s:%s: in.lock taken\n", SRCNAME, func);
+}
+
+static void
+release_in_lock (engine_filter_t filter, const char *func)
+{
+  LeaveCriticalSection (&filter->in.lock);
+  if (debug_filter > 1)
+    log_debug ("%s:%s: in.lock released\n", SRCNAME, func);
+}
+
+static void
+take_out_lock (engine_filter_t filter, const char *func)
+{
+  EnterCriticalSection (&filter->out.lock);
+  if (debug_filter > 1)
+    log_debug ("%s:%s: out.lock taken\n", SRCNAME, func);
+}
+
+static void
+release_out_lock (engine_filter_t filter, const char *func)
+{
+  LeaveCriticalSection (&filter->out.lock);
+  if (debug_filter > 1)
+    log_debug ("%s:%s: out.lock released\n", SRCNAME, func);
+}
+
+
+
 
 \f
 /* Create a new filter object. */
@@ -116,7 +154,6 @@ create_filter (void)
   filter->in.ready_event = CreateEvent (NULL, 0, 0, NULL);
   if (!filter->in.ready_event)
     log_error_w32 (-1, "%s:%s: CreateEvent failed", SRCNAME, __func__);
-  TRACEPOINT ();
 
   return filter;
 }
@@ -127,7 +164,6 @@ release_filter (engine_filter_t filter)
 {
   if (filter)
     {
-      TRACEPOINT ();
       if (filter->in.condvar)
         CloseHandle (filter->in.condvar);
       if (filter->out.condvar)
@@ -159,36 +195,42 @@ filter_gpgme_read_cb (void *handle, void *buffer, size_t size)
       return (ssize_t)(-1);
     }
 
-  log_debug ("%s:%s: enter\n",  SRCNAME, __func__);
-  EnterCriticalSection (&filter->in.lock);
+  if (debug_filter)
+    log_debug ("%s:%s: enter\n",  SRCNAME, __func__);
+  take_in_lock (filter, __func__);
   while (!filter->in.length)
     {
       if (filter->in.got_eof || filter->in.ready)
         {
-          LeaveCriticalSection (&filter->in.lock);
-          log_debug ("%s:%s: returning EOF\n", SRCNAME, __func__);
+          release_in_lock (filter, __func__);
+          if (debug_filter)
+            log_debug ("%s:%s: returning EOF\n", SRCNAME, __func__);
           return 0; /* Return EOF. */
         }
-      LeaveCriticalSection (&filter->in.lock);
-      log_debug ("%s:%s: waiting for in.condvar\n", SRCNAME, __func__);
+      release_in_lock (filter, __func__);
+      if (debug_filter)
+        log_debug ("%s:%s: waiting for in.condvar\n", SRCNAME, __func__);
       WaitForSingleObject (filter->in.condvar, 500);
-      EnterCriticalSection (&filter->in.lock);
-      log_debug ("%s:%s: continuing\n", SRCNAME, __func__);
+      take_in_lock (filter, __func__);
+      if (debug_filter)
+        log_debug ("%s:%s: continuing\n", SRCNAME, __func__);
     }
      
-  log_debug ("%s:%s: requested read size=%d (filter.in.length=%d)\n",
-             SRCNAME, __func__, (int)size, (int)filter->in.length);
+  if (debug_filter)
+    log_debug ("%s:%s: requested read size=%d (filter.in.length=%d)\n",
+               SRCNAME, __func__, (int)size, (int)filter->in.length);
   nbytes = size < filter->in.length ? size : filter->in.length;
   memcpy (buffer, filter->in.buffer, nbytes);
   if (filter->in.length > nbytes)
     memmove (filter->in.buffer, filter->in.buffer + nbytes, 
              filter->in.length - nbytes);
   filter->in.length -= nbytes;
-  LeaveCriticalSection (&filter->in.lock);
-
-  log_debug ("%s:%s: leave; result=%d\n",
-             SRCNAME, __func__, (int)nbytes);
+  release_in_lock (filter, __func__);
 
+  if (debug_filter)
+    log_debug ("%s:%s: leave; result=%d\n",
+               SRCNAME, __func__, (int)nbytes);
+  
   return nbytes;
 }
 
@@ -209,53 +251,67 @@ filter_gpgme_write_cb (void *handle, const void *buffer, size_t size)
       return (ssize_t)(-1);
     }
 
-  log_debug ("%s:%s: enter\n",  SRCNAME, __func__);
-  EnterCriticalSection (&filter->out.lock);
+  if (debug_filter)
+    log_debug ("%s:%s: enter\n",  SRCNAME, __func__);
+  take_out_lock (filter, __func__);
   while (filter->out.length)
     {
-      LeaveCriticalSection (&filter->out.lock);
-      log_debug ("%s:%s: waiting for out.condvar\n", SRCNAME, __func__);
+      release_out_lock (filter, __func__);
+      if (debug_filter)
+        log_debug ("%s:%s: waiting for out.condvar\n", SRCNAME, __func__);
       WaitForSingleObject (filter->out.condvar, 500);
-      EnterCriticalSection (&filter->out.lock);
-      log_debug ("%s:%s: continuing\n", SRCNAME, __func__);
+      take_out_lock (filter, __func__);
+      if (debug_filter)
+        log_debug ("%s:%s: continuing\n", SRCNAME, __func__);
     }
 
-  log_debug ("%s:%s: requested write size=%d\n",
-             SRCNAME, __func__, (int)size);
+  if (debug_filter)
+    log_debug ("%s:%s: requested write size=%d\n",
+               SRCNAME, __func__, (int)size);
   nbytes = size < FILTER_BUFFER_SIZE ? size : FILTER_BUFFER_SIZE;
   memcpy (filter->out.buffer, buffer, nbytes);
   filter->out.length = nbytes;
-  LeaveCriticalSection (&filter->out.lock);
+  release_out_lock (filter, __func__);
 
-  log_debug ("%s:%s: write; result=%d\n", SRCNAME, __func__, (int)nbytes);
+  if (debug_filter)
+    log_debug ("%s:%s: write; result=%d\n", SRCNAME, __func__, (int)nbytes);
   return nbytes;
 }
 
+
+/* Store a cancel parameter into FILTER.  Only use by the engine backends. */
+void
+engine_private_set_cancel (engine_filter_t filter, void *cancel_data)
+{
+  filter->cancel_data = cancel_data;
+}
+
+
 /* This function is called by the gpgme backend to notify a filter
    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)
+engine_private_finished (engine_filter_t filter, gpg_error_t status)
 {
   if (!filter)
     {
       log_debug ("%s:%s: called without argument\n", SRCNAME, __func__);
       return;
     }
-  log_debug ("%s:%s: filter %p: process terminated: %s <%s>\n", 
-             SRCNAME, __func__, filter, 
-             gpg_strerror (status), gpg_strsource (status));
-
-  EnterCriticalSection (&filter->in.lock);
-  if (filter->in.ready)
-    log_debug ("%s:%s: filter %p: Oops: already flagged as finished\n", 
-               SRCNAME, __func__, filter);
+  if (debug_filter)
+    log_debug ("%s:%s: filter %p: process terminated: %s <%s>\n", 
+               SRCNAME, __func__, filter, 
+               gpg_strerror (status), gpg_strsource (status));
+  
+  take_in_lock (filter, __func__);
   filter->in.ready = 1;
   filter->in.status = status;
+  filter->cancel_data = NULL;
   if (!SetEvent (filter->in.ready_event))
     log_error_w32 (-1, "%s:%s: SetEvent failed", SRCNAME, __func__);
-  LeaveCriticalSection (&filter->in.lock);
-  log_debug ("%s:%s: leaving\n", SRCNAME, __func__);
+  release_in_lock (filter, __func__);
+  if (debug_filter)
+    log_debug ("%s:%s: leaving\n", SRCNAME, __func__);
 }
 
 
@@ -266,8 +322,25 @@ engine_gpgme_finished (engine_filter_t filter, gpg_error_t status)
 int
 engine_init (void)
 {
-  op_gpgme_init ();
-  return 0;
+  gpg_error_t err;
+
+  err = op_gpgme_basic_init ();
+  if (err)
+    return err;
+
+  err = op_assuan_init ();
+  if (err)
+    {
+/*       MessageBox (NULL, */
+/*                   _("The user interface server is not available or does " */
+/*                     "not work.  Using an internal user interface.\n\n" */
+/*                     "This is limited to the OpenPGP protocol and " */
+/*                     "thus S/MIME protected message are not readable."), */
+/*                   _("GpgOL"), MB_ICONWARNING|MB_OK); */
+      err = op_gpgme_init ();
+    }
+
+  return err;
 }
 
 
@@ -275,8 +348,8 @@ engine_init (void)
 void
 engine_deinit (void)
 {
+  op_assuan_deinit ();
   op_gpgme_deinit ();
-
 }
 
 
@@ -296,7 +369,8 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
   gpg_error_t err;
   int nbytes;
 
-  log_debug ("%s:%s: enter; filter=%p\n", SRCNAME, __func__, filter); 
+  if (debug_filter)
+    log_debug ("%s:%s: enter; filter=%p\n", SRCNAME, __func__, filter); 
   /* Our implementation is for now straightforward without any
      additional buffer filling etc.  */
   if (!filter || !filter->outfnc)
@@ -307,22 +381,26 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
   if (filter->in.got_eof)
     return gpg_error (GPG_ERR_CONFLICT); /* EOF has already been indicated.  */
 
-  log_debug ("%s:%s: indata=%p indatalen=%d outfnc=%p\n",
-             SRCNAME, __func__, indata, (int)indatalen, filter->outfnc); 
+  if (debug_filter)
+    log_debug ("%s:%s: indata=%p indatalen=%d outfnc=%p\n",
+               SRCNAME, __func__, indata, (int)indatalen, filter->outfnc); 
   for (;;)
     {
       /* If there is something to write out, do this now to make space
          for more data.  */
-      EnterCriticalSection (&filter->out.lock);
+      take_out_lock (filter, __func__);
       while (filter->out.length)
         {
-          TRACEPOINT ();
+          if (debug_filter)
+            log_debug ("%s:%s: pushing %d bytes to the outfnc\n",
+                       SRCNAME, __func__, filter->out.length); 
           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);
+              if (debug_filter)
+                log_debug ("%s:%s: error writing data\n", SRCNAME, __func__);
+              release_out_lock (filter, __func__);
               return gpg_error (GPG_ERR_EIO);
             }
           assert (nbytes <= filter->out.length && nbytes >= 0);
@@ -333,12 +411,12 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
         }
       if (!PulseEvent (filter->out.condvar))
         log_error_w32 (-1, "%s:%s: PulseEvent(out) failed", SRCNAME, __func__);
-      LeaveCriticalSection (&filter->out.lock);
+      release_out_lock (filter, __func__);
       
-      EnterCriticalSection (&filter->in.lock);
+      take_in_lock (filter, __func__);
+
       if (!indata && !indatalen)
         {
-          TRACEPOINT ();
           filter->in.got_eof = 1;
           /* Flush requested.  Tell the output function to also flush.  */
           nbytes = filter->outfnc (filter->outfncdata, NULL, 0);
@@ -349,7 +427,7 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
             }
           else
             err = 0;
-          LeaveCriticalSection (&filter->in.lock);
+          release_in_lock (filter, __func__);
           return err; 
         }
 
@@ -358,7 +436,6 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
          processed.  */
       if (!filter->in.length && indatalen)
         {
-          TRACEPOINT ();
           filter->in.length = (indatalen > FILTER_BUFFER_SIZE
                                ? FILTER_BUFFER_SIZE : indatalen);
           memcpy (filter->in.buffer, indata, filter->in.length);
@@ -367,17 +444,18 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
         }
       if (!filter->in.length || (filter->in.ready && !filter->out.length))
         {
-          LeaveCriticalSection (&filter->in.lock);
+          release_in_lock (filter, __func__);
           err = 0;
           break;  /* the loop.  */
         }
       if (!PulseEvent (filter->in.condvar))
         log_error_w32 (-1, "%s:%s: PulseEvent(in) failed", SRCNAME, __func__);
-      LeaveCriticalSection (&filter->in.lock);
-      Sleep (0);
+      release_in_lock (filter, __func__);
+      Sleep (50);
     }
 
-  log_debug ("%s:%s: leave; err=%d\n", SRCNAME, __func__, err); 
+  if (debug_filter)
+    log_debug ("%s:%s: leave; err=%d\n", SRCNAME, __func__, err); 
   return err;
 }
 
@@ -443,7 +521,6 @@ engine_wait (engine_filter_t filter)
   gpg_error_t err;
   int more;
 
-  TRACEPOINT ();
   if (!filter || !filter->outfnc)
     return gpg_error (GPG_ERR_INV_VALUE);
 
@@ -455,34 +532,43 @@ engine_wait (engine_filter_t filter)
      wait for the out.lock as well as for the ready_event.  */
   do 
     {
-      EnterCriticalSection (&filter->out.lock);
-      while (filter->out.length)
+      more = 0;
+      take_out_lock (filter, __func__);
+      if (filter->out.length)
         {
           int nbytes; 
 
           nbytes = filter->outfnc (filter->outfncdata, 
                                    filter->out.buffer, filter->out.length);
-          if (nbytes == -1)
+          if (nbytes < 0)
             {
-              log_debug ("%s:%s: error writing data\n", SRCNAME, __func__);
-              LeaveCriticalSection (&filter->out.lock);
+              log_error ("%s:%s: error writing data\n", SRCNAME, __func__);
+              release_out_lock (filter, __func__);
               return gpg_error (GPG_ERR_EIO);
             }
-          
+         
           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;
+          if (filter->out.length)
+            {
+              if (debug_filter > 1)
+                log_debug ("%s:%s: still %d pending bytes for outfnc\n",
+                           SRCNAME, __func__, filter->out.length);
+              more = 1;
+            }
         }
       if (!PulseEvent (filter->out.condvar))
         log_error_w32 (-1, "%s:%s: PulseEvent(out) failed", SRCNAME, __func__);
-      LeaveCriticalSection (&filter->out.lock);
-      EnterCriticalSection (&filter->in.lock);
-      more = !filter->in.ready;
-      LeaveCriticalSection (&filter->in.lock);
+      release_out_lock (filter, __func__);
+      take_in_lock (filter, __func__);
+      if (!filter->in.ready)
+        more = 1;
+      release_in_lock (filter, __func__);
       if (more)
-        Sleep (100);
+        Sleep (50);
     }
   while (more);
 
@@ -505,14 +591,29 @@ engine_wait (engine_filter_t filter)
 void
 engine_cancel (engine_filter_t filter)
 {
+  void *cancel_data;
+
   if (!filter)
     return;
   
-  EnterCriticalSection (&filter->in.lock);
+  take_in_lock (filter, __func__);
+  cancel_data = filter->cancel_data;
+  filter->cancel_data = NULL;
   filter->in.ready = 1;
-  LeaveCriticalSection (&filter->in.lock);
-  log_debug ("%s:%s: filter %p canceled", SRCNAME, __func__, filter);
-  /* FIXME:  Here we need to kill the underlying gpgme process. */
+  release_in_lock (filter, __func__);
+  if (cancel_data)
+    {
+      log_debug ("%s:%s: filter %p: sending cancel command to backend",
+                 SRCNAME, __func__, filter);
+      engine_gpgme_cancel (cancel_data);
+      if (WaitForSingleObject (filter->in.ready_event, INFINITE)
+          != WAIT_OBJECT_0)
+        log_error_w32 (-1, "%s:%s: WFSO failed", SRCNAME, __func__);
+      else
+        log_debug ("%s:%s: filter %p: backend has been canceled", 
+                   SRCNAME, __func__,  filter);
+    }
+  log_debug ("%s:%s: filter %p: canceled", SRCNAME, __func__, filter);
   release_filter (filter);
 }
 
@@ -532,7 +633,7 @@ engine_encrypt_start (engine_filter_t filter,
   gpg_error_t err;
 
   err = op_gpgme_encrypt (protocol, filter->indata, filter->outdata,
-                          filter, recipients, NULL, 0);
+                          filter, NULL, recipients);
   return err;
 }
 
@@ -549,7 +650,7 @@ engine_sign_start (engine_filter_t filter, protocol_t protocol)
   gpg_error_t err;
 
   err = op_gpgme_sign (protocol, filter->indata, filter->outdata,
-                       filter);
+                       filter, NULL);
   return err;
 }
 
@@ -567,7 +668,7 @@ engine_decrypt_start (engine_filter_t filter, protocol_t protocol,
   gpg_error_t err;
 
   err = op_gpgme_decrypt (protocol, filter->indata, filter->outdata,
-                          filter, with_verify);
+                          filter, NULL, with_verify);
   return err;
 }
 
@@ -592,7 +693,7 @@ engine_verify_start (engine_filter_t filter, const char *signature,
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
 
-  err = op_gpgme_verify (protocol, filter->indata, signature, filter);
+  err = op_gpgme_verify (protocol, filter->indata, signature, filter, NULL);
   return err;
 }
 
index 93d0952..0d46950 100644 (file)
@@ -53,8 +53,8 @@ typedef struct engine_filter_s *engine_filter_t;
 int engine_init (void);
 void engine_deinit (void);
 
-/* This callback function is to be used only by engine-gpgme.c.   */
-void engine_gpgme_finished (engine_filter_t filter, gpg_error_t status);
+void engine_private_set_cancel (engine_filter_t filter, void *cancel_data);
+void engine_private_finished (engine_filter_t filter, gpg_error_t status);
 
 int engine_filter (engine_filter_t filter,
                    const void *indata, size_t indatalen);
index 9bafd9e..384385a 100644 (file)
@@ -345,8 +345,8 @@ GpgolExtCommands::InstallCommands (
   if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) 
     {
       toolbar_add_menu (pEECB, pnCommandIDBase, "", NULL,
-                        _("GPG &encrypt message"), &m_nCmdEncrypt,
-                        _("GPG &sign message"), &m_nCmdSign,
+                        _("&encrypt message with GnuPG"), &m_nCmdEncrypt,
+                        _("&sign message with GnuPG"), &m_nCmdSign,
                         NULL );
       
 
@@ -378,7 +378,7 @@ GpgolExtCommands::InstallCommands (
   if (m_lContext == EECONTEXT_VIEWER) 
     {
       toolbar_add_menu (pEECB, pnCommandIDBase, "", NULL,
-                        _("GPG Key &Manager"), &m_nCmdKeyManager,
+                        _("GnuPG Key &Manager"), &m_nCmdKeyManager,
                         NULL);
 
       hwnd_toolbar = toolbar_from_tbe (pTBEArray, nTBECnt, &tb_idx);
index 2746610..312db49 100644 (file)
@@ -84,7 +84,7 @@ GpgolItemEvents::OnOpen (LPEXCHEXTCALLBACK peecb)
 
 
 /* Like all the other Complete methods this one is called after OnOpen
-   has been called for all registred extensions.  FLAGS may have tehse
+   has been called for all registered extensions.  FLAGS may have these
    values:
 
     0 - The open action has not been canceled.
index 15823e9..2af0f03 100644 (file)
@@ -80,6 +80,10 @@ log_mapi_property (LPMESSAGE message, ULONG prop, const char *propname)
       log_debug ("%s: %20s=`%s'", __func__, propname, propval->Value.lpszA);
       break;
 
+    case PT_LONG:
+      log_debug ("%s: %20s=%ld", __func__, propname, propval->Value.l);
+      break;
+
     default:
       log_debug ("%s:%s: HrGetOneProp(%s) property type %lu not supported\n",
                  SRCNAME, __func__, propname,
@@ -482,7 +486,6 @@ mapi_change_message_class (LPMESSAGE message)
   HRESULT hr;
   SPropValue prop;
   LPSPropValue propval = NULL;
-  
   char *newvalue = NULL;
 
   if (!message)
@@ -582,21 +585,28 @@ mapi_change_message_class (LPMESSAGE message)
     }
   MAPIFreeBuffer (propval);
   if (!newvalue)
-    return 0;
-
-  prop.ulPropTag = PR_MESSAGE_CLASS_A;
-  prop.Value.lpszA = newvalue; 
-  hr = message->SetProps (1, &prop, NULL);
-  xfree (newvalue);
-  if (hr != S_OK)
     {
-      log_error ("%s:%s: can't set message class: hr=%#lx\n",
-                 SRCNAME, __func__, hr);
-      return 0;
+      /* We use our Sig-Status property to mark messages which passed
+         this function.  This helps use to avoids later tests.  */
+      if (!mapi_has_sig_status (message))
+        mapi_set_sig_status (message, "#");
+    }
+  else
+    {
+      prop.ulPropTag = PR_MESSAGE_CLASS_A;
+      prop.Value.lpszA = newvalue; 
+      hr = message->SetProps (1, &prop, NULL);
+      xfree (newvalue);
+      if (hr)
+        {
+          log_error ("%s:%s: can't set message class: hr=%#lx\n",
+                     SRCNAME, __func__, hr);
+          return 0;
+        }
     }
 
   hr = message->SaveChanges (KEEP_OPEN_READONLY);
-  if (hr != S_OK)
+  if (hr)
     {
       log_error ("%s:%s: SaveChanges() failed: hr=%#lx\n",
                  SRCNAME, __func__, hr); 
@@ -936,16 +946,30 @@ mapi_create_attach_table (LPMESSAGE message, int fast)
     {
       LPATTACH att;
 
-      hr = message->OpenAttach (pos, NULL, MAPI_BEST_ACCESS, &att);    
+      if (mapirows->aRow[pos].cValues < 1)
+        {
+          log_error ("%s:%s: invalid row at pos %d", SRCNAME, __func__, pos);
+          table[pos].mapipos = -1;
+          continue;
+        }
+      if (mapirows->aRow[pos].lpProps[0].ulPropTag != PR_ATTACH_NUM)
+        {
+          log_error ("%s:%s: invalid prop at pos %d", SRCNAME, __func__, pos);
+          table[pos].mapipos = -1;
+          continue;
+        }
+      table[pos].mapipos = mapirows->aRow[pos].lpProps[0].Value.l;
+
+      hr = message->OpenAttach (table[pos].mapipos, NULL,
+                                MAPI_BEST_ACCESS, &att);       
       if (FAILED (hr))
         {
-          log_error ("%s:%s: can't open attachment %d: hr=%#lx",
-                     SRCNAME, __func__, pos, hr);
+          log_error ("%s:%s: can't open attachment %d (%d): hr=%#lx",
+                     SRCNAME, __func__, pos, table[pos].mapipos, hr);
           table[pos].mapipos = -1;
           continue;
         }
 
-      table[pos].mapipos = pos;
       table[pos].method = get_attach_method (att);
       table[pos].filename = fast? NULL : get_attach_filename (att);
       table[pos].content_type = fast? NULL : get_attach_mime_tag (att);
@@ -965,9 +989,10 @@ mapi_create_attach_table (LPMESSAGE message, int fast)
       table[pos].attach_type = get_gpgolattachtype (att, moss_tag);
       att->Release ();
     }
-  table[pos].end_of_table = 1;
+  table[0].private_mapitable = mapitable;
   FreeProws (mapirows);
-  mapitable->Release ();
+  table[pos].end_of_table = 1;
+  mapitable = NULL;
 
   if (fast)
     {
@@ -996,10 +1021,14 @@ void
 mapi_release_attach_table (mapi_attach_item_t *table)
 {
   unsigned int pos;
+  LPMAPITABLE mapitable;
 
   if (!table)
     return;
 
+  mapitable = (LPMAPITABLE)table[0].private_mapitable;
+  if (mapitable)
+    mapitable->Release ();
   for (pos=0; !table[pos].end_of_table; pos++)
     {
       xfree (table[pos].filename);
@@ -1258,7 +1287,7 @@ mapi_mark_moss_attach (LPMESSAGE message, mapi_attach_item_t *item)
 
 
 
-/* Returns True if MESSAGE has a GpgOL Sig Status property.  */
+/* Returns True if MESSAGE has the GpgOL Sig Status property.  */
 int
 mapi_has_sig_status (LPMESSAGE msg)
 {
@@ -1273,6 +1302,31 @@ mapi_has_sig_status (LPMESSAGE msg)
   if (FAILED (hr))
     return 0; /* No.  */  
   if (PROP_TYPE (propval->ulPropTag) == PT_STRING8)
+    yes = 1;
+  else
+    yes = 0;
+
+  MAPIFreeBuffer (propval);
+  return yes;
+}
+
+
+/* Returns True if MESSAGE has a GpgOL Sig Status property and that it
+   is not set to unchecked.  */
+int
+mapi_test_sig_status (LPMESSAGE msg)
+{
+  HRESULT hr;
+  LPSPropValue propval = NULL;
+  ULONG tag;
+  int yes;
+
+  if (get_gpgolsigstatus_tag (msg, &tag) )
+    return 0; /* Error:  Assume No.  */
+  hr = HrGetOneProp ((LPMAPIPROP)msg, tag, &propval);
+  if (FAILED (hr))
+    return 0; /* No.  */  
+  if (PROP_TYPE (propval->ulPropTag) == PT_STRING8)
     yes = !(propval->Value.lpszA && !strcmp (propval->Value.lpszA, "?"));
   else
     yes = 0;
@@ -1282,9 +1336,17 @@ mapi_has_sig_status (LPMESSAGE msg)
 }
 
 
-/* Set the signature status property to STATUS_STRING.  To set the
-   status to not checked, set it to "?".  Note that this function does
-   not call SaveChanges.  */
+/* Set the signature status property to STATUS_STRING.  There are a
+   few special values:
+
+     "#" The message is not of interest to us.
+     "@" The message has been created and signed or encrypted by us.
+     "?" The signature status has not been checked.
+     "!" The signature verified okay 
+     "~" The signature was not fully verified.
+     "-" The signature is bad
+
+   Note that this function does not call SaveChanges.  */
 int 
 mapi_set_sig_status (LPMESSAGE message, const char *status_string)
 {
@@ -1469,6 +1531,8 @@ mapi_get_gpgol_body_attachment (LPMESSAGE message, size_t *r_nbytes,
   if (r_protected)
     *r_protected = 0;
 
+  mapi_release_attach_table (mapi_create_attach_table (message, 0));
+
   if (get_gpgolattachtype_tag (message, &moss_tag) )
     return NULL;
 
@@ -1497,19 +1561,33 @@ mapi_get_gpgol_body_attachment (LPMESSAGE message, size_t *r_nbytes,
       log_debug ("%s:%s: No attachments at all", SRCNAME, __func__);
       return NULL;
     }
+  log_debug ("%s:%s: message has %u attachments\n",
+             SRCNAME, __func__, n_attach);
 
   for (pos=0; pos < n_attach; pos++) 
     {
       LPATTACH att;
 
-      hr = message->OpenAttach (pos, NULL, MAPI_BEST_ACCESS, &att);    
+      if (mapirows->aRow[pos].cValues < 1)
+        {
+          log_error ("%s:%s: invalid row at pos %d", SRCNAME, __func__, pos);
+          continue;
+        }
+      if (mapirows->aRow[pos].lpProps[0].ulPropTag != PR_ATTACH_NUM)
+        {
+          log_error ("%s:%s: invalid prop at pos %d", SRCNAME, __func__, pos);
+          continue;
+        }
+      hr = message->OpenAttach (mapirows->aRow[pos].lpProps[0].Value.l,
+                                NULL, MAPI_BEST_ACCESS, &att); 
       if (FAILED (hr))
         {
-          log_error ("%s:%s: can't open attachment %d: hr=%#lx",
-                     SRCNAME, __func__, pos, hr);
+          log_error ("%s:%s: can't open attachment %d (%ld): hr=%#lx",
+                     SRCNAME, __func__, pos, 
+                     mapirows->aRow[pos].lpProps[0].Value.l, hr);
           continue;
         }
-      if ( (bodytype=has_gpgol_body_name (att))
+      if ((bodytype=has_gpgol_body_name (att))
            && get_gpgolattachtype (att, moss_tag) == ATTACHTYPE_FROMMOSS)
         {
           if (get_attach_method (att) == ATTACH_BY_VALUE)
@@ -1524,7 +1602,11 @@ mapi_get_gpgol_body_attachment (LPMESSAGE message, size_t *r_nbytes,
   FreeProws (mapirows);
   mapitable->Release ();
   if (!body)
-    log_error ("%s:%s: no suitable body attachment found", SRCNAME, __func__);
+    {
+      log_error ("%s:%s: no suitable body attachment found", SRCNAME,__func__);
+      body = native_to_utf8 (_("[The content of this message is not visible"
+                               " due to an processing error in GpgOL.]"));
+    }
   
   return body;
 }
index de601ae..e4602cf 100644 (file)
@@ -50,7 +50,7 @@ typedef enum
                                     S/MIME or PGP/MIME message. */
     ATTACHTYPE_FROMMOSS = 2,     /* Attachment created from MOSS.  */
     ATTACHTYPE_MOSSTEMPL = 3     /* Attachment has been created in the
-                                    course of sendig a message */ 
+                                    course of sending a message */ 
   }
 attachtype_t;
 
@@ -59,6 +59,8 @@ struct mapi_attach_item_s
 {
   int end_of_table;     /* True if this is the last plus one entry of
                            the table. */
+  void *private_mapitable; /* Only for use by mapi_release_attach_table. */
+
   int mapipos;          /* The position which needs to be passed to
                            MAPI to open the attachment.  -1 means that
                            there is no valid attachment.  */
@@ -76,7 +78,6 @@ struct mapi_attach_item_s
 
   /* The attachment type from Property GpgOL Attach Type.  */
   attachtype_t attach_type;
-
 };
 typedef struct mapi_attach_item_s mapi_attach_item_t;
 
@@ -106,6 +107,7 @@ char *mapi_get_attach (LPMESSAGE message,
                        mapi_attach_item_t *item, size_t *r_nbytes);
 int mapi_mark_moss_attach (LPMESSAGE message, mapi_attach_item_t *item);
 int mapi_has_sig_status (LPMESSAGE msg);
+int mapi_test_sig_status (LPMESSAGE msg);
 int mapi_set_sig_status (LPMESSAGE message, const char *status_string);
 
 char *mapi_get_message_content_type (LPMESSAGE message, 
index 4900f18..b25779e 100644 (file)
@@ -100,18 +100,17 @@ GpgolMessageEvents::QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
 
 
 /* Called from Exchange on reading a message.  Returns: S_FALSE to
-   signal Exchange to continue calling extensions.  PEECB is a pointer
+   signal Exchange to continue calling extensions.  EECB is a pointer
    to the IExchExtCallback interface. */
 STDMETHODIMP 
-GpgolMessageEvents::OnRead (LPEXCHEXTCALLBACK pEECB
+GpgolMessageEvents::OnRead (LPEXCHEXTCALLBACK eecb
 {
   LPMDB mdb = NULL;
   LPMESSAGE message = NULL;
   
   log_debug ("%s:%s: received\n", SRCNAME, __func__);
-  pEECB->GetObject (&mdb, (LPMAPIPROP *)&message);
-  log_mapi_property (message, PR_CONVERSATION_INDEX,"PR_CONVERSATION_INDEX");
-  switch (m_pExchExt->getMsgtype (pEECB))
+  eecb->GetObject (&mdb, (LPMAPIPROP *)&message);
+  switch (m_pExchExt->getMsgtype (eecb))
     {
     case MSGTYPE_UNKNOWN: 
       break;
@@ -123,13 +122,13 @@ GpgolMessageEvents::OnRead (LPEXCHEXTCALLBACK pEECB)
       log_debug ("%s:%s: processing multipart signed message\n", 
                  SRCNAME, __func__);
       m_processed = TRUE;
-      message_verify (message, m_pExchExt->getMsgtype (pEECB), 0);
+      message_verify (message, m_pExchExt->getMsgtype (eecb), 0);
       break;
     case MSGTYPE_GPGOL_MULTIPART_ENCRYPTED:
       log_debug ("%s:%s: processing multipart encrypted message\n",
                  SRCNAME, __func__);
       m_processed = TRUE;
-      message_decrypt (message, m_pExchExt->getMsgtype (pEECB), 0);
+      message_decrypt (message, m_pExchExt->getMsgtype (eecb), 0);
       /* Hmmm, we might want to abort it and run our own inspector
          instead.  */
       break;
@@ -137,26 +136,26 @@ GpgolMessageEvents::OnRead (LPEXCHEXTCALLBACK pEECB)
       log_debug ("%s:%s: processing opaque signed message\n", 
                  SRCNAME, __func__);
       m_processed = TRUE;
-      message_verify (message, m_pExchExt->getMsgtype (pEECB), 0);
+      message_verify (message, m_pExchExt->getMsgtype (eecb), 0);
       break;
     case MSGTYPE_GPGOL_CLEAR_SIGNED:
       log_debug ("%s:%s: processing clear signed pgp message\n", 
                  SRCNAME, __func__);
       m_processed = TRUE;
-      message_verify (message, m_pExchExt->getMsgtype (pEECB), 0);
+      message_verify (message, m_pExchExt->getMsgtype (eecb), 0);
       break;
     case MSGTYPE_GPGOL_OPAQUE_ENCRYPTED:
       log_debug ("%s:%s: processing opaque encrypted message\n",
                  SRCNAME, __func__);
       m_processed = TRUE;
-      message_decrypt (message, m_pExchExt->getMsgtype (pEECB), 0);
+      message_decrypt (message, m_pExchExt->getMsgtype (eecb), 0);
       /* Hmmm, we might want to abort it and run our own inspector
          instead.  */
       break;
     case MSGTYPE_GPGOL_PGP_MESSAGE:
       log_debug ("%s:%s: processing pgp message\n", SRCNAME, __func__);
       m_processed = TRUE;
-      message_decrypt (message, m_pExchExt->getMsgtype (pEECB), 0);
+      message_decrypt (message, m_pExchExt->getMsgtype (eecb), 0);
       /* Hmmm, we might want to abort it and run our own inspector
          instead.  */
       break;
@@ -170,10 +169,10 @@ GpgolMessageEvents::OnRead (LPEXCHEXTCALLBACK pEECB)
 
 
 /* Called by Exchange after a message has been read.  Returns: S_FALSE
-   to signal Exchange to continue calling extensions.  PEECB is a
-   pointer to the IExchExtCallback interface. LFLAGS are some flags. */
+   to signal Exchange to continue calling extensions.  EECB is a
+   pointer to the IExchExtCallback interface. FLAGS are some flags. */
 STDMETHODIMP 
-GpgolMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
+GpgolMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK eecb, ULONG flags)
 {
   log_debug ("%s:%s: received\n", SRCNAME, __func__);
 
@@ -186,24 +185,26 @@ GpgolMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
       LPMESSAGE message = NULL;
       LPMDB mdb = NULL;
 
-      if (FAILED (pEECB->GetWindow (&hwnd)))
+      if (FAILED (eecb->GetWindow (&hwnd)))
         hwnd = NULL;
-      hr = pEECB->GetObject (&mdb, (LPMAPIPROP *)&message);
+      hr = eecb->GetObject (&mdb, (LPMAPIPROP *)&message);
       if (SUCCEEDED (hr))
         {
           int ishtml, wasprotected;
           char *body;
 
           /* If the message was protected we don't allow a fallback to
-             the OOM display methods.  FIXME:  This is currently disabled. */
+             the OOM display methods.  */
           body = mapi_get_gpgol_body_attachment (message, NULL,
                                                  &ishtml, &wasprotected);
           if (body)
-            update_display (hwnd, /*wasprotected?NULL:*/pEECB, ishtml, body);
+            update_display (hwnd, wasprotected? NULL: eecb, ishtml, body);
           else
             update_display (hwnd, NULL, 0, 
                             _("[Crypto operation failed - "
                               "can't show the body of the message]"));
+          put_outlook_property (eecb, "EncryptedStatus", "MyStatus");
+
         }
       ul_release (message);
       ul_release (mdb);
@@ -214,7 +215,7 @@ GpgolMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
     {
       HWND hWnd = NULL;
 
-      if (FAILED (pEECB->GetWindow (&hWnd)))
+      if (FAILED (eecb->GetWindow (&hWnd)))
         hWnd = NULL;
       else
         log_window_hierarchy (hWnd, "%s:%s:%d: Windows hierarchy:",
@@ -227,10 +228,10 @@ GpgolMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
 
 
 /* Called by Exchange when a message will be written. Returns: S_FALSE
-   to signal Exchange to continue calling extensions.  PEECB is a
+   to signal Exchange to continue calling extensions.  EECB is a
    pointer to the IExchExtCallback interface. */
 STDMETHODIMP 
-GpgolMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
+GpgolMessageEvents::OnWrite (LPEXCHEXTCALLBACK eecb)
 {
   log_debug ("%s:%s: received\n", SRCNAME, __func__);
 
@@ -247,7 +248,7 @@ GpgolMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
      out unencrypted messages. */
   if (m_pExchExt->m_gpgEncrypt || m_pExchExt->m_gpgSign)
     {
-      pDisp = find_outlook_property (pEECB, "BodyFormat", &dispid);
+      pDisp = find_outlook_property (eecb, "BodyFormat", &dispid);
       if (!pDisp)
         {
           log_debug ("%s:%s: BodyFormat not found\n", SRCNAME, __func__);
@@ -287,7 +288,7 @@ GpgolMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
           log_debug ("%s:%s: BodyFormat is %d",
                      SRCNAME, __func__, aVariant.intVal);
           
-          if (FAILED(pEECB->GetWindow (&hWnd)))
+          if (FAILED(eecb->GetWindow (&hWnd)))
             hWnd = NULL;
           MessageBox (hWnd,
                       _("Sorry, we can only encrypt plain text messages and\n"
@@ -311,7 +312,7 @@ GpgolMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
 
 
 /* Called by Exchange when the data has been written to the message.
-   Encrypts and signs the message if the options are set.  PEECB is a
+   Encrypts and signs the message if the options are set.  EECB is a
    pointer to the IExchExtCallback interface.  Returns: S_FALSE to
    signal Exchange to continue calling extensions.  We return E_FAIL
    to signals Exchange an error; the message will not be sent.  Note
@@ -319,7 +320,7 @@ GpgolMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
    back the write operation and that no further extensions should be
    called. */
 STDMETHODIMP 
-GpgolMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
+GpgolMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK eecb, ULONG flags)
 {
   HRESULT hrReturn = S_FALSE;
   LPMESSAGE msg = NULL;
@@ -330,7 +331,7 @@ GpgolMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
   log_debug ("%s:%s: received\n", SRCNAME, __func__);
 
 
-  if (lFlags & (EEME_FAILED|EEME_COMPLETE_FAILED))
+  if (flags & (EEME_FAILED|EEME_COMPLETE_FAILED))
     return S_FALSE; /* We don't need to rollback anything in case
                        other extensions flagged a failure. */
           
@@ -341,11 +342,11 @@ GpgolMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
     return S_FALSE;
 
   /* Try to get the current window. */
-  if (FAILED(pEECB->GetWindow (&hWnd)))
+  if (FAILED(eecb->GetWindow (&hWnd)))
     hWnd = NULL;
 
   /* Get the object and call the encryption or signing fucntion.  */
-  HRESULT hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&msg);
+  HRESULT hr = eecb->GetObject (&pMDB, (LPMAPIPROP *)&msg);
   if (SUCCEEDED (hr))
     {
       if (m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
@@ -372,10 +373,10 @@ GpgolMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
 
 
 /* Called by Exchange when the user selects the "check names" command.
-   PEECB is a pointer to the IExchExtCallback interface.  Returns
+   EECB is a pointer to the IExchExtCallback interface.  Returns
    S_FALSE to signal Exchange to continue calling extensions. */
 STDMETHODIMP 
-GpgolMessageEvents::OnCheckNames(LPEXCHEXTCALLBACK pEECB)
+GpgolMessageEvents::OnCheckNames(LPEXCHEXTCALLBACK eecb)
 {
   log_debug ("%s:%s: received\n", SRCNAME, __func__);
   return S_FALSE;
@@ -383,10 +384,10 @@ GpgolMessageEvents::OnCheckNames(LPEXCHEXTCALLBACK pEECB)
 
 
 /* Called by Exchange when "check names" command is complete.
-   PEECB is a pointer to the IExchExtCallback interface.  Returns
+   EECB is a pointer to the IExchExtCallback interface.  Returns
    S_FALSE to signal Exchange to continue calling extensions. */
 STDMETHODIMP 
-GpgolMessageEvents::OnCheckNamesComplete (LPEXCHEXTCALLBACK pEECB,ULONG lFlags)
+GpgolMessageEvents::OnCheckNamesComplete (LPEXCHEXTCALLBACK eecb,ULONG flags)
 {
   log_debug ("%s:%s: received\n", SRCNAME, __func__);
   return S_FALSE;
@@ -394,11 +395,11 @@ GpgolMessageEvents::OnCheckNamesComplete (LPEXCHEXTCALLBACK pEECB,ULONG lFlags)
 
 
 /* Called by Exchange before the message data will be written and
-   submitted to MAPI.  PEECB is a pointer to the IExchExtCallback
+   submitted to MAPI.  EECB is a pointer to the IExchExtCallback
    interface.  Returns S_FALSE to signal Exchange to continue calling
    extensions. */
 STDMETHODIMP 
-GpgolMessageEvents::OnSubmit (LPEXCHEXTCALLBACK pEECB)
+GpgolMessageEvents::OnSubmit (LPEXCHEXTCALLBACK eecb)
 {
   log_debug ("%s:%s: received\n", SRCNAME, __func__);
   m_bOnSubmitActive = TRUE;
@@ -408,10 +409,10 @@ GpgolMessageEvents::OnSubmit (LPEXCHEXTCALLBACK pEECB)
 
 
 /* Called by Exchange after the message has been submitted to MAPI.
-   PEECB is a pointer to the IExchExtCallback interface. */
+   EECB is a pointer to the IExchExtCallback interface. */
 STDMETHODIMP_ (VOID) 
-GpgolMessageEvents::OnSubmitComplete (LPEXCHEXTCALLBACK pEECB,
-                                            ULONG lFlags)
+GpgolMessageEvents::OnSubmitComplete (LPEXCHEXTCALLBACK eecb,
+                                            ULONG flags)
 {
   log_debug ("%s:%s: received\n", SRCNAME, __func__);
   m_bOnSubmitActive = FALSE; 
index 18f1238..c6ba9c8 100644 (file)
@@ -254,7 +254,7 @@ message_verify (LPMESSAGE message, msgtype_t msgtype, int force)
      first to "?" to mark that no verification has yet happened. */
   if (force)
     mapi_set_sig_status (message, "?");
-  else if (mapi_has_sig_status (message))
+  else if (mapi_test_sig_status (message))
     return 0; /* Already checked that message.  */
 
   if (msgtype == MSGTYPE_GPGOL_CLEAR_SIGNED)
@@ -325,9 +325,13 @@ message_verify (LPMESSAGE message, msgtype_t msgtype, int force)
   xfree (inbuf);
                     
   if (err)
-    mapi_set_sig_status (message, gpg_strerror (err));
+    {
+      char buf[200];
+      snprintf (buf, sizeof buf, "- %s", gpg_strerror (err));
+      mapi_set_sig_status (message, gpg_strerror (err));
+    }
   else
-    mapi_set_sig_status (message, "Signature was good");
+    mapi_set_sig_status (message, "! Good signature");
 
   mapi_release_attach_table (table);
   return 0;
index 89db517..e9398a7 100644 (file)
@@ -132,8 +132,8 @@ check_protocol (protocol_t protocol)
 
 /* Create a new MAPI attchment for MESSAGE which will be used to
    prepare the MIME message.  On sucess the stream to write the data
-   to is stored at STREAM and the attchment object itself is the
-   retruned.  The caller needs to call SaveChanges.  Returns NULL on
+   to is stored at STREAM and the attachment object itself is the
+   returned.  The caller needs to call SaveChanges.  Returns NULL on
    failure in which case STREAM will be set to NULL.  */
 static LPATTACH
 create_mapi_attachment (LPMESSAGE message, sink_t sink)
@@ -240,12 +240,14 @@ write_buffer (sink_t sink, const void *data, size_t datalen)
   return sink->writefnc (sink, data, datalen);
 }
 
-/* Same as above but used for passing as callback function.  */
+/* Same as above but used for passing as callback function.  This
+   fucntion does not return an error code but the number of bytes
+   written.  */
 static int
-write_buffer_voidarg (void *opaque, const void *data, size_t datalen)
+write_buffer_for_cb (void *opaque, const void *data, size_t datalen)
 {
   sink_t sink = opaque;
-  return write_buffer (sink, data, datalen);
+  return write_buffer (sink, data, datalen) ? -1 : datalen;
 }
 
 
@@ -1018,6 +1020,11 @@ finalize_message (LPMESSAGE message, mapi_attach_item_t *att_table)
       return -1;
     }
 
+  /* Set a special property so that we are later able to identify
+     messages signed or encrypted by us.  */
+  if (mapi_set_sig_status (message, "@"))
+    return -1;
+
   /* Now delete all parts of the MAPI message except for the one
      attachment we just created.  */
   if (delete_all_attachments (message, att_table))
@@ -1037,6 +1044,7 @@ finalize_message (LPMESSAGE message, mapi_attach_item_t *att_table)
     IMessage_DeleteProps (message, &proparray, NULL);
   }
 
+
   /* Save the Changes.  */
   hr = IMessage_SaveChanges (message, KEEP_OPEN_READWRITE|FORCE_SAVE);
   if (hr)
@@ -1072,6 +1080,7 @@ sink_hashing_write (sink_t hashsink, const void *data, size_t datalen)
   return rc;
 }
 
+
 /* This function is called by the filter to collect the output which
    is a detached signature.  */
 static int
@@ -1087,7 +1096,7 @@ collect_signature (void *opaque, const void *data, size_t datalen)
   memcpy (db->buf + db->len, data, datalen);
   db->len += datalen;
 
-  return 0;
+  return datalen;
 }
 
 
@@ -1370,7 +1379,7 @@ mime_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients)
   /* Prepare the encryption.  We do this early as it is quite common
      that some recipients are not be available and thus the encryption
      will fail early. */
-  if (engine_create_filter (&filter, write_buffer_voidarg, sink))
+  if (engine_create_filter (&filter, write_buffer_for_cb, sink))
     goto failure;
   if (engine_encrypt_start (filter, protocol, recipients))
     goto failure;
@@ -1392,6 +1401,7 @@ mime_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients)
 
   /* Write the top header.  */
   generate_boundary (boundary);
+  TRACEPOINT ();
   if ((rc=write_multistring (sink,
                              "MIME-Version: 1.0\r\n"
                              "Content-Type: multipart/encrypted;\r\n"
@@ -1400,6 +1410,7 @@ mime_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients)
                              NULL)))
     goto failure;
 
+  TRACEPOINT ();
   /* Write the PGP/MIME encrypted part.  */
   if ((rc = write_boundary (sink, boundary, 0)))
     goto failure;
@@ -1418,9 +1429,11 @@ mime_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients)
                              "\r\n", NULL)))
     goto failure;
 
+  TRACEPOINT ();
   /* Create a new sink for encrypting the following stuff.  */
   encsink->cb_data = filter;
   encsink->writefnc = sink_encryption_write;
+  TRACEPOINT ();
   
   if ((body && n_att_usable) || n_att_usable > 1)
     {
@@ -1435,6 +1448,7 @@ mime_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients)
   else /* Only one part.  */
     *inner_boundary = 0;
 
+  TRACEPOINT ();
 
   if (body)
     rc = write_part (encsink, body, strlen (body), 
@@ -1444,6 +1458,7 @@ mime_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients)
                             *inner_boundary? inner_boundary : NULL);
   if (rc)
     goto failure;
+  TRACEPOINT ();
 
   xfree (body);
   body = NULL;
@@ -1461,20 +1476,27 @@ mime_encrypt (LPMESSAGE message, protocol_t protocol, char **recipients)
   filter = NULL; /* Not valid anymore.  */
   encsink->cb_data = NULL; /* Not needed anymore.  */
   
+  TRACEPOINT ();
 
   /* Write the final boundary and finish the attachment.  */
   if ((rc = write_boundary (sink, boundary, 1)))
     goto failure;
 
+  TRACEPOINT ();
+
   if (close_mapi_attachment (&attach, sink))
     goto failure;
 
+  TRACEPOINT ();
+
   if (finalize_message (message, att_table))
     goto failure;
 
   result = 0;  /* Everything is fine, fall through the cleanup now.  */
+  TRACEPOINT ();
 
  failure:
+  TRACEPOINT ();
   engine_cancel (filter);
   cancel_mapi_attachment (&attach, sink);
   xfree (body);
index c3116ff..fbbbb23 100644 (file)
@@ -309,8 +309,7 @@ start_attachment (mime_context_t ctx, int is_body)
       goto leave;
     }
 
-
-  /* The body attachment is special and should not be show in the list
+  /* The body attachment is special and should not be shown in the list
      of attachments.  */
   if (is_body)
     {
@@ -483,7 +482,7 @@ finish_attachment (mime_context_t ctx, int cancel)
         retval = 0;
       else if (ctx->mapi_attach)
         {
-          hr = IAttach_SaveChanges (ctx->mapi_attach, KEEP_OPEN_READWRITE);
+          hr = IAttach_SaveChanges (ctx->mapi_attach, 0);
           if (hr)
             {
               log_error ("%s:%s: SaveChanges(attachment) failed: hr=%#lx\n",
@@ -507,6 +506,14 @@ finish_attachment (mime_context_t ctx, int cancel)
 }
 
 
+static int
+finish_message (LPMESSAGE message)
+{
+  return 0;
+}
+
+
+
 /* Process the transition to body event. 
 
    This means we have received the empty line indicating the body and
@@ -778,7 +785,7 @@ plaintext_handler (void *handle, const void *buffer, size_t size)
           log_error ("%s: ctx=%p, rfc822 parser failed: line too long\n",
                      SRCNAME, ctx);
           ctx->line_too_long = 1;
-          return 0; /* Error. */
+          return -1; /* Error. */
         }
       if (*s != '\n')
         ctx->linebuf[pos++] = *s;
@@ -792,7 +799,7 @@ plaintext_handler (void *handle, const void *buffer, size_t size)
               log_error ("%s: ctx=%p, rfc822 parser failed: %s\n",
                          SRCNAME, ctx, strerror (errno));
               ctx->parser_error = 1;
-              return 0; /* Error. */
+              return -1; /* Error. */
             }
 
 
@@ -846,7 +853,7 @@ plaintext_handler (void *handle, const void *buffer, size_t size)
                         MessageBox (ctx->hwnd, _("Error writing to stream"),
                                     _("I/O-Error"), MB_ICONERROR|MB_OK);
                       ctx->parser_error = 1;
-                      return 0; /* Error. */
+                      return -1; /* Error. */
                     }
                 }
             }
@@ -1022,6 +1029,8 @@ mime_verify (protocol_t protocol, const char *message, size_t messagelen,
         }
       symenc_close (ctx->symenc);
       xfree (ctx);
+      if (!err)
+        finish_message (mapi_message);
     }
   return err;
 }
@@ -1118,7 +1127,7 @@ mime_decrypt (protocol_t protocol, LPSTREAM instream, LPMESSAGE mapi_message,
     {
       /* Cancel any left over attachment which means that the MIME
          structure was not complete.  However if we have not seen any
-         boundary the message is a non-MIME one but we way have
+         boundary the message is a non-MIME one but we may have
          started the body attachment (gpgol000.txt) - this one needs
          to be finished properly.  */
       finish_attachment (ctx, ctx->any_boundary? 1: 0);
@@ -1138,6 +1147,8 @@ mime_decrypt (protocol_t protocol, LPSTREAM instream, LPMESSAGE mapi_message,
         }
       symenc_close (ctx->symenc);
       xfree (ctx);
+      if (!err)
+        finish_message (mapi_message);
     }
   return err;
 }
index 1a4f860..e91b69c 100644 (file)
@@ -108,8 +108,22 @@ typedef struct MapiMessage_s *lpMapiMessage;
 #define MAPI_E_NOT_FOUND                   ((SCODE)0x8004010F)
 
 
-/* MAPILogon */
+/* Object types.  */
+#define MAPI_STORE      0x00000001u
+#define MAPI_ADDRBOOK   0x00000002u
+#define MAPI_FOLDER     0x00000003u
+#define MAPI_ABCONT     0x00000004u
+#define MAPI_MESSAGE    0x00000005u
+#define MAPI_MAILUSER   0x00000006u
+#define MAPI_ATTACH     0x00000007u
+#define MAPI_DISTLIST   0x00000008u    
+#define MAPI_PROFSECT   0x00000009u    
+#define MAPI_STATUS     0x0000000Au
+#define MAPI_SESSION    0x0000000Bu
+#define MAPI_FORMINFO   0x0000000Cu
+
 
+/* MAPILogon */
 #define MAPI_LOGON_UI           0x00000001
 #define MAPI_PASSWORD_UI        0x00020000
 #define MAPI_NEW_SESSION        0x00000002
@@ -118,7 +132,6 @@ typedef struct MapiMessage_s *lpMapiMessage;
 
 
 /* MAPISendMail */
-
 #define MAPI_DIALOG             0x00000008
 
 
index 80db60a..78d94b1 100644 (file)
@@ -23,6 +23,7 @@
 #define OLFLANGE_DEF_H
 
 class GpgolExtCommands;
+class GpgolUserEvents;
 class GpgolSessionEvents;
 class GpgolMessageEvents;
 class GpgolAttachedFileEvents;
index 89f5c78..a74c38f 100644 (file)
@@ -45,6 +45,7 @@
 #include "olflange-def.h"
 #include "olflange.h"
 #include "ext-commands.h"
+#include "user-events.h"
 #include "session-events.h"
 #include "message-events.h"
 #include "property-sheets.h"
@@ -295,12 +296,14 @@ GpgolExt::GpgolExt (void)
   msgtype_valid = FALSE;
 
   m_pExchExtCommands           = new GpgolExtCommands (this);
+  m_pExchExtUserEvents         = new GpgolUserEvents (this);
   m_pExchExtSessionEvents      = new GpgolSessionEvents (this);
   m_pExchExtMessageEvents      = new GpgolMessageEvents (this);
   m_pExchExtAttachedFileEvents = new GpgolAttachedFileEvents (this);
   m_pExchExtPropertySheets     = new GpgolPropertySheets (this);
   m_pOutlookExtItemEvents      = new GpgolItemEvents (this);
   if (!m_pExchExtCommands
+      || !m_pExchExtUserEvents
       || !m_pExchExtSessionEvents
       || !m_pExchExtMessageEvents
       || !m_pExchExtAttachedFileEvents
@@ -368,6 +371,11 @@ GpgolExt::QueryInterface(REFIID riid, LPVOID *ppvObj)
       *ppvObj = (LPUNKNOWN)m_pExchExtCommands;
       m_pExchExtCommands->SetContext (m_lContext);
     }
+  else if (riid == IID_IExchExtUserEvents) 
+    {
+      *ppvObj = (LPUNKNOWN) m_pExchExtUserEvents;
+      m_pExchExtUserEvents->SetContext (m_lContext);
+    }
   else if (riid == IID_IExchExtSessionEvents) 
     {
       *ppvObj = (LPUNKNOWN) m_pExchExtSessionEvents;
@@ -434,7 +442,8 @@ GpgolExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
   if (!version_shown)
     {
       version_shown = 1;
-      log_debug ("%s:%s: using gpgme %s\n", gpgme_check_version (NULL));
+      log_debug ("%s:%s: using gpgme %s\n", 
+                 SRCNAME, __func__, gpgme_check_version (NULL));
       log_debug ("%s:%s: detected Outlook build version 0x%lx (%lu.%lu)\n",
                  SRCNAME, __func__, lBuildVersion,
                  (lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK) >> 16,
index 6ad5d49..09b0f48 100644 (file)
@@ -54,6 +54,7 @@ private:
 
   /* Pointer to the other extension objects.  */
   GpgolExtCommands        *m_pExchExtCommands;
+  GpgolUserEvents         *m_pExchExtUserEvents;
   GpgolSessionEvents      *m_pExchExtSessionEvents;
   GpgolMessageEvents      *m_pExchExtMessageEvents;
   GpgolPropertySheets     *m_pExchExtPropertySheets;
diff --git a/src/user-events.cpp b/src/user-events.cpp
new file mode 100644 (file)
index 0000000..4371bfb
--- /dev/null
@@ -0,0 +1,129 @@
+/* user-events.cpp - Subclass impl of IExchExtUserEvents
+ *     Copyright (C) 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+#include "myexchext.h"
+#include "display.h"
+#include "common.h"
+#include "msgcache.h"
+#include "engine.h"
+#include "mapihelp.h"
+
+#include "olflange-def.h"
+#include "olflange.h"
+#include "user-events.h"
+
+
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     SRCNAME, __func__, __LINE__); \
+                        } while (0)
+
+
+/* Wrapper around UlRelease with error checking. */
+/* FIXME: Duplicated code.  */
+#if 0
+static void 
+ul_release (LPVOID punk)
+{
+  ULONG res;
+  
+  if (!punk)
+    return;
+  res = UlRelease (punk);
+//   log_debug ("%s UlRelease(%p) had %lu references\n", __func__, punk, res);
+}
+#endif
+
+
+
+
+/* Our constructor.  */
+GpgolUserEvents::GpgolUserEvents (GpgolExt *pParentInterface)
+{ 
+  m_pExchExt = pParentInterface;
+  m_lRef = 0; 
+}
+
+
+/* The QueryInterface which does the actual subclassing.  */
+STDMETHODIMP 
+GpgolUserEvents::QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
+{   
+  *ppvObj = NULL;
+  if (riid == IID_IExchExtUserEvents)
+    {
+      *ppvObj = (LPVOID)this;
+      AddRef();
+      return S_OK;
+    }
+  if (riid == IID_IUnknown)
+    {
+      *ppvObj = (LPVOID)m_pExchExt;  
+      m_pExchExt->AddRef();
+      return S_OK;
+    }
+  return E_NOINTERFACE;
+}
+
+
+
+/* Called from Outlook for all selection changes.
+
+   PEECB is a pointer to the IExchExtCallback interface.  */
+STDMETHODIMP_ (VOID)
+GpgolUserEvents::OnSelectionChange (LPEXCHEXTCALLBACK eecb) 
+{
+  HRESULT hr;
+  ULONG count, objtype;
+  char msgclass[256];
+
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+
+  hr = eecb->GetSelectionCount (&count);
+  if (SUCCEEDED (hr) && count > 0)
+    {
+      hr = eecb->GetSelectionItem (0L, NULL, NULL, &objtype,
+                                   msgclass, sizeof msgclass -1, NULL, 0L);
+      if (SUCCEEDED(hr) && objtype == MAPI_MESSAGE)
+        {
+          log_debug ("%s:%s: message class: %s\n",
+            SRCNAME, __func__, msgclass);
+        }
+    }
+}
+
+/* I assume this is called from Outlook for all object changes.
+
+   PEECB is a pointer to the IExchExtCallback interface.  */
+STDMETHODIMP_ (VOID)
+GpgolUserEvents::OnObjectChange (LPEXCHEXTCALLBACK eecb) 
+{ 
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+
+}
+
diff --git a/src/user-events.h b/src/user-events.h
new file mode 100644 (file)
index 0000000..7ae0037
--- /dev/null
@@ -0,0 +1,68 @@
+/* user-events.h - Definitions for our subclass of IExchExtUserEvents
+ *     Copyright (C) 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef USER_EVENTS_H
+#define USER_EVENTS_H
+
+/*
+   GpgolUserEvents 
+   The GpgolUserEvents class implements the reaction on the certain
+   user events.
+ */
+class GpgolUserEvents : public IExchExtUserEvents
+{
+  /* Constructor. */
+public:
+  GpgolUserEvents (GpgolExt *pParentInterface);
+
+  /* Attributes. */
+private:
+  ULONG   m_lRef;
+  ULONG   m_lContext;
+  GpgolExt *m_pExchExt;
+  
+public:
+  STDMETHODIMP QueryInterface (REFIID riid, LPVOID *ppvObj);
+  inline STDMETHODIMP_(ULONG) AddRef (void)
+  {
+    ++m_lRef; 
+    return m_lRef; 
+  };
+  inline STDMETHODIMP_(ULONG) Release (void) 
+  {
+    ULONG lCount = --m_lRef;
+    if (!lCount) 
+      delete this;
+    return lCount;     
+  };
+
+  STDMETHODIMP_ (VOID) OnSelectionChange (LPEXCHEXTCALLBACK eecb);
+  STDMETHODIMP_ (VOID) OnObjectChange (LPEXCHEXTCALLBACK eecb);
+
+  inline void SetContext (ULONG lContext)
+  { 
+    m_lContext = lContext;
+  };
+};
+
+
+#endif /*USER_EVENTS_H*/