Larger rewrites. Many parts won't work but at least a Reply
authorWerner Koch <wk@gnupg.org>
Tue, 23 Aug 2005 13:52:47 +0000 (13:52 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 23 Aug 2005 13:52:47 +0000 (13:52 +0000)
template gets initialzed with the plaintext.  Compiles but
further work is underway.

24 files changed:
configure.ac [new file with mode: 0644]
src/ChangeLog
src/Makefile.am
src/MapiGPGME.cpp
src/MapiGPGME.h
src/common.c
src/engine-gpgme.c
src/engine.h
src/gpgmsg.cpp [new file with mode: 0644]
src/gpgmsg.hh [new file with mode: 0644]
src/intern.h
src/keycache.c
src/main.c
src/msgcache.c [new file with mode: 0644]
src/msgcache.h [new file with mode: 0644]
src/myexchext.h [new file with mode: 0644]
src/mymapi.h
src/mymapitags.h
src/olflange.cpp
src/olflange.h
src/outlgpg.def
src/recipient-dialog.c
src/util.h
src/versioninfo.rc.in [new file with mode: 0644]

diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..78664d3
--- /dev/null
@@ -0,0 +1,216 @@
+# configure.ac - for Outlgpg
+# Copyright (C) 2005 g10 Code GmbH
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.59)
+min_automake_version="1.9.4"
+
+# Version number: Remember to change it immediately *after* a release.
+#                 Add a "-cvs" prefix for non-released code.
+AC_INIT(outlgpg, 0.99.5-cvs, bug-outlgpg@g10code.com)
+
+NEED_GPGME_API=1
+NEED_GPGME_VERSION=1.1.0
+
+
+PACKAGE=$PACKAGE_NAME
+PACKAGE_GT=${PACKAGE_NAME}
+VERSION=$PACKAGE_VERSION
+
+AC_CONFIG_SRCDIR(src/olgpgcore.def)
+AM_CONFIG_HEADER(config.h)
+AC_CANONICAL_TARGET()
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
+
+AC_GNU_SOURCE
+
+AC_SUBST(PACKAGE)
+AC_SUBST(PACKAGE_GT)
+AC_SUBST(VERSION)
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of this package])
+AC_DEFINE_UNQUOTED(PACKAGE_GT, "$PACKAGE_GT",
+                                [Name of this package for gettext])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version of this package])
+AC_DEFINE_UNQUOTED(PACKAGE_BUGREPORT, "$PACKAGE_BUGREPORT",
+                                        [Bug report address])
+AC_DEFINE_UNQUOTED(NEED_GPGME_VERSION, "$NEED_GPGME_VERSION",
+                                       [Required version of GPGME])
+
+BUILD_TIMESTAMP=`date --iso-8601=minutes`
+AC_SUBST(BUILD_TIMESTAMP)
+changequote(,)dnl
+BUILD_FILEVERSION=`echo "$VERSION" | sed 's/\([0-9.]*\).*/\1.0/;s/\./,/g'`
+changequote([,])dnl
+AC_SUBST(BUILD_FILEVERSION)
+
+
+AH_BOTTOM([
+/* Some global constants. */
+
+
+])
+
+AM_MAINTAINER_MODE
+
+# Checks for programs.
+AC_PROG_MAKE_SET
+AM_SANITY_CHECK
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+AC_CHECK_TOOL(AR, ar, :)
+AC_CHECK_TOOL(DLLTOOL, dlltool, :)
+AC_CHECK_TOOL(WINDRES, windres, :)
+
+
+try_gettext=yes
+have_dosish_system=no
+have_w32_system=no
+case "${host}" in
+    *-mingw32*)
+        # special stuff for Windoze NT
+        ac_cv_have_dev_random=no
+        AC_DEFINE(USE_ONLY_8DOT3,1,
+                  [set this to limit filenames to the 8.3 format])
+        AC_DEFINE(HAVE_DRIVE_LETTERS,1,
+                  [defined if we must run on a stupid file system])
+        AC_DEFINE(USE_SIMPLE_GETTEXT,1,
+                  [because the Unix gettext has too much overhead on
+                   MingW32 systems and these systems lack Posix functions,
+                   we use a simplified version of gettext])
+        have_dosish_system=yes
+        have_w32_system=yes
+        try_gettext="no"
+        ;;
+    *)
+    AC_MSG_ERROR([[
+***
+*** This software my only be build for W32 systems.  Use
+***     ./autogen.sh --build-w32
+*** to prepare it for such a build.
+***]])
+       ;;
+esac
+
+if test "$have_dosish_system" = yes; then
+   AC_DEFINE(HAVE_DOSISH_SYSTEM,1,
+             [Defined if we run on some of the PCDOS like systems
+              (DOS, Windoze. OS/2) with special properties like
+              no file modes])
+fi
+AM_CONDITIONAL(HAVE_DOSISH_SYSTEM, test "$have_dosish_system" = yes)
+
+if test "$have_w32_system" = yes; then
+   AC_DEFINE(HAVE_W32_SYSTEM,1, [Defined if we run on a W32 API based system])
+fi
+AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes)
+
+
+
+#
+# Checks for libraries.
+#
+
+
+AM_PATH_GPGME("$NEED_GPGME_API:$NEED_GPGME_VERSION",
+               have_gpgme=yes,have_gpgme=no)
+
+
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(string.h unistd.h langinfo.h termio.h locale.h)
+
+AC_CHECK_FUNCS(stpcpy)
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_TYPE_SIGNAL
+
+AM_CONDITIONAL(CROSS_COMPILING, test x$cross_compiling = xyes)
+
+# Add some extra libs here so that previous tests don't fail for
+# mysterious reasons - the final link step should bail out.
+if test "$have_w32_system" = yes; then
+   W32LIBS="-lwsock32"
+fi
+
+if test "$GCC" = yes; then
+    if test "$USE_MAINTAINER_MODE" = "yes"; then
+        CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
+        CFLAGS="$CFLAGS -Wno-format-y2k -Wformat-security"
+    else
+        CFLAGS="$CFLAGS -Wall"
+    fi
+fi
+
+AC_SUBST(W32LIBS)
+
+
+
+# AC_CONFIG_LINKS([
+# olflange/gpgexch.cpp:olflange/GPGExch.cpp
+# olflange/gpgexch.def:olflange/GPGExch.def
+# olflange/gpgexch.dsp:olflange/GPGExch.dsp
+# olflange/gpgexch.dsw:olflange/GPGExch.dsw
+# olflange/gpgexch.h:olflange/GPGExch.h
+# olflange/gpgexch.plg:olflange/GPGExch.plg
+# olflange/gpgexch.rc:olflange/GPGExch.rc
+# olflange/gpgexchange.h:olflange/GPGExchange.h
+# olflange/gpgoptions.cpp:olflange/GPGOptions.cpp
+# olflange/gpgoptionsdlg.cpp:olflange/GPGOptionsDlg.cpp
+# olflange/stdafx.cpp:olflange/StdAfx.cpp
+# olflange/stdafx.h:olflange/StdAfx.h
+# ])
+# 
+
+#
+# Print errors here so that they are visible all
+# together and the user can acquire them all together.
+#
+die=no
+if test "$have_gpgme" = "no"; then
+   die=yes
+   AC_MSG_NOTICE([[
+***  
+*** You need gpgme to build this program.
+**  This library is for example available at
+***   ftp://ftp.gnupg.org/gcrypt/gpgme/
+*** (at least version $NEED_GPGME_VERSION is required.)
+***]])
+fi
+if test "$die" = "yes"; then
+    AC_MSG_ERROR([[
+***
+*** Required libraries not found. Please consult the above messages
+*** and install them before running configure again.
+***]])
+fi
+
+
+AC_CONFIG_FILES([ Makefile
+src/Makefile
+src/versioninfo.rc        
+])
+AC_OUTPUT
index f840527..420bbeb 100644 (file)
@@ -1,3 +1,72 @@
+2005-08-23  Werner Koch  <wk@g10code.com>
+
+       * msgcache.c, msgcache.h: New.
+
+2005-08-22  Werner Koch  <wk@g10code.com>
+
+       * olflange.cpp: Major cleanups and partly rewrites.
+
+2005-08-18  Werner Koch  <wk@g10code.com>
+
+       * gpgmsg.cpp, gpgmsg.hh: New.
+       
+2005-08-17  Werner Koch  <wk@g10code.com>
+
+       * MapiGPGME.cpp (setMessageAccess): Removed as it was only used at
+       one place.
+       (setRTFBody): Use the above code here directly..
+       (setWindow, setMessage): Removed.  We can't use that because there
+       is only one instance of this class.
+       (decrypt): Add args HWND and MSG.  Changed caller.
+       (getBody): Changed to ..
+       (get_body): .. plain function and add new arg MSG.  Changed all
+       callers.
+       (isHtmlMessage): Likewise changed to ..
+       (is_html_message): .. plain function and add new arg MSG.
+       (doCmd): Removed.
+
+       * common.c (utf8_to_wchar): New.
+
+       * MapiGPGME.cpp (passphraseCallback): Removed.
+       (getPassphrase, clearPassphrase, storePassphrase): Removed.
+       (add_html_line_endings): Rewritten.
+
+       * engine-gpgme.c (op_sign_encrypt_start): Removed because it is
+       not used anywhere.
+       (op_sign): Renamed to ..
+       (do_sign): .. this and made local.
+
+2005-08-16  Werner Koch  <wk@g10code.com>
+
+       * MapiGPGME.cpp (signAttachment): Simplified.
+       * engine-gpgme.c (op_sign_file): Add arg TTL.
+       (op_sign_file_ext): Removed.
+       (op_sign_file_next): Renamed to ..
+       (do_sign_file): .. this and made local.
+       (do_sign_file): Updated to use new passphrase callback
+       semantics.
+       (op_decrypt_file): Ditto.
+       (free_recipients): Need to use gpgme_key_release and not just
+       free.
+
+       * engine-gpgme.c (do_decrypt): Factored some code out to ..
+       (update_passphrase_cache): .. new.
+       (op_sign_encrypt_file): Updated to use new passphrase callback
+       semantics.
+
+       * MapiGPGME.cpp (getBody): Properly distinguish property types.
+       (delete_buf): Removed macro.  We now use malloc for the body
+       string.  Changed other places to use delete directly for clarity.
+       (fail_if_null): Removed.  Replaced by direct tests and a call to
+       out_of_core.
+       (setDefaultKey): Now use malloc/free instead of new/delete.
+       Changed at other places too.
+       (getDefaultKey): Changed to return a const char *.
+
+       * common.c (wchar_to_utf8): New.
+       (out_of_core): Made global and call abort after displaying the
+       message box.
+
 2005-08-14  Werner Koch  <wk@g10code.com>
 
        * MapiGPGME.cpp (log_debug_w32): New.
index 7133203..abbf3b9 100644 (file)
@@ -28,6 +28,8 @@ outlgpg_SOURCES = \
        olflange-ids.h              \
        myexchext.h                 \
        MapiGPGME.cpp MapiGPGME.h   \
+       gpgmsg.cpp gpgmsg.hh        \
+       msgcache.c msgcache.h       \
         engine-gpgme.c engine.h    \
         common.c intern.h          \
        passcache.c passcache.h     \
index e9b350b..1b04eb6 100644 (file)
@@ -1,21 +1,22 @@
 /* MapiGPGME.cpp - Mapi support with GPGME
  *     Copyright (C) 2005 g10 Code GmbH
  *
- * This file is part of GPGME Dialogs.
- *
- * GPGME Dialogs 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.1 
- * of the License, or (at your option) any later version.
- *  
- * GPGME Dialogs is distributed in the hope that it will be useful,
+ * This file is part of OutlGPG.
+ * 
+ * OutlGPG 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.
+ * 
+ * OutlGPG 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with GPGME Dialogs; if not, write to the Free Software Foundation, 
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ * 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
@@ -24,6 +25,8 @@
 
 #include <windows.h>
 #include <time.h>
+#include <assert.h>
+#include <string.h>
 
 #ifdef __MINGW32__
 # include "mymapi.h"
 #include "MapiGPGME.h"
 #include "engine.h"
 
-/* These were omitted from the standard headers */
-#ifndef PR_BODY_HTML
-#define PR_BODY_HTML (PROP_TAG(PT_TSTRING, 0x1013))
-#endif
 
 /* Attachment information. */
 #define ATT_SIGN(action) ((action) & GPG_ATTACH_SIGN)
 #define EXT_MSG "pgp"
 #define EXT_SIG "sig"
 
-/* memory macros */
-#define delete_buf(buf) delete [] (buf)
-
-#define fail_if_null(p) do { if (!(p)) abort (); } while (0)
 
 
 /* Given that we are only able to configure one log file, it does not
@@ -84,6 +79,12 @@ static int lock_log (void);
 static void unlock_log (void);
 
 
+static HWND find_message_window (HWND parent, GpgMsg *msg);
+static void log_key_info (MapiGPGME *g, const char *prefix,
+                          gpgme_key_t *keys, gpgme_key_t locusr);
+
+
+
 
 
 /*
@@ -102,28 +103,13 @@ public:
     log_debug ("MapiGPGME.constructor: ready\n");
   }
 
-  MapiGPGMEImpl (LPMESSAGE msg)
-  {
-    clearConfig ();
-    clearObject ();
-    this->msg = msg;
-    this->passCache = new HashTable ();
-    op_init ();
-    prepareLogging ();
-    log_debug ("MapiGPGME.constructor: ready (msg=%p)\n", msg);
-  }
-  
   ~MapiGPGMEImpl ()
   {
     unsigned int i=0;
 
     log_debug ("MapiGPGME.destructor: called\n");
     op_deinit ();
-    if (defaultKey)
-      {
-       delete_buf (defaultKey);
-       defaultKey = NULL;
-      }
+    xfree (defaultKey);
     log_debug ("hash entries %d\n", passCache->size ());
     for (i = 0; i < passCache->size (); i++) 
       {
@@ -154,13 +140,13 @@ public:
     return PACKAGE_VERSION;
   }
     
-  int __stdcall encrypt (void);
-  int __stdcall decrypt (void);
-  int __stdcall sign (void);
-  int __stdcall verify (void);
-  int __stdcall signEncrypt (void);
+  int __stdcall encrypt (HWND hwnd, GpgMsg *msg);
+  int __stdcall decrypt (HWND hwnd, GpgMsg *msg);
+  int __stdcall sign (HWND hwnd, GpgMsg *msg);
+  int __stdcall signEncrypt (HWND hwnd, GpgMsg *msg);
+  int __stdcall verify (HWND hwnd, GpgMsg *msg);
+  int __stdcall attachPublicKey (const char *keyid);
 
-  int __stdcall doCmd(int doEncrypt, int doSign);
   int __stdcall doCmdAttach(int action);
   int __stdcall doCmdFile(int action, const char *in, const char *out);
 
@@ -284,23 +270,23 @@ public:
     return has;
   }
 
-  bool __stdcall deleteAttachment (int pos)
+  bool __stdcall deleteAttachment (GpgMsg * msg, int pos)
   {
-    if (msg->DeleteAttach (pos, 0, NULL, 0) == S_OK)
-      return true;
-    return false;
+//     if (msg->DeleteAttach (pos, 0, NULL, 0) == S_OK)
+//       return true;
+//     return false;
   }
 
-  LPATTACH __stdcall createAttachment (int &pos)
+  LPATTACH __stdcall createAttachment (GpgMsg * msg, int &pos)
   {
     ULONG attnum;      
     LPATTACH newatt = NULL;
     
-    if (msg->CreateAttach (NULL, 0, &attnum, &newatt) == S_OK)
-      {
-        pos = attnum;
-        return newatt;
-      }
+//     if (msg->CreateAttach (NULL, 0, &attnum, &newatt) == S_OK)
+//       {
+//         pos = attnum;
+//         return newatt;
+//       }
     return NULL;
   }
 
@@ -309,21 +295,9 @@ public:
   int __stdcall startKeyManager ();
   void __stdcall startConfigDialog (HWND parent);
 
-  int __stdcall attachPublicKey (const char *keyid);
-
   void __stdcall setDefaultKey (const char *key);
-  char* __stdcall getDefaultKey (void);
-
-  void __stdcall setMessage (LPMESSAGE msg);
-  void __stdcall setWindow (HWND hwnd);
+  const char * __stdcall getDefaultKey (void);
 
-  const char* __stdcall getPassphrase (const char *keyid);
-  void __stdcall storePassphrase (void *itm);
-  outlgpg_type_t __stdcall getMessageType (const char *body);
-
-  void __stdcall logDebug (const char *fmt, ...);
-  void __stdcall logDebug (const char *fmt, va_list a);
-    
   void __stdcall clearPassphrase (void) 
   {
     if (passCache != NULL)
@@ -332,21 +306,17 @@ public:
 
 
 private:
-  HWND       parent;
-  char       *defaultKey;
+  char       *defaultKey; /* Malloced default key or NULL. */
   HashTable   *passCache;
-  LPMESSAGE   msg;    /* The message we are working on.  Note, that
-                         this is a shallow copy <-- FIXME: What are
-                         the exact semantics of owenership. */
   LPMAPITABLE attachTable;
   LPSRowSet   attachRows;
   void       *recipSet;
 
   /* Options */
   int    nstorePasswd;  /* Time in seconds the passphrase is stored. */
+  bool    encryptDefault;
   bool    doEncrypt;
   bool    doSign;
-  bool    encryptDefault;
   bool    saveDecryptedAtt; /* Save decrypted attachments. */
   bool    autoSignAtt;     /* Sign all outgoing attachments. */
   int    encFormat;        /* Encryption format for attachments. */
@@ -371,8 +341,6 @@ private:
     this->attachTable = NULL;
     this->defaultKey = NULL;
     this->recipSet = NULL;
-    this->parent = NULL;
-    this->msg = NULL;
   }
 
   void clearConfig (void)
@@ -386,18 +354,7 @@ private:
     encFormat = DEFAULT_ATTACHMENT_FORMAT;
   }
 
-  HWND findMessageWindow (HWND parent);
-  void rtfSync (char *body);
-  int  setBody (char *body, bool isHtml);
-  int  setRTFBody (char *body);
-  bool isMessageEncrypted (void);
-  bool isHtmlBody (const char *body);
-  bool isHtmlMessage (void);
-  char *getBody (bool isHtml);
-    
   void cleanupTempFiles ();
-  char **getRecipients (bool isRootMsg);
-  void freeRecipients (char **recipients);
   void freeUnknownKeys (char **unknown, int n);
   void freeKeyArray (void **key);
 
@@ -406,11 +363,10 @@ private:
   char* getAttachFilename (LPATTACH obj);
   char* getAttachPathname (LPATTACH obj);
   bool  setAttachFilename (LPATTACH obj, const char *name, bool islong);
-  int   getMessageFlags ();
-  int   getMessageHasAttachments ();
-  bool  setMessageAccess (int access);
-  bool  setXHeader (const char *name, const char *val);
-  char* getXHeader (const char *name);
+  int   getMessageFlags (GpgMsg *msg);
+  int   getMessageHasAttachments (GpgMsg *msg);
+  bool  setXHeader (GpgMsg *msg, const char *name, const char *val);
+  char* getXHeader (GpgMsg *msg, const char *name);
   bool  checkAttachmentExtension (const char *ext);
   const char* getPGPExtension (int action);
   char* generateTempname (const char *name);
@@ -419,7 +375,7 @@ private:
   int   encryptAttachments (HWND hwnd);
   int   decryptAttachments (HWND hwnd);
   int   signAttachments (HWND hwnd);
-  LPATTACH openAttachment (int pos);
+  LPATTACH openAttachment (GpgMsg *msg, int pos);
   void  releaseAttachment (LPATTACH att);
   int   processAttachment (LPATTACH *att, HWND hwnd, int pos, int action);
   bool  saveDecryptedAttachment (HWND root, const char *srcname);
@@ -428,11 +384,11 @@ private:
 };
 
 
-/* Create an instance of the MapiGPGME class. MSG may be NULL. */
+/* Create an instance of the MapiGPGME class. */
 MapiGPGME *
-CreateMapiGPGME (LPMESSAGE msg)
+CreateMapiGPGME (void)
 {
-  return new MapiGPGMEImpl (msg);
+  return new MapiGPGMEImpl ();
 }
 
 
@@ -518,6 +474,12 @@ log_debug (const char *fmt, ...)
   va_end (a);
 }
 
+void 
+log_vdebug (const char *fmt, va_list a)
+{
+  do_log (fmt, a, 0);
+}
+
 
 void 
 log_debug_w32 (int w32err, const char *fmt, ...)
@@ -534,208 +496,84 @@ log_debug_w32 (int w32err, const char *fmt, ...)
 
 
 
-void 
-MapiGPGMEImpl::logDebug (const char *fmt, ...)
-{
-  va_list a;
-  
-  va_start (a, fmt);
-  do_log (fmt, a, 0);
-  va_end (a);
-}
-
-
-void 
-MapiGPGMEImpl::logDebug (const char *fmt, va_list a)
-{
-  do_log (fmt, a, 0);
-}
-
 
 
 void 
 MapiGPGMEImpl::cleanupTempFiles (void)
 {
-    HANDLE hd;
-    WIN32_FIND_DATA fnd;
-    char path[MAX_PATH+32], tmp[MAX_PATH+4];
-
-    GetTempPath (sizeof (path)-4, path);
-    if (path[strlen (path)-1] != '\\')
-       strcat (path, "\\");
-    strcpy (tmp, path);
-    strcat (path, "*"ATT_PREFIX"*");
-    hd = FindFirstFile (path, &fnd);
-    if (hd == INVALID_HANDLE_VALUE)
-       return;
-    do {
-       char *p = (char *)xcalloc (1, strlen (tmp) + strlen (fnd.cFileName) +2);
-       sprintf (p, "%s%s", tmp, fnd.cFileName);
-       log_debug ("delete tmp %s\n", p);
-       DeleteFile (p);
-       xfree (p);
-    } while (FindNextFile (hd, &fnd) == TRUE);
-    FindClose (hd);
-}
-
-
-int
-MapiGPGMEImpl::setRTFBody (char *body)
-{
-    setMessageAccess (MAPI_ACCESS_MODIFY);
-    HWND rtf = findMessageWindow (parent);
-    if (rtf != NULL) {
-        int rc;
-       
-       log_debug ("setRTFBody: window handle %p\n", rtf);
-       rc = SetWindowText (rtf, body);
-       log_debug_w32 (-1, "setRTFBody: window text is now `%s'", body);
-       return TRUE;
-    }
-    return FALSE;
-}
-
-
-int 
-MapiGPGMEImpl::setBody (char *body, bool isHtml)
-{
-    /* XXX: handle richtext/html */
-    SPropValue sProp; 
-    HRESULT hr;
-    int rc = TRUE;
-    
-    if (body == NULL) {
-       log_debug ("MapiGPGME.setBody: called with empty buffer\n");
-       return FALSE;
-    }
-    log_debug ("MapiGPGME.setBody: body is `%s'\n", body);
-    rtfSync (body);
-    sProp.ulPropTag = isHtml? PR_BODY_HTML : PR_BODY;
-    sProp.Value.lpszA = body;
-    hr = HrSetOneProp (msg, &sProp);
-    if (FAILED (hr))
-       rc = FALSE;
-    log_debug ("MapiGPGME.setBody: (html=%d) rc=%d\n", isHtml, rc);
-    return rc;
-}
-
-
-void
-MapiGPGMEImpl::rtfSync (char *body)
-{
-    BOOL bChanged = FALSE;
-    SPropValue sProp; 
-    HRESULT hr;
+  HANDLE hd;
+  WIN32_FIND_DATA fnd;
+  char path[MAX_PATH+32], tmp[MAX_PATH+32];
+  
+  assert (strlen (ATT_PREFIX) + 2 < 16 /* just a reasonable value*/ );
+  
+  *path = 0;
+  GetTempPath (sizeof (path)-4, path);
+  if (*path && path[strlen (path)-1] != '\\')
+    strcat (path, "\\");
+  strcpy (tmp, path);
+  strcat (path, "*"ATT_PREFIX"*");
+  hd = FindFirstFile (path, &fnd);
+  if (hd == INVALID_HANDLE_VALUE)
+    return;
 
-    /* Make sure that the Plaintext and the Richtext are in sync */
-    sProp.ulPropTag = PR_BODY;
-    sProp.Value.lpszA = "";
-    hr = HrSetOneProp(msg, &sProp);
-    RTFSync(msg, RTF_SYNC_BODY_CHANGED, &bChanged);
-    sProp.Value.lpszA = body;
-    hr = HrSetOneProp(msg, &sProp);
-    RTFSync(msg, RTF_SYNC_BODY_CHANGED, &bChanged);
+  do
+    {
+      char *p = (char *)xmalloc (strlen (tmp) + strlen (fnd.cFileName) + 2);
+      strcpy (stpcpy (p, tmp), fnd.cFileName);
+      log_debug ("deleting temp file `%s'\n", p);
+      DeleteFile (p);
+      xfree (p);
+    } 
+  while (FindNextFile (hd, &fnd) == TRUE);
+  FindClose (hd);
 }
 
 
-bool 
-MapiGPGMEImpl::isHtmlBody (const char *body)
+/* Update the display using the message MSG.  Return 0 on success. */
+static int
+update_display (HWND hwnd, GpgMsg *msg)
 {
-    char *p1, *p2;
+  HWND window;
 
-    /* XXX: it is possible but unlikely that the message text
-            contains the used keywords. */
-    p1 = strstr (body, "<HTML>");
-    p2 = strstr (body, "</HTML>");
-    if (p1 && p2)
-       return true;
-    p1 = strstr (body, "<html>");
-    p2 = strstr (body, "</html>");
-    if (p1 && p2)
-       return true;
-    /* XXX: use case insentensive strstr version. */
-    return false;
+  window = find_message_window (hwnd, msg);
+  if (window)
+    {
+      log_debug ("%s:%s: window handle %p\n", __FILE__, __func__, window);
+      SetWindowText (window, msg->getDisplayText ());
+      log_debug ("%s:%s: window text is now `%s'",
+                 __FILE__, __func__, msg->getDisplayText ());
+      return 0;
+    }
+  else
+    {
+      log_debug ("%s: window handle not found for parent %p\n",
+                 __func__, hwnd);
+      return -1;
+    }
 }
 
 
-/* Check whether a message is a HTMl message. */
-bool
-MapiGPGMEImpl::isHtmlMessage (void)
+static bool 
+is_html_body (const char *body)
 {
-    char *body = getBody (true);
-
-    /* We assume that getBody won't return a non-empty string if it is
-       a HTML message.  FIXME: This is a pretty ineffective test as it
-       needless allocates memory. */
-    if (body != NULL && strlen (body) > 1) {
-       delete_buf (body);
+  char *p1, *p2;
+  
+  /* XXX: it is possible but unlikely that the message text
+     contains the used keywords. */
+  p1 = strstr (body, "<HTML>");
+  p2 = strstr (body, "</HTML>");
+  if (p1 && p2)
+    return true;
+  p1 = strstr (body, "<html>");
+  p2 = strstr (body, "</html>");
+  if (p1 && p2)
        return true;
-    }
-    if (body != NULL)
-       delete_buf (body);
-    return false;
+  /* XXX: use case insentensive strstr version. */
+  return false;
 }
 
 
-/* Return a copy of the body content of current message.  PR_BODY_HTML
-   is used internally when called with ISHTML as true; PR_BODY
-   otherwise.  On success a new char object is retruned and the caller
-   is responsible for deleting it. On failure NULL is returned. */
-char* 
-MapiGPGMEImpl::getBody (bool isHtml)
-{
-    HRESULT hr;
-    LPSPropValue lpspvFEID = NULL;
-    char *body;
-    int type = isHtml? PR_BODY_HTML: PR_BODY;
-
-    log_debug ("getBody: enter\n");
-    
-    hr = HrGetOneProp ((LPMAPIPROP) msg, type, &lpspvFEID);
-    if (FAILED (hr))
-       return NULL;
-
-    log_debug ("getBody: proptag=0x%8lx\n",  lpspvFEID->ulPropTag);
-    if ( PROP_TYPE (lpspvFEID->ulPropTag) == PT_UNICODE)
-      {
-        int n;
-        n = WideCharToMultiByte (CP_UTF8, 0, 
-                                 lpspvFEID->Value.lpszW, -1,
-                                 NULL, 0,
-                                 NULL, NULL);
-        if (n < 0)
-          {
-            log_debug ("%s: error converting to utf8\n", __func__);
-            return NULL;
-          }
-        log_debug ("getBody: need buffer of %d bytes\n", n);
-        body = new char[n+1];
-        n = WideCharToMultiByte (CP_UTF8, 0, 
-                                 lpspvFEID->Value.lpszW, -1,
-                                 body, n,
-                                 NULL, NULL);
-        if (n < 0)
-          {
-            log_debug ("%s: error converting to utf8 (2)\n", __func__);
-            return NULL;
-          }
-
-        log_debug ("getBody: body=`%s'\n", body);
-      }
-    else
-      {
-        log_debug ("getBody: len=%d\n", strlen( lpspvFEID->Value.lpszA));
-        log_debug ("getBody: body=`%s'\n", lpspvFEID->Value.lpszA );
-        body = new char[strlen (lpspvFEID->Value.lpszA)+1];
-        fail_if_null (body);
-        strcpy (body, lpspvFEID->Value.lpszA);
-      }
-
-
-    MAPIFreeBuffer (lpspvFEID);
-    lpspvFEID = NULL;
-    return body;
-}
 
 
 void 
@@ -766,49 +604,6 @@ count_recipients (char **recipients)
 }
 
 
-/* Return an array of strings with the recipients of the message. On
-   success a new array is returned containing allocated strings for
-   each recipients.  Teh end of the array is marked by NULL.  Caller
-   is responsible for releasing the array.  On failure NULL is
-   returned.  */
-char** 
-MapiGPGMEImpl::getRecipients (bool isRootMsg)
-{
-    HRESULT hr;
-    LPMAPITABLE lpRecipientTable = NULL;
-    LPSRowSet lpRecipientRows = NULL;
-    char **rset = NULL;
-    size_t j=0;
-
-    if (!isRootMsg)
-       return NULL;
-        
-    static SizedSPropTagArray (1L, PropRecipientNum) = {1L, {PR_EMAIL_ADDRESS}};
-
-    hr = msg->GetRecipientTable (0, &lpRecipientTable);
-    if (SUCCEEDED (hr)) {
-        hr = HrQueryAllRows (lpRecipientTable, 
-                            (LPSPropTagArray) &PropRecipientNum,
-                            NULL, NULL, 0L, &lpRecipientRows);
-       rset = new char*[lpRecipientRows->cRows+1];
-       fail_if_null (rset);
-        for (j = 0L; j < lpRecipientRows->cRows; j++) {
-           const char *s = lpRecipientRows->aRow[j].lpProps[0].Value.lpszA;
-           rset[j] = new char[strlen (s)+1];
-           fail_if_null (rset[j]);
-           strcpy (rset[j], s);
-           log_debug ( "rset %d: %s\n", j, rset[j]);
-       }
-       rset[j] = NULL;
-       if (lpRecipientTable)
-           lpRecipientTable->Release();
-       if (lpRecipientRows)
-           FreeProws(lpRecipientRows); 
-    }
-
-    return rset;
-}
-
 
 void
 MapiGPGMEImpl::freeUnknownKeys (char **unknown, int n)
@@ -823,304 +618,341 @@ MapiGPGMEImpl::freeUnknownKeys (char **unknown, int n)
        xfree (unknown);
 }
 
-void 
-MapiGPGMEImpl::freeRecipients (char **recipients)
+
+/* Release an array of strings with recipient names. */
+static void
+free_recipient_array (char **recipients)
 {
-    for (int i=0; recipients[i] != NULL; i++) {
-       delete_buf (recipients[i]);     
-       recipients[i] = NULL;
+  int i;
+
+  if (recipients)
+    {
+      for (i=0; recipients[i]; i++) 
+       xfree (recipients[i]);  
+      xfree (recipients);
     }
-    delete recipients;
 }
 
 
-const char*
-MapiGPGMEImpl::getPassphrase (const char *keyid)
+
+/* Create a new body from body wth suitable line endings. aller must
+   release the result. */
+static char *
+add_html_line_endings (const char *body)
 {
-    cache_item_t item;
+  size_t count;
+  const char *s;
+  char *p, *result;
 
-    log_debug ("MapiGPGME.getPassphrase: enter\n");
-    item = (cache_item_t)passCache->get(keyid);
-    log_debug ("MapiGPGME.getPassphrase: leave (result=%p)\n", item);
-    if (item != NULL)
-       return item->pass;
-    return NULL;
+  for (count=0, s = body; *s; s++)
+    if (*s == '\n')
+      count++;
+  
+  result = (char*)xmalloc ((s - body) + count*10 + 1);
+  
+  for (s=body, p = result; *s; s++ )
+    if (*s == '\n')
+      p = stpcpy (p, "&nbsp;<br>\n");
+    else
+      *p++ = *s;
+  *p = 0;
+  
+  return result;
+  
 }
 
 
-void
-MapiGPGMEImpl::storePassphrase (void *itm)
-{
-    cache_item_t item, old;
-
-    log_debug ("MapiGPGME.storePassphrase: enter (%p)\n", itm);
-    item = (cache_item_t)itm;
-    log_debug ("MapiGPGME.storePassphrase: keyid is 0x%s\n",
-              item->keyid); 
-    old = (cache_item_t)passCache->get(item->keyid);
-    if (old != NULL)
-       cache_item_free (old);
-    passCache->put (item->keyid+8, item);
-    log_debug ("MapiGPGME.storePassphrase: keyid 0x%s\n",
-              item->keyid+8); /* FIXME: is the +8 save? */
-    log_debug ("MapiGPGME.storePassphrase: leave \n");
-}
 
+int 
+MapiGPGMEImpl::encrypt (HWND hwnd, GpgMsg *msg)
+{
+  log_debug ("%s:%s: enter\n", __FILE__, __func__);
+  gpgme_key_t *keys = NULL;
+  gpgme_key_t *keys2 = NULL;
+  bool is_html;
+  const char *plaintext;
+  char *ciphertext;
+  char **recipients = msg->getRecipients ();
+  char **unknown = NULL;
+  int opts = 0;
+  int err = 0;
+  size_t all = 0;
+  int n;
+  
 
-/* FIXME: This is an ineffective implementation which wastes way too
-   much memory. */
-static char *
-add_html_line_endings (char *newBody)
-{
-    char *p;
-    char *snew = (char*)xcalloc (1, 2*strlen (newBody));
-
-    p = strtok ((char *)newBody, "\n");
-    while (p != NULL) {
-       strcat (snew, p);
-       strcat (snew, "\n");
-       strcat (snew, "&nbsp;<br>");
-       p = strtok (NULL, "\n");
+  if (!msg || !*(plaintext = msg->getOrigText ())) 
+    {
+      free_recipient_array (recipients);
+      return 0;  /* Empty message - Nothing to encrypt. */
     }
-    
-    return snew;
-}
 
-int 
-MapiGPGMEImpl::encrypt (void)
-{
-    gpgme_key_t *keys=NULL, *keys2=NULL;
-    bool isHtml = isHtmlMessage ();
-    char *body = getBody (isHtml);
-    char *newBody = NULL;
-    char **recipients = getRecipients (true);
-    char **unknown = NULL;
-    int opts = 0;
-    int err = 0;
-    size_t all=0;
-
-    if (body == NULL || strlen (body) == 0) {
-       freeRecipients (recipients);
-       if (body != NULL)
-           delete_buf (body);
-       return 0;
-    }
+  n = op_lookup_keys (recipients, &keys, &unknown, &all);
+  log_debug ("%s: found %d need %d (%p)\n", __func__, n, all, unknown);
 
-    log_debug ("encrypt\n");
-    int n = op_lookup_keys (recipients, &keys, &unknown, &all);
-    log_debug ("fnd %d need %d (%p)\n", n, all, unknown);
-    if (n != count_recipients (recipients)) {
-       log_debug ("recipient_dialog_box2\n");
-       recipient_dialog_box2 (keys, unknown, all, &keys2, &opts);
-       xfree (keys);
-       keys = keys2;
-       if (opts & OPT_FLAG_CANCEL) {
-           freeRecipients (recipients);
-           delete_buf (body);
-           return 0;
+  if (n != count_recipients (recipients))
+    {
+      log_debug ("recipient_dialog_box2\n");
+      recipient_dialog_box2 (keys, unknown, all, &keys2, &opts);
+      xfree (keys);
+      keys = keys2;
+      if (opts & OPT_FLAG_CANCEL) 
+        {
+          free_recipient_array (recipients);
+          return 0;
        }
     }
 
-    err = op_encrypt ((void*)keys, body, &newBody);
-    if (err)
-       MessageBox (NULL, op_strerror (err), "GPG Encryption", MB_ICONERROR|MB_OK);
-    else {
-       if (isHtml) {
-           char *p = add_html_line_endings (newBody);
-           setBody (p, true);
-           xfree (p);
-       }
-       else
-           setBody (newBody, false);
-    }
-    delete_buf (body);
-    xfree (newBody);
-    freeRecipients (recipients);
-    freeUnknownKeys (unknown, n);
-    if (!err && hasAttachments ()) {
-       log_debug ("encrypt attachments\n");
-       recipSet = (void *)keys;
-       encryptAttachments (parent);
-    }
-    freeKeyArray ((void **)keys);
-    return err;
-}
-
-
-/* XXX: I would prefer to use MapiGPGME::passphraseCallback, but member 
-        functions have an incompatible calling convention. -ts
-    
-        Obviously they need to pass the THIS pointer.  Mixing this
-        with the gpgme convention (where OPAQUE may be viewed as the
-        THIS) is not possible. -wk
-*/
-gpgme_error_t 
-passphraseCallback (void *opaque, const char *uid_hint, 
-                   const char *passphrase_info,
-                   int last_was_bad, int fd)
-{
-    MapiGPGME *ctx = (MapiGPGME*)opaque;
-    const char *passwd;
-    char keyid[16+1];
-    DWORD nwritten = 0;
-    int i=0;
+  err = op_encrypt ((void*)keys, plaintext, &ciphertext);
+  if (err)
+    MessageBox (NULL, op_strerror (err),
+                "GPG Encryption", MB_ICONERROR|MB_OK);
+  else 
+    {
+      if (is_html) 
+        {
+          msg->setCipherText (add_html_line_endings (ciphertext), true);
+          ciphertext = NULL;
+        }
+      else
+        msg->setCipherText (ciphertext, false);
+      xfree (ciphertext);
+  }
 
-    log_debug ("MapiGPGME.passphraseCallback: enter\n");
-    while (uid_hint && *uid_hint != ' ')
-       keyid[i++] = *uid_hint++;
-    keyid[i] = '\0';
-    
-    passwd = ctx->getPassphrase (keyid+8);
-    /*log_debug ( "get keyid %s = '%s'\n", keyid+8, "***");*/
-    if (passwd != NULL) {
-       WriteFile ((HANDLE)fd, passwd, strlen (passwd), &nwritten, NULL);
-       WriteFile ((HANDLE)fd, "\n", 1, &nwritten, NULL);
+  free_recipient_array (recipients);
+  freeUnknownKeys (unknown, n);
+  if (!err && msg->hasAttachments ())
+    {
+      log_debug ("encrypt attachments\n");
+      recipSet = (void *)keys;
+      encryptAttachments (hwnd);
     }
-
-    log_debug ("MapiGPGME.passphraseCallback: leave\n");
-    return 0;
+  freeKeyArray ((void **)keys);
+  return err;
 }
 
 
+/* Decrypt the message MSG and update the window.  HWND identifies the
+   current window. */
 int 
-MapiGPGMEImpl::decrypt (void)
+MapiGPGMEImpl::decrypt (HWND hwnd, GpgMsg * msg)
 {
-    outlgpg_type_t id;
+  log_debug ("%s:%s: enter\n", __FILE__, __func__);
+  openpgp_t mtype;
+  char *plaintext = NULL;
+  int has_attach;
+  int err;
 
-    log_debug ("MapiGPGME.%s:%d: enter\n", __func__, __LINE__);
+  mtype = msg->getMessageType ();
+  if (mtype == OPENPGP_CLEARSIG)
+    {
+      log_debug ("%s:%s: leave (passing on to verify)\n", __FILE__, __func__);
+      return verify (hwnd, msg);
+    }
 
-    char *body = getBody (false);
-    char *newBody = NULL;    
-    bool hasAttach = hasAttachments ();
-    bool isHtml = isHtmlMessage ();
-    int err;
-
-    id = getMessageType (body);
-    if (id == GPG_TYPE_CLEARSIG) {
-       delete_buf (body);
-        log_debug ("MapiGPGME.decrypt: leave (passing on to verify)\n");
-       return verify ();
+  has_attach = msg->hasAttachments ();
+  if (mtype == OPENPGP_NONE && !has_attach ) 
+    {
+      MessageBox (NULL, "No valid OpenPGP data found.",
+                  "GPG Decryption", MB_ICONERROR|MB_OK);
+      log_debug ("MapiGPGME.decrypt: leave (no OpenPGP data)\n");
+      return 0;
     }
-    else if (id == GPG_TYPE_NONE && !hasAttach) {
-       MessageBox (NULL, "No valid OpenPGP data found.",
+
+  err = op_decrypt_start (msg->getOrigText (), &plaintext, nstorePasswd);
+
+  if (err)
+    {
+      if (has_attach && gpg_err_code (err) == GPG_ERR_NO_DATA)
+        ;
+      else
+        MessageBox (NULL, op_strerror (err),
                     "GPG Decryption", MB_ICONERROR|MB_OK);
-       delete_buf (body);
-        log_debug ("MapiGPGME.decrypt: leave (no OpenPGP data)\n");
-       return 0;
     }
+  else if (plaintext && *plaintext)
+    {  
+      int is_html = is_html_body (plaintext);
 
-    log_debug ("%s: at %d\n", __func__, __LINE__);
+      msg->setPlainText (plaintext);
+      plaintext = NULL;
 
-    err = op_decrypt_start (body, &newBody, nstorePasswd);
+      /* Also set PR_BODY but do not use 'SaveChanges' to make it
+         permanently.  This way the user can reply with the
+         plaintext but the ciphertext is still stored. */
+      log_debug ("decrypt isHtml=%d\n", is_html);
 
-    if (err) {
-       if (hasAttach && gpg_err_code (err) == GPG_ERR_NO_DATA)
-            ;
-       else
-            MessageBox (NULL, op_strerror (err),
-                        "GPG Decryption", MB_ICONERROR|MB_OK);
-    }
-    else if (newBody && *newBody) {    
-       /* Also set PR_BODY but do not use 'SaveChanges' to make it
-          permanently.  This way the user can reply with the
-          plaintext but the ciphertext is still stored. */
-       log_debug ("decrypt isHtml=%d\n", isHtmlBody (newBody));
-       setRTFBody (newBody);
-
-       /* XXX: find a way to handle text/html message in a better way! */
-       if (isHtmlBody (newBody)) {
-           const char *s = "The message text cannot be displayed.\n"
-                           "You have to save the decrypted message to view it.\n"
-                           "Then you need to re-open the message.\n\n"
-                           "Do you want to save the decrypted message?";
-           int id = MessageBox (NULL, s, "GPG Decryption", MB_YESNO|MB_ICONWARNING);
-           if (id == IDYES) {
-               log_debug ("decrypt: save plaintext message.\n");
-               setBody (newBody, true);
-               msg->SaveChanges (FORCE_SAVE);
-           }
+      /* XXX: find a way to handle text/html message in a better way! */
+      if (is_html || update_display (hwnd, msg))
+        {
+          const char s[] = 
+            "The message text cannot be displayed.\n"
+            "You have to save the decrypted message to view it.\n"
+            "Then you need to re-open the message.\n\n"
+            "Do you want to save the decrypted message?";
+          int what;
+          
+          what = MessageBox (NULL, s, "GPG Decryption",
+                             MB_YESNO|MB_ICONWARNING);
+          if (what == IDYES) 
+            {
+              log_debug ("decrypt: saving plaintext message.\n");
+              msg->saveChanges (1);
+            }
        }
-       else
-          setBody (newBody, false);
+      else
+        msg->saveChanges (0);
     }
 
-    if (hasAttach) {
-       log_debug ("decrypt attachments\n");
-       decryptAttachments (parent);
+  if (has_attach)
+    {
+      log_debug ("decrypt attachments\n");
+      decryptAttachments (hwnd);
     }
 
-    delete_buf (body);
-    xfree (newBody);
-    log_debug ("MapiGPGME.decrypt: leave (rc=%d)\n", err);
-    return err;
+  log_debug ("%s:%s: leave (rc=%d)\n", __FILE__, __func__, err);
+  return err;
 }
 
 
 /* Sign the current message. Returns 0 on success. */
 int
-MapiGPGMEImpl::sign (void)
+MapiGPGMEImpl::sign (HWND hwnd, GpgMsg * msg)
 {
-    char *body = getBody (false);
-    char *newBody = NULL;
-    int hasAttach = hasAttachments ();
-    int err = 0;
-
-    log_debug ("MapiGPGME.sign: enter\n");
-
-    /* We don't sign an empty body - a signature on a zero length
-       string is pretty much useless. */
-    if (body == NULL || strlen (body) == 0) {
-       if (body)
-           delete_buf (body);
-        log_debug ("MapiGPGME.sign: leave (empty message)\n");
-       return 0;
-    }
+  log_debug ("%s.%s: enter\n", __FILE__, __func__);
+  char *signedtext;
+  int err = 0;
 
-    err = op_sign_start (body, &newBody);
-    if (err)
-       MessageBox (NULL, op_strerror (err), "GPG Sign", MB_ICONERROR|MB_OK);
-    else
-       setBody (newBody, isHtmlBody (newBody));
+  /* We don't sign an empty body - a signature on a zero length string
+     is pretty much useless. */
+  if (!msg || !*msg->getOrigText ()) 
+    {
+      log_debug ("MapiGPGME.sign: leave (empty message)\n");
+      return 0;
+    }
 
-    if (hasAttach && autoSignAtt)
-       signAttachments (parent);
+  err = op_sign_start (msg->getOrigText (), &signedtext);
+  if (err)
+    MessageBox (NULL, op_strerror (err), "GPG Sign", MB_ICONERROR|MB_OK);
+  else
+    {
+      msg->setSignedText (signedtext);
+    }
+  
+  if (msg->hasAttachments () && autoSignAtt)
+    signAttachments (hwnd);
 
-    delete_buf (body);
-    xfree (newBody);
-    log_debug ("MapiGPGME.sign: leave (rc=%d)\n", err);
-    return err;
+  log_debug ("%s:%s: leave (rc=%d)\n", err);
+  return err;
 }
 
 
-bool
-MapiGPGMEImpl::isMessageEncrypted (void)
-{
-    char *body = getBody (false);
-    bool enc = getMessageType (body) == GPG_TYPE_MSG;
-    if (body != NULL)
-       delete_buf (body);
-    return enc;
+/* Perform a sign+encrypt operation using the data already store in
+   the instance variables. Return 0 on success. */
+int
+MapiGPGMEImpl::signEncrypt (HWND hwnd, GpgMsg *msg)
+{
+  log_debug ("%s:%s: enter\n", __FILE__, __func__);
+  char **recipients = msg->getRecipients ();
+  char **unknown = NULL;
+  gpgme_key_t locusr=NULL, *keys = NULL, *keys2 =NULL;
+  char *ciphertext = NULL;
+  int is_html;
+
+  /* Check for trivial case: We don't encrypt or sign an empty
+     message. */
+  if (!msg || !*msg->getOrigText ()) 
+    {
+      free_recipient_array (recipients);
+      log_debug ("%s.%s: leave (empty message)\n", __FILE__, __func__);
+      return 0;  /* Empty message - Nothing to encrypt. */
+    }
+
+  /* Pop up a dialog box to ask for the signer of the message. */
+  if (signer_dialog_box (&locusr, NULL) == -1)
+    {
+      free_recipient_array (recipients);
+      log_debug ("%s.%s: leave (dialog failed)\n", __FILE__, __func__);
+      return 0;
+    }
+
+  /* Now lookup the keys of all recipients. */
+  size_t all;
+  int n = op_lookup_keys (recipients, &keys, &unknown, &all);
+  if (n != count_recipients (recipients)) 
+    {
+      /* FIXME: The implementation is not correct: op_lookup_keys
+         returns the number of missing keys but we compare against the
+         total number of keys; thus the box would pop up even when all
+         have been found. */
+       recipient_dialog_box2 (keys, unknown, all, &keys2, NULL);
+       xfree (keys);
+       keys = keys2;
+    }
+  
+  log_key_info (this, "signEncrypt", keys, locusr);
+
+  is_html = is_html_body (msg->getOrigText ());
+
+    /* FIXME: Remove the cast and use proper types. */
+  int err = op_sign_encrypt ((void *)keys, (void*)locusr,
+                             msg->getOrigText (), &ciphertext);
+  if (err)
+    MessageBox (NULL, op_strerror (err),
+                "GPG Sign Encrypt", MB_ICONERROR|MB_OK);
+  else 
+    {
+      if (is_html) 
+        {
+          msg->setCipherText (add_html_line_endings (ciphertext), true);
+          ciphertext = NULL;
+        }
+      else
+        msg->setCipherText (ciphertext, false);
+      xfree (ciphertext);
+    }
+
+  freeUnknownKeys (unknown, n);
+  if (!err && msg->hasAttachments ())
+    {
+      log_debug ("%s:%s: have attachments\n", __FILE__, __func__);
+      recipSet = (void *)keys;
+      encryptAttachments (hwnd);
+    }
+  freeKeyArray ((void **)keys);
+  gpgme_key_release (locusr);
+  free_recipient_array (recipients);
+  log_debug ("%s:%s: leave (rc=%d)\n", err);
+  return err;
 }
 
 
-outlgpg_type_t
-MapiGPGMEImpl::getMessageType (const char *body)
+int 
+MapiGPGMEImpl::verify (HWND hwnd, GpgMsg *msg)
 {
-    if (strstr (body, "BEGIN PGP MESSAGE"))
-       return GPG_TYPE_MSG;
-    if (strstr (body, "BEGIN PGP SIGNED MESSAGE"))
-       return GPG_TYPE_CLEARSIG;
-    if (strstr (body, "BEGIN PGP SIGNATURE"))
-       return GPG_TYPE_SIG;
-    if (strstr (body, "BEGIN PGP PUBLIC KEY"))
-       return GPG_TYPE_PUBKEY;
-    if (strstr (body, "BEGIN PGP PRIVATE KEY"))
-       return GPG_TYPE_SECKEY;
-    return GPG_TYPE_NONE;
+  log_debug ("%s:%s: enter\n", __FILE__, __func__);
+  openpgp_t mtype;
+  int has_attach;
+  
+  mtype = msg->getMessageType ();
+  has_attach = msg->hasAttachments ();
+  if (mtype == OPENPGP_NONE && !has_attach ) 
+    {
+      log_debug ("%s:%s: leave (no OpenPGP data)\n", __FILE__, __func__);
+      return 0;
+    }
+
+  int err = op_verify_start (msg->getOrigText (), NULL);
+  if (err)
+    MessageBox (NULL, op_strerror (err), "GPG Verify", MB_ICONERROR|MB_OK);
+  else
+    update_display (hwnd, msg);
+
+  log_debug ("%s:%s: leave (rc=%d)\n", __FILE__, __func__, err);
+  return err;
 }
 
 
 
+
 int
 MapiGPGMEImpl::doCmdFile(int action, const char *in, const char *out)
 {
@@ -1128,7 +960,7 @@ MapiGPGMEImpl::doCmdFile(int action, const char *in, const char *out)
     if (ATT_SIGN (action) && ATT_ENCR (action))
        return !op_sign_encrypt_file (recipSet, in, out);
     if (ATT_SIGN (action) && !ATT_ENCR (action))
-       return !op_sign_file (OP_SIG_NORMAL, in, out);
+       return !op_sign_file (OP_SIG_NORMAL, in, out, nstorePasswd);
     if (!ATT_SIGN (action) && ATT_ENCR (action))
        return !op_encrypt_file (recipSet, in, out);
     return !op_decrypt_file (in, out);    
@@ -1138,34 +970,18 @@ MapiGPGMEImpl::doCmdFile(int action, const char *in, const char *out)
 int
 MapiGPGMEImpl::doCmdAttach (int action)
 {
-    log_debug ("doCmdAttach action=%d\n", action);
-    if (ATT_SIGN (action) && ATT_ENCR (action))
-       return signEncrypt ();
-    if (ATT_SIGN (action) && !ATT_ENCR (action))
-       return sign ();
-    if (!ATT_SIGN (action) && ATT_ENCR (action))
-       return encrypt ();
-    return decrypt ();
+//     log_debug ("doCmdAttach action=%d\n", action);
+//     if (ATT_SIGN (action) && ATT_ENCR (action))
+//     return signEncrypt ();
+//     if (ATT_SIGN (action) && !ATT_ENCR (action))
+//     return sign ();
+//     if (!ATT_SIGN (action) && ATT_ENCR (action))
+//     return encrypt ();
+// FIXME!!!
+  return 0; /*decrypt ();*/
 }
 
 
-/* Man processing entry point.  Perform encryption or/and signing
-   depending on the flags DOENCRYPT and DOSIGN.  It works on the
-   message already set into the instance variable MSG.  Returns 0 on
-   success or an error code. */
-int
-MapiGPGMEImpl::doCmd (int doEncrypt, int doSign)
-{
-    log_debug ("MapiGPGME.doCmd doEncrypt=%d doSign=%d\n", doEncrypt, doSign);
-    if (doEncrypt && doSign)
-       return signEncrypt ();
-    if (doEncrypt && !doSign)
-       return encrypt ();
-    if (!doEncrypt && doSign)
-       return sign ();
-    return -1;
-}
-
 
 static const char *
 userid_from_key (gpgme_key_t k)
@@ -1210,170 +1026,50 @@ log_key_info (MapiGPGME *g, const char *prefix,
 }
            
 
-/* Perform a sign+encrypt operation using the data already store in
-   the instance variables. Return 0 on success. */
-int
-MapiGPGMEImpl::signEncrypt (void)
-{
-    bool isHtml = isHtmlMessage ();
-    char *body = getBody (isHtml);
-    char *newBody = NULL;
-    char **recipients = getRecipients (TRUE);
-    char **unknown = NULL;
-    gpgme_key_t locusr=NULL, *keys = NULL, *keys2 =NULL;
-
-    log_debug ("MapiGPGME.signEncrypt: enter\n");
-    
-    /* Check for trivial case: We don't encrypt or sign an empty
-       message. */
-    if (body == NULL || strlen (body) == 0) {
-       freeRecipients (recipients);
-       if (body)
-           delete_buf (body);
-        log_debug ("MapiGPGME.signEncrypt: leave (empty message)\n");
-       return 0;
-    }
-
-    /* Pop up a dialog box to ask for the signer of the message. */
-    if (signer_dialog_box (&locusr, NULL) == -1) {
-       freeRecipients (recipients);
-       delete_buf (body);
-        log_debug ("MapiGPGME.signEncrypt: leave (dialog failed)\n");
-       return 0;
-    }
-    log_debug ("MapiGPGME.signEncrypt: using signer's keyid %s\n",
-              keyid_from_key (locusr));
-
-    /* Now lookup the keys of all recipients. */
-    size_t all;
-    int n = op_lookup_keys (recipients, &keys, &unknown, &all);
-    if (n != count_recipients (recipients)) {
-      /* FIXME: The implementation is not correct: op_lookup_keys
-         returns the number of missing keys but we compare against the
-         total number of keys; thus the box would pop up even when all
-         have been found. */
-       recipient_dialog_box2 (keys, unknown, all, &keys2, NULL);
-       xfree (keys);
-       keys = keys2;
-    }
-
-    log_key_info (this, "signEncrypt", keys, locusr);
-    /* FIXME: Remove the cast and use proper types. */
-    int err = op_sign_encrypt ((void *)keys, (void*)locusr, body, &newBody);
-    if (err)
-       MessageBox (NULL, op_strerror (err),
-                    "GPG Sign Encrypt", MB_ICONERROR|MB_OK);
-    else {
-       if (isHtml) {
-           char *p = add_html_line_endings (newBody);
-           setBody (p, true);
-           xfree (p);
-       }
-       else
-           setBody (newBody, false);
-    }
-
-    delete_buf (body);
-    xfree (newBody);
-    freeUnknownKeys (unknown, n);
-    if (!err && hasAttachments ()) {
-       log_debug ("MapiGPGME.signEncrypt: have attachments\n");
-
-        /** WORK(wk) **/
-       recipSet = (void *)keys;
-       encryptAttachments (parent);
-    }
-    freeKeyArray ((void **)keys);
-    gpgme_key_release (locusr);
-    freeRecipients (recipients);
-    log_debug ("MapiGPGME.signEncrypt: leave (rc=%d)\n", err);
-    return err;
-}
-
-
-int 
-MapiGPGMEImpl::verify (void)
-{
-    char *body = getBody (false);
-    char *newBody = NULL;
-    
-    log_debug ("MapiGPGME.verify: enter\n");
-
-    int err = op_verify_start (body, &newBody);
-    if (err)
-       MessageBox (NULL, op_strerror (err), "GPG Verify", MB_ICONERROR|MB_OK);
-    else
-       setRTFBody (newBody);
-
-    delete_buf (body);
-    xfree (newBody);
-    log_debug ("MapiGPGME.verify: leave (rc=%d)\n", err);
-    return err;
-}
-
 
 void 
 MapiGPGMEImpl::setDefaultKey (const char *key)
 {
-    if (defaultKey) {
-       delete_buf (defaultKey);
-       defaultKey = NULL;
-    }
-    defaultKey = new char[strlen (key)+1];
-    fail_if_null (defaultKey);
-    strcpy (defaultKey, key);
+    xfree (defaultKey);
+    defaultKey = xstrdup (key);
 }
 
 
-char* 
+const char* 
 MapiGPGMEImpl::getDefaultKey (void)
 {
   return defaultKey;
 }
 
 
-/* Store the message MSG we want to work on in our object. */
-void 
-MapiGPGMEImpl::setMessage (LPMESSAGE msg)
-{
-    this->msg = msg;
-    log_debug ("MapiGPGME.setMessage %p\n", msg);
-}
-
 
-void
-MapiGPGMEImpl::setWindow(HWND hwnd)
+/* We need this to find the mailer window because we directly change
+   the text of the window instead of the MAPI object itself. */
+static HWND
+find_message_window (HWND parent, GpgMsg *msg)
 {
-    this->parent = hwnd;
-}
+  HWND child;
 
+  if (!parent)
+    return NULL;
 
-/* We need this to find the mailer window because we directly change the text
-   of the window instead of the MAPI object itself. */
-HWND
-MapiGPGMEImpl::findMessageWindow (HWND parent)
-{
-    HWND child;
-
-    if (parent == NULL)
-       return NULL;
-
-    child = GetWindow (parent, GW_CHILD);
-    while (child != NULL) {
-       char buf[1024+1];
-       HWND rtf;
-
-       memset (buf, 0, sizeof (buf));
-       GetWindowText (child, buf, sizeof (buf)-1);
-       if (getMessageType (buf) != GPG_TYPE_NONE)
-           return child;
-       rtf = findMessageWindow (child);
-       if (rtf != NULL)
-           return rtf;
-       child = GetNextWindow (child, GW_HWNDNEXT);     
+  child = GetWindow (parent, GW_CHILD);
+  while (child)
+    {
+      char buf[1024+1];
+      HWND w;
+
+      memset (buf, 0, sizeof (buf));
+      GetWindowText (child, buf, sizeof (buf)-1);
+      if (msg->matchesString (buf))
+        return child;
+      w = find_message_window (child, msg);
+      if (w)
+        return w;
+      child = GetNextWindow (child, GW_HWNDNEXT);      
     }
-    /*log_debug ("no message window found.\n");*/
-    return NULL;
+
+  return NULL;
 }
 
 
@@ -1439,13 +1135,14 @@ MapiGPGMEImpl::streamOnFile (const char *file, LPATTACH att)
 
 
 int
-MapiGPGMEImpl::getMessageFlags (void)
+MapiGPGMEImpl::getMessageFlags (GpgMsg * msg)
 {
     HRESULT hr;
     LPSPropValue propval = NULL;
     int flags = 0;
 
-    hr = HrGetOneProp (msg, PR_MESSAGE_FLAGS, &propval);
+    // FIXME
+//     hr = HrGetOneProp (msg, PR_MESSAGE_FLAGS, &propval);
     if (FAILED (hr))
        return 0;
     flags = propval->Value.l;
@@ -1455,13 +1152,14 @@ MapiGPGMEImpl::getMessageFlags (void)
 
 
 int
-MapiGPGMEImpl::getMessageHasAttachments (void)
+MapiGPGMEImpl::getMessageHasAttachments (GpgMsg * msg)
 {
     HRESULT hr;
     LPSPropValue propval = NULL;
     int nattach = 0;
 
-    hr = HrGetOneProp (msg, PR_HASATTACH, &propval);
+    // FIXME
+//     hr = HrGetOneProp (msg, PR_HASATTACH, &propval);
     if (FAILED (hr))
        return 0;
     nattach = propval->Value.b? 1 : 0;
@@ -1470,20 +1168,6 @@ MapiGPGMEImpl::getMessageHasAttachments (void)
 }
 
 
-bool
-MapiGPGMEImpl::setMessageAccess (int access)
-{
-    HRESULT hr;
-
-    SPropValue prop;
-    prop.ulPropTag = PR_ACCESS;
-    prop.Value.l = access;
-    hr = HrSetOneProp (msg, &prop);
-    if (hr < 0)
-      log_debug_w32 (-1,"%s: to 0x%08lx failed");
-    return FAILED (hr)? false: true;
-}
-
 
 bool
 MapiGPGMEImpl::setAttachMethod (LPATTACH obj, int mode)
@@ -1620,7 +1304,7 @@ MapiGPGMEImpl::getPGPExtension (int action)
 
 
 bool 
-MapiGPGMEImpl::setXHeader (const char *name, const char *val)
+MapiGPGMEImpl::setXHeader (GpgMsg * msg, const char *name, const char *val)
 {  
 #ifndef __MINGW32__
     USES_CONVERSION;
@@ -1638,7 +1322,8 @@ MapiGPGMEImpl::setXHeader (const char *name, const char *val)
     mnid[0].lpguid = &guid;
     mnid[0].ulKind = MNID_STRING;
 //     mnid[0].Kind.lpwstrName = A2W (name);
-    hr = msg->GetIDsFromNames (1, (LPMAPINAMEID*)mnid, MAPI_CREATE, &pProps);
+// FIXME
+//    hr = msg->GetIDsFromNames (1, (LPMAPINAMEID*)mnid, MAPI_CREATE, &pProps);
     if (FAILED (hr)) {
        log_debug ("set X-Header failed.\n");
        return false;
@@ -1646,7 +1331,7 @@ MapiGPGMEImpl::setXHeader (const char *name, const char *val)
     
     pv.ulPropTag = (pProps->aulPropTag[0] & 0xFFFF0000) | PT_STRING8;
     pv.Value.lpszA = (char *)val;
-    hr = HrSetOneProp(msg, &pv);       
+//FIXME     hr = HrSetOneProp(msg, &pv);       
     if (!SUCCEEDED (hr)) {
        log_debug ("set X-Header failed.\n");
        return false;
@@ -1658,7 +1343,7 @@ MapiGPGMEImpl::setXHeader (const char *name, const char *val)
 
 
 char*
-MapiGPGMEImpl::getXHeader (const char *name)
+MapiGPGMEImpl::getXHeader (GpgMsg *msg, const char *name)
 {
     /* XXX: PR_TRANSPORT_HEADERS is not available in my MSDN. */
     return NULL;
@@ -1682,30 +1367,31 @@ MapiGPGMEImpl::freeAttachments (void)
 int
 MapiGPGMEImpl::getAttachments (void)
 {
-    static SizedSPropTagArray (1L, PropAttNum) = {1L, {PR_ATTACH_NUM}};
-    HRESULT hr;    
+  // FIXME
+//     static SizedSPropTagArray (1L, PropAttNum) = {1L, {PR_ATTACH_NUM}};
+//     HRESULT hr;    
    
-    hr = msg->GetAttachmentTable (0, &attachTable);
-    if (FAILED (hr))
-       return FALSE;
-
-    hr = HrQueryAllRows (attachTable, (LPSPropTagArray) &PropAttNum,
-                        NULL, NULL, 0L, &attachRows);
-    if (FAILED (hr)) {
-       freeAttachments ();
-       return FALSE;
-    }
+//     hr = msg->GetAttachmentTable (0, &attachTable);
+//     if (FAILED (hr))
+//     return FALSE;
+
+//     hr = HrQueryAllRows (attachTable, (LPSPropTagArray) &PropAttNum,
+//                      NULL, NULL, 0L, &attachRows);
+//     if (FAILED (hr)) {
+//     freeAttachments ();
+//     return FALSE;
+//     }
     return TRUE;
 }
 
 
 LPATTACH
-MapiGPGMEImpl::openAttachment (int pos)
+MapiGPGMEImpl::openAttachment (GpgMsg * msg, int pos)
 {
     HRESULT hr;
     LPATTACH att = NULL;
     
-    hr = msg->OpenAttach (pos, NULL, MAPI_BEST_ACCESS, &att);  
+    //    hr = msg->OpenAttach (pos, NULL, MAPI_BEST_ACCESS, &att);    
     if (SUCCEEDED (hr))
        return att;
     return NULL;
@@ -1742,24 +1428,17 @@ MapiGPGMEImpl::signAttachment (const char *datfile)
     LPATTACH newatt;
     int pos=0, err=0;
 
+    log_debug ("MapiGPGME.%s:%d: enter\n", __func__, __LINE__);
+
     sigfile = (char *)xcalloc (1,strlen (datfile)+5);
     strcpy (sigfile, datfile);
     strcat (sigfile, ".asc");
 
-    newatt = createAttachment (pos);
+    newatt = createAttachment (NULL/*FIXME*/, pos);
     setAttachMethod (newatt, ATTACH_BY_VALUE);
     setAttachFilename (newatt, sigfile, false);
 
-    if (nstorePasswd == 0)
-       err = op_sign_file (OP_SIG_DETACH, datfile, sigfile);
-    else if (passCache->size () == 0) {
-       cache_item_t itm=NULL;
-       err = op_sign_file_ext (OP_SIG_DETACH, datfile, sigfile, &itm);
-       if (!err)
-           storePassphrase (itm);
-    }
-    else
-       err = op_sign_file_next (passphraseCallback, this, OP_SIG_DETACH, datfile, sigfile);
+    err = op_sign_file (OP_SIG_DETACH, datfile, sigfile, nstorePasswd);
 
     if (streamFromFile (sigfile, newatt)) {
        log_debug ("signAttachment: commit changes.\n");
@@ -1768,6 +1447,8 @@ MapiGPGMEImpl::signAttachment (const char *datfile)
     releaseAttachment (newatt);
     xfree (sigfile);
 
+    log_debug ("MapiGPGME.%s: leave (rc=%d)\n", __func__, err);
+
     return (!err)? true : false;
 }
 
@@ -1800,8 +1481,8 @@ MapiGPGMEImpl::processAttachment (LPATTACH *attm, HWND hwnd,
                                MAPI_MODIFY, (LPUNKNOWN*) &emb);
        if (FAILED (hr))
            return FALSE;
-       setWindow (hwnd);
-       setMessage (emb);
+//FIXME        setWindow (hwnd);
+//     setMessage (emb);
        if (doCmdAttach (action))
            success = FALSE;
        emb->SaveChanges (FORCE_SAVE);
@@ -1858,11 +1539,11 @@ MapiGPGMEImpl::processAttachment (LPATTACH *attm, HWND hwnd,
        xfree (tmp);
        
        if (action != GPG_ATTACH_SIGN)
-           deleteAttachment (pos);
+           deleteAttachment (NULL/*FIXME*/,pos);
 
        if (action == GPG_ATTACH_ENCRYPT) {
            LPATTACH newatt;
-           *attm = newatt = createAttachment (pos);
+           *attm = newatt = createAttachment (NULL/*FIXME*/,pos);
            setAttachMethod (newatt, ATTACH_BY_VALUE);
            setAttachFilename (newatt, outname, false);
 
@@ -1906,7 +1587,7 @@ MapiGPGMEImpl::decryptAttachments (HWND hwnd)
        return TRUE;
     }
     for (int i=0; i < n; i++) {
-       LPATTACH amsg = openAttachment (i);
+      LPATTACH amsg = openAttachment (NULL/*FIXME*/,i);
        if (amsg)
           processAttachment (&amsg, hwnd, i, GPG_ATTACH_DECRYPT);
     }
@@ -1930,7 +1611,7 @@ MapiGPGMEImpl::signAttachments (HWND hwnd)
        return TRUE;
     }
     for (int i=0; i < n; i++) {
-       LPATTACH amsg = openAttachment (i);
+        LPATTACH amsg = openAttachment (NULL/*FIXME*/,i);
        if (!amsg)
            continue;
        processAttachment (&amsg, hwnd, i, GPG_ATTACH_SIGN);
@@ -1955,7 +1636,7 @@ MapiGPGMEImpl::encryptAttachments (HWND hwnd)
        return TRUE;
     }
     for (int i=0; i < n; i++) {
-       LPATTACH amsg = openAttachment (i);
+      LPATTACH amsg = openAttachment (NULL/*FIXME*/,i);
        if (amsg == NULL)
            continue;
        processAttachment (&amsg, hwnd, i, GPG_ATTACH_ENCRYPT);
@@ -2075,6 +1756,7 @@ MapiGPGMEImpl::readOptions (void)
     load_extension_value ("defaultKey", &val);
     if (val == NULL || *val == '"') {
        encryptDefault = 0;
+        xfree (defaultKey);
        defaultKey = NULL;
     }
     else {
@@ -2152,7 +1834,7 @@ MapiGPGMEImpl::attachPublicKey (const char *keyid)
     patt[0] = xstrdup (keyid);
     err = op_export_keys (patt, keyfile);
 
-    newatt = createAttachment (pos);
+    newatt = createAttachment (NULL/*FIXME*/,pos);
     setAttachMethod (newatt, ATTACH_BY_VALUE);
     setAttachFilename (newatt, keyfile, false);
     /* XXX: set proper RFC3156 MIME types. */
index dd7aab5..3c3ab07 100644 (file)
@@ -1,33 +1,27 @@
 /* MapiGPGME.h - Mapi support with GPGME
  *     Copyright (C) 2005 g10 Code GmbH
  *
- * This file is part of GPGME Dialogs.
- *
- * GPGME Dialogs 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.1 
- * of the License, or (at your option) any later version.
- *  
- * GPGME Dialogs is distributed in the hope that it will be useful,
+ * This file is part of OutlGPG.
+ * 
+ * OutlGPG 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.
+ * 
+ * OutlGPG 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with GPGME Dialogs; if not, write to the Free Software Foundation, 
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ * 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 MAPI_GPGME_H
 #define MAPI_GPGME_H
 
-typedef enum {
-    GPG_TYPE_NONE = 0,
-    GPG_TYPE_MSG,
-    GPG_TYPE_SIG,
-    GPG_TYPE_CLEARSIG,
-    GPG_TYPE_PUBKEY,   /* the key types are recognized but nut supported */
-    GPG_TYPE_SECKEY     /* by this implementaiton. */
-} outlgpg_type_t;
+#include "gpgmsg.hh"
 
 typedef enum {
     GPG_ATTACH_NONE = 0,
@@ -51,37 +45,16 @@ public:
 
   virtual const char * __stdcall versionString (void) = 0;
 
-  virtual int __stdcall encrypt (void) = 0;
-  virtual int __stdcall decrypt (void) = 0;
-  virtual int __stdcall sign (void) = 0;
-  virtual int __stdcall verify (void) = 0;
-  virtual int __stdcall signEncrypt (void) = 0;
+  virtual int __stdcall encrypt (HWND hwnd, GpgMsg *msg) = 0;
+  virtual int __stdcall decrypt (HWND hwnd, GpgMsg *msg) = 0;
+  virtual int __stdcall sign (HWND hwnd, GpgMsg *msg) = 0;
+  virtual int __stdcall signEncrypt (HWND hwnd, GpgMsg *msg) = 0;
+  virtual int __stdcall verify (HWND hwnd, GpgMsg *msg) = 0;
   virtual int __stdcall attachPublicKey (const char *keyid) = 0;
 
-  virtual int __stdcall doCmd (int doEncrypt, int doSign) = 0;
-  virtual int __stdcall doCmdAttach (int action) = 0;
   virtual int __stdcall doCmdFile (int action,
                                    const char *in, const char *out) = 0;
 
-  virtual const char* __stdcall getAttachmentExtension (const char *fname) = 0;
-  virtual void __stdcall freeAttachments (void) = 0;
-  virtual int __stdcall getAttachments (void) = 0;
-  virtual int __stdcall countAttachments (void) = 0;
-  virtual bool __stdcall hasAttachments (void) = 0;
-  virtual bool __stdcall deleteAttachment (int pos) = 0;
-  virtual LPATTACH __stdcall createAttachment (int &pos) = 0;
-
-  virtual outlgpg_type_t __stdcall getMessageType (const char *body) = 0;
-  virtual void __stdcall setMessage (LPMESSAGE msg) = 0;
-  virtual void __stdcall setWindow (HWND hwnd) = 0;
-
-  virtual const char * __stdcall getPassphrase (const char *keyid) = 0;
-  virtual void __stdcall storePassphrase (void *itm) = 0;
-  virtual void __stdcall clearPassphrase (void) = 0;
-
-  virtual void __stdcall logDebug (const char *fmt, ...) = 0;
-  virtual void __stdcall logDebug (const char *fmt, va_list a) = 0;
-
   virtual int __stdcall readOptions (void) = 0;
   virtual int __stdcall writeOptions (void) = 0;
 
@@ -104,7 +77,7 @@ public:
   virtual const char * __stdcall getLogFile (void) = 0;
   virtual void __stdcall setLogFile (const char *logfile) = 0;
   virtual void __stdcall setDefaultKey (const char *key) = 0;
-  virtual char * __stdcall getDefaultKey (void) = 0;
+  virtual const char * __stdcall getDefaultKey (void) = 0;
 
   virtual void  __stdcall showVersion (void) = 0;
 
@@ -126,7 +99,7 @@ public:
 
 extern "C" {
 
-MapiGPGME * __stdcall CreateMapiGPGME (LPMESSAGE msg);
+MapiGPGME * __stdcall CreateMapiGPGME (void);
 
 }
 
index 53084f1..2426fe3 100644 (file)
@@ -73,10 +73,11 @@ center_window (HWND childwnd, HWND style)
 }
 
 
-static void
+void
 out_of_core (void)
 {
     MessageBox (NULL, "Out of core!", "Fatal Error", MB_OK);
+    abort ();
 }
 
 void*
@@ -166,3 +167,81 @@ w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
   else
     return -1;
 }
+
+
+/* Return a malloced string encoded in UTF-8 from the wide char input
+   string STRING.  Caller must xfree this value. On failure returns
+   NULL; caller may use GetLastError to get the actual error number.
+   The result of calling this function with STRING set to NULL is not
+   defined. */
+char *
+wchar_to_utf8 (const wchar_t *string)
+{
+  int n;
+  char *result;
+
+  /* Note, that CP_UTF8 is not defined in Windows versions earlier
+     than NT.*/
+  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
+  if (n < 0)
+    return NULL;
+
+  result = xmalloc (n+1);
+  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
+  if (n < 0)
+    {
+      xfree (result);
+      return NULL;
+    }
+  return result;
+}
+
+/* Return a malloced wide char string from an UTF-8 encoded input
+   string STRING.  Caller must xfree this value. On failure returns
+   NULL; caller may use GetLastError to get the actual error number.
+   The result of calling this function with STRING set to NULL is not
+   defined. */
+wchar_t *
+utf8_to_wchar (const char *string)
+{
+  int n;
+  wchar_t *result;
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
+  if (n < 0)
+    return NULL;
+
+  result = xmalloc ((n+1) * sizeof *result);
+  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
+  if (n < 0)
+    {
+      xfree (result);
+      return NULL;
+    }
+  return result;
+}
+
+
+/* Same as above but convert only the first LEN characters.  STRING
+   must be at least LEN characters long. */
+wchar_t *
+utf8_to_wchar2 (const char *string, size_t len)
+{
+  int n;
+  wchar_t *result;
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0);
+  if (n < 0)
+    return NULL;
+
+  result = xmalloc ((n+1) * sizeof *result);
+  n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n);
+  if (n < 0)
+    {
+      xfree (result);
+      return NULL;
+    }
+  result[n] = 0;
+  return result;
+}
+
index c53833a..bb8176b 100644 (file)
@@ -45,14 +45,15 @@ struct _gpgme_engine_info  _gpgme_engine_ops_gpgsm;
 static void
 cleanup (void)
 {
-    if (debug_file) {
-       xfree (debug_file);
-       debug_file = NULL;
+  if (debug_file)
+    {
+      xfree (debug_file);
+      debug_file = NULL;
     }
 }
 
 
-/* enable or disable GPGME debug mode. */
+/* Enable or disable GPGME debug mode. */
 void
 op_set_debug_mode (int val, const char *file)
 {
@@ -106,18 +107,47 @@ op_init (void)
 }
 
 
+/* Release a GPGME key array KEYS. */
 static void
 free_recipients (gpgme_key_t *keys)
 {
-    int i;
+  int i;
+  
+  if (!keys)
+    return;
+  for (i=0; keys[i]; i++)
+    gpgme_key_release (keys[i]);
+  xfree (keys);
+}
 
-    if (keys == NULL)
-       return;
-    for (i=0; keys[i] != NULL; i++) {
-       xfree (keys[i]);
-       keys[i] = NULL;
+
+/* 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
+   context used by the passphrase callback.  
+
+   On any error we flush a possible passphrase for the used keyID from
+   the cache.  On success we store the passphrase into the cache.  The
+   cache will take care of the supplied TTL and for example actually
+   delete it if the TTL is 0 or an empty value is used. We also wipe
+   the passphrase from the context here. */
+static void
+update_passphrase_cache (int err, struct decrypt_key_s *pass_cb_value)
+{
+  if (*pass_cb_value->keyid)
+    {
+      if (err)
+        passcache_flush (pass_cb_value->keyid);
+      else
+        passcache_put (pass_cb_value->keyid, pass_cb_value->pass,
+                       pass_cb_value->ttl);
+    }
+  if (pass_cb_value->pass)
+    {
+      wipestring (pass_cb_value->pass);
+      xfree (pass_cb_value->pass);
+      pass_cb_value->pass = NULL;
     }
-    xfree (keys);
 }
 
 
@@ -146,26 +176,33 @@ ftello (FILE *f)
 }
 
 
+/* 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;
-    buf = gpgme_data_release_and_get_mem (*dat, &n);
-    *dat = NULL;
-    if (n == 0) {
-       fclose (out);
-       return GPG_ERR_EOF;
+  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);
-    xfree (buf);
-    return 0;
+  fwrite (buf, 1, n, out);
+  fclose (out);
+  /* FIXME: We have no error checking above. */
+  xfree (buf);
+  return 0;
 }
 
 
@@ -197,454 +234,468 @@ op_export_keys (const char *pattern[], const char *outfile)
 }
 
 
+/* FIXME: Why is RSET a void* ???*/
 int
 op_sign_encrypt_file (void *rset, const char *infile, const char *outfile)
 {
-    gpgme_data_t in = NULL;
-    gpgme_data_t out = NULL;
-    gpgme_ctx_t ctx=NULL;
-    gpgme_error_t err;
-    gpgme_key_t *keys = (gpgme_key_t*)rset;
-    struct decrypt_key_s *hd;
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;
+  gpgme_ctx_t ctx = NULL;
+  gpgme_error_t err;
+  gpgme_key_t *keys = (gpgme_key_t*)rset;
+  struct decrypt_key_s *hd;
+  
+  hd = xcalloc (1, sizeof *hd);
 
-    err = gpgme_data_new_from_file (&in, infile, 1);
-    if (err)
-       return err;
+  err = gpgme_data_new_from_file (&in, infile, 1);
+  if (err)
+    goto fail;
     
-    hd = xcalloc (1, sizeof *hd);
-    err = gpgme_new (&ctx);
-    if (err)
-       goto fail;
+  err = gpgme_new (&ctx);
+  if (err)
+    goto fail;
         
-    gpgme_set_passphrase_cb (ctx, passphrase_callback_box, hd);
+  err = gpgme_data_new (&out);
+  if (err)
+    goto fail;
 
-    err = gpgme_data_new (&out);
-    if (err)
-       goto fail;
+  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, hd);
+  hd->ctx = ctx;    
+  err = gpgme_op_encrypt_sign (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
+  hd->ctx = NULL;    
+  update_passphrase_cache (err, hd);
 
-    err = gpgme_op_encrypt_sign (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
-    if (!err)
-       err = data_to_file (&out, outfile);
+  if (!err)
+    err = data_to_file (&out, outfile);
     
-fail:
-    if (ctx != NULL)
-       gpgme_release (ctx);
-    if (in != NULL)
-       gpgme_data_release (in);
-    if (out != NULL)
-       gpgme_data_release (out);
-    xfree (hd);
-    return err;
+ fail:
+  if (ctx)
+    gpgme_release (ctx);
+  if (in)
+    gpgme_data_release (in);
+  if (out)
+    gpgme_data_release (out);
+  xfree (hd);
+  return err;
 }
 
 
-int
-op_sign_file_next (gpgme_passphrase_cb_t pass_cb, void *pass_cb_value,
-                  int mode, const char *infile, const char *outfile)
+/* Sign the file with name INFILE and write the output to a new file
+   OUTFILE. PASSCB is the passphrase callback to use and DK the value
+   we will pass to it.  MODE is one of the GPGME signing modes. */
+static int
+do_sign_file (gpgme_passphrase_cb_t pass_cb,
+              struct decrypt_key_s *dk,
+              int mode, const char *infile, const char *outfile)
 {
-    gpgme_data_t in=NULL;
-    gpgme_data_t out=NULL;
-    gpgme_ctx_t ctx=NULL;
-    gpgme_error_t err;
-
-    err = gpgme_data_new_from_file (&in, infile, 1);
-    if (err)
-       return err;    
-
-    err = gpgme_new (&ctx);
-    if (err)
-       goto fail;
-
-    gpgme_set_armor (ctx, 1);
-    gpgme_set_passphrase_cb (ctx, pass_cb, pass_cb_value);
-
-    err = gpgme_data_new (&out);
-    if (err)
-       goto fail;
-
-    err = gpgme_op_sign (ctx, in, out, mode);
-    if (!err)
-       err = data_to_file (&out, outfile);
-
-fail:
-    if (in != NULL)
-       gpgme_data_release (in);
-    if (out != NULL)
-       gpgme_data_release (out);
-    if (ctx != NULL)
-       gpgme_release (ctx);    
-    return err;
-}
-
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;
+  gpgme_ctx_t ctx = NULL;
+  gpgme_error_t err;
 
-int
-op_sign_file (int mode, const char *infile, const char *outfile)
-{
-    struct decrypt_key_s *hd;
-    gpgme_error_t err;
+  err = gpgme_data_new_from_file (&in, infile, 1);
+  if (err)
+    goto fail;    
 
-    hd = xcalloc (1, sizeof *hd);
-    hd->flags = 0x01;
+  err = gpgme_new (&ctx);
+  if (err)
+    goto fail;
+  
+  gpgme_set_armor (ctx, 1);
+  
+  err = gpgme_data_new (&out);
+  if (err)
+    goto fail;
 
-    err = op_sign_file_next (passphrase_callback_box, hd, mode, infile, outfile);
+  gpgme_set_passphrase_cb (ctx, pass_cb, dk);
+  dk->ctx = ctx;
+  err = gpgme_op_sign (ctx, in, out, mode);
+  dk->ctx = NULL;
+  update_passphrase_cache (err, dk);
+  
+  if (!err)
+    err = data_to_file (&out, outfile);
 
-    xfree (hd);
-    return err;
+ fail:
+  if (in)
+    gpgme_data_release (in);
+  if (out)
+    gpgme_data_release (out);
+  if (ctx)
+    gpgme_release (ctx);    
+  return err;
 }
 
 
 int
-op_sign_file_ext (int mode, const char *infile, const char *outfile,
-                 cache_item_t *ret_itm)
+op_sign_file (int mode, const char *infile, const char *outfile, int ttl)
 {
-    struct decrypt_key_s *hd;
-    cache_item_t itm;
-    int err;
-
-    hd = (struct decrypt_key_s *)xcalloc (1, sizeof *hd);
-    hd->flags = 0x01;
-    err = op_sign_file_next (passphrase_callback_box, hd, mode, infile, outfile);
+  struct decrypt_key_s *hd;
+  gpgme_error_t err;
+  
+  hd = xcalloc (1, sizeof *hd);
+  hd->ttl = ttl;
+  hd->flags = 0x01;
 
-    if (ret_itm != NULL) {
-       itm = cache_item_new ();
-       itm->pass = hd->pass; 
-       hd->pass = NULL;
-       memcpy (itm->keyid, hd->keyid, sizeof (hd->keyid));
-       *ret_itm = itm;
-    }
+  err = do_sign_file (passphrase_callback_box, hd, mode, infile, outfile);
 
-    free_decrypt_key (hd);
-    return err;
+  xfree (hd);
+  return err;
 }
 
 
+/* Decrypt file INFILE into file OUTFILE. */
 int
 op_decrypt_file (const char *infile, const char *outfile)
 {    
-    gpgme_data_t in = NULL;
-    gpgme_data_t out = NULL;    
-    gpgme_ctx_t ctx = NULL;
-    gpgme_error_t err;
-    struct decrypt_key_s *hd;
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;    
+  gpgme_ctx_t ctx = NULL;
+  gpgme_error_t err;
+  struct decrypt_key_s *dk;
+  
+  dk = xcalloc (1, sizeof *dk);
 
-    err = gpgme_data_new_from_file (&in, infile, 1);
-    if (err)
-       return err;
+  err = gpgme_data_new_from_file (&in, infile, 1);
+  if (err)
+    goto fail;
 
-    hd = xcalloc (1, sizeof *hd);
-    err = gpgme_new (&ctx);
-    if (err)
-       goto fail;
+  err = gpgme_new (&ctx);
+  if (err)
+    goto fail;
 
-    /* XXX: violates the information hiding principle */
-    {
-       struct decrypt_key_s *cb = (struct decrypt_key_s *)hd;
-       cb->ctx = (void *)ctx;
-    }
-    gpgme_set_passphrase_cb (ctx, passphrase_callback_box, hd);
+  err = gpgme_data_new (&out);
+  if (err)
+    goto fail;
 
-    err = gpgme_data_new (&out);
-    if (err)
-       goto fail;
+  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, dk);
+  dk->ctx = ctx;
+  err = gpgme_op_decrypt (ctx, in, out);
+  dk->ctx = NULL;
+  update_passphrase_cache (err, dk);
 
-    err = gpgme_op_decrypt (ctx, in, out);
-    if (!err)
-       err = data_to_file (&out, outfile);
-
-fail:
-    if (in != NULL)
-       gpgme_data_release (in);
-    if (out != NULL)
-       gpgme_data_release (out);
-    if (ctx != NULL)
-       gpgme_release (ctx);
-    xfree (hd);
-    return err;
+  if (!err)
+    err = data_to_file (&out, outfile);
+
+ fail:
+  if (in)
+    gpgme_data_release (in);
+  if (out)
+    gpgme_data_release (out);
+  if (ctx)
+    gpgme_release (ctx);
+  xfree (dk);
+  return err;
 }
 
 
+/* Try to figure out why the encryption failed and provide a suitable
+   error code. */
 static gpgme_error_t
 check_encrypt_result (gpgme_ctx_t ctx, gpgme_error_t err)
 {
-    gpgme_encrypt_result_t res;
-    res = 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! */
+  gpgme_encrypt_result_t res;
+
+  res = 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;
 }
 
 
+
+/* Decrypt the data in file INFILE and write the ciphertext to the new
+   file OUTFILE. */
+/*FIXME: Why is RSET a void*???.  Why do we have this fucntion when
+  there is already a version yusing streams? */
 int
 op_encrypt_file (void *rset, const char *infile, const char *outfile)
 {
-    gpgme_data_t in=NULL;
-    gpgme_data_t out=NULL;
-    gpgme_error_t err;
-    gpgme_ctx_t ctx=NULL;
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;
+  gpgme_error_t err;
+  gpgme_ctx_t ctx = NULL;
 
-    err = gpgme_data_new_from_file (&in, infile, 1);
-    if (err)
-       return err;
+  err = gpgme_data_new_from_file (&in, infile, 1);
+  if (err)
+    goto fail;
 
-    err = gpgme_new (&ctx);
-    if (err)
-       goto fail;
+  err = gpgme_new (&ctx);
+  if (err)
+    goto fail;
 
-    err = gpgme_data_new (&out);
-    if (err)
-       goto fail;
+  err = gpgme_data_new (&out);
+  if (err)
+    goto fail;
 
-    gpgme_set_armor (ctx, 1);
-    err = gpgme_op_encrypt (ctx, (gpgme_key_t*)rset, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
-    if (!err)
-       err = data_to_file (&out, outfile);
-    else
-       err = check_encrypt_result (ctx, err);
+  gpgme_set_armor (ctx, 1);
+  err = gpgme_op_encrypt (ctx, (gpgme_key_t*)rset,
+                          GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
+  if (!err)
+    err = data_to_file (&out, outfile);
+  else
+    err = check_encrypt_result (ctx, err);
 
-fail:
-    if (ctx != NULL)
-       gpgme_release (ctx);
-    if (in != NULL)
-       gpgme_data_release (in);
-    if (out != NULL)
-       gpgme_data_release (out);
-    return err;
+ fail:
+  if (ctx)
+    gpgme_release (ctx);
+  if (in)
+    gpgme_data_release (in);
+  if (out)
+    gpgme_data_release (out);
+  return err;
 }
 
-
+/* Encrypt data from INFILE into the newly created file OUTFILE.  This
+   version of the function internally works on streams to avoid
+   copying data into memory buffers. */
+/*FIXME: Why is RSET a void*??? */
 int
 op_encrypt_file_io (void *rset, const char *infile, const char *outfile)
 {
-    FILE *fin = NULL, *fout=NULL;
-    gpgme_data_t in = NULL;
-    gpgme_data_t out = NULL;
-    gpgme_error_t err;
-    gpgme_ctx_t ctx = NULL;
+  FILE *fin = NULL;
+  FILE *fout = NULL;
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;
+  gpgme_error_t err;
+  gpgme_ctx_t ctx = NULL;
 
-    fin = fopen (infile, "rb");
-    if (fin == NULL)
-       return GPG_ERR_UNKNOWN_ERRNO;
-    err = gpgme_data_new_from_stream (&in, fin);
-    if (err)
-       goto fail;
+  fin = fopen (infile, "rb");
+  if (!fin)
+    {
+      err = GPG_ERR_UNKNOWN_ERRNO; /* FIXME: use errno */
+      goto fail;
+    }
+
+  err = gpgme_data_new_from_stream (&in, fin);
+  if (err)
+    goto fail;
 
-    fout = fopen (outfile, "wb");
-    if (fout == NULL) {
-       err = GPG_ERR_UNKNOWN_ERRNO;
-       goto fail;
+  fout = fopen (outfile, "wb");
+  if (!fout)
+    {
+      err = GPG_ERR_UNKNOWN_ERRNO;
+      goto fail;
     }
-    err = gpgme_data_new_from_stream (&out, fout);
-    if (err)
-       goto fail;
 
-    err = gpgme_new (&ctx);
-    if (err)
-       goto fail;
+  err = gpgme_data_new_from_stream (&out, fout);
+  if (err)
+    goto fail;
 
-    gpgme_set_armor (ctx, 1);
-    err = gpgme_op_encrypt (ctx, (gpgme_key_t*)rset, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
-
-fail:
-    if (fin != NULL)
-       fclose (fin);
-    if (fout != NULL)
-       fclose (fout);
-    if (out != NULL)
-       gpgme_data_release (out);
-    if (in != NULL)
-       gpgme_data_release (in);
-    if (ctx != NULL)
-       gpgme_release (ctx);
-    return err;
+  err = gpgme_new (&ctx);
+  if (err)
+    goto fail;
+  
+  gpgme_set_armor (ctx, 1);
+  err = gpgme_op_encrypt (ctx, (gpgme_key_t*)rset,
+                          GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
+
+ fail:
+  if (fin)
+    fclose (fin);
+  /* FIXME: Shouldn't we remove the file on error here? */
+  if (fout)
+    fclose (fout);
+  if (out)
+    gpgme_data_release (out);
+  if (in)
+    gpgme_data_release (in);
+  if (ctx)
+    gpgme_release (ctx);
+  return err;
 }
 
+/* Yet another encrypt versions; this time frommone memory buffer to a
+   newly allocated one. */
+/*FIXME: Why is RSET a void*??? */
 int
 op_encrypt (void *rset, const char *inbuf, char **outbuf)
 {
-    gpgme_key_t *keys = (gpgme_key_t *)rset;
-    gpgme_data_t in=NULL, out=NULL;
-    gpgme_error_t err;
-    gpgme_ctx_t ctx;
+  gpgme_key_t *keys = (gpgme_key_t *)rset;
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;
+  gpgme_error_t err;
+  gpgme_ctx_t ctx = NULL;
     
-    *outbuf = NULL;
-    op_init ();
-    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_textmode (ctx, 1);
-    gpgme_set_armor (ctx, 1);
-    err = gpgme_op_encrypt (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
-    if (!err) {
-       size_t n = 0;   
-       *outbuf = gpgme_data_release_and_get_mem (out, &n);
-       (*outbuf)[n] = 0;
-       out = NULL;
-    }
-    else
-       err = check_encrypt_result (ctx, err);
+  *outbuf = NULL;
 
-leave:
-    if (ctx != NULL)
-       gpgme_release (ctx);
-    if (in != NULL)
-       gpgme_data_release (in);
-    if (out != NULL)
-       gpgme_data_release (out);
-    return err;
-}
+  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;
 
-int
-op_sign_encrypt_start (const char *inbuf, char **outbuf)
-{
-    gpgme_key_t *keys = NULL;
-    gpgme_key_t locusr=NULL;
-    int opts = 0;
-    int err;
+  err = gpgme_data_new (&out);
+  if (err)
+    goto leave;
 
-    recipient_dialog_box (&keys, &opts);
-    if (opts & OPT_FLAG_CANCEL)
-       return 0;
-    err = signer_dialog_box (&locusr, NULL);
-    if (err == -1) { /* Cancel */
-       free_recipients (keys);
-       return 0;
+  gpgme_set_textmode (ctx, 1);
+  gpgme_set_armor (ctx, 1);
+  err = gpgme_op_encrypt (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
+  if (!err)
+    {
+      size_t n = 0;    
+      *outbuf = gpgme_data_release_and_get_mem (out, &n);
+      (*outbuf)[n] = 0;
+      out = NULL;
     }
-    
-    err = op_sign_encrypt ((void*)keys, (void*)locusr, inbuf, outbuf);
-    free_recipients (keys);
+  else
+    err = check_encrypt_result (ctx, err);
 
-    return err;
+ leave:
+  if (ctx)
+    gpgme_release (ctx);
+  if (in)
+    gpgme_data_release (in);
+  if (out)
+    gpgme_data_release (out);
+  return err;
 }
 
+
+/* Sign and encrypt the data in INBUF into a newly allocated buffer at
+   OUTBUF. */
+/*FIXME: Why is RSET a void*??? */
 int
 op_sign_encrypt (void *rset, void *locusr, const char *inbuf, char **outbuf)
 {
-    gpgme_ctx_t ctx;
-    gpgme_key_t *keys = (gpgme_key_t*)rset;
-    gpgme_data_t in=NULL, out=NULL;
-    gpgme_error_t err;
-    struct decrypt_key_s *hd;
-
-    op_init ();
-    *outbuf = NULL;
+  gpgme_key_t *keys = (gpgme_key_t*)rset;
+  gpgme_ctx_t ctx = NULL;
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;
+  gpgme_error_t err;
+  struct decrypt_key_s *dk = NULL;
 
-    err = gpgme_new (&ctx);
-    if (err)
-       return err;
+  op_init ();
+  
+  *outbuf = NULL;
 
-    hd = (struct decrypt_key_s *)xcalloc (1, sizeof *hd);
-    hd->flags = 0x01;
+  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;
+  dk = (struct decrypt_key_s *)xcalloc (1, sizeof *dk);
+  dk->flags = 0x01;
+  
+  err = gpgme_data_new_from_mem (&in, inbuf, strlen (inbuf), 1);
+  if (err)
+    goto leave;
 
-    gpgme_set_passphrase_cb (ctx, passphrase_callback_box, hd);
-    gpgme_set_armor (ctx, 1);
-    gpgme_signers_add (ctx, (gpgme_key_t)locusr);
-    err = gpgme_op_encrypt_sign (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
-    if (!err) {
-       size_t n = 0;
-       *outbuf = gpgme_data_release_and_get_mem (out, &n);
-       (*outbuf)[n] = 0;
-       out = NULL;
+  err = gpgme_data_new (&out);
+  if (err)
+    goto leave;
+  
+  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, dk);
+  gpgme_set_armor (ctx, 1);
+  gpgme_signers_add (ctx, (gpgme_key_t)locusr);
+  err = gpgme_op_encrypt_sign (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
+  if (!err) 
+    {
+      size_t n = 0;
+      *outbuf = gpgme_data_release_and_get_mem (out, &n);
+      (*outbuf)[n] = 0;
+      out = NULL;
     }
-    else
-       err = check_encrypt_result (ctx, err);
+  else
+    err = check_encrypt_result (ctx, err);
 
-leave:
-    free_decrypt_key (hd);
+ leave:
+  free_decrypt_key (dk);
+  if (ctx)
     gpgme_release (ctx);
+  if (out)
     gpgme_data_release (out);
+  if (in)
     gpgme_data_release (in);
-    return err;
+  return err;
 }
 
 
-int
-op_sign_start (const char *inbuf, char **outbuf)
+static int
+do_sign (gpgme_key_t locusr, const char *inbuf, char **outbuf)
 {
-    gpgme_key_t locusr = NULL;
-    int err;
-
-    log_debug ("engine-gpgme.op_sign_start: enter\n");
-    err = signer_dialog_box (&locusr, NULL);
-    if (err == -1) { /* Cancel */
-        log_debug ("engine-gpgme.op_sign_start: leave (canceled)\n");
-       return 0;
-    }
-    err = op_sign ((void*)locusr, inbuf, outbuf);
-    log_debug ("engine-gpgme.op_sign_start: leave (rc=%d (%s))\n",
-               err, gpg_strerror (err));
-    return err;
-}
+  gpgme_error_t err;
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;
+  gpgme_ctx_t ctx = NULL;
+  struct decrypt_key_s *dk = NULL;
 
+  log_debug ("engine-gpgme.do_sign: enter\n");
 
-int
-op_sign (void *locusr, const char *inbuf, char **outbuf)
-{
-    gpgme_error_t err;
-    gpgme_data_t in=NULL, out=NULL;
-    gpgme_ctx_t ctx;
-    struct decrypt_key_s *hd;
+  *outbuf = NULL;
+  op_init ();
+  
+  err = gpgme_new (&ctx);
+  if (err) 
+    goto leave;
 
-    log_debug ("engine-gpgme.op_sign: enter\n");
-    *outbuf = NULL;
-    op_init ();
-    err = gpgme_new (&ctx);
-    if (err) 
-        goto really_leave;
+  dk = (struct decrypt_key_s *)xcalloc (1, sizeof *dk);
+  dk->flags = 0x01;
 
-    hd = (struct decrypt_key_s *)xcalloc (1, sizeof *hd);
-    hd->flags = 0x01;
+  err = gpgme_data_new_from_mem (&in, inbuf, strlen (inbuf), 1);
+  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_data_new (&out);
+  if (err)
+    goto leave;
     
-    gpgme_set_passphrase_cb (ctx, passphrase_callback_box, hd);
-    gpgme_signers_add (ctx, (gpgme_key_t)locusr);
-    gpgme_set_textmode (ctx, 1);
-    gpgme_set_armor (ctx, 1);
-    err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_CLEAR);
-    if (!err) {
-       size_t n = 0;
-       *outbuf = gpgme_data_release_and_get_mem (out, &n);
-       (*outbuf)[n] = 0;
-       out = NULL;
+  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, dk);
+  gpgme_signers_add (ctx, locusr);
+  gpgme_set_textmode (ctx, 1);
+  gpgme_set_armor (ctx, 1);
+  err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_CLEAR);
+  if (!err)
+    {
+      size_t n = 0;
+      *outbuf = gpgme_data_release_and_get_mem (out, &n);
+      (*outbuf)[n] = 0;
+      out = NULL;
     }
 
 leave:
-    err = 0; /* fixme: the orginal code didn't returned an error.  Correct?*/
-    free_decrypt_key (hd);
+ leave:
+  free_decrypt_key (dk);
+  if (ctx)
     gpgme_release (ctx);
+  if (in)
     gpgme_data_release (in);
+  if (out)
     gpgme_data_release (out);
-  really_leave:
-    log_debug ("engine-gpgme.op_sign: leave (rc=%d (%s))\n",
-               err, gpg_strerror (err));
-    return err;
+  log_debug ("engine-gpgme.do_sign: leave (rc=%d (%s))\n",
+             err, gpgme_strerror (err));
+  return err;
 }
 
 
-/* Worker fucntion for the decryption.  PASS_CB is the passphrase
+
+int
+op_sign_start (const char *inbuf, char **outbuf)
+{
+  gpgme_key_t locusr = NULL;
+  int err;
+
+  log_debug ("engine-gpgme.op_sign_start: enter\n");
+  err = signer_dialog_box (&locusr, NULL);
+  if (err == -1)
+    { /* Cancel */
+      log_debug ("engine-gpgme.op_sign_start: leave (canceled)\n");
+      return 0;
+    }
+  err = do_sign (locusr, inbuf, outbuf);
+  log_debug ("engine-gpgme.op_sign_start: leave (rc=%d (%s))\n",
+             err, gpg_strerror (err));
+  return err;
+}
+
+
+
+/* Worker function for the decryption.  PASS_CB is the passphrase
    callback and PASS_CB_VALUE is passed as opaque argument to the
    callback.  INBUF is the string with ciphertext.  On success a newly
    allocated string with the plaintext will be stored at the address
@@ -681,27 +732,7 @@ do_decrypt (gpgme_passphrase_cb_t pass_cb,
   pass_cb_value->ctx = ctx;    
   err = gpgme_op_decrypt_verify (ctx, in, out);
   pass_cb_value->ctx = NULL;    
-
-  /* Do passphrase cache update immediately after the operation.  On
-     any error we flush a possible passphrase for the used keyID from
-     the cache.  On success we store the passphrase into the cache.
-     The cache will take care of the supplied TTL and for example
-     actually delete it if the TTL is 0 or an empty value is used. We
-     also wipe the passphrase from the context here. */
-  if (*pass_cb_value->keyid)
-    {
-      if (err)
-        passcache_flush (pass_cb_value->keyid);
-      else
-        passcache_put (pass_cb_value->keyid, pass_cb_value->pass,
-                       pass_cb_value->ttl);
-    }
-  if (pass_cb_value->pass)
-    {
-      wipestring (pass_cb_value->pass);
-      xfree (pass_cb_value->pass);
-      pass_cb_value->pass = NULL;
-    }
+  update_passphrase_cache (err, pass_cb_value);
 
   /* Act upon the result of the decryption operation. */
   if (!err) 
@@ -738,8 +769,7 @@ do_decrypt (gpgme_passphrase_cb_t pass_cb,
     }
 
 
-  
-  /* If the callback indicated a cancel operation, clear the error. */
+    /* If the callback indicated a cancel operation, clear the error. */
   if (pass_cb_value->opts & OPT_FLAG_CANCEL)
     err = 0;
   
@@ -752,31 +782,6 @@ leave:
 }
 
 
-
-/* FIXME: Do we still needs this one? */
-#if 0
-int
-op_decrypt_start_ext (const char *inbuf, char **outbuf, cache_item_t *ret_itm)
-{
-    struct decrypt_key_s *hd;
-    cache_item_t itm;
-    int err;
-
-    hd = xcalloc (1, sizeof *hd);
-    err = op_decrypt (passphrase_callback_box, hd, inbuf, outbuf);
-
-    if (ret_itm != NULL) {
-       itm = cache_item_new ();
-       itm->pass = hd->pass; 
-       hd->pass = NULL;
-       memcpy (itm->keyid, hd->keyid, sizeof (hd->keyid));
-       *ret_itm = itm;
-    }
-    free_decrypt_key (hd);
-    return err;
-}
-#endif
-
 /* Run the decryption.  Decrypts INBUF to OUTBUF, caller must xfree
    the result at OUTBUF.  TTL is the time in seconds to cache a
    passphrase. */
@@ -795,56 +800,59 @@ op_decrypt_start (const char *inbuf, char **outbuf, int ttl)
 }
 
 
-/* FIXME: Do we still needs this one? */
-#if 0
-int
-op_decrypt_next (gpgme_passphrase_cb_t pass_cb, void *pass_cb_value,
-                const char *inbuf, char **outbuf)
-{
-    return op_decrypt (pass_cb, pass_cb_value, inbuf, outbuf);
-}
-#endif
-
+/* 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. */
 int
 op_verify_start (const char *inbuf, char **outbuf)
 {
-    gpgme_data_t in=NULL, out=NULL;
-    gpgme_ctx_t ctx;
-    gpgme_error_t err;
-    gpgme_verify_result_t res=NULL;
+  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;
 
-    op_init ();
-    *outbuf = NULL;
+  *outbuf = NULL;
 
-    err = gpgme_new (&ctx);
-    if (err)
-       return err;
+  op_init ();
 
-    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) {
-       size_t n=0;
-       if (outbuf != NULL) {
-           *outbuf = gpgme_data_release_and_get_mem (out, &n);
-           (*outbuf)[n] = 0;
-           out = NULL;
+  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)
+    {
+      size_t n=0;
+      if (outbuf) 
+        {
+          *outbuf = gpgme_data_release_and_get_mem (out, &n);
+          (*outbuf)[n] = 0;
+          out = NULL;
        }
-       res = gpgme_op_verify_result (ctx);
+      res = gpgme_op_verify_result (ctx);
     }
-    if (res != NULL
-       verify_dialog_box (res);
+  if (res
+    verify_dialog_box (res);
 
-leave:
+ leave:
+  if (out)
     gpgme_data_release (out);
+  if (in)
     gpgme_data_release (in);
+  if (ctx)
     gpgme_release (ctx);
-    return err;
+  return err;
 }
 
 
index 08b4f2d..4f53fbb 100644 (file)
@@ -47,7 +47,6 @@ int op_encrypt_start (const char *inbuf, char **outbuf);
 int op_encrypt (void *rset, const char *inbuf, char **outbuf);
 int op_encrypt_file (void *rset, const char *infile, const char *outfile);
 
-int op_sign_encrypt_start (const char *inbuf, char **outbuf);
 int op_sign_encrypt (void *rset, void *locusr, const char *inbuf, 
                     char **outbuf);
 int op_sign_encrypt_file (void *rset, const char *infile, const char *outfile);
@@ -55,18 +54,10 @@ int op_sign_encrypt_file (void *rset, const char *infile, const char *outfile);
 int op_verify_start (const char *inbuf, char **outbuf);
 
 int op_sign_start (const char *inbuf, char **outbuf);
-int op_sign (void *locusr, const char *inbuf, char **outbuf);
-int op_sign_file (int mode, const char *infile, const char *outfile);
-int op_sign_file_ext (int mode, const char *infile, const char *outfile,
-                     cache_item_t *ret_itm);
-int op_sign_file_next (gpgme_passphrase_cb_t pass_cb, void *pass_cb_value,
-                      int mode, const char *infile, const char *outfile);
+int op_sign_file (int mode, const char *infile, const char *outfile, int ttl);
 
 int op_decrypt_file (const char *infile, const char *outfile);
-int op_decrypt_next (gpgme_passphrase_cb_t pass_cb, void *pass_cb_value,
-                     const char *inbuf, char **outbuf);
 int op_decrypt_start (const char *inbuf, char **outbuf, int ttl);
-int op_decrypt_start_ext (const char *inbuf, char **outbuf, cache_item_t *ret_itm);
 
 int op_lookup_keys (char **id, gpgme_key_t **keys, char ***unknown, size_t *n);
 
diff --git a/src/gpgmsg.cpp b/src/gpgmsg.cpp
new file mode 100644 (file)
index 0000000..f8a9d86
--- /dev/null
@@ -0,0 +1,504 @@
+/* gpgmsg.cpp - Implementation ofthe GpgMsg class
+ *     Copyright (C) 2005 g10 Code GmbH
+ *
+ * This file is part of OutlGPG.
+ * 
+ * OutlGPG 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.
+ * 
+ * OutlGPG 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 <assert.h>
+#include <string.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+
+#include "gpgmsg.hh"
+#include "util.h"
+#include "msgcache.h"
+
+/*
+   The implementation class of MapiGPGME.  
+ */
+class GpgMsgImpl : public GpgMsg
+{
+public:    
+  GpgMsgImpl () 
+  {
+    this->message = NULL;
+    this->body = NULL;
+    this->body_plain = NULL;
+    this->body_cipher = NULL;
+    this->body_signed = NULL;
+    this->body_cipher_is_html = false;
+  }
+
+  ~GpgMsgImpl ()
+  {
+    if (message)
+      message->Release ();
+    xfree (body);
+    xfree (body_plain);
+    xfree (body_cipher);
+    xfree (body_signed);
+  }
+
+  void destroy ()
+  {
+    delete this;
+  }
+
+  void operator delete (void *p) 
+  {
+    ::operator delete (p);
+  }
+
+  void setMapiMessage (LPMESSAGE msg)
+  {
+    if (message)
+      {
+        message->Release ();
+        message = NULL;
+      }
+    if (msg)
+      {
+      log_debug ("%s:%s:%d: here\n", __FILE__, __func__, __LINE__);
+        msg->AddRef ();
+      log_debug ("%s:%s:%d: here\n", __FILE__, __func__, __LINE__);
+        message = msg;
+      }
+  }
+  
+  openpgp_t getMessageType (void);
+  bool hasAttachments (void);
+  const char *getOrigText (void);
+  const char *GpgMsgImpl::getDisplayText (void);
+  const char *getPlainText (void);
+  void setPlainText (char *string);
+  void setCipherText (char *string, bool html);
+  void setSignedText (char *string);
+  void saveChanges (bool permanent);
+  bool matchesString (const char *string);
+  char **getRecipients (void);
+
+
+private:
+  LPMESSAGE message;  /* Pointer to the message. */
+  char *body;         /* utf-8 encoded body string or NULL. */
+  char *body_plain;   /* Plaintext version of BODY or NULL. */
+  char *body_cipher;  /* Enciphered version of BODY or NULL. */
+  char *body_signed;  /* Signed version of BODY or NULL. */
+  bool body_cipher_is_html; /* Indicating that BODY_CIPHER holds HTML. */
+  
+  void loadBody (void);
+  
+  
+};
+
+
+/* Return a new instance and initialize with the MAPI message object
+   MSG. */
+GpgMsg *
+CreateGpgMsg (LPMESSAGE msg)
+{
+  GpgMsg *m = new GpgMsgImpl ();
+  if (!m)
+    out_of_core ();
+  m->setMapiMessage (msg);
+  return m;
+}
+
+
+/* Load the body and make it available as an UTF8 string in the
+   instance variable BODY.  */
+void
+GpgMsgImpl::loadBody (void)
+{
+  HRESULT hr;
+  LPSPropValue lpspvFEID = NULL;
+  LPSTREAM stream;
+  SPropValue prop;
+  STATSTG statInfo;
+  ULONG nread;
+
+  if (body || !message)
+    return;
+  
+#if 1
+  hr = message->OpenProperty (PR_BODY, &IID_IStream,
+                              0, 0, (LPUNKNOWN*)&stream);
+  if ( hr != S_OK )
+    {
+      log_debug_w32 (hr, "%s:%s: OpenProperty failed", __FILE__, __func__);
+      return;
+    }
+
+  hr = stream->Stat (&statInfo, STATFLAG_NONAME);
+  if ( hr != S_OK )
+    {
+      log_debug_w32 (hr, "%s:%s: Stat failed", __FILE__, __func__);
+      stream->Release ();
+      return;
+    }
+  
+  /* FIXME: We might want to read only the first 1k to decide whetehr
+     this is actually an OpenPGP message and only then continue
+     reading.  This requires some changes in this module. */
+  body = (char*)xmalloc ((size_t)statInfo.cbSize.QuadPart + 2);
+  hr = stream->Read (body, (size_t)statInfo.cbSize.QuadPart, &nread);
+  if ( hr != S_OK )
+    {
+      log_debug_w32 (hr, "%s:%s: Read failed", __FILE__, __func__);
+      xfree (body);
+      body = NULL;
+      stream->Release ();
+      return;
+    }
+  body[nread] = 0;
+  body[nread+1] = 0;
+  if (nread != statInfo.cbSize.QuadPart)
+    {
+      log_debug ("%s:%s: not enough bytes returned\n", __FILE__, __func__);
+      xfree (body);
+      body = NULL;
+      stream->Release ();
+      return;
+    }
+  stream->Release ();
+
+  /* Fixme: We need to optimize this. */
+  {
+    char *tmp;
+    tmp = wchar_to_utf8 ((wchar_t*)body);
+    if (!tmp)
+      log_debug ("%s: error converting to utf8\n", __func__);
+    else
+      {
+        xfree (body);
+        body = tmp;
+      }
+  }
+
+#else /* Old method. */
+  hr = HrGetOneProp ((LPMAPIPROP)message, PR_BODY, &lpspvFEID);
+  if (FAILED (hr))
+    {
+      log_debug ("%s: HrGetOneProp failed\n", __func__);
+      return;
+    }
+    
+  switch ( PROP_TYPE (lpspvFEID->ulPropTag) )
+    {
+    case PT_UNICODE:
+      body = wchar_to_utf8 (lpspvFEID->Value.lpszW);
+      if (!body)
+        log_debug ("%s: error converting to utf8\n", __func__);
+      break;
+      
+    case PT_STRING8:
+      body = xstrdup (lpspvFEID->Value.lpszA);
+      break;
+      
+    default:
+      log_debug ("%s: proptag=0x%08lx not supported\n",
+                 __func__, lpspvFEID->ulPropTag);
+      break;
+    }
+  MAPIFreeBuffer (lpspvFEID);
+#endif  
+
+  if (body)
+    log_debug ("%s:%s: loaded body `%s' at %p\n",
+               __FILE__, __func__, body, body);
+  
+
+//   prop.ulPropTag = PR_ACCESS;
+//   prop.Value.l = MAPI_ACCESS_MODIFY;
+//   hr = HrSetOneProp (message, &prop);
+//   if (FAILED (hr))
+//     log_debug_w32 (-1,"%s:%s: updating access to 0x%08lx failed",
+//                    __FILE__, __func__, prop.Value.l);
+}
+
+
+/* Return the type of a message. */
+openpgp_t
+GpgMsgImpl::getMessageType (void)
+{
+  const char *s;
+  
+  loadBody ();
+  
+  if (!body || !(s = strstr (body, "BEGIN PGP ")))
+    return OPENPGP_NONE;
+
+  /* (The extra strstr() above is just a simple optimization.) */
+  if (strstr (body, "BEGIN PGP MESSAGE"))
+    return OPENPGP_MSG;
+  else if (strstr (body, "BEGIN PGP SIGNED MESSAGE"))
+    return OPENPGP_CLEARSIG;
+  else if (strstr (body, "BEGIN PGP SIGNATURE"))
+    return OPENPGP_SIG;
+  else if (strstr (body, "BEGIN PGP PUBLIC KEY"))
+    return OPENPGP_PUBKEY;
+  else if (strstr (body, "BEGIN PGP PRIVATE KEY"))
+    return OPENPGP_SECKEY;
+  else
+    return OPENPGP_NONE;
+}
+
+
+/* Return the body text as received or composed.  This is guaranteed
+   to never return NULL.  */
+const char *
+GpgMsgImpl::getOrigText ()
+{
+  loadBody ();
+  
+  return body? body : "";
+}
+
+
+/* Return the text of the message to be used for the display.  The
+   message objects has intrinsic knowledge about the correct text.  */
+const char *
+GpgMsgImpl::getDisplayText (void)
+{
+  loadBody ();
+
+  if (body_plain)
+    return body_plain;
+  else if (body)
+    return body;
+  else
+    return "";
+}
+
+
+
+/* Save STRING as the plaintext version of the message.  WARNING:
+   ownership of STRING is transferred to this object. */
+void
+GpgMsgImpl::setPlainText (char *string)
+{
+  xfree (body_plain);
+  body_plain = string;
+  msgcache_put (body_plain, 0, message);
+}
+
+/* Save STRING as the ciphertext version of the message.  WARNING:
+   ownership of STRING is transferred to this object. HTML indicates
+   whether the ciphertext was originally HTML. */
+void
+GpgMsgImpl::setCipherText (char *string, bool html)
+{
+  xfree (body_cipher);
+  body_cipher = string;
+  body_cipher_is_html = html;
+}
+
+/* Save STRING as the signed version of the message.  WARNING:
+   ownership of STRING is transferred to this object. */
+void
+GpgMsgImpl::setSignedText (char *string)
+{
+  xfree (body_signed);
+  body_signed = string;
+}
+
+/* Save the changes made to the message.  With PERMANENT set to true
+   they are really stored, when not set they are only saved
+   temporary. */
+void
+GpgMsgImpl::saveChanges (bool permanent)
+{
+  SPropValue sProp; 
+  HRESULT hr;
+  int rc = TRUE;
+
+  if (!body_plain)
+    return; /* Nothing to save. */
+
+  return;
+  
+  /* Make sure that the Plaintext and the Richtext are in sync. */
+//   if (message)
+//     {
+//       BOOL changed;
+
+//       sProp.ulPropTag = PR_BODY_A;
+//       sProp.Value.lpszA = "";
+//       hr = HrSetOneProp(message, &sProp);
+//       changed = false;
+//       RTFSync(message, RTF_SYNC_BODY_CHANGED, &changed);
+//       sProp.Value.lpszA = body_plain;
+//       hr = HrSetOneProp(message, &sProp);
+//       RTFSync(message, RTF_SYNC_BODY_CHANGED, &changed);
+//     }
+
+  sProp.ulPropTag = PR_BODY_W;
+  sProp.Value.lpszW = utf8_to_wchar (body_plain);
+  if (!sProp.Value.lpszW)
+    {
+      log_debug_w32 (-1, "%s:%s: error converting from utf8\n",
+                     __FILE__, __func__);
+      return;
+    }
+  hr = HrSetOneProp (message, &sProp);
+  xfree (sProp.Value.lpszW);
+  if (hr < 0)
+    log_debug_w32 (-1, "%s:%s: HrSetOneProp failed", __FILE__, __func__);
+  else
+    {
+      log_debug ("%s:%s: PR_BODY set to `%s'\n",
+                 __FILE__, __func__, body_plain);
+      {
+        GpgMsg *xmsg = CreateGpgMsg (message);
+        log_debug ("%s:%s:    cross check `%s'\n",
+                   __FILE__, __func__, xmsg->getOrigText ());
+        delete xmsg;
+      }
+      if (permanent && message)
+        {
+          hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
+          if (hr < 0)
+            log_debug_w32 (-1, "%s:%s: SaveChanges failed",
+                           __FILE__, __func__);
+        }
+    }
+
+  log_debug ("%s:%s: leave\n", __FILE__, __func__);
+}
+
+
+/* Returns true if STRING matches the actual message. */ 
+bool
+GpgMsgImpl::matchesString (const char *string)
+{
+  /* FIXME:  This is a too simple implementation. */
+  if (string && strstr (string, "BEGIN PGP ") )
+    return true;
+  return false;
+}
+
+
+
+/* Return an array of strings with the recipients of the message. On
+   success a malloced array is returned containing allocated strings
+   for each recipient.  The end of the array is marked by NULL.
+   Caller is responsible for releasing the array.  On failure NULL is
+   returned.  */
+char ** 
+GpgMsgImpl::getRecipients ()
+{
+  static SizedSPropTagArray (1L, PropRecipientNum) = {1L, {PR_EMAIL_ADDRESS}};
+  HRESULT hr;
+  LPMAPITABLE lpRecipientTable = NULL;
+  LPSRowSet lpRecipientRows = NULL;
+  char **rset;
+  const char *s;
+  int i, j;
+
+  if (!message)
+    return NULL;
+
+  hr = message->GetRecipientTable (0, &lpRecipientTable);
+  if (FAILED (hr)) 
+    {
+      log_debug_w32 (-1, "%s:%s: GetRecipientTable failed",
+                     __FILE__, __func__);
+      return NULL;
+    }
+
+  hr = HrQueryAllRows (lpRecipientTable, (LPSPropTagArray) &PropRecipientNum,
+                       NULL, NULL, 0L, &lpRecipientRows);
+  if (FAILED (hr)) 
+    {
+      log_debug_w32 (-1, "%s:%s: GHrQueryAllRows failed", __FILE__, __func__);
+      if (lpRecipientTable)
+        lpRecipientTable->Release();
+      return NULL;
+    }
+
+  rset = (char**)xcalloc (lpRecipientRows->cRows+1, sizeof *rset);
+
+  for (i = j = 0; i < lpRecipientRows->cRows; i++)
+    {
+      LPSPropValue row;
+
+      if (!lpRecipientRows->aRow[j].cValues)
+        continue;
+      row = lpRecipientRows->aRow[j].lpProps;
+
+      switch ( PROP_TYPE (row->ulPropTag) )
+        {
+        case PT_UNICODE:
+          rset[j] = wchar_to_utf8 (row->Value.lpszW);
+          if (rset[j])
+            j++;
+          else
+            log_debug ("%s:%s: error converting recipient to utf8\n",
+                       __FILE__, __func__);
+          break;
+      
+        case PT_STRING8: /* Assume Ascii. */
+          rset[j++] = xstrdup (row->Value.lpszA);
+          break;
+          
+        default:
+          log_debug ("%s:%s: proptag=0x%08lx not supported\n",
+                     __FILE__, __func__, row->ulPropTag);
+          break;
+        }
+    }
+  rset[j] = NULL;
+
+  if (lpRecipientTable)
+    lpRecipientTable->Release();
+  if (lpRecipientRows)
+    FreeProws(lpRecipientRows);        
+  
+  log_debug ("%s:%s: got %d recipients:\n",
+             __FILE__, __func__, j);
+  for (i=0; rset[i]; i++)
+    log_debug ("%s:%s: \t`%s'\n", __FILE__, __func__, rset[i]);
+
+  return rset;
+}
+
+
+
+
+
+/* Returns whether the message has any attachments. */
+bool
+GpgMsgImpl::hasAttachments ()
+{
+//   if (!attachRows)
+//     getAttachments ();
+
+//   bool has = attachRows->cRows > 0? true : false;
+//     freeAttachments ();
+//     return has;
+  return false;
+}
+
+
+
diff --git a/src/gpgmsg.hh b/src/gpgmsg.hh
new file mode 100644 (file)
index 0000000..b83737b
--- /dev/null
@@ -0,0 +1,109 @@
+/* gpgmsg.hh - The GpgMsg class
+ *     Copyright (C) 2005 g10 Code GmbH
+ *
+ * This file is part of OutlGPG.
+ * 
+ * OutlGPG 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.
+ * 
+ * OutlGPG 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 GPGMSG_HH
+#define GPGMSG_HH
+
+
+/* Type of a message. */
+typedef enum 
+  {
+    OPENPGP_NONE = 0,
+    OPENPGP_MSG,
+    OPENPGP_SIG,
+    OPENPGP_CLEARSIG,
+    OPENPGP_PUBKEY,   /* Note, that this type is only partly supported */
+    OPENPGP_SECKEY    /* Note, that this type is only partly supported */
+  }
+openpgp_t;
+
+
+
+/* To manage a message we use our own class to keep track about all
+   the information we known on the content of a message.  This is
+   useful to remember the state of conversion (sometimes we need to
+   copy between utf8 and the native character set) and to parse the
+   message down into the MIME structure. */
+
+class GpgMsg
+{
+public:    
+  virtual void destroy () = 0;
+  void operator delete (void *p)
+    {
+      if (p)
+        {
+          GpgMsg *m = (GpgMsg*)(p);
+          m->destroy();
+        }
+    }
+
+  /* Set a new MAPI message into the object. */
+  virtual void setMapiMessage (LPMESSAGE msg);
+
+  /* Return the type of the message. */
+  virtual openpgp_t getMessageType (void);
+
+  /* Returns whether the message has any attachments. */
+  virtual bool hasAttachments (void);
+
+  /* Return the body text as received or composed.  This is guaranteed
+     to never return NULL.  Usually getMessageType is used to check
+     whether there is a suitable message. */
+  virtual const char *getOrigText (void);
+
+  /* Return the text of the message to be used for the display.  The
+     message objects has intrinsic knowledge about the correct
+     text.  */
+  virtual const char *getDisplayText (void);
+
+  /* Save STRING as the plaintext version of the message.  WARNING:
+     ownership of STRING is transferred to this object. */
+  virtual void setPlainText (char *string);
+
+  /* Save STRING as the ciphertext version of the message.  WARNING:
+     ownership of STRING is transferred to this object. */
+  virtual void setCipherText (char *string, bool html);
+
+  /* Save STRING as the signed version of the message.  WARNING:
+     ownership of STRING is transferred to this object. */
+  virtual void setSignedText (char *string);
+  
+  /* Save the changes made to the message.  With PERMANENT set to true
+     they are really stored, when not set they are only saved
+     temporary. */
+  virtual void saveChanges (bool permanent);
+
+  /* Return true if STRING matches the actual message. */ 
+  virtual bool matchesString (const char *string);
+
+  /* Return a malloced array of malloced strings with the recipients
+     of the message. Caller is responsible for freeing this array and
+     the strings.  On failure NULL is returned.  */
+  virtual char **getRecipients (void);
+
+};
+
+
+/* Create a new instance and initialize with the MAPI message object
+   MSG. */
+GpgMsg *CreateGpgMsg (LPMESSAGE msg);
+
+#endif /*GPGMSG_HH*/
index 92dab71..50e420e 100644 (file)
@@ -83,8 +83,6 @@ HRESULT w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e);
 
 /*-- MapiGPGME.cpp --*/
 int initialize_mapi_gpgme (void);
-void log_debug (const char *fmt, ...);
-void log_debug_w32 (int w32err, const char *fmt, ...);
 
 
 /*-- recipient-dialog.c --*/
index 3427d79..3b0f75e 100644 (file)
 #include "keycache.h"
 #include "intern.h"
 
-#pragma data_seg(".SHARDAT")
 static keycache_t pubring = NULL;
 static keycache_t secring = NULL;
 static time_t last_timest = 0;
-#pragma data_seg()
 
 
 /* Initialize global keycache objects */
index 3d3a332..d7f6347 100644 (file)
  * along with GPGME Dialogs; if not, write to the Free Software Foundation, 
  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  */
+
+#include <config.h>
+
 #include <windows.h>
 
 #include <gpgme.h>
 
+#include "mymapi.h"
+#include "mymapitags.h"
+
+
 #include "intern.h"
 #include "passcache.h"
+#include "msgcache.h"
+#include "mymapi.h"
 
 
 int WINAPI
@@ -40,6 +49,8 @@ DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
       /* Early initializations of our subsystems. */
       if (initialize_passcache ())
         return FALSE;
+      if (initialize_msgcache ())
+        return FALSE;
       if (initialize_mapi_gpgme ())
         return FALSE;
     }
diff --git a/src/msgcache.c b/src/msgcache.c
new file mode 100644 (file)
index 0000000..ffb93cd
--- /dev/null
@@ -0,0 +1,139 @@
+/* msgcache.cpp - Implementation of a message cache.
+ *     Copyright (C) 2005 g10 Code GmbH
+ *
+ * This file is part of OutlGPG.
+ * 
+ * OutlGPG 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.
+ * 
+ * OutlGPG 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.
+ */
+
+/* Due to some peculiarities of Outlook 2003 and possible also earlier
+   versions we need fixup the text of a reply before editing starts.
+   This is done using the Echache extension mechanism and this module
+   provides the means of caching and locating messages.  To be exact,
+   we don't cache entire messages but just the plaintext after
+   decryption.
+
+   What we do here is to save the plaintext in a list under a key
+   taken from the PR_STORE_ENTRYID property.  It seems that this is a
+   reliable key to match the message again after Reply has been
+   called.  We can't use PR_ENTRYID because this one is different in
+   the reply template message.
+
+   To keep the memory size at bay we but a limit on the maximum cache
+   size; thus depending on the total size of the messages the number
+   of open inspectors with decrypted messages which can be matched
+   against a reply template is limited. We try to make sure that there
+   is at least one message; this makes sure that in the most common
+   case the plaintext is always available.  We use a circular buffer
+   so that the oldest messages are flushed from the cache first.  I
+   don't think that it makes much sense to take the sieze of a message
+   into account here.
+*/
+   
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+#include <assert.h>
+#include <string.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+
+#include "msgcache.h"
+#include "util.h"
+
+
+/* A Item to hold a cache message, i.e. the plaintext and a key. */
+struct cache_item
+{
+  struct cache_item *next;  
+
+  char *plaintext;  /* The malloced plaintext of the message.  This is
+                       assumed to be a valid C String, UTF8
+                       encoded. */
+  size_t length;    /* The length of that plaintext used to compute
+                       the total size of the cache. */
+
+  /* The length of the key and the key itself.  The cache item is
+     dynamically allocated to fit the size of the key.  Note, that
+     the key is a binary blob. */
+  size_t keylen;
+  char key[1];
+};
+typedef struct cache_item *cache_item_t;
+
+
+/* The actual cache is a simple list anchord at this global
+   variable. */
+static cache_item_t the_cache;
+
+/* Mutex used to serialize access to the cache. */
+static HANDLE cache_mutex;
+
+
+
+/* Initialize this module.  Called at a very early stage during DLL
+   loading.  Returns 0 on success. */
+int
+initialize_msgcache (void)
+{
+  SECURITY_ATTRIBUTES sa;
+  
+  memset (&sa, 0, sizeof sa);
+  sa.bInheritHandle = TRUE;
+  sa.lpSecurityDescriptor = NULL;
+  sa.nLength = sizeof sa;
+  cache_mutex = CreateMutex (&sa, FALSE, NULL);
+  return cache_mutex? 0 : -1;
+}
+
+
+/* Put the BODY of a message into the cache.  BODY should be a
+   malloced string, UTF8 encoded.  If TRANSFER is given as true, the
+   ownership of the malloced memory for BODY is transferred to this
+   module.  MESSAGE is the MAPI message object used to retrieve the
+   storarge key for the BODY. */
+void
+msgcache_put (char *body, int transfer, LPMESSAGE message)
+{
+  cache_item_t item;
+
+  item = xcalloc (1, sizeof *item);
+  item->plaintext = xstrdup (body);
+  item->length = strlen (body);
+
+  the_cache = item;
+}
+
+
+/* Locate a plaintext stored under a key derived from the MAPI object
+   MESSAGE and return it.  Returns NULL if no plaintext is available.
+   FIXME: We need to make sure that the cache object is locked until
+   it has been processed by the caller - required a
+   msgcache_get_unlock fucntion or similar. */
+const char *
+msgcache_get (LPMESSAGE message)
+{
+  if (the_cache && the_cache->plaintext)
+    {
+      return the_cache->plaintext;
+    }
+  return NULL;
+}
+
diff --git a/src/msgcache.h b/src/msgcache.h
new file mode 100644 (file)
index 0000000..0b6f676
--- /dev/null
@@ -0,0 +1,46 @@
+/* msgcache.h - Interface to the message cache.
+ *     Copyright (C) 2005 g10 Code GmbH
+ *
+ * This file is part of OutlGPG.
+ * 
+ * OutlGPG 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.
+ * 
+ * OutlGPG 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 MSGCACHE_H
+#define MSGCACHE_H
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+}
+#endif
+#endif
+
+/* Initialize the message cache subsystem. */
+int initialize_msgcache (void);
+
+/* Put BODY into tye cace, derive the key from MESSAGE.  TRANSFER
+   controls whether the cache will snatch ownership of body. */
+void msgcache_put (char *body, int transfer, LPMESSAGE message);
+
+/* Return the plaintext stored under a key derived from MESSAGE or
+   NULL if none was found. */
+const char *msgcache_get (LPMESSAGE message);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*MSGCACHE_H*/
diff --git a/src/myexchext.h b/src/myexchext.h
new file mode 100644 (file)
index 0000000..2494285
--- /dev/null
@@ -0,0 +1,333 @@
+/* myexchext.h - Simple replacement for exchext.h
+
+ * This file defines the interface used by Exchange extensions.  It
+ * has been compiled by g10 Code GmbH from several sources describing
+ * the interface.
+ *
+ * Revisions:
+ * 2005-08-12  Initial version.
+ *
+ */
+
+#ifndef EXCHEXT_H
+#define EXCHEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+}
+#endif
+#endif
+
+#include <commctrl.h>
+#include <unknwn.h>
+#include "mymapi.h"
+
+
+/* Constants used by Install. */
+#define EECONTEXT_SESSION               0x00000001
+#define EECONTEXT_VIEWER                0x00000002
+#define EECONTEXT_REMOTEVIEWER          0x00000003
+#define EECONTEXT_SEARCHVIEWER          0x00000004
+#define EECONTEXT_ADDRBOOK              0x00000005
+#define EECONTEXT_SENDNOTEMESSAGE       0x00000006
+#define EECONTEXT_READNOTEMESSAGE       0x00000007
+#define EECONTEXT_SENDPOSTMESSAGE       0x00000008
+#define EECONTEXT_READPOSTMESSAGE       0x00000009
+#define EECONTEXT_READREPORTMESSAGE     0x0000000A
+#define EECONTEXT_SENDRESENDMESSAGE     0x0000000B
+#define EECONTEXT_PROPERTYSHEETS        0x0000000C
+#define EECONTEXT_ADVANCEDCRITERIA      0x0000000D
+#define EECONTEXT_TASK                  0x0000000E
+
+/* Constants for GetVersion. */
+#define EECBGV_GETBUILDVERSION          0x00000001
+#define EECBGV_GETACTUALVERSION         0x00000002
+#define EECBGV_GETVIRTUALVERSION        0x00000004
+#define EECBGV_BUILDVERSION_MAJOR       0x000d0000
+#define EECBGV_BUILDVERSION_MAJOR_MASK  0xffff0000
+#define EECBGV_BUILDVERSION_MINOR_MASK  0x0000ffff
+
+/* Some toolbar IDs. */
+#define EETBID_STANDARD                 0x00000001
+
+/* Constants use for QueryHelpText. */
+#define EECQHT_STATUS                   0x00000001
+#define EECQHT_TOOLTIP                  0x00000002
+
+/* Flags use by the methods of IExchExtPropertySheets.  */
+#define EEPS_MESSAGE                    0x00000001
+#define EEPS_FOLDER                     0x00000002
+#define EEPS_STORE                      0x00000003
+#define EEPS_TOOLSOPTIONS               0x00000004
+
+
+/* Command IDs. */
+#define EECMDID_ToolsCustomizeToolbar          134
+#define EECMDID_ToolsOptions                   136
+
+
+/* GUIDs */
+DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+DEFINE_OLEGUID(IID_IUnknown,                  0x00000000, 0, 0);
+DEFINE_OLEGUID(IID_IDispatch,                 0x00020400, 0, 0);
+
+DEFINE_OLEGUID(IID_IExchExtCallback,          0x00020d10, 0, 0);
+DEFINE_OLEGUID(IID_IExchExt,                  0x00020d11, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtCommands,          0x00020d12, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtUserEvents,        0x00020d13, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtSessionEvents,     0x00020d14, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtMessageEvents,     0x00020d15, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtAttachedFileEvents,0x00020d16, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtPropertySheets,    0x00020d17, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtAdvancedCriteria,  0x00020d18, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtModeless,          0x00020d19, 0, 0);
+DEFINE_OLEGUID(IID_IExchExtModelessCallback,  0x00020d1a, 0, 0);
+DEFINE_OLEGUID(IID_IOutlookExtCallback,       0x0006720d, 0, 0);
+
+
+/* Type definitions. */
+
+/* Parameters for the toolbar entries for
+   IExchExtCommands::InstallCommands. */
+struct TBENTRY
+{
+  HWND hwnd;
+  ULONG tbid;
+  ULONG ulFlags;
+  UINT itbbBase;
+};
+typedef struct TBENTRY TBENTRY;
+typedef struct TBENTRY *LPTBENTRY;
+
+
+
+
+
+\f
+/**** Class declarations.  ***/
+typedef struct IExchExt IExchExt;
+typedef IExchExt *LPEXCHEXT;
+
+typedef struct IExchExtMessageEvents IExchExtMessageEvents;
+typedef IExchExtMessageEvents *LPEXCHEXTMESSAGEEVENTS;
+
+typedef struct IExchExtCommands IExchExtCommands;
+typedef IExchExtCommands *LPEXCHEXTCOMMANDS;
+
+typedef struct IExchExtPropertySheets IExchExtPropertySheets;
+typedef IExchExtPropertySheets *LPEXCHEXTPROPERTYSHEETS;
+
+typedef struct IExchExtCallback IExchExtCallback;
+typedef IExchExtCallback *LPEXCHEXTCALLBACK;
+
+typedef struct IOutlookExtCallback IOutlookExtCallback;
+typedef IOutlookExtCallback *LPOUTLOOKEXTCALLBACK;
+
+/* The next classes are not yet defined. but if so they should go here. */
+typedef struct IExchExtModeless IExchExtModeless; 
+typedef IExchExtModeless *LPEXCHEXTMODELESS;
+typedef struct IExchExtModelessCallback IExchExtModelessCallback;
+typedef IExchExtModelessCallback *LPEXCHEXTMODELESSCALLBACK;
+
+
+
+
+/*** Class declarations of classes defined elsewhere. ***/
+struct IMAPISession;
+typedef struct IMAPISession *LPMAPISESSION;
+
+struct IAddrBook;
+typedef struct IAddrBook *LPADRBOOK;
+
+struct IMAPIFolder;
+typedef struct IMAPIFolder *LPMAPIFOLDER;
+
+struct IMAPIProp;
+typedef struct IMAPIProp *LPMAPIPROP;
+
+struct IPersistMessage;
+typedef struct IPersistMessage *LPPERSISTMESSAGE;
+
+struct IMAPIMessageSite;
+typedef struct IMAPIMessageSite *LPMAPIMESSAGESITE;
+
+struct IMAPIViewContext;
+typedef struct IMAPIViewContext *LPMAPIVIEWCONTEXT;
+
+
+
+/*** Types derived from the above class definitions. ***/
+
+/* Callback used to load an extension. */
+typedef LPEXCHEXT (CALLBACK *LPFNEXCHEXTENTRY)(void);
+
+/* Parameters for the IExchExtCallback::ChooseFolder. */
+typedef UINT (STDAPICALLTYPE *LPEECFHOOKPROC)(HWND, UINT, WPARAM, LPARAM);
+
+struct EXCHEXTCHOOSEFOLDER
+{
+  UINT cbLength;
+  HWND hwnd;
+  LPTSTR szCaption;
+  LPTSTR szLabel;
+  LPTSTR szHelpFile;
+  ULONG ulHelpID;
+  HINSTANCE hinst;
+  UINT uiDlgID;
+  LPEECFHOOKPROC lpeecfhp;
+  DWORD dwHookData;
+  ULONG ulFlags;
+  LPMDB pmdb;
+  LPMAPIFOLDER pfld;
+  LPTSTR szName;
+  DWORD dwReserved1;
+  DWORD dwReserved2;
+  DWORD dwReserved3;
+};
+typedef struct EXCHEXTCHOOSEFOLDER EXCHEXTCHOOSEFOLDER;
+typedef struct EXCHEXTCHOOSEFOLDER *LPEXCHEXTCHOOSEFOLDER;
+
+
+
+
+/**** Class definitions.  ***/
+
+EXTERN_C const IID IID_IExchExt;
+#undef INTERFACE
+#define INTERFACE IExchExt
+DECLARE_INTERFACE_(IExchExt, IUnknown)
+{
+  /*** IUnknown methods. ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+  /*** IExchExt methods. ***/
+  STDMETHOD(Install)(THIS_ LPEXCHEXTCALLBACK, ULONG, ULONG) PURE;
+};
+
+
+
+EXTERN_C const IID IID_IExchExtMessageEvents;
+#undef INTERFACE
+#define INTERFACE IExchExtMessageEvents
+DECLARE_INTERFACE_(IExchExtMessageEvents, IUnknown)
+{
+  /*** IUnknown methods. ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+  /*** IExchExtMessageEvents methods. ***/
+  STDMETHOD(OnRead)(THIS_ LPEXCHEXTCALLBACK) PURE;
+  STDMETHOD(OnReadComplete)(THIS_ LPEXCHEXTCALLBACK, ULONG) PURE;
+  STDMETHOD(OnWrite)(THIS_ LPEXCHEXTCALLBACK) PURE;
+  STDMETHOD(OnWriteComplete)(THIS_ LPEXCHEXTCALLBACK, ULONG) PURE;
+  STDMETHOD(OnCheckNames)(THIS_ LPEXCHEXTCALLBACK) PURE;
+  STDMETHOD(OnCheckNamesComplete)(THIS_ LPEXCHEXTCALLBACK, ULONG) PURE;
+  STDMETHOD(OnSubmit)(THIS_ LPEXCHEXTCALLBACK) PURE;
+  STDMETHOD_(void, OnSubmitComplete)(THIS_ LPEXCHEXTCALLBACK, ULONG) PURE;
+};
+
+
+
+EXTERN_C const IID IID_IExchExtCommands;
+#undef INTERFACE
+#define INTERFACE IExchExtCommands
+DECLARE_INTERFACE_(IExchExtCommands, IUnknown)
+{
+  /*** IUnknown methods. ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+  /*** IExchExtCommands methods. ***/
+  STDMETHOD(InstallCommands)(THIS_ LPEXCHEXTCALLBACK, HWND, HMENU,
+                             UINT*, LPTBENTRY, UINT, ULONG) PURE;
+  STDMETHOD_(void, InitMenu)(THIS_ LPEXCHEXTCALLBACK) PURE;
+  STDMETHOD(DoCommand)(THIS_ LPEXCHEXTCALLBACK, UINT) PURE;
+  STDMETHOD(Help)(THIS_ LPEXCHEXTCALLBACK, UINT) PURE;
+  STDMETHOD(QueryHelpText)(THIS_ UINT, ULONG, LPTSTR, UINT) PURE;
+  STDMETHOD(QueryButtonInfo)(THIS_ ULONG, UINT, LPTBBUTTON,
+                             LPTSTR, UINT, ULONG) PURE;
+  STDMETHOD(ResetToolbar)(THIS_ ULONG, ULONG) PURE;
+};
+
+
+
+EXTERN_C const IID IID_IExchExtPropertySheets;
+#undef INTERFACE
+#define INTERFACE IExchExtPropertySheets
+DECLARE_INTERFACE_(IExchExtPropertySheets, IUnknown)
+{
+  /*** IUnknown methods. ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+  /*** IExchExtPropertySheet methods. ***/
+  STDMETHOD_(ULONG, GetMaxPageCount)(THIS_ ULONG) PURE;
+  STDMETHOD(GetPages)(THIS_ LPEXCHEXTCALLBACK, ULONG,
+                      LPPROPSHEETPAGE, ULONG*) PURE;
+  STDMETHOD_(void, FreePages)(THIS_ LPPROPSHEETPAGE, ULONG, ULONG) PURE;
+};
+
+
+
+EXTERN_C const IID IID_IExchExtCallback;
+#undef INTERFACE
+#define INTERFACE IExchExtCallback
+DECLARE_INTERFACE_(IExchExtCallback, IUnknown)
+{
+  /*** IUnknown methods. ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+  /*** IExchExtCallback methods. ***/
+  STDMETHOD(GetVersion)(THIS_ ULONG*, ULONG) PURE;
+  STDMETHOD(GetWindow)(THIS_ HWND*) PURE;
+  STDMETHOD(GetMenu)(THIS_ HMENU*) PURE;
+  STDMETHOD(GetToolbar)(THIS_ ULONG, HWND*) PURE;
+  STDMETHOD(GetSession)(THIS_ LPMAPISESSION*, LPADRBOOK*) PURE;
+  STDMETHOD(GetObject)(THIS_ LPMDB*, LPMAPIPROP*) PURE;
+  STDMETHOD(GetSelectionCount)(THIS_ ULONG*) PURE;
+  STDMETHOD(GetSelectionItem)(THIS_ ULONG, ULONG*, LPENTRYID*, ULONG*,
+                              LPTSTR, ULONG, ULONG*, ULONG) PURE;
+  STDMETHOD(GetMenuPos)(THIS_ ULONG, HMENU*, ULONG*, ULONG*, ULONG) PURE;
+  STDMETHOD(GetSharedExtsDir)(THIS_ LPTSTR, ULONG, ULONG) PURE;
+  STDMETHOD(GetRecipients)(THIS_ LPADRLIST*) PURE;
+  STDMETHOD(SetRecipients)(THIS_ LPADRLIST) PURE;
+  STDMETHOD(GetNewMessageSite)(THIS_ ULONG, LPMAPIFOLDER, LPPERSISTMESSAGE,
+                               LPMESSAGE*, LPMAPIMESSAGESITE*,
+                               LPMAPIVIEWCONTEXT*, ULONG) PURE;
+  STDMETHOD(RegisterModeless)(THIS_ LPEXCHEXTMODELESS,
+                              LPEXCHEXTMODELESSCALLBACK*) PURE;
+  STDMETHOD(ChooseFolder)(THIS_ LPEXCHEXTCHOOSEFOLDER) PURE;
+};
+
+
+
+EXTERN_C const IID IID_IOutlookExtCallback;
+#undef INTERFACE
+#define INTERFACE IOutlookExtCallback
+DECLARE_INTERFACE_(IOutlookExtCallback, IUnknown)
+{
+  /*** IUnknown methods. ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+  /*** IOutlookExtCallback.  **/
+  STDMETHOD(GetObject)(LPUNKNOWN *ppunk);
+  STDMETHOD(GetOfficeCharacter)(void **ppmsotfc);
+};
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*EXCHEXT_H*/
index 062f087..298d4be 100644 (file)
@@ -131,9 +131,14 @@ typedef struct MapiMessage_s *lpMapiMessage;
 #define ATTACH_OLE            6  
 
 
-#define FORCE_SAVE                    0x00000004U
+#define KEEP_OPEN_READONLY            0x00000001
+#define KEEP_OPEN_READWRITE           0x00000002
+#define FORCE_SAVE                    0x00000004
+#define MAPI_DEFERRED_ERRORS          0x00000008
 
-#define RTF_SYNC_BODY_CHANGED         1 /* FIXME FIXME */
+
+#define RTF_SYNC_RTF_CHANGED          1
+#define RTF_SYNC_BODY_CHANGED         2
 
 
 #ifndef MAPI_DIM
@@ -480,26 +485,26 @@ typedef struct _ADRLIST
 typedef const IID *LPCIID;
 
 
-typedef struct IAttach IAttach;
-typedef IAttach *LPATTACH;
+struct IAttach;
+typedef struct IAttach *LPATTACH;
 
-typedef struct IMAPIAdviseSink IMAPIAdviseSink;
-typedef IMAPIAdviseSink *LPMAPIADVISESINK;
+struct IMAPIAdviseSink;
+typedef struct IMAPIAdviseSink *LPMAPIADVISESINK;
 
-typedef struct IMAPIProgress IMAPIProgress;
-typedef IMAPIProgress *LPMAPIPROGRESS;
+struct IMAPIProgress;
+typedef struct IMAPIProgress *LPMAPIPROGRESS;
 
-typedef struct IMAPITable IMAPITable;
-typedef IMAPITable *LPMAPITABLE;
+struct IMAPITable;
+typedef struct IMAPITable *LPMAPITABLE;
 
-typedef struct IMAPIProp IMAPIProp;
-typedef IMAPIProp *LPMAPIPROP;
+struct IMAPIProp;
+typedef struct IMAPIProp *LPMAPIPROP;
 
-typedef struct IMessage IMessage;
-typedef IMessage *LPMESSAGE;
+struct IMessage;
+typedef struct IMessage *LPMESSAGE;
 
-typedef struct IMsgStore IMsgStore;
-typedef IMsgStore *LPMDB;
+struct IMsgStore;
+typedef struct IMsgStore *LPMDB;
 
 
 
index 313f569..259500d 100644 (file)
 #define PR_RTF_SYNC_PREFIX_COUNT                PROP_TAG( PT_LONG,      0x1010)
 #define PR_RTF_SYNC_TRAILING_COUNT              PROP_TAG( PT_LONG,      0x1011)
 #define PR_ORIGINALLY_INTENDED_RECIP_ENTRYID    PROP_TAG( PT_BINARY,    0x1012)
+#define PR_BODY_HTML                            PROP_TAG( PT_TSTRING,   0x1013)
+#define PR_BODY_HTML_W                          PROP_TAG( PT_UNICODE,   0x1013)
+#define PR_BODY_HTML_A                          PROP_TAG( PT_STRING8,   0x1013)
 #define PR_CONTENT_INTEGRITY_CHECK              PROP_TAG( PT_BINARY,    0x0C00)
 #define PR_EXPLICIT_CONVERSION                  PROP_TAG( PT_LONG,      0x0C01)
 #define PR_IPM_RETURN_REQUESTED                 PROP_TAG( PT_BOOLEAN,   0x0C02)
index e5d0c0e..9ee6460 100644 (file)
 #include "myexchext.h"
 #include "MapiGPGME.h"
 #include "intern.h"
+#include "gpgmsg.hh"
+#include "msgcache.h"
 
 #include "olflange-ids.h"
 #include "olflange-def.h"
 #include "olflange.h"
 
+
+#define TRACEPOINT() do { ExchLogInfo ("%s:%s:%d: tracepoint\n", \
+                                       __FILE__, __func__, __LINE__); \
+                        } while (0)
+
+
 bool g_bInitDll = FALSE;
 
+
+/* FIXME!!!! Huh?  We only have one m_gpg object??? This is strange,
+   AFAICS, Exchange may create several contexts and thus we may be
+   required to run several instances of mapiGPGME concurrently. */
 MapiGPGME *m_gpg = NULL;
 
 
 static void 
 ExchLogInfo (const char * fmt, ...)
 {
-    if (m_gpg) {
-        va_list a;
+  va_list a;
   
-        va_start (a, fmt);
-        m_gpg->logDebug (fmt, a);
-        va_end (a);
-    }
+  va_start (a, fmt);
+  log_vdebug (fmt, a);
+  va_end (a);
 }
 
 
 
 
-/* DllRegisterServer
- Registers this object as exchange extension. Sets the contextes which are 
- implemented by this object. */
+/* Registers this module as an Exchange extension. This basically updates
+   some Registry entries. */
 STDAPI 
 DllRegisterServer (void)
 {    
@@ -81,7 +90,25 @@ DllRegisterServer (void)
     lstrcpy (szKeyBuf, "Software\\Microsoft\\Exchange\\Client\\Extensions");
     lstrcpy (szEntry, "4.0;");
     lstrcat (szEntry, szModuleFileName);
-    lstrcat (szEntry, ";1;11000111111100");  /* context information */
+    lstrcat (szEntry, ";1"); /* Entry point ordinal. */
+    /* Context information string:
+      pos       context
+      1        EECONTEXT_SESSION
+      2        EECONTEXT_VIEWER
+      3        EECONTEXT_REMOTEVIEWER
+      4        EECONTEXT_SEARCHVIEWER
+      5        EECONTEXT_ADDRBOOK
+      6        EECONTEXT_SENDNOTEMESSAGE
+      7        EECONTEXT_READNOTEMESSAGE
+      8        EECONTEXT_SENDPOSTMESSAGE
+      9        EECONTEXT_READPOSTMESSAGE
+      10       EECONTEXT_READREPORTMESSAGE
+      11       EECONTEXT_SENDRESENDMESSAGE
+      12       EECONTEXT_PROPERTYSHEETS
+      13       EECONTEXT_ADVANCEDCRITERIA
+      14       EECONTEXT_TASK
+    */
+    lstrcat (szEntry, ";11000111111100"); 
     ec = RegCreateKeyEx (HKEY_LOCAL_MACHINE, szKeyBuf, 0, NULL, 
                                   REG_OPTION_NON_VOLATILE,
                                   KEY_ALL_ACCESS, NULL, &hkey, NULL);
@@ -115,7 +142,7 @@ DllRegisterServer (void)
 }
 
 
-/* DllUnregisterServer - Unregisters this object in the exchange extension list. */
+/* Unregisters this module as an Exchange extension. */
 STDAPI 
 DllUnregisterServer (void)
 {
@@ -145,50 +172,200 @@ DllUnregisterServer (void)
 
 
 
+/* Locate a property using the current callback LPEECB and traverse
+   down to the last element in the dot delimited NAME.  Returns the
+   Dispatch object and if R_DISPID is not NULL, the dispatch-id of the
+   last part.  Returns NULL on error.  The traversal implictly starts
+   at the object returned by the outlook application callback. */
+static LPDISPATCH
+find_outlook_property (LPEXCHEXTCALLBACK lpeecb,
+                       const char *name, DISPID *r_dispid)
+{
+  HRESULT hr;
+  LPOUTLOOKEXTCALLBACK pCb;
+  LPUNKNOWN pObj;
+  LPDISPATCH pDisp;
+  DISPID dispid;
+  wchar_t *wname;
+  const char *s;
+
+  ExchLogInfo ("%s:%s: looking for `%s'\n", __FILE__, __func__, name);
+
+  pCb = NULL;
+  pObj = NULL;
+  lpeecb->QueryInterface (IID_IOutlookExtCallback, (LPVOID*)&pCb);
+  if (pCb)
+    pCb->GetObject (&pObj);
+  for (; pObj && (s = strchr (name, '.')) && s != name; name = s + 1)
+    {
+      DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+      VARIANT vtResult;
+
+      /* Our loop expects that all objects except for the last one are
+         of class IDispatch.  This is pretty reasonable. */
+      pObj->QueryInterface (IID_IDispatch, (LPVOID*)&pDisp);
+      if (!pDisp)
+        return NULL;
+      
+      wname = utf8_to_wchar2 (name, s-name);
+      if (!wname)
+        return NULL;
+
+      hr = pDisp->GetIDsOfNames(IID_NULL, &wname, 1,
+                                LOCALE_SYSTEM_DEFAULT, &dispid);
+      xfree (wname);
+      ExchLogInfo ("   dispid(%.*s)=%d  (hr=0x%x)\n",
+                   (int)(s-name), name, dispid, hr);
+      vtResult.pdispVal = NULL;
+      hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                          DISPATCH_METHOD, &dispparamsNoArgs,
+                          &vtResult, NULL, NULL);
+      pObj = vtResult.pdispVal;
+      /* FIXME: Check that the class of the returned object is as
+         expected.  To do this we better let GetIdsOfNames also return
+         the ID of "Class". */
+      ExchLogInfo ("%s:%s: %.*s=%p  (hr=0x%x)\n",
+                   __FILE__, __func__, (int)(s-name), name, pObj, hr);
+      pDisp->Release ();
+      pDisp = NULL;
+      /* Fixme: Do we need to release pObj? */
+    }
+  if (!pObj || !*name)
+    return NULL;
+
+  pObj->QueryInterface (IID_IDispatch, (LPVOID*)&pDisp);
+  if (!pDisp)
+    return NULL;
+  wname = utf8_to_wchar (name);
+  if (!wname)
+    {
+      pDisp->Release ();
+      return NULL;
+    }
+      
+  hr = pDisp->GetIDsOfNames(IID_NULL, &wname, 1,
+                            LOCALE_SYSTEM_DEFAULT, &dispid);
+  xfree (wname);
+  ExchLogInfo ("   dispid(%s)=%d  (hr=0x%x)\n", name, dispid, hr);
+  if (r_dispid)
+    *r_dispid = dispid;
+
+  ExchLogInfo ("%s:%s:    got IDispatch=%p dispid=%d\n",
+               __FILE__, __func__, pDisp, dispid);
+  return pDisp;
+}
+
+
+/* Return Outlook's Application object. */
+/* FIXME: We should be able to fold most of the code into
+   find_outlook_property. */
+static LPUNKNOWN
+get_outlook_application_object (LPEXCHEXTCALLBACK lpeecb)
+{
+  LPOUTLOOKEXTCALLBACK pCb = NULL;
+  LPDISPATCH pDisp = NULL;
+  LPUNKNOWN pUnk = NULL;
+
+  lpeecb->QueryInterface (IID_IOutlookExtCallback, (LPVOID*)&pCb);
+  if (pCb)
+    pCb->GetObject (&pUnk);
+  if (pUnk)
+    {
+      pUnk->QueryInterface (IID_IDispatch, (LPVOID*)&pDisp);
+      pUnk->Release();
+      pUnk = NULL;
+    }
+
+  if (pDisp)
+    {
+      WCHAR *name = L"Class";
+      DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+      DISPID dispid;
+      VARIANT vtResult;
+
+      pDisp->GetIDsOfNames(IID_NULL, &name, 1,
+                           LOCALE_SYSTEM_DEFAULT, &dispid);
+      vtResult.pdispVal = NULL;
+      pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                    DISPATCH_PROPERTYGET, &dispparamsNoArgs,
+                    &vtResult, NULL, NULL);
+      ExchLogInfo ("%s:%s: Outlookcallback returned object of class=%d\n",
+                   __FILE__, __func__, vtResult.intVal);
+    }
+  if (pDisp)
+    {
+      WCHAR *name = L"Application";
+      DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+      DISPID dispid;
+      VARIANT vtResult;
+      
+      pDisp->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
+      //ExchLogInfo ("   dispid(Application)=%d\n", dispid);
+      vtResult.pdispVal = NULL;
+      pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                     DISPATCH_METHOD, &dispparamsNoArgs,
+                     &vtResult, NULL, NULL);
+      pUnk = vtResult.pdispVal;
+      //ExchLogInfo ("%s:%s: Outlook.Application=%p\n",
+      //             __FILE__, __func__, pUnk);
+      pDisp->Release();
+      pDisp = NULL;
+    }
+  return pUnk;
+}
+
+
 
-/* ExchEntryPoint -
- The entry point which Exchange calls.
- This is called for each context entry. Creates a new CAvkExchExt object
- every time so each context will get its own CAvkExchExt interface.
- Return value: Pointer to Exchange Extension Object */
+/* The entry point which Exchange calls.  This is called for each
+   context entry. Creates a new CGPGExchExt object every time so each
+   context will get its own CGPGExchExt interface. */
 EXTERN_C LPEXCHEXT __stdcall
 ExchEntryPoint (void)
 {
-    ExchLogInfo ("extension entry point...\n");
-    return new CGPGExchExt;
+  ExchLogInfo ("%s:%s: creating new CGPGExchExt object\n", __FILE__, __func__);
+  return new CGPGExchExt;
 }
 
 
-/* constructor of CGPGExchExt
- Initializes members and creates the interface objects for the new context.
- Does the dll initialization if it was not done before. */
+/* Constructor of CGPGExchExt
+
+   Initializes members and creates the interface objects for the new
+   context.  Does the DLL initialization if it has not been done
+   before. */
 CGPGExchExt::CGPGExchExt (void)
 { 
-    m_lRef = 1;
-    m_lContext = 0;
-    m_hWndExchange = 0;
-    m_gpgEncrypt = FALSE;
-    m_gpgSign = FALSE;
-    m_pExchExtMessageEvents = new CGPGExchExtMessageEvents (this);
-    m_pExchExtCommands = new CGPGExchExtCommands (this);
-    m_pExchExtPropertySheets = new CGPGExchExtPropertySheets (this);
-    if (!g_bInitDll) {
-       if (m_gpg == NULL) {
-           m_gpg = CreateMapiGPGME (NULL);
-           m_gpg->readOptions ();
-       }
-       g_bInitDll = TRUE;
-       ExchLogInfo("CGPGExchExt load\n");
+  m_lRef = 1;
+  m_lContext = 0;
+  m_hWndExchange = 0;
+  m_gpgEncrypt = FALSE;
+  m_gpgSign = FALSE;
+  m_pExchExtMessageEvents = new CGPGExchExtMessageEvents (this);
+  m_pExchExtCommands = new CGPGExchExtCommands (this);
+  m_pExchExtPropertySheets = new CGPGExchExtPropertySheets (this);
+  if (!m_pExchExtMessageEvents || !m_pExchExtCommands
+      || !m_pExchExtPropertySheets)
+    out_of_core ();
+  
+  if (!g_bInitDll)
+    {
+      if (!m_gpg)
+        {
+          m_gpg = CreateMapiGPGME ();
+          m_gpg->readOptions ();
+        }
+      g_bInitDll = TRUE;
+      ExchLogInfo ("%s:%s: one time init done\n", __FILE__, __func__);
     }
-    else
-       ExchLogInfo("CGPGExchExt exists\n");
 }
 
 
-/* constructor of CGPGExchExt - Uninitializes the dll in the dession context. */
+/*  Uninitializes the dll in the session context. 
+   FIXME:  One instance only????  For what the hell do we use g_bInitDll then?
+*/
 CGPGExchExt::~CGPGExchExt (void) 
 {
+  ExchLogInfo ("%s:%s: cleaning up CGPGExchExt object\n", __FILE__, __func__);
+
     if (m_lContext == EECONTEXT_SESSION) {
        if (g_bInitDll) {
            if (m_gpg != NULL) {
@@ -197,19 +374,19 @@ CGPGExchExt::~CGPGExchExt (void)
                m_gpg = NULL;
            }
            g_bInitDll = FALSE;
+            ExchLogInfo ("%s:%s: one time deinit done\n", __FILE__, __func__);
        }       
     }
 }
 
 
-/* CGPGExchExt::QueryInterface
- Called by Exchage to request for interfaces.
-
- Return value: S_OK if the interface is supported, otherwise E_NOINTERFACE: */
+/* Called by Exchange to retrieve an object pointer for a named
+   interface.  This is a standard COM method.  REFIID is the ID of the
+   interface and PPVOBJ will get the address of the object pointer if
+   this class defines the requested interface.  Return value: S_OK if
+   the interface is supported, otherwise E_NOINTERFACE. */
 STDMETHODIMP 
-CGPGExchExt::QueryInterface(
-       REFIID riid,      // The interface ID.
-       LPVOID * ppvObj)  // The address of interface object pointer.
+CGPGExchExt::QueryInterface(REFIID riid, LPVOID *ppvObj)
 {
     HRESULT hr = S_OK;
 
@@ -220,10 +397,11 @@ CGPGExchExt::QueryInterface(
     }
     else if (riid == IID_IExchExtMessageEvents) {
         *ppvObj = (LPUNKNOWN) m_pExchExtMessageEvents;
+        m_pExchExtMessageEvents->SetContext (m_lContext);
     }
     else if (riid == IID_IExchExtCommands) {
         *ppvObj = (LPUNKNOWN)m_pExchExtCommands;
-        m_pExchExtCommands->SetContext(m_lContext);
+        m_pExchExtCommands->SetContext (m_lContext);
     }
     else if (riid == IID_IExchExtPropertySheets) {
        if (m_lContext != EECONTEXT_PROPERTYSHEETS)
@@ -233,7 +411,9 @@ CGPGExchExt::QueryInterface(
     else
         hr = E_NOINTERFACE;
 
-    if (*ppvObj != NULL)
+    /* On success we need to bump up the reference counter for the
+       requested object. */
+    if (*ppvObj)
         ((LPUNKNOWN)*ppvObj)->AddRef();
 
     /*ExchLogInfo("QueryInterface %d\n", __LINE__);*/
@@ -241,46 +421,78 @@ CGPGExchExt::QueryInterface(
 }
 
 
-/* CGPGExchExt::Install
- Called once for each new context. Checks the exchange extension version 
- number and the context.
- Return value: S_OK if the extension should used in the requested context, 
-               otherwise S_FALSE. */
-STDMETHODIMP CGPGExchExt::Install(
-       LPEXCHEXTCALLBACK pEECB, // The pointer to Exchange Extension callback function.
-       ULONG lContext,          // The context code at time of being called.
-       ULONG lFlags)            // The flag to say if install is for modal or not.
+/* Called once for each new context. Checks the Exchange extension
+   version number and the context.  Returns: S_OK if the extension
+   should used in the requested context, otherwise S_FALSE.  PEECB is
+   a pointer to Exchange extension callback function.  LCONTEXT is the
+   context code at time of being called. LFLAGS carries flags to
+   indicate whether the extension should be installed modal.
+*/
+STDMETHODIMP 
+CGPGExchExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
 {
-    ULONG lBuildVersion;
-
-    m_lContext = lContext;
-
-    /*ExchLogInfo("Install %d\n", __LINE__);*/
-    // check the version 
-    pEECB->GetVersion (&lBuildVersion, EECBGV_GETBUILDVERSION);
-    if (EECBGV_BUILDVERSION_MAJOR != (lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK))
-        return S_FALSE;
-
-    // and the context
-    if ((lContext == EECONTEXT_PROPERTYSHEETS) ||
-       (lContext == EECONTEXT_SENDNOTEMESSAGE) ||
-       (lContext == EECONTEXT_SENDPOSTMESSAGE) ||
-       (lContext == EECONTEXT_SENDRESENDMESSAGE) ||
-       (lContext == EECONTEXT_READNOTEMESSAGE) ||
-       (lContext == EECONTEXT_READPOSTMESSAGE) ||
-       (lContext == EECONTEXT_READREPORTMESSAGE) ||
-       (lContext == EECONTEXT_VIEWER))
-       return S_OK;
-    return S_FALSE;
+  ULONG lBuildVersion;
+
+  /* Save the context in an instance variable. */
+  m_lContext = lContext;
+
+  ExchLogInfo ("%s:%s: context=0x%lx (%s) flags=0x%lx\n", __FILE__, __func__, 
+               lContext,
+               (lContext == EECONTEXT_SESSION?           "Session":
+                lContext == EECONTEXT_VIEWER?            "Viewer":
+                lContext == EECONTEXT_REMOTEVIEWER?      "RemoteViewer":
+                lContext == EECONTEXT_SEARCHVIEWER?      "SearchViewer":
+                lContext == EECONTEXT_ADDRBOOK?          "AddrBook" :
+                lContext == EECONTEXT_SENDNOTEMESSAGE?   "SendNoteMessage" :
+                lContext == EECONTEXT_READNOTEMESSAGE?   "ReadNoteMessage" :
+                lContext == EECONTEXT_SENDPOSTMESSAGE?   "SendPostMessage" :
+                lContext == EECONTEXT_READPOSTMESSAGE?   "ReadPostMessage" :
+                lContext == EECONTEXT_READREPORTMESSAGE? "ReadReportMessage" :
+                lContext == EECONTEXT_SENDRESENDMESSAGE? "SendResendMessage" :
+                lContext == EECONTEXT_PROPERTYSHEETS?    "PropertySheets" :
+                lContext == EECONTEXT_ADVANCEDCRITERIA?  "AdvancedCriteria" :
+                lContext == EECONTEXT_TASK?              "Task" : ""),
+               lFlags);
+  
+  /* Check version. */
+  pEECB->GetVersion (&lBuildVersion, EECBGV_GETBUILDVERSION);
+  if (EECBGV_BUILDVERSION_MAJOR
+      != (lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK))
+    {
+      ExchLogInfo ("%s:%s: invalid version 0x%lx\n",
+                   __FILE__, __func__, lBuildVersion);
+      return S_FALSE;
+    }
+  
+
+  /* Check context. */
+  if (   lContext == EECONTEXT_PROPERTYSHEETS
+      || lContext == EECONTEXT_SENDNOTEMESSAGE
+      || lContext == EECONTEXT_SENDPOSTMESSAGE
+      || lContext == EECONTEXT_SENDRESENDMESSAGE
+      || lContext == EECONTEXT_READNOTEMESSAGE
+      || lContext == EECONTEXT_READPOSTMESSAGE
+      || lContext == EECONTEXT_READREPORTMESSAGE
+      || lContext == EECONTEXT_VIEWER)
+    {
+      LPUNKNOWN pApplication = get_outlook_application_object (pEECB);
+      ExchLogInfo ("%s:%s: pApplication=%p\n",
+                   __FILE__, __func__, pApplication);
+      return S_OK;
+    }
+  
+  ExchLogInfo ("%s:%s: can't handle this context\n", __FILE__, __func__);
+  return S_FALSE;
 }
 
 
-CGPGExchExtMessageEvents::CGPGExchExtMessageEvents (CGPGExchExt *pParentInterface)
+
+CGPGExchExtMessageEvents::CGPGExchExtMessageEvents 
+                                              (CGPGExchExt *pParentInterface)
 { 
-    m_pExchExt = pParentInterface;
-    m_lRef = 0; 
-    m_bOnSubmitCalled = FALSE;
+  m_pExchExt = pParentInterface;
+  m_lRef = 0; 
+  m_bOnSubmitActive = FALSE;
 };
 
 
@@ -302,154 +514,160 @@ CGPGExchExtMessageEvents::QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
 }
 
 
-/* CGPGExchExtMessageEvents::OnRead - Called from Exchange on reading a message.
- Return value: S_FALSE to signal Exchange to continue calling extensions. */
-STDMETHODIMP CGPGExchExtMessageEvents::OnRead(
-       LPEXCHEXTCALLBACK pEECB) // A pointer to IExchExtCallback interface.
+/* Called from Exchange on reading a message.  Returns: S_FALSE to
+   signal Exchange to continue calling extensions.  PEECB is a pointer
+   to the IExchExtCallback interface. */
+STDMETHODIMP 
+CGPGExchExtMessageEvents::OnRead (LPEXCHEXTCALLBACK pEECB) 
 {
-    ExchLogInfo ("OnRead\n");
-    return S_FALSE;
+  ExchLogInfo ("%s:%s: received\n", __FILE__, __func__);
+  return S_FALSE;
 }
 
 
-/* CGPGExchExtMessageEvents::OnReadComplete
- Called by Exchange after a message has been read.
-
- Return value: S_FALSE to signal Exchange to continue calling extensions. */
-STDMETHODIMP CGPGExchExtMessageEvents::OnReadComplete(
-       LPEXCHEXTCALLBACK pEECB, // A pointer to IExchExtCallback interface.
-       ULONG lFlags)
+/* 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. */
+STDMETHODIMP 
+CGPGExchExtMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK pEECB,
+                                          ULONG lFlags)
 {
-    ExchLogInfo ("OnReadComplete\n");
+    ExchLogInfo ("%s:%s: received\n", __FILE__, __func__);
     return S_FALSE;
 }
 
 
-/* CGPGExchExtMessageEvents::OnWrite - Called by Exchange when a message will be written.
- @rdesc S_FALSE to signal Exchange to continue calling extensions. */
-STDMETHODIMP CGPGExchExtMessageEvents::OnWrite(
-       LPEXCHEXTCALLBACK pEECB) // A pointer to IExchExtCallback interface.
+/* Called by Exchange when a message will be written. Returns: S_FALSE
+   to signal Exchange to continue calling extensions.  PEECB is a
+   pointer to the IExchExtCallback interface. */
+STDMETHODIMP 
+CGPGExchExtMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
 {
-    ExchLogInfo ("OnWrite\n");
+    ExchLogInfo ("%s:%s: received\n", __FILE__, __func__);
     return S_FALSE;
 }
 
 
-/* CGPGExchExtMessageEvents::OnWriteComplete
- Called by Exchange when the data has been written to the message.
- Encrypts and signs the message if the options are set.
- @pEECB - A pointer to IExchExtCallback interface.
-
- Return value: S_FALSE: signals Exchange to continue calling extensions
-               E_FAIL:  signals Exchange an error; the message will not be sent */
-STDMETHODIMP CGPGExchExtMessageEvents::OnWriteComplete (
-                 LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
+/* 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
+   pointer to the IExchExtCallback interface.  Returns: S_FALSE to
+   signal Exchange to continue calling extensions.  E_FAIL to signals
+   Exchange an error; the message will not be sent */
+STDMETHODIMP 
+CGPGExchExtMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB,
+                                           ULONG lFlags)
 {
-    HRESULT hrReturn = S_FALSE;
-    LPMESSAGE pMessage = NULL;
-    LPMDB pMDB = NULL;
-    HWND hWnd = NULL;
-
-    if (FAILED(pEECB->GetWindow (&hWnd)))
-       hWnd = NULL;
-
-    if (!m_bOnSubmitCalled) /* the user is just saving the message */
-       return S_FALSE;
-
-    if (m_bWriteFailed)     /* operation failed already */
-       return S_FALSE;
-
-    HRESULT hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
-    if (SUCCEEDED (hr)) {
-       if (m_pExchExt->m_gpgEncrypt || m_pExchExt->m_gpgSign) {
-           m_gpg->setMessage (pMessage);
-           if (m_gpg->doCmd (m_pExchExt->m_gpgEncrypt,
-                             m_pExchExt->m_gpgSign)) {
-               hrReturn = E_FAIL;
-               m_bWriteFailed = TRUE;  
-           }
-       }
+  ExchLogInfo ("%s:%s: received\n", __FILE__, __func__);
+
+  HRESULT hrReturn = S_FALSE;
+  LPMESSAGE msg = NULL;
+  LPMDB pMDB = NULL;
+  HWND hWnd = NULL;
+  int rc;
+          
+  if (FAILED(pEECB->GetWindow (&hWnd)))
+    hWnd = NULL;
+
+  if (!m_bOnSubmitActive) /* the user is just saving the message */
+    return S_FALSE;
+  
+  if (m_bWriteFailed)     /* operation failed already */
+    return S_FALSE;
+  
+  HRESULT hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&msg);
+  if (SUCCEEDED (hr))
+    {
+      log_debug ("%s:%s:%d: here\n", __FILE__, __func__, __LINE__);
+      
+      GpgMsg *m = CreateGpgMsg (msg);
+      log_debug ("%s:%s:%d: here\n", __FILE__, __func__, __LINE__);
+      if (m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
+        rc = m_gpg->signEncrypt (hWnd, m);
+      if (m_pExchExt->m_gpgEncrypt && !m_pExchExt->m_gpgSign)
+        rc = m_gpg->encrypt (hWnd, m);
+      if (!m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
+        rc = m_gpg->sign (hWnd, m);
+      else
+        rc = 0;
+      log_debug ("%s:%s:%d: here\n", __FILE__, __func__, __LINE__);
+      delete m;
+      
+      if (rc)
+        {
+          hrReturn = E_FAIL;
+          m_bWriteFailed = TRUE;       
+        }
     }
-    if (pMessage != NULL)
-       UlRelease(pMessage);
-    if (pMDB != NULL)
-       UlRelease(pMDB);
-
-    return hrReturn;
-}
 
-/* CGPGExchExtMessageEvents::OnCheckNames
+  if (msg)
+    UlRelease(msg);
+  if (pMDB) 
+    UlRelease(pMDB);
 
- Called by Exchange when the user selects the "check names" command.
-
- @pEECB - A pointer to IExchExtCallback interface.
+  return hrReturn;
+}
 
- Return value: S_FALSE to signal Exchange to continue calling extensions.
-*/
-STDMETHODIMP CGPGExchExtMessageEvents::OnCheckNames(LPEXCHEXTCALLBACK pEECB)
+/* Called by Exchange when the user selects the "check names" command.
+   PEECB is a pointer to the IExchExtCallback interface.  Returns
+   S_FALSE to signal Exchange to continue calling extensions. */
+STDMETHODIMP 
+CGPGExchExtMessageEvents::OnCheckNames(LPEXCHEXTCALLBACK pEECB)
 {
-    return S_FALSE;
+  ExchLogInfo ("%s:%s: received\n", __FILE__, __func__);
+  return S_FALSE;
 }
 
 
-/* CGPGExchExtMessageEvents::OnCheckNamesComplete
-
- Called by Exchange when "check names" command is complete.
-
-  @pEECB - A pointer to IExchExtCallback interface.
-
- Return value: S_FALSE to signal Exchange to continue calling extensions.
-*/
-STDMETHODIMP CGPGExchExtMessageEvents::OnCheckNamesComplete(
-                       LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
+/* Called by Exchange when "check names" command is complete.
+   PEECB is a pointer to the IExchExtCallback interface.  Returns
+   S_FALSE to signal Exchange to continue calling extensions. */
+STDMETHODIMP 
+CGPGExchExtMessageEvents::OnCheckNamesComplete (LPEXCHEXTCALLBACK pEECB,
+                                                ULONG lFlags)
 {
-    return S_FALSE;
+  ExchLogInfo ("%s:%s: received\n", __FILE__, __func__);
+  return S_FALSE;
 }
 
 
-/* CGPGExchExtMessageEvents::OnSubmit
-
- Called by Exchange before the message data will be written and submitted.
- to MAPI.
-
- @pEECB - A pointer to IExchExtCallback interface.
-
- Return value: S_FALSE to signal Exchange to continue calling extensions.
-*/
-STDMETHODIMP CGPGExchExtMessageEvents::OnSubmit(
-                           LPEXCHEXTCALLBACK pEECB)
+/* Called by Exchange before the message data will be written and
+   submitted to MAPI.  PEECB is a pointer to the IExchExtCallback
+   interface.  Returns S_FALSE to signal Exchange to continue calling
+   extensions. */
+STDMETHODIMP 
+CGPGExchExtMessageEvents::OnSubmit (LPEXCHEXTCALLBACK pEECB)
 {
-    m_bOnSubmitCalled = TRUE;
-    m_bWriteFailed = FALSE;
-    return S_FALSE;
+  ExchLogInfo ("%s:%s: received\n", __FILE__, __func__);
+  m_bOnSubmitActive = TRUE;
+  m_bWriteFailed = FALSE;
+  return S_FALSE;
 }
 
 
-/* CGPGExchExtMessageEvents::OnSubmitComplete
-
-  @pEECB - A pointer to IExchExtCallback interface.
-
- Called by Echange after the message has been submitted to MAPI.
-*/
-STDMETHODIMP_ (VOID) CGPGExchExtMessageEvents::OnSubmitComplete (
-                           LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
+/* Called by Echange after the message has been submitted to MAPI.
+   PEECB is a pointer to the IExchExtCallback interface. */
+STDMETHODIMP_ (VOID) 
+CGPGExchExtMessageEvents::OnSubmitComplete (LPEXCHEXTCALLBACK pEECB,
+                                            ULONG lFlags)
 {
-    m_bOnSubmitCalled = FALSE; 
+  ExchLogInfo ("%s:%s: received\n", __FILE__, __func__);
+  m_bOnSubmitActive = FALSE; 
 }
 
 
+
 CGPGExchExtCommands::CGPGExchExtCommands (CGPGExchExt* pParentInterface)
 { 
-    m_pExchExt = pParentInterface; 
-    m_lRef = 0; 
-    m_lContext = 0; 
-    m_nCmdEncrypt = 0;  
-    m_nCmdSign = 0; 
-    m_nToolbarButtonID1 = 0; 
-    m_nToolbarButtonID2 = 0; 
-    m_nToolbarBitmap1 = 0;
-    m_nToolbarBitmap2 = 0; 
-    m_hWnd = NULL; 
+  m_pExchExt = pParentInterface; 
+  m_lRef = 0; 
+  m_lContext = 0; 
+  m_nCmdEncrypt = 0;  
+  m_nCmdSign = 0; 
+  m_nToolbarButtonID1 = 0; 
+  m_nToolbarButtonID2 = 0; 
+  m_nToolbarBitmap1 = 0;
+  m_nToolbarBitmap2 = 0; 
+  m_hWnd = NULL; 
 };
 
 
@@ -467,201 +685,314 @@ CGPGExchExtCommands::QueryInterface (REFIID riid, LPVOID FAR * ppvObj)
 }
 
 
-// XXX IExchExtSessionEvents::OnDelivery: could be used to automatically decrypt new mails
-// when they arrive
 
-/* CGPGExchExtCommands::InstallCommands
+// We can't read the Body object because it would fire up the
+// security pop-up.  Writing is okay.
+//       vtResult.pdispVal = NULL;
+//       pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+//                     DISPATCH_PROPERTYGET, &dispparamsNoArgs,
+//                     &vtResult, NULL, NULL);
 
- Called by Echange to install commands and toolbar buttons.
+//       ExchLogInfo ("%s:%s: Body=%p (%s)\n", __FILE__, __func__, 
+//                    vtResult.pbVal,
+//                    (tmp = wchar_to_utf8 ((wchar_t*)vtResult.pbVal)));
 
- Return value: S_FALSE to signal Exchange to continue calling extensions.
-*/
-STDMETHODIMP CGPGExchExtCommands::InstallCommands(
+
+
+// XXX IExchExtSessionEvents::OnDelivery: could be used to automatically decrypt new mails
+// when they arrive
+
+/* Called by Echange to install commands and toolbar buttons.  Returns
+    S_FALSE to signal Exchange to continue calling extensions. */
+STDMETHODIMP 
+CGPGExchExtCommands::InstallCommands (
        LPEXCHEXTCALLBACK pEECB, // The Exchange Callback Interface.
-       HWND hWnd,               // The window handle to main window of context.
+       HWND hWnd,               // The window handle to the main window
+                                 // of context.
        HMENU hMenu,             // The menu handle to main menu of context.
        UINT FAR * pnCommandIDBase,  // The base conmmand id.
        LPTBENTRY pTBEArray,     // The array of toolbar button entries.
        UINT nTBECnt,            // The count of button entries in array.
        ULONG lFlags)            // reserved
 {
-    HMENU hMenuTools;
-    m_hWnd = hWnd;
+  HRESULT hr;
+  HMENU hMenuTools;
+  m_hWnd = hWnd;
+  LPDISPATCH pDisp;
+  DISPID dispid;
+  DISPID dispid_put = DISPID_PROPERTYPUT;
+  DISPPARAMS dispparams;
+  VARIANT aVariant;
+  int force_encrypt = 0;
+  
+  ExchLogInfo ("%s:%s: context=0x%lx (%s) flags=0x%lx\n", __FILE__, __func__, 
+               m_lContext,
+               (m_lContext == EECONTEXT_SESSION?           "Session"          :
+                m_lContext == EECONTEXT_VIEWER?            "Viewer"           :
+                m_lContext == EECONTEXT_REMOTEVIEWER?      "RemoteViewer"     :
+                m_lContext == EECONTEXT_SEARCHVIEWER?      "SearchViewer"     :
+                m_lContext == EECONTEXT_ADDRBOOK?          "AddrBook"         :
+                m_lContext == EECONTEXT_SENDNOTEMESSAGE?   "SendNoteMessage"  :
+                m_lContext == EECONTEXT_READNOTEMESSAGE?   "ReadNoteMessage"  :
+                m_lContext == EECONTEXT_SENDPOSTMESSAGE?   "SendPostMessage"  :
+                m_lContext == EECONTEXT_READPOSTMESSAGE?   "ReadPostMessage"  :
+                m_lContext == EECONTEXT_READREPORTMESSAGE? "ReadReportMessage":
+                m_lContext == EECONTEXT_SENDRESENDMESSAGE? "SendResendMessage":
+                m_lContext == EECONTEXT_PROPERTYSHEETS?    "PropertySheets"   :
+                m_lContext == EECONTEXT_ADVANCEDCRITERIA?  "AdvancedCriteria" :
+                m_lContext == EECONTEXT_TASK?              "Task" : ""),
+               lFlags);
+
+
+  /* Outlook 2003 sometimes displays the plaintext sometimes the
+     orginal undecrypted text when doing a Reply.  This seems to
+     depend on the sieze of the message; my guess it that only short
+     messages are locally saved in the process and larger ones are
+     fetyched again from the backend - or the other way around.
+     Anyway, we can't rely on that and thus me make sure to update the
+     Body object right here with our own copy of the plaintext.  To
+     match the text we use the Storage ID Property of MAPI.  
+
+     Unfortunately there seems to be no way of resetting the Saved
+     property after updating the body, thus even without entering a
+     single byte the user will be asked when cancelling a reply
+     whether he really wants to do that.  
+
+     Note, that we can't optimize the code here by first reading the
+     body becuase this would pop up the securiy window, telling tghe
+     user that someone is trying to read these data.
+  */
+  if (m_lContext == EECONTEXT_SENDNOTEMESSAGE)
+    {
+      LPMDB pMDB = NULL;
+      LPMESSAGE pMessage = NULL;
+      const char *body;
+      
+      /*  Note that for read and send the object returned by the
+          outlook extension callback is of class 43 (MailItem) so we
+          only need to ask for Body then. */
+        hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
+      if (FAILED(hr))
+        ExchLogInfo ("%s:%s: getObject failed: hr=%#x\n", hr);
+      else if ( (body = msgcache_get (pMessage)) 
+                && (pDisp = find_outlook_property (pEECB, "Body", &dispid)))
+        {
+          dispparams.cNamedArgs = 1;
+          dispparams.rgdispidNamedArgs = &dispid_put;
+          dispparams.cArgs = 1;
+          dispparams.rgvarg = &aVariant;
+          dispparams.rgvarg[0].vt = VT_LPWSTR;
+          dispparams.rgvarg[0].bstrVal = utf8_to_wchar (body);
+          hr = pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                             DISPATCH_PROPERTYPUT, &dispparams,
+                             NULL, NULL, NULL);
+          xfree (dispparams.rgvarg[0].bstrVal);
+          ExchLogInfo ("%s:%s: PROPERTYPUT(body) result -> %d\n",
+                       __FILE__, __func__, hr);
+
+          pDisp->Release();
+          pDisp = NULL;
+
+          /* Because we found the plaintext in the cache we can assume
+             that the orginal message has been encrypted and thus we
+             now set a flag to make sure that by default the reply
+             gets encrypted too. */
+          force_encrypt = 1;
+        }
+    }
 
-    /* XXX: factor out common code */
-    if (m_lContext == EECONTEXT_READNOTEMESSAGE) {
-       int nTBIndex;
-       HWND hwndToolbar = NULL;
-       CHAR szBuffer[128];
 
-        pEECB->GetMenuPos (EECMDID_ToolsCustomizeToolbar, &hMenuTools, NULL, NULL, 0);
-        AppendMenu (hMenuTools, MF_SEPARATOR, 0, NULL);
+
+  /* XXX: factor out common code */
+  if (m_lContext == EECONTEXT_READNOTEMESSAGE) {
+    int nTBIndex;
+    HWND hwndToolbar = NULL;
+    CHAR szBuffer[128];
+
+    pEECB->GetMenuPos (EECMDID_ToolsCustomizeToolbar, &hMenuTools,
+                       NULL, NULL, 0);
+    AppendMenu (hMenuTools, MF_SEPARATOR, 0, NULL);
        
-       LoadString (glob_hinst, IDS_DECRYPT_MENU_ITEM, szBuffer, 128);
-        AppendMenu (hMenuTools, MF_BYPOSITION | MF_STRING, *pnCommandIDBase, szBuffer);
+    LoadString (glob_hinst, IDS_DECRYPT_MENU_ITEM, szBuffer, 128);
+    AppendMenu (hMenuTools, MF_BYPOSITION | MF_STRING,
+                *pnCommandIDBase, szBuffer);
 
-        m_nCmdEncrypt = *pnCommandIDBase;
-        (*pnCommandIDBase)++;
+    m_nCmdEncrypt = *pnCommandIDBase;
+    (*pnCommandIDBase)++;
        
-       for (nTBIndex = nTBECnt-1; nTBIndex > -1; --nTBIndex) { 
-           if (EETBID_STANDARD == pTBEArray[nTBIndex].tbid) {
-               hwndToolbar = pTBEArray[nTBIndex].hwnd;         
-               m_nToolbarButtonID1 = pTBEArray[nTBIndex].itbbBase;
-               pTBEArray[nTBIndex].itbbBase++;
-               break;          
-           }   
-       }
+    for (nTBIndex = nTBECnt-1; nTBIndex > -1; --nTBIndex) {    
+      if (EETBID_STANDARD == pTBEArray[nTBIndex].tbid) {
+        hwndToolbar = pTBEArray[nTBIndex].hwnd;                
+        m_nToolbarButtonID1 = pTBEArray[nTBIndex].itbbBase;
+        pTBEArray[nTBIndex].itbbBase++;
+        break;         
+      }        
+    }
 
-       if (hwndToolbar) {
-           TBADDBITMAP tbab;
-           tbab.hInst = glob_hinst;
-           tbab.nID = IDB_DECRYPT;
-           m_nToolbarBitmap1 = SendMessage(hwndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab);
-           m_nToolbarButtonID2 = pTBEArray[nTBIndex].itbbBase;
-           pTBEArray[nTBIndex].itbbBase++;
-       }
+    if (hwndToolbar) {
+      TBADDBITMAP tbab;
+      tbab.hInst = glob_hinst;
+      tbab.nID = IDB_DECRYPT;
+      m_nToolbarBitmap1 = SendMessage(hwndToolbar, TB_ADDBITMAP,
+                                      1, (LPARAM)&tbab);
+      m_nToolbarButtonID2 = pTBEArray[nTBIndex].itbbBase;
+      pTBEArray[nTBIndex].itbbBase++;
     }
+  }
 
-    if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) {
-       CHAR szBuffer[128];
-       int nTBIndex;
-       HWND hwndToolbar = NULL;
+  if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) {
+    CHAR szBuffer[128];
+    int nTBIndex;
+    HWND hwndToolbar = NULL;
 
-        pEECB->GetMenuPos(EECMDID_ToolsCustomizeToolbar, &hMenuTools, NULL, NULL, 0);
-        AppendMenu(hMenuTools, MF_SEPARATOR, 0, NULL);
+    pEECB->GetMenuPos(EECMDID_ToolsCustomizeToolbar, &hMenuTools,
+                      NULL, NULL, 0);
+    AppendMenu(hMenuTools, MF_SEPARATOR, 0, NULL);
        
-       LoadString(glob_hinst, IDS_ENCRYPT_MENU_ITEM, szBuffer, 128);
-        AppendMenu(hMenuTools, MF_BYPOSITION | MF_STRING, *pnCommandIDBase, szBuffer);
-
-        m_nCmdEncrypt = *pnCommandIDBase;
-        (*pnCommandIDBase)++;
-
-       LoadString(glob_hinst, IDS_SIGN_MENU_ITEM, szBuffer, 128);
-        AppendMenu(hMenuTools, MF_BYPOSITION | MF_STRING, *pnCommandIDBase, szBuffer);
-
-        m_nCmdSign = *pnCommandIDBase;
-        (*pnCommandIDBase)++;
-
-       for (nTBIndex = nTBECnt-1; nTBIndex > -1; --nTBIndex)
-       {
-           if (EETBID_STANDARD == pTBEArray[nTBIndex].tbid)
-           {
-               hwndToolbar = pTBEArray[nTBIndex].hwnd;
-               m_nToolbarButtonID1 = pTBEArray[nTBIndex].itbbBase;
-               pTBEArray[nTBIndex].itbbBase++;
-               break;  
-           }
-       }
-
-       if (hwndToolbar) {
-           TBADDBITMAP tbab;
-           tbab.hInst = glob_hinst;
-           tbab.nID = IDB_ENCRYPT;
-           m_nToolbarBitmap1 = SendMessage(hwndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab);
-           m_nToolbarButtonID2 = pTBEArray[nTBIndex].itbbBase;
-           pTBEArray[nTBIndex].itbbBase++;
-           tbab.nID = IDB_SIGN;
-           m_nToolbarBitmap2 = SendMessage(hwndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab);
-       }
-       m_pExchExt->m_gpgEncrypt = m_gpg->getEncryptDefault ();
-       m_pExchExt->m_gpgSign = m_gpg->getSignDefault ();
+    LoadString(glob_hinst, IDS_ENCRYPT_MENU_ITEM, szBuffer, 128);
+    AppendMenu(hMenuTools, MF_BYPOSITION | MF_STRING,
+               *pnCommandIDBase, szBuffer);
+
+    m_nCmdEncrypt = *pnCommandIDBase;
+    (*pnCommandIDBase)++;
+
+    LoadString(glob_hinst, IDS_SIGN_MENU_ITEM, szBuffer, 128);
+    AppendMenu(hMenuTools, MF_BYPOSITION | MF_STRING,
+               *pnCommandIDBase, szBuffer);
+
+    m_nCmdSign = *pnCommandIDBase;
+    (*pnCommandIDBase)++;
+
+    for (nTBIndex = nTBECnt-1; nTBIndex > -1; --nTBIndex)
+      {
+        if (EETBID_STANDARD == pTBEArray[nTBIndex].tbid)
+          {
+            hwndToolbar = pTBEArray[nTBIndex].hwnd;
+            m_nToolbarButtonID1 = pTBEArray[nTBIndex].itbbBase;
+            pTBEArray[nTBIndex].itbbBase++;
+            break;     
+          }
+      }
+
+    if (hwndToolbar) {
+      TBADDBITMAP tbab;
+      tbab.hInst = glob_hinst;
+      tbab.nID = IDB_ENCRYPT;
+      m_nToolbarBitmap1 = SendMessage(hwndToolbar, TB_ADDBITMAP,
+                                      1, (LPARAM)&tbab);
+      m_nToolbarButtonID2 = pTBEArray[nTBIndex].itbbBase;
+      pTBEArray[nTBIndex].itbbBase++;
+      tbab.nID = IDB_SIGN;
+      m_nToolbarBitmap2 = SendMessage(hwndToolbar, TB_ADDBITMAP,
+                                      1, (LPARAM)&tbab);
     }
-
-    if (m_lContext == EECONTEXT_VIEWER) {
-       CHAR szBuffer[128];
-       int nTBIndex;
-       HWND hwndToolbar = NULL;
-
-        pEECB->GetMenuPos (EECMDID_ToolsCustomizeToolbar, &hMenuTools, NULL, NULL, 0);
-        AppendMenu (hMenuTools, MF_SEPARATOR, 0, NULL);
+    m_pExchExt->m_gpgEncrypt = m_gpg->getEncryptDefault ();
+    m_pExchExt->m_gpgSign = m_gpg->getSignDefault ();
+    if (force_encrypt)
+      m_pExchExt->m_gpgEncrypt = true;
+  }
+
+  if (m_lContext == EECONTEXT_VIEWER) {
+    CHAR szBuffer[128];
+    int nTBIndex;
+    HWND hwndToolbar = NULL;
+
+    pEECB->GetMenuPos (EECMDID_ToolsCustomizeToolbar, &hMenuTools,
+                       NULL, NULL, 0);
+    AppendMenu (hMenuTools, MF_SEPARATOR, 0, NULL);
        
-       LoadString (glob_hinst, IDS_KEY_MANAGER, szBuffer, 128);
-        AppendMenu (hMenuTools, MF_BYPOSITION | MF_STRING, *pnCommandIDBase, szBuffer);
-
-        m_nCmdEncrypt = *pnCommandIDBase;
-        (*pnCommandIDBase)++;  
-
-       for (nTBIndex = nTBECnt-1; nTBIndex > -1; --nTBIndex) {
-           if (EETBID_STANDARD == pTBEArray[nTBIndex].tbid) {
-               hwndToolbar = pTBEArray[nTBIndex].hwnd;
-               m_nToolbarButtonID1 = pTBEArray[nTBIndex].itbbBase;
-               pTBEArray[nTBIndex].itbbBase++;
-               break;  
-           }
-       }
-       if (hwndToolbar) {
-           TBADDBITMAP tbab;
-           tbab.hInst = glob_hinst;
-           tbab.nID = IDB_KEY_MANAGER;
-           m_nToolbarBitmap1 = SendMessage(hwndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab);
-       }       
+    LoadString (glob_hinst, IDS_KEY_MANAGER, szBuffer, 128);
+    AppendMenu (hMenuTools, MF_BYPOSITION | MF_STRING,
+                *pnCommandIDBase, szBuffer);
+
+    m_nCmdEncrypt = *pnCommandIDBase;
+    (*pnCommandIDBase)++;      
+
+    for (nTBIndex = nTBECnt-1; nTBIndex > -1; --nTBIndex) {
+      if (EETBID_STANDARD == pTBEArray[nTBIndex].tbid) {
+        hwndToolbar = pTBEArray[nTBIndex].hwnd;
+        m_nToolbarButtonID1 = pTBEArray[nTBIndex].itbbBase;
+        pTBEArray[nTBIndex].itbbBase++;
+        break; 
+      }
     }
-    return S_FALSE;
+    if (hwndToolbar) {
+      TBADDBITMAP tbab;
+      tbab.hInst = glob_hinst;
+      tbab.nID = IDB_KEY_MANAGER;
+      m_nToolbarBitmap1 = SendMessage(hwndToolbar, TB_ADDBITMAP,
+                                      1, (LPARAM)&tbab);
+    }  
+  }
+  return S_FALSE;
 }
 
 
-/* CGPGExchExtCommands::DoCommand - Called by Exchange when a user selects a command. 
-
- Return value: S_OK if command is handled, otherwise S_FALSE.
-*/
-STDMETHODIMP CGPGExchExtCommands::DoCommand(
-       LPEXCHEXTCALLBACK pEECB, // The Exchange Callback Interface.
-       UINT nCommandID)         // The command id.
+/* Called by Exchange when a user selects a command.  Return value:
+   S_OK if command is handled, otherwise S_FALSE. */
+STDMETHODIMP 
+CGPGExchExtCommands::DoCommand (
+                  LPEXCHEXTCALLBACK pEECB, // The Exchange Callback Interface.
+                  UINT nCommandID)         // The command id.
 {
-
-    if ((nCommandID != m_nCmdEncrypt) && 
-       (nCommandID != m_nCmdSign))
-       return S_FALSE; 
-
-    if (m_lContext == EECONTEXT_READNOTEMESSAGE) {
-       LPMESSAGE pMessage = NULL;
-       LPMDB pMDB = NULL;
-       HWND hWnd = NULL;
-
-       if (FAILED (pEECB->GetWindow (&hWnd)))
-           hWnd = NULL;
-       HRESULT hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
-       if (SUCCEEDED (hr)) {
-           if (nCommandID == m_nCmdEncrypt) {
-               m_gpg->setWindow (hWnd);
-               m_gpg->setMessage (pMessage);
-               m_gpg->decrypt ();
+  HRESULT hr;
+
+  if ((nCommandID != m_nCmdEncrypt) 
+      && (nCommandID != m_nCmdSign))
+    return S_FALSE; 
+
+  if (m_lContext == EECONTEXT_READNOTEMESSAGE) 
+    {
+      HWND hWnd = NULL;
+      LPMESSAGE pMessage = NULL;
+      LPMDB pMDB = NULL;
+
+      if (FAILED (pEECB->GetWindow (&hWnd)))
+        hWnd = NULL;
+      hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
+      if (SUCCEEDED (hr))
+        {
+          if (nCommandID == m_nCmdEncrypt)
+            {
+              GpgMsg *m = CreateGpgMsg (pMessage);
+              m_gpg->decrypt (hWnd, m);
+              delete m;
            }
        }
-       if (pMessage != NULL)
-           UlRelease(pMessage);
-       if (pMDB != NULL)
-           UlRelease(pMDB);
+      if (pMessage)
+        UlRelease(pMessage);
+      if (pMDB)
+        UlRelease(pMDB);
     }
-    if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) {
-       HWND hWnd = NULL;
-       if (FAILED(pEECB->GetWindow (&hWnd)))
-           hWnd = NULL;
-       if (nCommandID == m_nCmdEncrypt)
-           m_pExchExt->m_gpgEncrypt = !m_pExchExt->m_gpgEncrypt;
-       if (nCommandID == m_nCmdSign)
-           m_pExchExt->m_gpgSign = !m_pExchExt->m_gpgSign;
+  else if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) 
+    {
+      if (nCommandID == m_nCmdEncrypt)
+        m_pExchExt->m_gpgEncrypt = !m_pExchExt->m_gpgEncrypt;
+      if (nCommandID == m_nCmdSign)
+        m_pExchExt->m_gpgSign = !m_pExchExt->m_gpgSign;
     }
-    if (m_lContext == EECONTEXT_VIEWER) {
-       if (m_gpg->startKeyManager ())
-           MessageBox (NULL, "Could not start Key-Manager", "GPGExch", MB_ICONERROR|MB_OK);
+  else if (m_lContext == EECONTEXT_VIEWER)
+    {
+      if (m_gpg->startKeyManager ())
+        MessageBox (NULL, "Could not start Key-Manager",
+                    "OutlGPG", MB_ICONERROR|MB_OK);
     }
-    return S_OK; 
+
+  return S_OK; 
 }
 
-STDMETHODIMP_(VOID) CGPGExchExtCommands::InitMenu(
-       LPEXCHEXTCALLBACK pEECB) // The pointer to Exchange Callback Interface.
+
+STDMETHODIMP_(VOID) 
+CGPGExchExtCommands::InitMenu(LPEXCHEXTCALLBACK pEECB) 
 {
 }
 
-/* CGPGExchExtCommands::Help
 
- Called by Exhange when the user requests help for a menu item.
-
- Return value: S_OK when it is a menu item of this plugin and the help was shown;
-               otherwise S_FALSE
-*/
-STDMETHODIMP CGPGExchExtCommands::Help (
+/* Called by Exhange when the user requests help for a menu item.
+   Return value: S_OK when it is a menu item of this plugin and the
+   help was shown; otherwise S_FALSE.  */
+STDMETHODIMP 
+CGPGExchExtCommands::Help (
        LPEXCHEXTCALLBACK pEECB, // The pointer to Exchange Callback Interface.
        UINT nCommandID)         // The command id.
 {
@@ -709,35 +1040,40 @@ STDMETHODIMP CGPGExchExtCommands::Help (
     return S_FALSE;
 }
 
-/* CGPGExchExtCommands::QueryHelpText
-
- Called by Exhange to get the status bar text or the tooltip of a menu item.
 
- @rdesc S_OK when it is a menu item of this plugin and the text was set;
-        otherwise S_FALSE.
-*/
-STDMETHODIMP CGPGExchExtCommands::QueryHelpText(
-       UINT nCommandID,  // The command id corresponding to menu item activated.
-       ULONG lFlags,     // Identifies either EECQHT_STATUS or EECQHT_TOOLTIP.
-    LPTSTR pszText,   // A pointer to buffer to be populated with text to display.
-       UINT nCharCnt)    // The count of characters available in psz buffer.
+/* Called by Exhange to get the status bar text or the tooltip of a
+   menu item.  Returns S_OK when it is a menu item of this plugin and
+   the text was set; otherwise S_FALSE. */
+STDMETHODIMP 
+CGPGExchExtCommands::QueryHelpText(
+          UINT nCommandID,  // The command id corresponding to the
+                            //  menu item activated.
+         ULONG lFlags,     // Identifies either EECQHT_STATUS
+                            //  or EECQHT_TOOLTIP.
+          LPTSTR pszText,   // A pointer to buffer to be populated 
+                            //  with text to display.
+         UINT nCharCnt)    // The count of characters available in psz buffer.
 {
        
     if (m_lContext == EECONTEXT_READNOTEMESSAGE) {
        if (nCommandID == m_nCmdEncrypt) {
            if (lFlags == EECQHT_STATUS)
-               LoadString (glob_hinst, IDS_DECRYPT_STATUSBAR, pszText, nCharCnt);
+               LoadString (glob_hinst, IDS_DECRYPT_STATUSBAR,
+                            pszText, nCharCnt);
            if (lFlags == EECQHT_TOOLTIP)
-               LoadString (glob_hinst, IDS_DECRYPT_TOOLTIP, pszText, nCharCnt);
+               LoadString (glob_hinst, IDS_DECRYPT_TOOLTIP,
+                            pszText, nCharCnt);
            return S_OK;
        }
     }
     if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) {
        if (nCommandID == m_nCmdEncrypt) {
            if (lFlags == EECQHT_STATUS)
-               LoadString (glob_hinst, IDS_ENCRYPT_STATUSBAR, pszText, nCharCnt);
+               LoadString (glob_hinst, IDS_ENCRYPT_STATUSBAR,
+                            pszText, nCharCnt);
            if (lFlags == EECQHT_TOOLTIP)
-               LoadString (glob_hinst, IDS_ENCRYPT_TOOLTIP, pszText, nCharCnt);
+               LoadString (glob_hinst, IDS_ENCRYPT_TOOLTIP,
+                            pszText, nCharCnt);
            return S_OK;
        }
        if (nCommandID == m_nCmdSign) {
@@ -751,30 +1087,30 @@ STDMETHODIMP CGPGExchExtCommands::QueryHelpText(
     if (m_lContext == EECONTEXT_VIEWER) {
        if (nCommandID == m_nCmdEncrypt) {
            if (lFlags == EECQHT_STATUS)
-               LoadString (glob_hinst, IDS_KEY_MANAGER_STATUSBAR, pszText, nCharCnt);
+               LoadString (glob_hinst, IDS_KEY_MANAGER_STATUSBAR,
+                            pszText, nCharCnt);
            if (lFlags == EECQHT_TOOLTIP)
-               LoadString (glob_hinst, IDS_KEY_MANAGER_TOOLTIP, pszText, nCharCnt);
+               LoadString (glob_hinst, IDS_KEY_MANAGER_TOOLTIP,
+                            pszText, nCharCnt);
            return S_OK;
        }       
     }
     return S_FALSE;
 }
 
-/////////////////////////////////////////////////////////////////////////////
-// CGPGExchExtCommands::QueryButtonInfo 
-//
-// Called by Exchange to get toolbar button infos,
-//
-// @rdesc S_OK when it is a button of this plugin and the requested info was delivered;
-//        otherwise S_FALSE
-//
-STDMETHODIMP CGPGExchExtCommands::QueryButtonInfo (
+
+/* Called by Exchange to get toolbar button infos.  Returns S_OK when
+   it is a button of this plugin and the requested info was delivered;
+   otherwise S_FALSE. */
+STDMETHODIMP 
+CGPGExchExtCommands::QueryButtonInfo (
        ULONG lToolbarID,       // The toolbar identifier.
        UINT nToolbarButtonID,  // The toolbar button index.
-    LPTBBUTTON pTBB,        // A pointer to toolbar button structure (see TBBUTTON structure).
+        LPTBBUTTON pTBB,        // A pointer to toolbar button structure
+                                //  (see TBBUTTON structure).
        LPTSTR lpszDescription, // A pointer to string describing button.
        UINT nCharCnt,          // The maximum size of lpsz buffer.
-    ULONG lFlags)           // EXCHEXT_UNICODE may be specified
+        ULONG lFlags)           // EXCHEXT_UNICODE may be specified
 {
        if (m_lContext == EECONTEXT_READNOTEMESSAGE)
        {
@@ -786,7 +1122,8 @@ STDMETHODIMP CGPGExchExtCommands::QueryButtonInfo (
                        pTBB->fsStyle = TBSTYLE_BUTTON;
                        pTBB->dwData = 0;
                        pTBB->iString = -1;
-                       LoadString(glob_hinst, IDS_DECRYPT_TOOLTIP, lpszDescription, nCharCnt);
+                       LoadString(glob_hinst, IDS_DECRYPT_TOOLTIP,
+                                   lpszDescription, nCharCnt);
                        return S_OK;
                }
        }
@@ -802,7 +1139,8 @@ STDMETHODIMP CGPGExchExtCommands::QueryButtonInfo (
                        pTBB->fsStyle = TBSTYLE_BUTTON | TBSTYLE_CHECK;
                        pTBB->dwData = 0;
                        pTBB->iString = -1;
-                       LoadString(glob_hinst, IDS_ENCRYPT_TOOLTIP, lpszDescription, nCharCnt);
+                       LoadString(glob_hinst, IDS_ENCRYPT_TOOLTIP,
+                                   lpszDescription, nCharCnt);
                        return S_OK;
                }
                if (nToolbarButtonID == m_nToolbarButtonID2)
@@ -815,7 +1153,8 @@ STDMETHODIMP CGPGExchExtCommands::QueryButtonInfo (
                        pTBB->fsStyle = TBSTYLE_BUTTON | TBSTYLE_CHECK;
                        pTBB->dwData = 0;
                        pTBB->iString = -1;
-                       LoadString(glob_hinst, IDS_SIGN_TOOLTIP, lpszDescription, nCharCnt);
+                       LoadString(glob_hinst, IDS_SIGN_TOOLTIP,
+                                   lpszDescription, nCharCnt);
                        return S_OK;
                }
        }
@@ -829,7 +1168,8 @@ STDMETHODIMP CGPGExchExtCommands::QueryButtonInfo (
                        pTBB->fsStyle = TBSTYLE_BUTTON;
                        pTBB->dwData = 0;
                        pTBB->iString = -1;
-                       LoadString(glob_hinst, IDS_KEY_MANAGER_TOOLTIP, lpszDescription, nCharCnt);
+                       LoadString(glob_hinst, IDS_KEY_MANAGER_TOOLTIP,
+                                   lpszDescription, nCharCnt);
                        return S_OK;
                }
        }
@@ -838,6 +1178,7 @@ STDMETHODIMP CGPGExchExtCommands::QueryButtonInfo (
 }
 
 
+
 STDMETHODIMP 
 CGPGExchExtCommands::ResetToolbar (ULONG lToolbarID, ULONG lFlags)
 {      
@@ -845,7 +1186,8 @@ CGPGExchExtCommands::ResetToolbar (ULONG lToolbarID, ULONG lFlags)
 }
 
 
-CGPGExchExtPropertySheets::CGPGExchExtPropertySheets(CGPGExchExt* pParentInterface)
+CGPGExchExtPropertySheets::CGPGExchExtPropertySheets (
+                                    CGPGExchExt* pParentInterface)
 { 
     m_pExchExt = pParentInterface;
     m_lRef = 0; 
@@ -871,16 +1213,12 @@ CGPGExchExtPropertySheets::QueryInterface(REFIID riid, LPVOID FAR * ppvObj)
 }
 
 
-/* CGPGExchExtPropertySheets::GetMaxPageCount
-
- Called by Echange to get the maximum number of property pages which are
- to be added.
-
- Return value: The maximum number of custom pages for the property sheet.
-*/
+/* Called by Echange to get the maximum number of property pages which
+   are to be added. LFLAGS is a bitmask indicating what type of
+   property sheet is being displayed. Return value: The maximum number
+   of custom pages for the property sheet.  */
 STDMETHODIMP_ (ULONG) 
-CGPGExchExtPropertySheets::GetMaxPageCount(
-       ULONG lFlags) // A bitmask indicating what type of property sheet is being displayed.
+CGPGExchExtPropertySheets::GetMaxPageCount(ULONG lFlags)
 {
     if (lFlags == EEPS_TOOLSOPTIONS)
        return 1;       
@@ -888,18 +1226,19 @@ CGPGExchExtPropertySheets::GetMaxPageCount(
 }
 
 
-/* CGPGExchExtPropertySheets::GetPages
-
- Called by Exchange to request information about the property page.
-
- Return value: S_OK to signal Echange to use the pPSP information.
-*/
+/* Called by Exchange to request information about the property page.
+   Return value: S_OK to signal Echange to use the pPSP
+   information. */
 STDMETHODIMP 
 CGPGExchExtPropertySheets::GetPages(
        LPEXCHEXTCALLBACK pEECB, // A pointer to Exchange callback interface.
-       ULONG lFlags,            // A  bitmask indicating what type of property sheet is being displayed.
-       LPPROPSHEETPAGE pPSP,    // The output parm pointing to pointer to list of property sheets.
-       ULONG FAR * plPSP)       // The output parm pointing to buffer contaiing number of property sheets actually used.
+       ULONG lFlags,            // A  bitmask indicating what type of
+                                 //  property sheet is being displayed.
+       LPPROPSHEETPAGE pPSP,    // The output parm pointing to pointer
+                                 //  to list of property sheets.
+       ULONG FAR * plPSP)       // The output parm pointing to buffer 
+                                 //  containing the number of property 
+                                 //  sheets actually used.
 {
     int resid = 0;
 
@@ -924,7 +1263,13 @@ CGPGExchExtPropertySheets::GetPages(
     return S_OK;
 }
 
+
 STDMETHODIMP_ (VOID) 
-CGPGExchExtPropertySheets::FreePages (LPPROPSHEETPAGE pPSP, ULONG lFlags, ULONG lPSP)
+CGPGExchExtPropertySheets::FreePages (LPPROPSHEETPAGE pPSP,
+                                      ULONG lFlags, ULONG lPSP)
 {
 }
+
+
+
+
index dca967b..f4b7f63 100644 (file)
@@ -79,7 +79,8 @@ public:
   /* attributes */
 private:
   ULONG   m_lRef;
-  BOOL    m_bOnSubmitCalled;
+  ULONG   m_lContext;
+  BOOL    m_bOnSubmitActive;
   CGPGExchExt* m_pExchExt;
   BOOL    m_bWriteFailed;
   
@@ -106,6 +107,11 @@ public:
   STDMETHODIMP OnCheckNamesComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags);
   STDMETHODIMP OnSubmit (LPEXCHEXTCALLBACK pEECB);
   STDMETHODIMP_ (VOID)OnSubmitComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags);
+
+  inline void SetContext (ULONG lContext)
+  { 
+    m_lContext = lContext;
+  };
 };
 
 /*
index d34150d..56c477d 100644 (file)
@@ -6,4 +6,4 @@ EXPORTS
     ExchEntryPoint = ExchEntryPoint@0            @1
     DllRegisterServer = DllRegisterServer@0      @2    PRIVATE
     DllUnregisterServer = DllUnregisterServer@0  @3    PRIVATE
-    CreateMapiGPGME@4                            @4
+    CreateMapiGPGME@0                            @4
index 082cf6f..12f289a 100644 (file)
@@ -128,10 +128,10 @@ load_rsetbox (HWND hwnd)
            sprintf( keybuf+strlen( keybuf ), "/%s", s );
        strcat( keybuf, " " );
        if( (val = gpgme_key_get_ulong_attr( key, GPGME_ATTR_LEN, NULL, 1 )) )
-           sprintf( keybuf+strlen( keybuf ), "%d", val );
+           sprintf( keybuf+strlen( keybuf ), "%ld", val );
        else {
            val = gpgme_key_get_ulong_attr( key, GPGME_ATTR_LEN, NULL, 0 );
-           sprintf( keybuf+strlen( keybuf ), "%d", val );
+           sprintf( keybuf+strlen( keybuf ), "%ld", val );
        }
        s = keybuf;
        ListView_SetItemText( hwnd, 0, 2, (char *) s );
index 3e1d5c7..25d2a2b 100644 (file)
@@ -49,7 +49,33 @@ void* xmalloc (size_t n);
 void* xcalloc (size_t m, size_t n);
 char* xstrdup (const char *s);
 void  xfree (void *p);
+void out_of_core (void);
 
+char *wchar_to_utf8 (const wchar_t *string);
+wchar_t *utf8_to_wchar (const char *string);
+wchar_t *utf8_to_wchar2 (const char *string, size_t len);
+
+
+/*-- MapiGPGME.cpp --*/
+void log_debug (const char *fmt, ...) __attribute__ ((format (printf,1,2)));
+void log_vdebug (const char *fmt, va_list a);
+void log_debug_w32 (int w32err, const char *fmt,
+                    ...) __attribute__ ((format (printf,2,3)));
+
+
+/*****  Missing functions.  ****/
+
+#ifndef HAVE_STPCPY
+static inline char *
+_outlgpg_stpcpy (char *a, const char *b)
+{
+  while (*b)
+    *a++ = *b++;
+  *a = 0;
+  return a;
+}
+#define stpcpy(a,b) _outlgpg_stpcpy ((a), (b))
+#endif /*!HAVE_STPCPY*/
 
 
 
diff --git a/src/versioninfo.rc.in b/src/versioninfo.rc.in
new file mode 100644 (file)
index 0000000..748cc44
--- /dev/null
@@ -0,0 +1,56 @@
+/* versioninfo.rc.in 
+ *    Copyright (C) 2005 g10 Code GmbH
+ * 
+ * This file is free software; as a special exception the author gives
+ * unlimited permission to copy and/or distribute it, with or without
+ * modifications, as long as this notice is preserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+/* This file is processed by configure to create versioninfo.rc */
+
+#line __LINE__ "versioninfo.rc.in"
+
+#include "afxres.h"
+
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION @BUILD_FILEVERSION@
+ PRODUCTVERSION @BUILD_FILEVERSION@
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x21L
+#else
+ FILEFLAGS 0x20L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "Comments", "This plugin is available under the terms of the GNU Lesser General Public License.\0"
+            VALUE "CompanyName", "g10 Code GmbH\0"
+            VALUE "FileDescription", "OutlGPG - GnuPG plugin for Outlook\0"
+            VALUE "FileVersion", "@VERSION@\0"
+            VALUE "InternalName", "OutlGPG\0"
+            VALUE "LegalCopyright", "Copyright © 2005 g10 Code GmbH\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "outlgpg.dll\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "OutlGPG\0"
+            VALUE "ProductVersion", "@VERSION@\0"
+            VALUE "SpecialBuild", "@BUILD_TIMESTAMP@\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+