Refactored a lot of code.
authorWerner Koch <wk@gnupg.org>
Thu, 19 Jul 2007 17:56:20 +0000 (17:56 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 19 Jul 2007 17:56:20 +0000 (17:56 +0000)
Added some new MAPI helper functions.

29 files changed:
NEWS
po/de.po
src/ChangeLog
src/Makefile.am
src/attach.cpp [deleted file]
src/attach.h [deleted file]
src/attached-file-events.cpp [new file with mode: 0644]
src/attached-file-events.h [new file with mode: 0644]
src/display.cpp
src/ext-commands.cpp [new file with mode: 0644]
src/ext-commands.h [new file with mode: 0644]
src/gpgmsg.cpp
src/main.c
src/mapihelp.cpp [new file with mode: 0644]
src/mapihelp.h [new file with mode: 0644]
src/message-events.cpp [new file with mode: 0644]
src/message-events.h [new file with mode: 0644]
src/myexchext.h
src/mymapi.h
src/ol-ext-callback.cpp [new file with mode: 0644]
src/ol-ext-callback.h [new file with mode: 0644]
src/olflange-def.h
src/olflange.cpp
src/olflange.h
src/property-sheets.cpp [new file with mode: 0644]
src/property-sheets.h [new file with mode: 0644]
src/session-events.cpp [new file with mode: 0644]
src/session-events.h [new file with mode: 0644]
src/util.h

diff --git a/NEWS b/NEWS
index a299920..bd9283f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Noteworthy changes for version 0.9.92
+==================================================
+
+
 Noteworthy changes for version 0.9.91 (2006-10-13)
 ==================================================
 
index 438c099..6857ae0 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: GPGol 0.9.4\n"
 "Report-Msgid-Bugs-To: bug-gpgol@g10code.com\n"
 "POT-Creation-Date: 2006-08-28 15:44+0200\n"
-"PO-Revision-Date: 2006-04-24 16:41+0200\n"
+"PO-Revision-Date: 2007-04-13 12:55+0200\n"
 "Last-Translator: Werner Koch <wk@gnupg.org>\n"
 "Language-Team: de\n"
 "MIME-Version: 1.0\n"
index 5cc5174..c002a6a 100644 (file)
@@ -1,3 +1,47 @@
+2007-07-19  Werner Koch  <wk@g10code.com>
+
+       * attached-file-events.cpp: Renamed from attach.c.
+       * attached-file-events.h: Renamed from attach.h.  Removed some
+       inlines to the impl file.
+
+       * Makefile.am (gpgol_LDADD): Add libole32.
+
+2007-07-18  Werner Koch  <wk@g10code.com>
+
+       * mapihelp.c (log_mapi_property): Support STRIGN8 and UNICODE.
+
+       * myexchext.h (IExchExtUserEvents, IExchExtSessionEvents): New
+       declarations.
+       * session-events.cpp, session-events.h: New.
+       * olflange.cpp (GpgolExt, QueryInterface): Hook session-events in.
+
+       * olflange.cpp (DllRegisterServer): Register only for interfaces
+       we really use.
+       (ext_context_name): New. Factored out from several places.
+       (Install): Initialize for Session context.
+
+       Renamed all CGPGExchExt* classes to Gpgol*.
+       
+       * olflange.h, olflange.cpp: Factor most code out to ..
+       * ext-commands.cpp, ext-commands.h, message-events.cpp
+       * message-events.h, property-sheets.cpp, property-sheets.h
+       * ol-ext-callback.cpp, ol-ext-callback.h: .. New.
+
+2007-07-17  Werner Koch  <wk@g10code.com>
+
+       * Makefile.am (gpgol_LDADD): Add ws2_32.
+
+       * main.c (log_window_hierarchy, do_log_window_hierarchy): New.
+       * olflange.cpp (show_window_hierarchy): Replace by
+       log_window_hierarchy.
+       (g_initdll): Make static.
+       (InstallCommands): Factor some code out to ..
+       (toolbar_from_tbe, toolbar_add_menu): .. new.
+
+       * mapihelp.c, mapihelp.h: New. 
+       * olflange.cpp (show_mapi_property): Factor out to mapihelp.c
+       and rename to log_mapi_property.
+
 2007-04-10  Werner Koch  <wk@g10code.com>
 
        * display.cpp (find_message_window): Add arg LEVEL for debugging.
index 0898a25..b026da1 100644 (file)
@@ -41,10 +41,16 @@ gpgol_SOURCES = \
         passphrase-dialog.c         \
         recipient-dialog.c          \
         verify-dialog.c             \
+       mapihelp.cpp mapihelp.h     \
        mymapi.h  mymapitags.h      \
         vasprintf.c                 \
        watcher.cpp \
-       attach.cpp attach.h \
+       ext-commands.cpp ext-commands.h       \
+       session-events.cpp  session-events.h  \
+       message-events.cpp  message-events.h  \
+       attached-file-events.cpp attached-file-events.h \
+       property-sheets.cpp property-sheets.h \
+       ol-ext-callback.cpp ol-ext-callback.h \
        w32-gettext.c w32-gettext.h 
 
 
@@ -70,7 +76,7 @@ clean-local:
 
 gpgol_LDADD = $(srcdir)/gpgol.def  \
        -L . -lgpgme -lgpg-error -lmapi32 -lshell32 -lgdi32 -lcomdlg32 \
-        -loleaut32
+        -lole32 -loleaut32 -lws2_32
 
 resource.o: resource.rc versioninfo.rc gpgol-rsrcs.rc olflange-rsrcs.rc
 
diff --git a/src/attach.cpp b/src/attach.cpp
deleted file mode 100644 (file)
index 5d89e45..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <windows.h>
-
-#include "mymapi.h"
-#include "mymapitags.h"
-#include "myexchext.h"
-#include "olflange-def.h"
-#include "olflange.h"
-#include "attach.h"
-#include "util.h"
-
-
-STDMETHODIMP 
-CGPGExchExtAttachedFileEvents::OnReadPattFromSzFile 
-  (LPATTACH att, LPTSTR lpszFile, ULONG ulFlags)
-{
-  log_debug ("%s: att=%p lpszFile=%s ulFlags=%lx\n", 
-            __func__, att, lpszFile, ulFlags);
-  return S_FALSE;
-}
-  
-
-STDMETHODIMP 
-CGPGExchExtAttachedFileEvents::OnWritePattToSzFile 
-  (LPATTACH att, LPTSTR lpszFile, ULONG ulFlags)
-{
-  log_debug ("%s: att=%p lpszFile=%s ulFlags=%lx\n",
-            __func__, att, lpszFile, ulFlags);
-  return S_FALSE;
-}
-
-
-STDMETHODIMP
-CGPGExchExtAttachedFileEvents::QueryDisallowOpenPatt (LPATTACH att)
-{
-  log_debug ("%s: att=%p\n", __func__, att);
-  return S_FALSE;
-}
-
-
-STDMETHODIMP 
-CGPGExchExtAttachedFileEvents::OnOpenPatt (LPATTACH att)
-{
-  log_debug ("%s: att=%p\n", __func__, att);
-  return S_FALSE;
-}
-
-
-
-STDMETHODIMP 
-CGPGExchExtAttachedFileEvents::OnOpenSzFile (LPTSTR lpszFile, ULONG ulFlags)
-{
-  log_debug ("%s: lpszFile=%s ulflags=%lx\n", __func__, lpszFile, ulFlags);
-  return S_FALSE;
-}
diff --git a/src/attach.h b/src/attach.h
deleted file mode 100644 (file)
index cd1e139..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-
-#ifndef ATTACH_H
-#define ATTACH_H
-
-#include "util.h"
-
-class CGPGExchExtAttachedFileEvents : public IExchExtAttachedFileEvents
-{
-private:
-  CGPGExchExt *m_pExchExt;
-  ULONG        m_ref;
-
-public:
-  CGPGExchExtAttachedFileEvents (CGPGExchExt *pParentInterface)
-    {
-      m_pExchExt = pParentInterface;
-      m_ref = 0;
-    }
-  
-  
-  inline STDMETHODIMP_(ULONG) AddRef (void)
-    {
-      ++m_ref;
-      return m_ref;
-    }
-  
-  inline STDMETHODIMP_(ULONG) Release (void)
-    {
-      ULONG count = --m_ref;
-      if (!count)
-       delete this;
-      return count;
-    }
-  
-  STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
-    {
-      *ppvObj = NULL;
-      if (riid == IID_IExchExtAttachedFileEvents)
-       {
-         *ppvObj = (LPVOID)this;
-         AddRef ();
-         return S_OK;
-       }
-      
-      if (riid == IID_IUnknown)
-       {
-         *ppvObj = (LPVOID)m_pExchExt;
-         m_pExchExt->AddRef ();
-         return S_OK;
-       }
-      log_debug ("%s: request for unknown interface\n", __func__);
-      return E_NOINTERFACE;
-    }
-  
-  STDMETHODIMP OnReadPattFromSzFile (LPATTACH att, LPTSTR lpszFile, 
-                                    ULONG ulFlags);
-  STDMETHODIMP OnWritePattToSzFile (LPATTACH att, LPTSTR lpszFile, 
-                                   ULONG ulFlags);
-  STDMETHODIMP QueryDisallowOpenPatt (LPATTACH att);
-  STDMETHODIMP OnOpenPatt (LPATTACH att);
-  STDMETHODIMP OnOpenSzFile (LPTSTR lpszFile, ULONG ulFlags);
-};
-
-#endif /*ATTACH_H*/
diff --git a/src/attached-file-events.cpp b/src/attached-file-events.cpp
new file mode 100644 (file)
index 0000000..2e0da27
--- /dev/null
@@ -0,0 +1,114 @@
+/* attached-file-events.cpp - GpgolAttachedFileEvents implementation
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <windows.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+#include "myexchext.h"
+#include "intern.h"
+#include "olflange-def.h"
+#include "olflange.h"
+#include "attached-file-events.h"
+
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     SRCNAME, __func__, __LINE__); \
+                        } while (0)
+
+
+
+/* Our constructor.  */
+GpgolAttachedFileEvents::GpgolAttachedFileEvents (GpgolExt *pParentInterface)
+{ 
+  m_pExchExt = pParentInterface;
+  m_ref = 0;
+}
+
+
+/* The QueryInterfac.  */
+STDMETHODIMP 
+GpgolAttachedFileEvents::QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
+{
+  *ppvObj = NULL;
+  if (riid == IID_IExchExtAttachedFileEvents)
+    {
+      *ppvObj = (LPVOID)this;
+      AddRef ();
+      return S_OK;
+    }
+  if (riid == IID_IUnknown)
+    {
+      *ppvObj = (LPVOID)m_pExchExt;
+      m_pExchExt->AddRef ();
+      return S_OK;
+    }
+  return E_NOINTERFACE;
+}
+
+/* Fixme: We need to figure out what this exactly does.  There is no
+   public information available exepct for the MAPI book which is out
+   of print.  */
+STDMETHODIMP 
+GpgolAttachedFileEvents::OnReadPattFromSzFile 
+  (LPATTACH att, LPTSTR file, ULONG flags)
+{
+  log_debug ("%s:%s: att=%p file=`%s' flags=%lx\n", 
+            SRCNAME, __func__, att, file, flags);
+  return S_FALSE;
+}
+  
+STDMETHODIMP 
+GpgolAttachedFileEvents::OnWritePattToSzFile 
+  (LPATTACH att, LPTSTR file, ULONG flags)
+{
+  log_debug ("%s:%s: att=%p file=`%s' flags=%lx\n", 
+            SRCNAME, __func__, att, file, flags);
+  return S_FALSE;
+}
+
+
+STDMETHODIMP
+GpgolAttachedFileEvents::QueryDisallowOpenPatt (LPATTACH att)
+{
+  log_debug ("%s:%s: att=%p\n", SRCNAME, __func__, att);
+  return S_FALSE;
+}
+
+
+STDMETHODIMP 
+GpgolAttachedFileEvents::OnOpenPatt (LPATTACH att)
+{
+  log_debug ("%s:%s: att=%p\n", SRCNAME, __func__, att);
+  return S_FALSE;
+}
+
+
+STDMETHODIMP 
+GpgolAttachedFileEvents::OnOpenSzFile (LPTSTR file, ULONG flags)
+{
+  log_debug ("%s:%s: file=`%s' flags=%lx\n", SRCNAME, __func__, file, flags);
+  return S_FALSE;
+}
diff --git a/src/attached-file-events.h b/src/attached-file-events.h
new file mode 100644 (file)
index 0000000..3ebebe9
--- /dev/null
@@ -0,0 +1,67 @@
+/* attached-file-events.h - GpgolAttachedFileEvents definitions.
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#ifndef ATTACHED_FILE_EVENTS_H
+#define ATTACHED_FILE_EVENTS_H
+
+/*
+   GpgolAttachedFileEvents
+
+   The GpgolAttachedFileEvents class implements the processing of
+   events related to attachments.
+ */
+class GpgolAttachedFileEvents : public IExchExtAttachedFileEvents
+{
+ public:
+  GpgolAttachedFileEvents (GpgolExt *pParentInterface);
+
+ private:
+  GpgolExt *m_pExchExt;
+  ULONG     m_ref;
+  
+ public:
+  STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR *ppvObj);
+  inline STDMETHODIMP_(ULONG) AddRef (void)
+    {
+      ++m_ref;
+      return m_ref;
+    }
+  inline STDMETHODIMP_(ULONG) Release (void)
+    {
+      ULONG count = --m_ref;
+      if (!count)
+       delete this;
+      return count;
+    }
+  
+  
+  STDMETHODIMP OnReadPattFromSzFile (LPATTACH att, LPTSTR lpszFile, 
+                                    ULONG ulFlags);
+  STDMETHODIMP OnWritePattToSzFile (LPATTACH att, LPTSTR lpszFile, 
+                                   ULONG ulFlags);
+  STDMETHODIMP QueryDisallowOpenPatt (LPATTACH att);
+  STDMETHODIMP OnOpenPatt (LPATTACH att);
+  STDMETHODIMP OnOpenSzFile (LPTSTR lpszFile, ULONG ulFlags);
+
+};
+
+#endif /*ATTACHED_FILE_EVENTS_H*/
index 3db3ec6..351ce9f 100644 (file)
@@ -79,35 +79,6 @@ add_html_line_endings (const char *body)
   
 }
 
-// static HWND
-// show_window_hierarchy (HWND parent, int level)
-// {
-//   HWND child;
-
-//   child = GetWindow (parent, GW_CHILD);
-//   while (child)
-//     {
-//       char buf[1024+1];
-//       char name[200];
-//       int nname;
-//       char *pname;
-      
-//       memset (buf, 0, sizeof (buf));
-//       GetWindowText (child, buf, sizeof (buf)-1);
-//       nname = GetClassName (child, name, sizeof (name)-1);
-//       if (nname)
-//         pname = name;
-//       else
-//         pname = NULL;
-//       log_debug ("### %*shwnd=%p (%s) `%s'", level*2, "", child,
-//                  pname? pname:"", buf);
-//       show_window_hierarchy (child, level+1);
-//       child = GetNextWindow (child, GW_HWNDNEXT);   
-//     }
-
-//   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.  To do
diff --git a/src/ext-commands.cpp b/src/ext-commands.cpp
new file mode 100644 (file)
index 0000000..a78bb78
--- /dev/null
@@ -0,0 +1,696 @@
+/* ext-commands.cpp - Subclass impl of IExchExtCommands
+ *     Copyright (C) 2004, 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+#include "myexchext.h"
+#include "display.h"
+#include "intern.h"
+#include "gpgmsg.hh"
+#include "msgcache.h"
+#include "engine.h"
+#include "mapihelp.h"
+
+#include "olflange-ids.h"
+#include "olflange-def.h"
+#include "olflange.h"
+#include "ol-ext-callback.h"
+#include "ext-commands.h"
+
+
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     SRCNAME, __func__, __LINE__); \
+                        } while (0)
+
+static void toolbar_add_menu (LPEXCHEXTCALLBACK pEECB, 
+                              UINT FAR *pnCommandIDBase, ...)
+#if __GNUC__ >= 4 
+                               __attribute__ ((sentinel))
+#endif
+  ;
+
+
+
+
+/* Wrapper around UlRelease with error checking. */
+/* FIXME: Duplicated code.  */
+static void 
+ul_release (LPVOID punk)
+{
+  ULONG res;
+  
+  if (!punk)
+    return;
+  res = UlRelease (punk);
+//   log_debug ("%s UlRelease(%p) had %lu references\n", __func__, punk, res);
+}
+
+
+
+
+
+/* Constructor */
+GpgolExtCommands::GpgolExtCommands (GpgolExt* 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; 
+}
+
+
+
+STDMETHODIMP 
+GpgolExtCommands::QueryInterface (REFIID riid, LPVOID FAR * ppvObj)
+{
+    *ppvObj = NULL;
+    if ((riid == IID_IExchExtCommands) || (riid == IID_IUnknown)) {
+        *ppvObj = (LPVOID)this;
+        AddRef ();
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+
+/* Return the toolbar's window from the button entry array.  On
+   success the handle of the window is return as well as the
+   corresponding index at R_IDX.  On error NULL is returned and
+   the value at R_IDX is not changed. */
+static HWND
+toolbar_from_tbe (LPTBENTRY pTBEArray, UINT nTBECnt, int *r_idx)
+{
+  int nTBIndex;
+
+  for (nTBIndex = nTBECnt-1; nTBIndex > -1; --nTBIndex)
+    {  
+      if (EETBID_STANDARD == pTBEArray[nTBIndex].tbid)
+        {
+          *r_idx = nTBIndex;
+          return pTBEArray[nTBIndex].hwnd;
+        }      
+    }
+  return NULL;
+}
+
+/* Add a new menu.  The variable entries are made up of pairs of
+   strings and UINT *.  A NULL is used to terminate this list. An empty
+   string is translated to a separator menu item. */
+static void
+toolbar_add_menu (LPEXCHEXTCALLBACK pEECB, 
+                  UINT FAR *pnCommandIDBase, ...)
+{
+  va_list arg_ptr;
+  HMENU menu;
+  const char *string;
+  UINT *cmdptr;
+  
+  va_start (arg_ptr, pnCommandIDBase);
+  pEECB->GetMenuPos (EECMDID_ToolsCustomizeToolbar, &menu, NULL, NULL, 0);
+  while ( (string = va_arg (arg_ptr, const char *)) )
+    {
+      cmdptr = va_arg (arg_ptr, UINT*);
+
+      if (!*string)
+        AppendMenu (menu, MF_SEPARATOR, 0, NULL);
+      else
+       {
+          AppendMenu (menu, MF_STRING, *pnCommandIDBase, string);
+          if (cmdptr)
+            *cmdptr = *pnCommandIDBase;
+          (*pnCommandIDBase)++;
+        }
+    }
+  va_end (arg_ptr);
+}
+
+
+
+/* Called by Exchange to install commands and toolbar buttons.  Returns
+   S_FALSE to signal Exchange to continue calling extensions. */
+STDMETHODIMP 
+GpgolExtCommands::InstallCommands (
+       LPEXCHEXTCALLBACK pEECB, // The Exchange Callback Interface.
+       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 command id.
+       LPTBENTRY pTBEArray,     // The array of toolbar button entries.
+       UINT nTBECnt,            // The count of button entries in array.
+       ULONG lFlags)            // reserved
+{
+  HRESULT hr;
+  m_hWnd = hWnd;
+  LPDISPATCH pDisp;
+  DISPID dispid;
+  DISPID dispid_put = DISPID_PROPERTYPUT;
+  DISPPARAMS dispparams;
+  VARIANT aVariant;
+  int force_encrypt = 0;
+  int tb_idx;
+  HWND hwnd_toolbar;
+  TBADDBITMAP tbab;
+
+  
+  log_debug ("%s:%s: context=%s flags=0x%lx\n", SRCNAME, __func__, 
+             ext_context_name (m_lContext), lFlags);
+
+
+  /* Outlook 2003 sometimes displays the plaintext and sometimes the
+     original undecrypted text when doing a reply.  This seems to
+     depend on the size of the message; my guess it that only short
+     messages are locally saved in the process and larger ones are
+     fetched 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 ConversationIndex property.
+
+     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 because this would pop up the securiy window, telling the
+     user that someone is trying to read this data.
+  */
+  if (m_lContext == EECONTEXT_SENDNOTEMESSAGE)
+    {
+      LPMDB pMDB = NULL;
+      LPMESSAGE pMessage = NULL;
+      
+      /*  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))
+        log_debug ("%s:%s: getObject failed: hr=%#lx\n", SRCNAME,__func__,hr);
+      else if (!opt.compat.no_msgcache)
+        {
+          const char *body;
+          char *key = NULL;
+          size_t keylen = 0;
+          void *refhandle = NULL;
+     
+          pDisp = find_outlook_property (pEECB, "ConversationIndex", &dispid);
+          if (pDisp)
+            {
+              DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+
+              aVariant.bstrVal = NULL;
+              hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                                  DISPATCH_PROPERTYGET, &dispparamsNoArgs,
+                                  &aVariant, NULL, NULL);
+              if (hr != S_OK)
+                log_debug ("%s:%s: retrieving ConversationIndex failed: %#lx",
+                           SRCNAME, __func__, hr);
+              else if (aVariant.vt != VT_BSTR)
+                log_debug ("%s:%s: ConversationIndex is not a string (%d)",
+                           SRCNAME, __func__, aVariant.vt);
+              else if (aVariant.bstrVal)
+                {
+                  char *p;
+
+                  key = wchar_to_utf8 (aVariant.bstrVal);
+                  log_debug ("%s:%s: ConversationIndex is `%s'",
+                           SRCNAME, __func__, key);
+                  /* The key is a hex string.  Convert it to binary. */
+                  for (keylen=0,p=key; hexdigitp(p) && hexdigitp(p+1); p += 2)
+                    ((unsigned char*)key)[keylen++] = xtoi_2 (p);
+                  
+                 SysFreeString (aVariant.bstrVal);
+                }
+
+              pDisp->Release();
+              pDisp = NULL;
+            }
+          
+          if (key && keylen
+              && (body = msgcache_get (key, keylen, &refhandle)) 
+              && (pDisp = find_outlook_property (pEECB, "Body", &dispid)))
+            {
+#if 1
+              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);
+              log_debug ("%s:%s: PROPERTYPUT(body) result -> %#lx\n",
+                         SRCNAME, __func__, hr);
+#else
+              log_window_hierarchy (hWnd, "%s:%s:%d: Windows hierarchy:",
+                                    SRCNAME, __func__, __LINE__);
+#endif
+              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;
+            }
+          msgcache_unref (refhandle);
+          xfree (key);
+        }
+      
+      ul_release (pMessage);
+      ul_release (pMDB);
+    }
+
+
+  if (m_lContext == EECONTEXT_READNOTEMESSAGE)
+    {
+      if (opt.compat.auto_decrypt)
+        watcher_set_callback_ctx ((void *)pEECB);
+
+      toolbar_add_menu (pEECB, pnCommandIDBase, "", NULL,
+                        _("&Decrypt and verify message"), &m_nCmdEncrypt,
+                        NULL);
+      
+      hwnd_toolbar = toolbar_from_tbe (pTBEArray, nTBECnt, &tb_idx);
+      if (hwnd_toolbar)
+        {
+          m_nToolbarButtonID1 = pTBEArray[tb_idx].itbbBase;
+          pTBEArray[tb_idx].itbbBase++;
+
+          tbab.hInst = glob_hinst;
+          tbab.nID = IDB_DECRYPT;
+          m_nToolbarBitmap1 = SendMessage(hwnd_toolbar, TB_ADDBITMAP,
+                                          1, (LPARAM)&tbab);
+          m_nToolbarButtonID2 = pTBEArray[tb_idx].itbbBase;
+          pTBEArray[tb_idx].itbbBase++;
+        }
+    }
+
+  if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) 
+    {
+      toolbar_add_menu (pEECB, pnCommandIDBase, "", NULL,
+                        _("GPG &encrypt message"), &m_nCmdEncrypt,
+                        _("GPG &sign message"), &m_nCmdSign,
+                        NULL );
+      
+
+      hwnd_toolbar = toolbar_from_tbe (pTBEArray, nTBECnt, &tb_idx);
+      if (hwnd_toolbar) 
+        {
+          m_nToolbarButtonID1 = pTBEArray[tb_idx].itbbBase;
+          pTBEArray[tb_idx].itbbBase++;
+
+          tbab.hInst = glob_hinst;
+          tbab.nID = IDB_ENCRYPT;
+          m_nToolbarBitmap1 = SendMessage (hwnd_toolbar, TB_ADDBITMAP,
+                                           1, (LPARAM)&tbab);
+
+          m_nToolbarButtonID2 = pTBEArray[tb_idx].itbbBase;
+          pTBEArray[tb_idx].itbbBase++;
+
+          tbab.nID = IDB_SIGN;
+          m_nToolbarBitmap2 = SendMessage (hwnd_toolbar, TB_ADDBITMAP,
+                                           1, (LPARAM)&tbab);
+        }
+
+      m_pExchExt->m_gpgEncrypt = opt.encrypt_default;
+      m_pExchExt->m_gpgSign    = opt.sign_default;
+      if (force_encrypt)
+        m_pExchExt->m_gpgEncrypt = true;
+    }
+
+  if (m_lContext == EECONTEXT_VIEWER) 
+    {
+      toolbar_add_menu (pEECB, pnCommandIDBase, "", NULL,
+                        _("GPG Key &Manager"), &m_nCmdEncrypt,
+                        NULL);
+
+      hwnd_toolbar = toolbar_from_tbe (pTBEArray, nTBECnt, &tb_idx);
+      if (hwnd_toolbar)
+        {
+          m_nToolbarButtonID1 = pTBEArray[tb_idx].itbbBase;
+          pTBEArray[tb_idx].itbbBase++;
+
+          tbab.hInst = glob_hinst;
+          tbab.nID = IDB_KEY_MANAGER;
+          m_nToolbarBitmap1 = SendMessage(hwnd_toolbar, TB_ADDBITMAP,
+                                          1, (LPARAM)&tbab);
+        }      
+    }
+  return S_FALSE;
+}
+
+
+/* Called by Exchange when a user selects a command.  Return value:
+   S_OK if command is handled, otherwise S_FALSE. */
+STDMETHODIMP 
+GpgolExtCommands::DoCommand (
+                  LPEXCHEXTCALLBACK pEECB, // The Exchange Callback Interface.
+                  UINT nCommandID)         // The command id.
+{
+  HRESULT hr;
+
+  log_debug ("%s:%s: commandID=%u (%#x)\n",
+             SRCNAME, __func__, nCommandID, nCommandID);
+  if (nCommandID == SC_CLOSE && m_lContext == EECONTEXT_READNOTEMESSAGE)
+    {
+      /* This is the system close command. Replace it with our own to
+         avoid the "save changes" query, apparently induced by OL
+         internal syncronisation of our SetWindowText message with its
+         own OOM (in this case Body). */
+      LPDISPATCH pDisp;
+      DISPID dispid;
+      DISPPARAMS dispparams;
+      VARIANT aVariant;
+      
+      pDisp = find_outlook_property (pEECB, "Close", &dispid);
+      if (pDisp)
+        {
+          dispparams.rgvarg = &aVariant;
+          dispparams.rgvarg[0].vt = VT_INT;
+          dispparams.rgvarg[0].intVal = 1; /* olDiscard */
+          dispparams.cArgs = 1;
+          dispparams.cNamedArgs = 0;
+          hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                              DISPATCH_METHOD, &dispparams,
+                              NULL, NULL, NULL);
+          pDisp->Release();
+          pDisp = NULL;
+          if (hr == S_OK)
+            {
+              log_debug ("%s:%s: invoking Close succeeded", SRCNAME,__func__);
+              return S_OK; /* We handled the close command. */
+            }
+
+          log_debug ("%s:%s: invoking Close failed: %#lx",
+                     SRCNAME, __func__, hr);
+        }
+
+      /* We are not interested in the close command - pass it on. */
+      return S_FALSE; 
+    }
+  else if (nCommandID == 154)
+    {
+      log_debug ("%s:%s: command Reply called\n", SRCNAME, __func__);
+      /* What we might want to do is to call Reply, then GetInspector
+         and then Activate - this allows us to get full control over
+         the quoted message and avoids the ugly msgcache. */
+    }
+  else if (nCommandID == 155)
+    {
+      log_debug ("%s:%s: command ReplyAll called\n", SRCNAME, __func__);
+    }
+  else if (nCommandID == 156)
+    {
+      log_debug ("%s:%s: command Forward called\n", SRCNAME, __func__);
+    }
+  
+
+  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;
+//       else
+//         log_window_hierarchy (hWnd, "%s:%s:%d: Windows hierarchy:",
+//                               SRCNAME, __func__, __LINE__);
+
+      hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
+      if (SUCCEEDED (hr))
+        {
+          if (nCommandID == m_nCmdEncrypt)
+            {
+              GpgMsg *m = CreateGpgMsg (pMessage);
+              m->setExchangeCallback ((void*)pEECB);
+              m->decrypt (hWnd, 0);
+              delete m;
+           }
+       }
+      ul_release (pMessage);
+      ul_release (pMDB);
+    }
+  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;
+    }
+  else if (m_lContext == EECONTEXT_VIEWER)
+    {
+      if (start_key_manager ())
+        MessageBox (NULL, _("Could not start Key-Manager"),
+                    "GpgOL", MB_ICONERROR|MB_OK);
+    }
+
+  return S_OK; 
+}
+
+/* Called by Exchange when it receives a WM_INITMENU message, allowing
+   the extension object to enable, disable, or update its menu
+   commands before the user sees them. This method is called
+   frequently and should be written in a very efficient manner. */
+STDMETHODIMP_(VOID) 
+GpgolExtCommands::InitMenu(LPEXCHEXTCALLBACK pEECB) 
+{
+#if 0
+  log_debug ("%s:%s: context=%s\n",
+             SRCNAME, __func__, ext_context_name (m_lContext));
+#endif
+}
+
+
+/* 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 
+GpgolExtCommands::Help (
+       LPEXCHEXTCALLBACK pEECB, // The pointer to Exchange Callback Interface.
+       UINT nCommandID)         // The command id.
+{
+    if (m_lContext == EECONTEXT_READNOTEMESSAGE) {
+       if (nCommandID == m_nCmdEncrypt) {
+           MessageBox (m_hWnd,
+                        _("Decrypt and verify the message."),
+                        "GpgOL", MB_OK);
+           return S_OK;
+       }
+    }
+    if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) {
+       if (nCommandID == m_nCmdEncrypt) {
+           MessageBox(m_hWnd,
+                       _("Select this option to encrypt the message."),
+                       "GpgOL", MB_OK);        
+           return S_OK;
+       } 
+       else if (nCommandID == m_nCmdSign) {
+           MessageBox(m_hWnd,
+                       _("Select this option to sign the message."),
+                       "GpgOL", MB_OK);        
+           return S_OK;
+       } 
+    }
+
+    if (m_lContext == EECONTEXT_VIEWER) {
+       if (nCommandID == m_nCmdEncrypt) {
+               MessageBox(m_hWnd, 
+                           _("Open GPG Key Manager"),
+                           "GpgOL", MB_OK);
+               return S_OK;
+       } 
+    }
+
+    return S_FALSE;
+}
+
+
+/* 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 
+GpgolExtCommands::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)
+               lstrcpyn (pszText, ".", nCharCnt);
+           if (lFlags == EECQHT_TOOLTIP)
+               lstrcpyn (pszText,
+                          _("Decrypt message and verify signature"),
+                          nCharCnt);
+           return S_OK;
+       }
+    }
+    if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) {
+       if (nCommandID == m_nCmdEncrypt) {
+           if (lFlags == EECQHT_STATUS)
+               lstrcpyn (pszText, ".", nCharCnt);
+           if (lFlags == EECQHT_TOOLTIP)
+               lstrcpyn (pszText,
+                          _("Encrypt message with GPG"),
+                          nCharCnt);
+           return S_OK;
+       }
+       if (nCommandID == m_nCmdSign) {
+           if (lFlags == EECQHT_STATUS)
+               lstrcpyn (pszText, ".", nCharCnt);
+           if (lFlags == EECQHT_TOOLTIP)
+               lstrcpyn (pszText,
+                          _("Sign message with GPG"),
+                          nCharCnt);
+           return S_OK;
+       }
+    }
+    if (m_lContext == EECONTEXT_VIEWER) {
+       if (nCommandID == m_nCmdEncrypt) {
+           if (lFlags == EECQHT_STATUS)
+               lstrcpyn (pszText, ".", nCharCnt);
+           if (lFlags == EECQHT_TOOLTIP)
+               lstrcpyn (pszText,
+                          _("Open GPG Key Manager"),
+                          nCharCnt);
+           return S_OK;
+       }       
+    }
+    return S_FALSE;
+}
+
+
+/* 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 
+GpgolExtCommands::QueryButtonInfo (
+       ULONG lToolbarID,       // The toolbar identifier.
+       UINT nToolbarButtonID,  // The toolbar button index.
+        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
+{
+       if (m_lContext == EECONTEXT_READNOTEMESSAGE)
+       {
+               if (nToolbarButtonID == m_nToolbarButtonID1)
+               {
+                       pTBB->iBitmap = m_nToolbarBitmap1;             
+                       pTBB->idCommand = m_nCmdEncrypt;
+                       pTBB->fsState = TBSTATE_ENABLED;
+                       pTBB->fsStyle = TBSTYLE_BUTTON;
+                       pTBB->dwData = 0;
+                       pTBB->iString = -1;
+                       lstrcpyn (lpszDescription,
+                                  _("Decrypt message and verify signature"),
+                                  nCharCnt);
+                       return S_OK;
+               }
+       }
+       if (m_lContext == EECONTEXT_SENDNOTEMESSAGE)
+       {
+               if (nToolbarButtonID == m_nToolbarButtonID1)
+               {
+                       pTBB->iBitmap = m_nToolbarBitmap1;             
+                       pTBB->idCommand = m_nCmdEncrypt;
+                       pTBB->fsState = TBSTATE_ENABLED;
+                       if (m_pExchExt->m_gpgEncrypt)
+                               pTBB->fsState |= TBSTATE_CHECKED;
+                       pTBB->fsStyle = TBSTYLE_BUTTON | TBSTYLE_CHECK;
+                       pTBB->dwData = 0;
+                       pTBB->iString = -1;
+                       lstrcpyn (lpszDescription,
+                                  _("Encrypt message with GPG"),
+                                  nCharCnt);
+                       return S_OK;
+               }
+               if (nToolbarButtonID == m_nToolbarButtonID2)
+               {
+                       pTBB->iBitmap = m_nToolbarBitmap2;             
+                       pTBB->idCommand = m_nCmdSign;
+                       pTBB->fsState = TBSTATE_ENABLED;
+                       if (m_pExchExt->m_gpgSign)
+                               pTBB->fsState |= TBSTATE_CHECKED;
+                       pTBB->fsStyle = TBSTYLE_BUTTON | TBSTYLE_CHECK;
+                       pTBB->dwData = 0;
+                       pTBB->iString = -1;
+                       lstrcpyn (lpszDescription,
+                                  _("Sign message with GPG"),
+                                  nCharCnt);
+                       return S_OK;
+               }
+       }
+       if (m_lContext == EECONTEXT_VIEWER)
+       {
+               if (nToolbarButtonID == m_nToolbarButtonID1)
+               {
+                       pTBB->iBitmap = m_nToolbarBitmap1;             
+                       pTBB->idCommand = m_nCmdEncrypt;
+                       pTBB->fsState = TBSTATE_ENABLED;
+                       pTBB->fsStyle = TBSTYLE_BUTTON;
+                       pTBB->dwData = 0;
+                       pTBB->iString = -1;
+                       lstrcpyn (lpszDescription,
+                                  _("Open GPG Key Manager"),
+                                  nCharCnt);
+                       return S_OK;
+               }
+       }
+
+       return S_FALSE;
+}
+
+
+
+STDMETHODIMP 
+GpgolExtCommands::ResetToolbar (ULONG lToolbarID, ULONG lFlags)
+{      
+  return S_OK;
+}
+
+
diff --git a/src/ext-commands.h b/src/ext-commands.h
new file mode 100644 (file)
index 0000000..3e70a28
--- /dev/null
@@ -0,0 +1,89 @@
+/* ext-commands.h - Definitions for our subclass of IExchExtCommands
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef EXT_COMMANDS_H
+#define EXT_COMMANDS_H
+
+
+/*
+   GpgolExtCommands 
+
+   Makes the menu and toolbar extensions. Implements the own commands.
+ */
+class GpgolExtCommands : public IExchExtCommands
+{
+public:
+  GpgolExtCommands (GpgolExt* pParentInterface);
+  
+private:
+  ULONG m_lRef;
+  ULONG m_lContext;
+  
+  UINT  m_nCmdEncrypt;
+  UINT  m_nCmdSign;
+
+  UINT  m_nToolbarButtonID1;
+  UINT  m_nToolbarButtonID2;     
+  UINT  m_nToolbarBitmap1;
+  UINT  m_nToolbarBitmap2;
+  
+  HWND  m_hWnd;
+  
+  GpgolExt* m_pExchExt;
+  
+public:
+  STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
+  inline STDMETHODIMP_(ULONG) AddRef (void)
+  { 
+    ++m_lRef;
+    return m_lRef; 
+  };
+  inline STDMETHODIMP_(ULONG) Release (void) 
+  {
+    ULONG lCount = --m_lRef;
+    if (!lCount) 
+      delete this;
+    return lCount;
+  };
+
+  STDMETHODIMP InstallCommands (LPEXCHEXTCALLBACK pEECB, HWND hWnd,
+                                HMENU hMenu, UINT FAR * pnCommandIDBase,
+                                LPTBENTRY pTBEArray,
+                                UINT nTBECnt, ULONG lFlags);
+  STDMETHODIMP DoCommand (LPEXCHEXTCALLBACK pEECB, UINT nCommandID);
+  STDMETHODIMP_(void) InitMenu (LPEXCHEXTCALLBACK pEECB);
+  STDMETHODIMP Help (LPEXCHEXTCALLBACK pEECB, UINT nCommandID);
+  STDMETHODIMP QueryHelpText (UINT nCommandID, ULONG lFlags,
+                              LPTSTR szText, UINT nCharCnt);
+  STDMETHODIMP QueryButtonInfo (ULONG lToolbarID, UINT nToolbarButtonID, 
+                                LPTBBUTTON pTBB, LPTSTR lpszDescription,
+                                UINT nCharCnt, ULONG lFlags);
+  STDMETHODIMP ResetToolbar (ULONG nToolbarID, ULONG lFlags);
+
+  inline void SetContext (ULONG lContext)
+  { 
+    m_lContext = lContext;
+  };
+};
+
+
+
+#endif /*EXT_COMMANDS_H*/
index 517ee81..7621068 100644 (file)
@@ -1,14 +1,14 @@
-/* gpgmsg.cpp - Implementation ofthe GpgMsg class
+/* gpgmsg.cpp - Implementation of the GpgMsg class
  *     Copyright (C) 2005, 2006 g10 Code GmbH
  *
- * This file is part of GPGol.
+ * This file is part of GpgOL.
  * 
- * GPGol is free software; you can redistribute it and/or
+ * GpgOL is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
- * GPGol is distributed in the hope that it will be useful,
+ * GpgOL is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU Lesser General Public License for more details.
index 1b4159e..5ed8920 100644 (file)
@@ -237,7 +237,7 @@ log_debug_w32 (int w32err, const char *fmt, ...)
   va_list a;
 
   if (w32err == -1)
-      w32err = GetLastError ();
+    w32err = GetLastError ();
   
   va_start (a, fmt);
   do_log (fmt, a, w32err, 0, NULL, 0);
@@ -250,7 +250,7 @@ log_error_w32 (int w32err, const char *fmt, ...)
   va_list a;
 
   if (w32err == -1)
-      w32err = GetLastError ();
+    w32err = GetLastError ();
   
   va_start (a, fmt);
   do_log (fmt, a, w32err, 1, NULL, 0);
@@ -268,6 +268,54 @@ log_hexdump (const void *buf, size_t buflen, const char *fmt, ...)
   va_end (a);
 }
 
+
+/* Helper to log_window_hierarchy.  */
+static HWND
+do_log_window_hierarchy (HWND parent, int level)
+{
+  HWND child;
+
+  child = GetWindow (parent, GW_CHILD);
+  while (child)
+    {
+      char buf[1024+1];
+      char name[200];
+      int nname;
+      char *pname;
+      
+      memset (buf, 0, sizeof (buf));
+      GetWindowText (child, buf, sizeof (buf)-1);
+      nname = GetClassName (child, name, sizeof (name)-1);
+      if (nname)
+        pname = name;
+      else
+        pname = NULL;
+      log_debug ("    %*shwnd=%p (%s) `%s'", level*2, "", child,
+                 pname? pname:"", buf);
+      do_log_window_hierarchy (child, level+1);
+      child = GetNextWindow (child, GW_HWNDNEXT);      
+    }
+
+  return NULL;
+}
+
+
+/* Print a debug message using the format string FMT followed by the
+   window hierarchy of WINDOW.  */
+void
+log_window_hierarchy (HWND window, const char *fmt, ...)
+{
+  va_list a;
+
+  va_start (a, fmt);
+  do_log (fmt, a, 0, 0, NULL, 0);
+  va_end (a);
+  do_log_window_hierarchy (window, 0);
+}
+
+
+
+
 const char *
 log_srcname (const char *file)
 {
diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp
new file mode 100644 (file)
index 0000000..9cf1616
--- /dev/null
@@ -0,0 +1,247 @@
+/* mapihelp.cpp - Helper functions for MAPI
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+#include "intern.h"
+#include "mapihelp.h"
+
+
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     SRCNAME, __func__, __LINE__); \
+                        } while (0)
+
+
+/* Print a MAPI property to the log stream. */
+void
+log_mapi_property (LPMESSAGE message, ULONG prop, const char *propname)
+{
+  HRESULT hr;
+  LPSPropValue propval = NULL;
+  size_t keylen;
+  void *key;
+  char *buf;
+
+  if (!message)
+    return; /* No message: Nop. */
+
+  hr = HrGetOneProp ((LPMAPIPROP)message, prop, &propval);
+  if (FAILED (hr))
+    {
+      log_debug ("%s:%s: HrGetOneProp(%s) failed: hr=%#lx\n",
+                 SRCNAME, __func__, propname, hr);
+      return;
+    }
+    
+  switch ( PROP_TYPE (propval->ulPropTag) )
+    {
+    case PT_BINARY:
+      keylen = propval->Value.bin.cb;
+      key = propval->Value.bin.lpb;
+      log_hexdump (key, keylen, "%s: %20s=", __func__, propname);
+      break;
+
+    case PT_UNICODE:
+      buf = wchar_to_utf8 (propval->Value.lpszW);
+      if (!buf)
+        log_debug ("%s:%s: error converting to utf8\n", SRCNAME, __func__);
+      else
+        log_debug ("%s: %20s=`%s'", __func__, propname, buf);
+      xfree (buf);
+      break;
+      
+    case PT_STRING8:
+      log_debug ("%s: %20s=`%s'", __func__, propname, propval->Value.lpszA);
+      break;
+
+    default:
+      log_debug ("%s:%s: HrGetOneProp(%s) property type %lu not supported\n",
+                 SRCNAME, __func__, propname,
+                 PROP_TYPE (propval->ulPropTag) );
+      return;
+    }
+  MAPIFreeBuffer (propval);
+}
+
+
+/* This function checks whether MESSAGE requires processing by us and
+   adjusts the message class to our own.  Return true if the message
+   was changed. */
+int
+mapi_change_message_class (LPMESSAGE message)
+{
+  HRESULT hr;
+  SPropValue prop;
+  LPSPropValue propval = NULL;
+  
+  char *newvalue = NULL;
+
+  if (!message)
+    return 0; /* No message: Nop. */
+
+  hr = HrGetOneProp ((LPMAPIPROP)message, PR_MESSAGE_CLASS_A, &propval);
+  if (FAILED (hr))
+    {
+      log_error ("%s:%s: HrGetOneProp() failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      return 0;
+    }
+    
+  if ( PROP_TYPE (propval->ulPropTag) == PT_STRING8 )
+    {
+      const char *s = propval->Value.lpszA;
+      if (!strncmp (s, "IPM.Note.SMIME", 14) && (!s[14] || s[14] =='.'))
+        {
+          /* This is either "IPM.Note.SMIME" or "IPM.Note.SMIME.foo".
+             Note that we ncan't just insert a new aprt and keep the
+             SMIME; we need to change the SMIME part of the class name
+             so that Outlook does not proxcess it as an SMIME
+             message. */
+          newvalue = (char*)xmalloc (strlen (s) + 1);
+          strcpy (stpcpy (newvalue, "IPM.Note.GpgSM"), s+14);
+        }
+    }
+  MAPIFreeBuffer (propval);
+  if (!newvalue)
+    return 0;
+
+  prop.ulPropTag = PR_MESSAGE_CLASS_A;
+  prop.Value.lpszA = newvalue; 
+  hr = message->SetProps (1, &prop, NULL);
+  xfree (newvalue);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: can't set message class: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      return 0;
+    }
+
+  hr = message->SaveChanges (KEEP_OPEN_READONLY);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: SaveChanges() failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr); 
+      return 0;
+    }
+
+  return 1;
+}
+
+
+/* Return the message class as a scalar.  This function knows only
+   about out own message classes.  Returns MSGCLS_UNKNOWN for any
+   MSGCLASS we have no special support for.  */
+msgclass_t
+mapi_get_message_class (LPMESSAGE message)
+{
+  HRESULT hr;
+  LPSPropValue propval = NULL;
+  msgclass_t msgcls = MSGCLS_UNKNOWN;
+
+  if (!message)
+    return msgcls; 
+
+  hr = HrGetOneProp ((LPMAPIPROP)message, PR_MESSAGE_CLASS_A, &propval);
+  if (FAILED (hr))
+    {
+      log_error ("%s:%s: HrGetOneProp() failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      return msgcls;
+    }
+    
+  if ( PROP_TYPE (propval->ulPropTag) == PT_STRING8 )
+    {
+      const char *s = propval->Value.lpszA;
+      if (!strncmp (s, "IPM.Note.GpgSM", 14) && (!s[14] || s[14] =='.'))
+        {
+          s += 14;
+          if (!*s)
+            msgcls = MSGCLS_GPGSM;
+          else if (!strcmp (s, ".MultipartSigned"))
+            msgcls = MSGCLS_GPGSM_MULTIPART_SIGNED;
+          else
+            log_debug ("%s:%s: message class `%s' not supported",
+                       SRCNAME, __func__, s-14);
+        }
+    }
+  MAPIFreeBuffer (propval);
+  return msgcls;
+}
+
+
+/* This function is pretty useless because IConverterSession won't
+   take attachments in to account.  Need to write our own version.  */
+// int
+// mapi_to_mime (LPMESSAGE message, const char *filename)
+// {
+//   HRESULT hr;
+//   LPCONVERTERSESSION session;
+//   LPSTREAM stream;
+
+//   hr = CoCreateInstance (CLSID_IConverterSession, NULL, CLSCTX_INPROC_SERVER,
+//                          IID_IConverterSession, (void **) &session);
+//   if (FAILED (hr))
+//     {
+//       log_error ("%s:%s: can't create new IConverterSession object: hr=%#lx",
+//                  SRCNAME, __func__, hr);
+//       return -1;
+//     }
+
+
+//   hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
+//                          (STGM_CREATE | STGM_READWRITE),
+//                          (char*)filename, NULL, &stream); 
+//   if (FAILED (hr)) 
+//     {
+//       log_error ("%s:%s: can't create file `%s': hr=%#lx\n",
+//                  SRCNAME, __func__, filename, hr); 
+//       hr = -1;
+//     }
+//   else
+//     {
+//       hr = session->MAPIToMIMEStm (message, stream, 0);
+//       if (FAILED (hr))
+//         {
+//           log_error ("%s:%s: MAPIToMIMEStm failed: hr=%#lx",
+//                      SRCNAME, __func__, hr);
+//           stream->Revert ();
+//           hr = -1;
+//         }
+//       else
+//         {
+//           stream->Commit (0);
+//           hr = 0;
+//         }
+
+//       stream->Release ();
+//     }
+
+//   session->Release ();
+//   return hr;
+// }
+
+
diff --git a/src/mapihelp.h b/src/mapihelp.h
new file mode 100644 (file)
index 0000000..25ba9ab
--- /dev/null
@@ -0,0 +1,42 @@
+/* mapihelp.h - Helper functions for MAPI
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
+ *
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef MAPIHELP_H
+#define MAPIHELP_H
+
+/* The list of message classes we support.  */
+typedef enum 
+  {
+    MSGCLS_UNKNOWN = 0,
+    MSGCLS_GPGSM,
+    MSGCLS_GPGSM_MULTIPART_SIGNED
+  }
+msgclass_t;
+
+
+void log_mapi_property (LPMESSAGE message, ULONG prop, const char *propname);
+int mapi_change_message_class (LPMESSAGE message);
+msgclass_t mapi_get_message_class (LPMESSAGE message);
+int mapi_to_mime (LPMESSAGE message, const char *filename);
+
+
+
+#endif /*MAPIHELP_H*/
diff --git a/src/message-events.cpp b/src/message-events.cpp
new file mode 100644 (file)
index 0000000..062382f
--- /dev/null
@@ -0,0 +1,413 @@
+/* message-events.cpp - Subclass impl of IExchExtMessageEvents
+ *     Copyright (C) 2004, 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <windows.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+#include "myexchext.h"
+#include "display.h"
+#include "intern.h"
+#include "gpgmsg.hh"
+#include "msgcache.h"
+#include "engine.h"
+#include "mapihelp.h"
+
+#include "olflange-ids.h"
+#include "olflange-def.h"
+#include "olflange.h"
+#include "ol-ext-callback.h"
+#include "message-events.h"
+
+
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     SRCNAME, __func__, __LINE__); \
+                        } while (0)
+
+
+
+/* Wrapper around UlRelease with error checking. */
+/* FIXME: Duplicated code.  */
+static void 
+ul_release (LPVOID punk)
+{
+  ULONG res;
+  
+  if (!punk)
+    return;
+  res = UlRelease (punk);
+//   log_debug ("%s UlRelease(%p) had %lu references\n", __func__, punk, res);
+}
+
+
+
+
+
+
+/* Our constructor.  */
+GpgolMessageEvents::GpgolMessageEvents (GpgolExt *pParentInterface)
+{ 
+  m_pExchExt = pParentInterface;
+  m_lRef = 0; 
+  m_bOnSubmitActive = FALSE;
+  m_want_html = FALSE;
+  m_is_smime = FALSE;
+}
+
+
+/* The QueryInterfac.  */
+STDMETHODIMP 
+GpgolMessageEvents::QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
+{   
+  *ppvObj = NULL;
+  if (riid == IID_IExchExtMessageEvents)
+    {
+      *ppvObj = (LPVOID)this;
+      AddRef();
+      return S_OK;
+    }
+  if (riid == IID_IUnknown)
+    {
+      *ppvObj = (LPVOID)m_pExchExt;  
+      m_pExchExt->AddRef();
+      return S_OK;
+    }
+  return E_NOINTERFACE;
+}
+
+
+
+/* Called from Exchange on reading a message.  Returns: S_FALSE to
+   signal Exchange to continue calling extensions.  PEECB is a pointer
+   to the IExchExtCallback interface. */
+STDMETHODIMP 
+GpgolMessageEvents::OnRead (LPEXCHEXTCALLBACK pEECB) 
+{
+  LPMDB pMDB = NULL;
+  LPMESSAGE pMessage = NULL;
+  msgclass_t msgcls;
+  
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+  pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
+  log_mapi_property (pMessage, PR_CONVERSATION_INDEX,"PR_CONVERSATION_INDEX");
+  msgcls = mapi_get_message_class (pMessage);
+  switch (msgcls)
+    {
+    case MSGCLS_UNKNOWN: 
+      break;
+    case MSGCLS_GPGSM:
+    case MSGCLS_GPGSM_MULTIPART_SIGNED:
+      log_debug ("%s:%s: need to handle msgcls %d\n", 
+                 SRCNAME, __func__, msgcls);
+      m_is_smime = TRUE;
+      break;
+    }
+  
+  ul_release (pMessage);
+  ul_release (pMDB);
+
+  return S_FALSE;
+}
+
+
+/* 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 
+GpgolMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
+{
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+
+  /* The preview_info stuff does not work because for some reasons we
+     can't update the window.  Thus disabled for now. */
+  if (!m_is_smime && opt.preview_decrypt /*|| !opt.compat.no_preview_info*/)
+    {
+      HRESULT hr;
+      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))
+        {
+          GpgMsg *m = CreateGpgMsg (pMessage);
+          m->setExchangeCallback ((void*)pEECB);
+          m->setPreview (1);
+          /* If preview decryption has been requested, do so.  If not,
+             pass true as the second arg to let the fucntion display a
+             hint on what kind of message this is. */
+          m->decrypt (hWnd, !opt.preview_decrypt);
+          delete m;
+       }
+      ul_release (pMessage);
+      ul_release (pMDB);
+    }
+
+
+#if 0
+    {
+      HWND hWnd = NULL;
+
+      if (FAILED (pEECB->GetWindow (&hWnd)))
+        hWnd = NULL;
+      else
+        log_window_hierarchy (hWnd, "%s:%s:%d: Windows hierarchy:",
+                              SRCNAME, __func__, __LINE__);
+    }
+#endif
+
+  return S_FALSE;
+}
+
+
+/* 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 
+GpgolMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
+{
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+
+  HRESULT hr;
+  LPDISPATCH pDisp;
+  DISPID dispid;
+  VARIANT aVariant;
+  DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+  HWND hWnd = NULL;
+
+
+  /* If we are going to encrypt, check that the BodyFormat is
+     something we support.  This helps avoiding surprise by sending
+     out unencrypted messages. */
+  if (m_pExchExt->m_gpgEncrypt || m_pExchExt->m_gpgSign)
+    {
+      pDisp = find_outlook_property (pEECB, "BodyFormat", &dispid);
+      if (!pDisp)
+        {
+          log_debug ("%s:%s: BodyFormat not found\n", SRCNAME, __func__);
+          m_bWriteFailed = TRUE;       
+          return E_FAIL;
+        }
+      
+      aVariant.bstrVal = NULL;
+      hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                          DISPATCH_PROPERTYGET, &dispparamsNoArgs,
+                          &aVariant, NULL, NULL);
+      if (hr != S_OK)
+        {
+          log_debug ("%s:%s: retrieving BodyFormat failed: %#lx",
+                     SRCNAME, __func__, hr);
+          m_bWriteFailed = TRUE;       
+          pDisp->Release();
+          return E_FAIL;
+        }
+  
+      if (aVariant.vt != VT_INT && aVariant.vt != VT_I4)
+        {
+          log_debug ("%s:%s: BodyFormat is not an integer (%d)",
+                     SRCNAME, __func__, aVariant.vt);
+          m_bWriteFailed = TRUE;       
+          pDisp->Release();
+          return E_FAIL;
+        }
+  
+      if (aVariant.intVal == 1)
+        m_want_html = 0;
+      else if (aVariant.intVal == 2)
+        m_want_html = 1;
+      else
+        {
+
+          log_debug ("%s:%s: BodyFormat is %d",
+                     SRCNAME, __func__, aVariant.intVal);
+          
+          if (FAILED(pEECB->GetWindow (&hWnd)))
+            hWnd = NULL;
+          MessageBox (hWnd,
+                      _("Sorry, we can only encrypt plain text messages and\n"
+                      "no RTF messages. Please make sure that only the text\n"
+                      "format has been selected."),
+                      "GpgOL", MB_ICONERROR|MB_OK);
+
+          m_bWriteFailed = TRUE;       
+          pDisp->Release();
+          return E_FAIL;
+        }
+      pDisp->Release();
+      
+    }
+  
+  
+  return S_FALSE;
+}
+
+
+/* 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.  We return E_FAIL
+   to signals Exchange an error; the message will not be sent.  Note
+   that we don't return S_OK because this would mean that we rolled
+   back the write operation and that no further extensions should be
+   called. */
+STDMETHODIMP 
+GpgolMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags)
+{
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+
+  HRESULT hrReturn = S_FALSE;
+  LPMESSAGE msg = NULL;
+  LPMDB pMDB = NULL;
+  HWND hWnd = NULL;
+  int rc;
+
+  if (lFlags & (EEME_FAILED|EEME_COMPLETE_FAILED))
+    return S_FALSE; /* We don't need to rollback anything in case
+                       other extensions flagged a failure. */
+          
+  if (!m_bOnSubmitActive) /* The user is just saving the message. */
+    return S_FALSE;
+  
+  if (m_bWriteFailed)     /* Operation failed already. */
+    return S_FALSE;
+  
+  if (FAILED(pEECB->GetWindow (&hWnd)))
+    hWnd = NULL;
+
+  HRESULT hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&msg);
+  if (SUCCEEDED (hr))
+    {
+//      SPropTagArray proparray;
+
+      GpgMsg *m = CreateGpgMsg (msg);
+      m->setExchangeCallback ((void*)pEECB);
+      if (m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
+        rc = m->signEncrypt (hWnd, m_want_html);
+      else if (m_pExchExt->m_gpgEncrypt && !m_pExchExt->m_gpgSign)
+        rc = m->encrypt (hWnd, m_want_html);
+      else if (!m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
+        rc = m->sign (hWnd, m_want_html);
+      else
+        rc = 0;
+      delete m;
+
+      /* If we are encrypting we need to make sure that the other
+         format gets deleted and is not actually sent in the clear.
+         Note that this other format is always HTML because we have
+         moved that into an attachment and kept PR_BODY.  It seems
+         that OL always creates text and HTML if HTML has been
+         selected. */
+      /* ARGHH: This seems to delete also the PR_BODY for some reasonh
+         - need to disable this safe net. */
+//       if (m_pExchExt->m_gpgEncrypt)
+//         {
+//           log_debug ("%s:%s: deleting possible extra property PR_BODY_HTML\n",
+//                      SRCNAME, __func__);
+//           proparray.cValues = 1;
+//           proparray.aulPropTag[0] = PR_BODY_HTML;
+//           msg->DeleteProps (&proparray, NULL);
+//         }
+     
+      if (rc)
+        {
+          hrReturn = E_FAIL;
+          m_bWriteFailed = TRUE;       
+
+         /* Outlook should now correctly react and do not deliver
+            the message in case of an error.
+          */
+         #if 0
+          if (m_pExchExt->m_gpgEncrypt)
+            {
+              log_debug ("%s:%s: deleting property PR_BODY due to error\n",
+                         SRCNAME, __func__);
+              proparray.cValues = 1;
+              proparray.aulPropTag[0] = PR_BODY;
+              hr = msg->DeleteProps (&proparray, NULL);
+              if (hr != S_OK)
+                log_debug ("%s:%s: DeleteProps failed: hr=%#lx\n",
+                           SRCNAME, __func__, hr);
+              /* FIXME: We should delete the attachments too. 
+                 We really, really should do this!!!          */
+            }
+          #endif
+        }
+    }
+
+  ul_release (msg);
+  ul_release (pMDB);
+
+  return hrReturn;
+}
+
+/* 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 
+GpgolMessageEvents::OnCheckNames(LPEXCHEXTCALLBACK pEECB)
+{
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+  return S_FALSE;
+}
+
+
+/* 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 
+GpgolMessageEvents::OnCheckNamesComplete (LPEXCHEXTCALLBACK pEECB,ULONG lFlags)
+{
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+  return S_FALSE;
+}
+
+
+/* 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 
+GpgolMessageEvents::OnSubmit (LPEXCHEXTCALLBACK pEECB)
+{
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+  m_bOnSubmitActive = TRUE;
+  m_bWriteFailed = FALSE;
+  return S_FALSE;
+}
+
+
+/* Called by Echange after the message has been submitted to MAPI.
+   PEECB is a pointer to the IExchExtCallback interface. */
+STDMETHODIMP_ (VOID) 
+GpgolMessageEvents::OnSubmitComplete (LPEXCHEXTCALLBACK pEECB,
+                                            ULONG lFlags)
+{
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+  m_bOnSubmitActive = FALSE; 
+}
+
+
diff --git a/src/message-events.h b/src/message-events.h
new file mode 100644 (file)
index 0000000..06b583b
--- /dev/null
@@ -0,0 +1,79 @@
+/* message-events.h - Definitions for out subclass of IExchExtMessageEvents
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef MESSAGE_EVENTS_H
+#define MESSAGE_EVENTS_H
+
+/*
+   GpgolMessageEvents 
+   The GpgolMessageEvents class implements the reaction of the exchange 
+   message events.
+ */
+class GpgolMessageEvents : public IExchExtMessageEvents
+{
+  /* Constructor. */
+ public:
+  GpgolMessageEvents (GpgolExt* pParentInterface);
+  
+  /* Attributes.  */
+ private:
+  ULONG   m_lRef;
+  ULONG   m_lContext;
+  BOOL    m_bOnSubmitActive;
+  GpgolExt* m_pExchExt;
+  BOOL    m_bWriteFailed;
+  BOOL    m_want_html;       /* Encryption of HTML is desired. */
+  BOOL    m_is_smime;        /* The message has an smime message class
+                                we want to process.  */
+  
+ public:
+  STDMETHODIMP QueryInterface (REFIID riid, LPVOID *ppvObj);
+  inline STDMETHODIMP_(ULONG) AddRef (void)
+    {
+      ++m_lRef; 
+      return m_lRef; 
+    };
+  inline STDMETHODIMP_(ULONG) Release (void) 
+    {
+      ULONG lCount = --m_lRef;
+      if (!lCount) 
+        delete this;
+      return lCount;   
+    };
+  
+  STDMETHODIMP OnRead (LPEXCHEXTCALLBACK pEECB);
+  STDMETHODIMP OnReadComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags);
+  STDMETHODIMP OnWrite (LPEXCHEXTCALLBACK pEECB);
+  STDMETHODIMP OnWriteComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags);
+  STDMETHODIMP OnCheckNames (LPEXCHEXTCALLBACK pEECB);
+  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;
+  };
+};
+
+
+#endif /*MESSAGE_EVENTS_H*/
index 0339aaf..a4ef16e 100644 (file)
@@ -7,7 +7,7 @@
  * Revisions:
  * 2005-08-12  Initial version.
  * 2005-09-18  Add IExchExtAttachedFileEvents.
- *
+ * 2007-07-18  Add IExchExtUserEvents and IExchExtSessionEvents.
  */
 
 #ifndef EXCHEXT_H
@@ -122,6 +122,12 @@ typedef struct TBENTRY *LPTBENTRY;
 typedef struct IExchExt IExchExt;
 typedef IExchExt *LPEXCHEXT;
 
+typedef struct IExchExtUserEvents IExchExtUserEvents;
+typedef IExchExtUserEvents *LPEXCHEXTUSEREVENTS;
+
+typedef struct IExchExtSessionEvents IExchExtSessionEvents;
+typedef IExchExtSessionEvents *LPEXCHEXTSESSIONEVENTS;
+
 typedef struct IExchExtMessageEvents IExchExtMessageEvents;
 typedef IExchExtMessageEvents *LPEXCHEXTMESSAGEEVENTS;
 
@@ -225,6 +231,39 @@ DECLARE_INTERFACE_(IExchExt, IUnknown)
 
 
 
+EXTERN_C const IID IID_IExchExtUserEvents;
+#undef INTERFACE
+#define INTERFACE IExchExtUserEvents
+DECLARE_INTERFACE_(IExchExtUserEvents, IUnknown)
+{
+  /*** IUnknown methods. ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+  /*** IExchExtUserEvents methods. ***/
+  STDMETHOD_(void, OnSelectionChange)(THIS_ LPEXCHEXTCALLBACK) PURE;
+  STDMETHOD_(void, OnObjectChange)(THIS_ LPEXCHEXTCALLBACK) PURE;
+};
+
+
+
+EXTERN_C const IID IID_IExchExtSessionEvents;
+#undef INTERFACE
+#define INTERFACE IExchExtSessionEvents
+DECLARE_INTERFACE_(IExchExtSessionEvents, IUnknown)
+{
+  /*** IUnknown methods. ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+  /*** IExchExtSessionEvents methods. ***/
+  STDMETHOD(OnDelivery)(THIS_ LPEXCHEXTCALLBACK) PURE;
+};
+
+
+
 EXTERN_C const IID IID_IExchExtMessageEvents;
 #undef INTERFACE
 #define INTERFACE IExchExtMessageEvents
index 7da9b62..17e9efc 100644 (file)
@@ -1,7 +1,7 @@
 /* mymapi.h - MAPI definitions required for GPGol and Mingw32
  * Copyright (C) 1998 Justin Bradford
  * Copyright (C) 2000 Fran├žois Gouget
- * Copyright (C) 2005 g10 Code GmbH
+ * Copyright (C) 2005, 2007 g10 Code GmbH
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,6 +27,9 @@
    Revisions:
    2005-07-26  Initial version (wk at g10code).
    2005-08-14  Tweaked for use with myexchext.h.
+   2007-07-19  Add IConverterSession.  Info taken from
+                 http://blogs.msdn.com/stephen_griffin/archive/2007/06/22/
+                 iconvertersession-do-you-converter-session.aspx
 */
 
 #ifndef MAPI_H
@@ -204,6 +207,12 @@ DEFINE_OLEGUID(PS_ROUTING_EMAIL_ADDRESSES,0x20380,0,0);
 DEFINE_OLEGUID(PS_ROUTING_ENTRYID,0x20383,0,0);
 DEFINE_OLEGUID(PS_ROUTING_SEARCH_KEY,0x20384,0,0);
 
+DEFINE_GUID(CLSID_IConverterSession, 0x4e3a7680, 0xb77a,
+            0x11d0, 0x9d, 0xa5, 0x0, 0xc0, 0x4f, 0xd6, 0x56, 0x85); 
+DEFINE_GUID(IID_IConverterSession, 0x4b401570, 0xb77b,
+            0x11d0, 0x9d, 0xa5, 0x0, 0xc0, 0x4f, 0xd6, 0x56, 0x85);
+
+
 
 struct _ENTRYID
 {
@@ -481,6 +490,41 @@ typedef struct _ADRLIST
 } ADRLIST, *LPADRLIST;
 
 
+
+/* Definitions required for IConverterSession. */
+typedef enum tagMIMESAVETYPE
+  {    
+    SAVE_RFC822        = 0,
+    SAVE_RFC1521 = 1
+  } 
+MIMESAVETYPE;
+
+typedef enum tagENCODINGTYPE
+  {
+    IET_BINARY  = 0,
+    IET_BASE64  = 1,
+    IET_UUENCODE = 2,
+    IET_QP      = 3,
+    IET_7BIT    = 4,
+    IET_8BIT    = 5,
+    IET_INETCSET = 6,
+    IET_UNICODE         = 7,
+    IET_RFC1522         = 8,
+    IET_ENCODED         = 9,
+    IET_CURRENT         = 10,
+    IET_UNKNOWN         = 11,
+    IET_BINHEX40 = 12,
+    IET_LAST    = 13
+  }
+ENCODINGTYPE;
+
+#define CCSF_SMTP        0x0002
+#define CCSF_NOHEADERS   0x0004
+#define CCSF_INCLUDE_BCC  0x0020
+#define CCSF_USE_RTF     0x0080
+#define CCSF_NO_MSGID    0x4000
+
+
 \f
 /**** Class definitions ****/
 typedef const IID *LPCIID;
@@ -507,6 +551,10 @@ typedef struct IMessage *LPMESSAGE;
 struct IMsgStore;
 typedef struct IMsgStore *LPMDB;
 
+struct IConverterSession;
+typedef struct IConverterSession *LPCONVERTERSESSION;
+
+
 
 
 EXTERN_C const IID IID_IMAPIProp;
@@ -657,6 +705,33 @@ DECLARE_INTERFACE_(IMAPITable,IUnknown)
 };
 
 
+
+EXTERN_C const IID IID_IConverterSession;
+#undef INTERFACE
+#define INTERFACE IConverterSession
+DECLARE_INTERFACE_(IConverterSession, IUnknown)
+{
+  /*** IUnknown methods ***/
+  STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
+  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
+  STDMETHOD_(ULONG,Release)(THIS) PURE;
+
+  /*** IConverterSession ***/
+  STDMETHOD(PlaceHolder1)(THIS);
+  STDMETHOD(SetEncoding)(THIS_ ENCODINGTYPE);
+  STDMETHOD(PlaceHolder2)(THIS);
+  STDMETHOD(MIMEToMAPI)(THIS_ LPSTREAM, LPMESSAGE, LPCSTR, ULONG);
+  STDMETHOD(MAPIToMIMEStm)(THIS_ LPMESSAGE,LPSTREAM,ULONG);
+  STDMETHOD(PlaceHolder3)(THIS);
+  STDMETHOD(PlaceHolder4)(THIS);
+  STDMETHOD(PlaceHolder5)(THIS);
+  STDMETHOD(SetTextWrapping)(THIS_ BOOL, ULONG);
+  STDMETHOD(SetSaveFormat)(THIS_ MIMESAVETYPE);
+  STDMETHOD(PlaceHolder8)(THIS);
+  STDMETHOD(PlaceHolder9)(THIS);
+};
+
+
 \f
 /****  Function prototypes. *****/
 
diff --git a/src/ol-ext-callback.cpp b/src/ol-ext-callback.cpp
new file mode 100644 (file)
index 0000000..1178b67
--- /dev/null
@@ -0,0 +1,297 @@
+/* ol-ext-callback.cpp - Code to use the IOutlookExtCallback.
+ *     Copyright (C) 2004, 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+#include "myexchext.h"
+#include "display.h"
+#include "intern.h"
+#include "gpgmsg.hh"
+#include "msgcache.h"
+#include "engine.h"
+#include "mapihelp.h"
+
+#include "olflange-ids.h"
+#include "olflange-def.h"
+#include "olflange.h"
+#include "ol-ext-callback.h"
+
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     SRCNAME, __func__, __LINE__); \
+                        } while (0)
+
+
+/* Wrapper around UlRelease with error checking. */
+/* FIXME: Duplicated code.  */
+static void 
+ul_release (LPVOID punk)
+{
+  ULONG res;
+  
+  if (!punk)
+    return;
+  res = UlRelease (punk);
+//   log_debug ("%s UlRelease(%p) had %lu references\n", __func__, punk, res);
+}
+
+
+
+
+
+/* Locate a property using the provided callback LPEECB and traverse
+   down to the last element of 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. */
+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;
+
+  log_debug ("%s:%s: looking for `%s'\n", SRCNAME, __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);
+      //log_debug ("   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". */
+      //log_debug ("%s:%s: %.*s=%p  (hr=0x%x)\n",
+      //           SRCNAME, __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);
+  //log_debug ("   dispid(%s)=%d  (hr=0x%x)\n", name, dispid, hr);
+  if (r_dispid)
+    *r_dispid = dispid;
+
+  log_debug ("%s:%s:    got IDispatch=%p dispid=%u\n",
+            SRCNAME, __func__, pDisp, (unsigned int)dispid);
+  return pDisp;
+}
+
+
+int
+put_outlook_property (void *pEECB, const char *key, const char *value)
+{
+  int result = -1;
+  HRESULT hr;
+  LPMDB pMDB = NULL;
+  LPMESSAGE pMessage = NULL;
+  LPDISPATCH pDisp;
+  DISPID dispid;
+  DISPID dispid_put = DISPID_PROPERTYPUT;
+  DISPPARAMS dispparams;
+  VARIANT aVariant;
+
+  if (!pEECB)
+    return -1;
+
+  hr = ((LPEXCHEXTCALLBACK)pEECB)->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
+  if (FAILED (hr))
+    log_debug ("%s:%s: getObject failed: hr=%#lx\n", SRCNAME, __func__, hr);
+  else if ( (pDisp = find_outlook_property ((LPEXCHEXTCALLBACK)pEECB,
+                                            key, &dispid)))
+    {
+      BSTR abstr;
+
+      dispparams.cNamedArgs = 1;
+      dispparams.rgdispidNamedArgs = &dispid_put;
+      dispparams.cArgs = 1;
+      dispparams.rgvarg = &aVariant;
+      {
+        wchar_t *tmp = utf8_to_wchar (value);
+        abstr = SysAllocString (tmp);
+        xfree (tmp);
+      }
+      if (!abstr)
+        log_error ("%s:%s: SysAllocString failed\n", SRCNAME, __func__);
+      else
+        {
+          dispparams.rgvarg[0].vt = VT_BSTR;
+          dispparams.rgvarg[0].bstrVal = abstr;
+          hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                              DISPATCH_PROPERTYPUT, &dispparams,
+                              NULL, NULL, NULL);
+          log_debug ("%s:%s: PROPERTYPUT(%s) result -> %#lx\n",
+                     SRCNAME, __func__, key, hr);
+          SysFreeString (abstr);
+        }
+      
+      pDisp->Release ();
+      pDisp = NULL;
+      result = 0;
+    }
+
+  ul_release (pMessage);
+  ul_release (pMDB);
+  return result;
+}
+
+int
+put_outlook_property_int (void *pEECB, const char *key, int value)
+{
+  int result = -1;
+  HRESULT hr;
+  LPMDB pMDB = NULL;
+  LPMESSAGE pMessage = NULL;
+  LPDISPATCH pDisp;
+  DISPID dispid;
+  DISPID dispid_put = DISPID_PROPERTYPUT;
+  DISPPARAMS dispparams;
+  VARIANT aVariant;
+
+  if (!pEECB)
+    return -1;
+
+  hr = ((LPEXCHEXTCALLBACK)pEECB)->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
+  if (FAILED (hr))
+    log_debug ("%s:%s: getObject failed: hr=%#lx\n", SRCNAME, __func__, hr);
+  else if ( (pDisp = find_outlook_property ((LPEXCHEXTCALLBACK)pEECB,
+                                            key, &dispid)))
+    {
+      dispparams.cNamedArgs = 1;
+      dispparams.rgdispidNamedArgs = &dispid_put;
+      dispparams.cArgs = 1;
+      dispparams.rgvarg = &aVariant;
+      dispparams.rgvarg[0].vt = VT_I4;
+      dispparams.rgvarg[0].intVal = value;
+      hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                         DISPATCH_PROPERTYPUT, &dispparams,
+                         NULL, NULL, NULL);
+      log_debug ("%s:%s: PROPERTYPUT(%s) result -> %#lx\n",
+                 SRCNAME, __func__, key, hr);
+
+      pDisp->Release ();
+      pDisp = NULL;
+      result = 0;
+    }
+
+  ul_release (pMessage);
+  ul_release (pMDB);
+  return result;
+}
+
+
+/* Return an Outlook OO property named KEY.  This needs to be some
+   kind of string. PEECP is required to indificate the context.  On
+   error NULL is returned.   It is usually used with "Body". */
+char *
+get_outlook_property (void *pEECB, const char *key)
+{
+  char *result = NULL;
+  HRESULT hr;
+  LPDISPATCH pDisp;
+  DISPID dispid;
+  DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+  VARIANT aVariant;
+
+  if (!pEECB)
+    return NULL;
+
+  pDisp = find_outlook_property ((LPEXCHEXTCALLBACK)pEECB, key, &dispid);
+  if (!pDisp)
+    return NULL;
+
+  aVariant.bstrVal = NULL;
+  hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                      DISPATCH_PROPERTYGET, &dispparamsNoArgs,
+                      &aVariant, NULL, NULL);
+  if (hr != S_OK)
+    log_debug ("%s:%s: retrieving `%s' failed: %#lx",
+               SRCNAME, __func__, key, hr);
+  else if (aVariant.vt != VT_BSTR)
+    log_debug ("%s:%s: `%s' is not a string (%d)",
+                           SRCNAME, __func__, key, aVariant.vt);
+  else if (aVariant.bstrVal)
+    {
+      result = wchar_to_utf8 (aVariant.bstrVal);
+      log_debug ("%s:%s: `%s' is `%s'",
+                 SRCNAME, __func__, key, result);
+      /* From MSDN (Invoke): It is up to the caller to free the return value.*/
+      SysFreeString (aVariant.bstrVal);
+    }
+
+  pDisp->Release();
+  pDisp = NULL;
+
+  return result;
+}
+
+
+
diff --git a/src/ol-ext-callback.h b/src/ol-ext-callback.h
new file mode 100644 (file)
index 0000000..2afbdcd
--- /dev/null
@@ -0,0 +1,33 @@
+/* ol-ext-callback.h - Definitions for ol-ext-callback.cpp
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef OL_EXT_CALLBACK_H
+#define OL_EXT_CALLBACK_H
+
+
+LPDISPATCH find_outlook_property (LPEXCHEXTCALLBACK lpeecb,
+                                  const char *name, DISPID *r_dispid);
+int put_outlook_property (void *pEECB, const char *key, const char *value);
+int put_outlook_property_int (void *pEECB, const char *key, int value);
+char *get_outlook_property (void *pEECB, const char *key);
+
+
+#endif /*OL_EXT_CALLBACK_H*/
index 94e61f3..a67cebb 100644 (file)
 #ifndef OLFLANGE_DEF_H
 #define OLFLANGE_DEF_H
 
-class CGPGExchExtMessageEvents;
-class CGPGExchExtCommands;
-class CGPGExchExtPropertySheets;
-class CGPGExchExtAttachedFileEvents;
+class GpgolExtCommands;
+class GpgolSessionEvents;
+class GpgolMessageEvents;
+class GpgolAttachedFileEvents;
+class GpgolPropertySheets;
 
 bool GPGOptionsDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
index e9d1971..b796f09 100644 (file)
@@ -1,15 +1,15 @@
 /* olflange.cpp - Flange between Outlook and the GpgMsg class
  *     Copyright (C) 2001 G Data Software AG, http://www.gdata.de
- *     Copyright (C) 2004, 2005 g10 Code GmbH
+ *     Copyright (C) 2004, 2005, 2007 g10 Code GmbH
  * 
- * This file is part of GPGol.
+ * This file is part of GpgOL.
  * 
- * GPGol is free software; you can redistribute it and/or
+ * GpgOL is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
- * GPGol is distributed in the hope that it will be useful,
+ * GpgOL is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU Lesser General Public License for more details.
 #include "gpgmsg.hh"
 #include "msgcache.h"
 #include "engine.h"
+#include "mapihelp.h"
 
 #include "olflange-ids.h"
 #include "olflange-def.h"
 #include "olflange.h"
-#include "attach.h"
+#include "ext-commands.h"
+#include "session-events.h"
+#include "message-events.h"
+#include "property-sheets.h"
+#include "attached-file-events.h"
+
 
 #define CLSIDSTR_GPGOL   "{42d30988-1a3a-11da-c687-000d6080e735}"
 DEFINE_GUID(CLSID_GPGOL, 0x42d30988, 0x1a3a, 0x11da, 
@@ -55,11 +61,37 @@ DEFINE_GUID(CLSID_GPGOL, 0x42d30988, 0x1a3a, 0x11da,
                         } while (0)
 
 
-bool g_initdll = FALSE;
+static bool g_initdll = FALSE;
+
 
-static HWND show_window_hierarchy (HWND parent, int level);
+
+\f
+/* Return a string for the context NO.  This never return NULL. */
+const char *
+ext_context_name (unsigned long no)
+{
+  switch (no)
+    {
+    case EECONTEXT_SESSION:           return "Session";
+    case EECONTEXT_VIEWER:            return "Viewer";
+    case EECONTEXT_REMOTEVIEWER:      return "RemoteViewer";
+    case EECONTEXT_SEARCHVIEWER:      return "SearchViewer";
+    case EECONTEXT_ADDRBOOK:          return "AddrBook";
+    case EECONTEXT_SENDNOTEMESSAGE:   return "SendNoteMessage";
+    case EECONTEXT_READNOTEMESSAGE:   return "ReadNoteMessage";
+    case EECONTEXT_SENDPOSTMESSAGE:   return "SendPostMessage";
+    case EECONTEXT_READPOSTMESSAGE:   return "ReadPostMessage";
+    case EECONTEXT_READREPORTMESSAGE: return "ReadReportMessage";
+    case EECONTEXT_SENDRESENDMESSAGE: return "SendResendMessage";
+    case EECONTEXT_PROPERTYSHEETS:    return "PropertySheets";
+    case EECONTEXT_ADVANCEDCRITERIA:  return "AdvancedCriteria";
+    case EECONTEXT_TASK:              return "Task";
+    default: return "?";
+    }
+}
 
 
+\f
 /* Registers this module as an Exchange extension. This basically updates
    some Registry entries. */
 STDAPI 
@@ -91,13 +123,27 @@ DllRegisterServer (void)
      7         EECONTEXT_READNOTEMESSAGE
      8         EECONTEXT_SENDPOSTMESSAGE
      9         EECONTEXT_READPOSTMESSAGE
-     10 EECONTEXT_READREPORTMESSAGE
-     11 EECONTEXT_SENDRESENDMESSAGE
-     12 EECONTEXT_PROPERTYSHEETS
-     13 EECONTEXT_ADVANCEDCRITERIA
-     14 EECONTEXT_TASK
-  */
+      EECONTEXT_READREPORTMESSAGE
+      EECONTEXT_SENDRESENDMESSAGE
+      EECONTEXT_PROPERTYSHEETS
+      EECONTEXT_ADVANCEDCRITERIA
+      EECONTEXT_TASK
+                   ___123456789abcde___ */                 
   lstrcat (szEntry, ";11000111111100"); 
+  /* Interfaces to we want to hook into:
+     pos  interface
+     1    IExchExtCommands            
+     2    IExchExtUserEvents          
+     3    IExchExtSessionEvents       
+     4    IExchExtMessageEvents       
+     5    IExchExtAttachedFileEvents  
+     6    IExchExtPropertySheets      
+     7    IExchExtAdvancedCriteria    
+     -    IExchExt              
+     -    IExchExtModeless
+     -    IExchExtModelessCallback
+                   ___1234567___ */
+  lstrcat (szEntry, ";1111110"); 
   ec = RegCreateKeyEx (HKEY_LOCAL_MACHINE, szKeyBuf, 0, NULL, 
                        REG_OPTION_NON_VOLATILE,
                        KEY_ALL_ACCESS, NULL, &hkey, NULL);
@@ -199,378 +245,44 @@ DllUnregisterServer (void)
   return S_OK;
 }
 
-/* Wrapper around UlRelease with error checking. */
-static void 
-ul_release (LPVOID punk)
-{
-  ULONG res;
-  
-  if (!punk)
-    return;
-  res = UlRelease (punk);
-//   log_debug ("%s UlRelease(%p) had %lu references\n", __func__, punk, res);
-}
-
-
-
-/* DISPLAY a MAPI property. */
-static void
-show_mapi_property (LPMESSAGE message, ULONG prop, const char *propname)
-{
-  HRESULT hr;
-  LPSPropValue lpspvFEID = NULL;
-  size_t keylen;
-  void *key;
-
-  if (!message)
-    return; /* No message: Nop. */
-
-  hr = HrGetOneProp ((LPMAPIPROP)message, prop, &lpspvFEID);
-  if (FAILED (hr))
-    {
-      log_debug ("%s: HrGetOneProp(%s) failed: hr=%#lx\n",
-                 __func__, propname, hr);
-      return;
-    }
-    
-  if ( PROP_TYPE (lpspvFEID->ulPropTag) != PT_BINARY )
-    {
-      log_debug ("%s: HrGetOneProp(%s) returned unexpected property type\n",
-                 __func__, propname);
-      MAPIFreeBuffer (lpspvFEID);
-      return;
-    }
-  keylen = lpspvFEID->Value.bin.cb;
-  key = lpspvFEID->Value.bin.lpb;
-  log_hexdump (key, keylen, "%s: %20s=", __func__, propname);
-  MAPIFreeBuffer (lpspvFEID);
-}
-
-
-
-/* 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;
-
-  log_debug ("%s:%s: looking for `%s'\n", SRCNAME, __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);
-      //log_debug ("   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". */
-      //log_debug ("%s:%s: %.*s=%p  (hr=0x%x)\n",
-      //           SRCNAME, __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);
-  //log_debug ("   dispid(%s)=%d  (hr=0x%x)\n", name, dispid, hr);
-  if (r_dispid)
-    *r_dispid = dispid;
-
-  log_debug ("%s:%s:    got IDispatch=%p dispid=%u\n",
-            SRCNAME, __func__, pDisp, (unsigned int)dispid);
-  return pDisp;
-}
-
-
-/* Return Outlook's Application object. */
-/* FIXME: We should be able to fold most of the code into
-   find_outlook_property. */
-#if 0 /* Not used as of now. */
-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);
-      log_debug ("%s:%s: Outlookcallback returned object of class=%d\n",
-                   SRCNAME, __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);
-      //log_debug ("   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;
-      //log_debug ("%s:%s: Outlook.Application=%p\n",
-      //             SRCNAME, __func__, pUnk);
-      pDisp->Release();
-      pDisp = NULL;
-    }
-  return pUnk;
-}
-#endif /* commented */
-
-
-int
-put_outlook_property (void *pEECB, const char *key, const char *value)
-{
-  int result = -1;
-  HRESULT hr;
-  LPMDB pMDB = NULL;
-  LPMESSAGE pMessage = NULL;
-  LPDISPATCH pDisp;
-  DISPID dispid;
-  DISPID dispid_put = DISPID_PROPERTYPUT;
-  DISPPARAMS dispparams;
-  VARIANT aVariant;
 
-  if (!pEECB)
-    return -1;
-
-  hr = ((LPEXCHEXTCALLBACK)pEECB)->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
-  if (FAILED (hr))
-    log_debug ("%s:%s: getObject failed: hr=%#lx\n", SRCNAME, __func__, hr);
-  else if ( (pDisp = find_outlook_property ((LPEXCHEXTCALLBACK)pEECB,
-                                            key, &dispid)))
-    {
-      BSTR abstr;
-
-      dispparams.cNamedArgs = 1;
-      dispparams.rgdispidNamedArgs = &dispid_put;
-      dispparams.cArgs = 1;
-      dispparams.rgvarg = &aVariant;
-      {
-        wchar_t *tmp = utf8_to_wchar (value);
-        abstr = SysAllocString (tmp);
-        xfree (tmp);
-      }
-      if (!abstr)
-        log_error ("%s:%s: SysAllocString failed\n", SRCNAME, __func__);
-      else
-        {
-          dispparams.rgvarg[0].vt = VT_BSTR;
-          dispparams.rgvarg[0].bstrVal = abstr;
-          hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
-                              DISPATCH_PROPERTYPUT, &dispparams,
-                              NULL, NULL, NULL);
-          log_debug ("%s:%s: PROPERTYPUT(%s) result -> %#lx\n",
-                     SRCNAME, __func__, key, hr);
-          SysFreeString (abstr);
-        }
-      
-      pDisp->Release ();
-      pDisp = NULL;
-      result = 0;
-    }
-
-  ul_release (pMessage);
-  ul_release (pMDB);
-  return result;
-}
-
-int
-put_outlook_property_int (void *pEECB, const char *key, int value)
-{
-  int result = -1;
-  HRESULT hr;
-  LPMDB pMDB = NULL;
-  LPMESSAGE pMessage = NULL;
-  LPDISPATCH pDisp;
-  DISPID dispid;
-  DISPID dispid_put = DISPID_PROPERTYPUT;
-  DISPPARAMS dispparams;
-  VARIANT aVariant;
-
-  if (!pEECB)
-    return -1;
-
-  hr = ((LPEXCHEXTCALLBACK)pEECB)->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
-  if (FAILED (hr))
-    log_debug ("%s:%s: getObject failed: hr=%#lx\n", SRCNAME, __func__, hr);
-  else if ( (pDisp = find_outlook_property ((LPEXCHEXTCALLBACK)pEECB,
-                                            key, &dispid)))
-    {
-      dispparams.cNamedArgs = 1;
-      dispparams.rgdispidNamedArgs = &dispid_put;
-      dispparams.cArgs = 1;
-      dispparams.rgvarg = &aVariant;
-      dispparams.rgvarg[0].vt = VT_I4;
-      dispparams.rgvarg[0].intVal = value;
-      hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
-                         DISPATCH_PROPERTYPUT, &dispparams,
-                         NULL, NULL, NULL);
-      log_debug ("%s:%s: PROPERTYPUT(%s) result -> %#lx\n",
-                 SRCNAME, __func__, key, hr);
-
-      pDisp->Release ();
-      pDisp = NULL;
-      result = 0;
-    }
-
-  ul_release (pMessage);
-  ul_release (pMDB);
-  return result;
-}
 
-
-/* Retuirn an Outlook OO property anmed KEY.  This needs to be some
-   kind of string. PEECP is required to indificate the context.  On
-   error NULL is returned.   It is usually used with "Body". */
-char *
-get_outlook_property (void *pEECB, const char *key)
-{
-  char *result = NULL;
-  HRESULT hr;
-  LPDISPATCH pDisp;
-  DISPID dispid;
-  DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
-  VARIANT aVariant;
-
-  if (!pEECB)
-    return NULL;
-
-  pDisp = find_outlook_property ((LPEXCHEXTCALLBACK)pEECB, key, &dispid);
-  if (!pDisp)
-    return NULL;
-
-  aVariant.bstrVal = NULL;
-  hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
-                      DISPATCH_PROPERTYGET, &dispparamsNoArgs,
-                      &aVariant, NULL, NULL);
-  if (hr != S_OK)
-    log_debug ("%s:%s: retrieving `%s' failed: %#lx",
-               SRCNAME, __func__, key, hr);
-  else if (aVariant.vt != VT_BSTR)
-    log_debug ("%s:%s: `%s' is not a string (%d)",
-                           SRCNAME, __func__, key, aVariant.vt);
-  else if (aVariant.bstrVal)
-    {
-      result = wchar_to_utf8 (aVariant.bstrVal);
-      log_debug ("%s:%s: `%s' is `%s'",
-                 SRCNAME, __func__, key, result);
-      /* From MSDN (Invoke): It is up to the caller to free the return value.*/
-      SysFreeString (aVariant.bstrVal);
-    }
-
-  pDisp->Release();
-  pDisp = NULL;
-
-  return result;
-}
-
-
-
-/* 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. */
+\f
+/* The entry point which Exchange/Outlook calls.  This is called for
+   each context entry.  Creates a new GpgolExt object every time so
+   each context will get its own GpgolExt interface. */
 EXTERN_C LPEXCHEXT __stdcall
 ExchEntryPoint (void)
 {
-  log_debug ("%s:%s: creating new CGPGExchExt object\n", SRCNAME, __func__);
-  return new CGPGExchExt;
+  log_debug ("%s:%s: creating new GpgolExt object\n", SRCNAME, __func__);
+  return new GpgolExt;
 }
 
 
-/* Constructor of CGPGExchExt
+
+/* Constructor of GpgolExt
 
    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)
+GpgolExt::GpgolExt (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);
-  m_pExchExtAttachedFileEvents = new CGPGExchExtAttachedFileEvents (this);
-  if (!m_pExchExtMessageEvents || !m_pExchExtCommands
-      || !m_pExchExtPropertySheets || !m_pExchExtAttachedFileEvents)
+
+  m_pExchExtCommands           = new GpgolExtCommands (this);
+  m_pExchExtSessionEvents      = new GpgolSessionEvents (this);
+  m_pExchExtMessageEvents      = new GpgolMessageEvents (this);
+  m_pExchExtAttachedFileEvents = new GpgolAttachedFileEvents (this);
+  m_pExchExtPropertySheets     = new GpgolPropertySheets (this);
+  if (!m_pExchExtCommands
+      || !m_pExchExtSessionEvents
+      || !m_pExchExtMessageEvents
+      || !m_pExchExtAttachedFileEvents
+      || !m_pExchExtPropertySheets)
     out_of_core ();
   
   if (!g_initdll)
@@ -587,26 +299,11 @@ CGPGExchExt::CGPGExchExt (void)
 
 
 /*  Uninitializes the DLL in the session context. */
-CGPGExchExt::~CGPGExchExt (void) 
+GpgolExt::~GpgolExt (void) 
 {
-  log_debug ("%s:%s: cleaning up CGPGExchExt object; "
-             "context=0x%lx (%s)\n", SRCNAME, __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" : ""));
-  
+  log_debug ("%s:%s: cleaning up GpgolExt object; context=%s\n",
+             SRCNAME, __func__, ext_context_name (m_lContext));
+    
   if (m_lContext == EECONTEXT_SESSION)
     {
       if (g_initdll)
@@ -628,7 +325,7 @@ CGPGExchExt::~CGPGExchExt (void)
    this class defines the requested interface.  Return value: S_OK if
    the interface is supported, otherwise E_NOINTERFACE. */
 STDMETHODIMP 
-CGPGExchExt::QueryInterface(REFIID riid, LPVOID *ppvObj)
+GpgolExt::QueryInterface(REFIID riid, LPVOID *ppvObj)
 {
   HRESULT hr = S_OK;
   
@@ -638,36 +335,40 @@ CGPGExchExt::QueryInterface(REFIID riid, LPVOID *ppvObj)
     {
       *ppvObj = (LPUNKNOWN) this;
     }
+  else if (riid == IID_IExchExtCommands) 
+    {
+      *ppvObj = (LPUNKNOWN)m_pExchExtCommands;
+      m_pExchExtCommands->SetContext (m_lContext);
+    }
+  else if (riid == IID_IExchExtSessionEvents) 
+    {
+      *ppvObj = (LPUNKNOWN) m_pExchExtSessionEvents;
+      m_pExchExtSessionEvents->SetContext (m_lContext);
+    }
   else if (riid == IID_IExchExtMessageEvents) 
     {
       *ppvObj = (LPUNKNOWN) m_pExchExtMessageEvents;
       m_pExchExtMessageEvents->SetContext (m_lContext);
     }
-  else if (riid == IID_IExchExtCommands) 
+  else if (riid == IID_IExchExtAttachedFileEvents)
     {
-      *ppvObj = (LPUNKNOWN)m_pExchExtCommands;
-      m_pExchExtCommands->SetContext (m_lContext);
-    }
+      *ppvObj = (LPUNKNOWN)m_pExchExtAttachedFileEvents;
+    }  
   else if (riid == IID_IExchExtPropertySheets) 
     {
       if (m_lContext != EECONTEXT_PROPERTYSHEETS)
        return E_NOINTERFACE;
       *ppvObj = (LPUNKNOWN) m_pExchExtPropertySheets;
     }
-  else if (riid == IID_IExchExtAttachedFileEvents)
-    {
-      *ppvObj = (LPUNKNOWN)m_pExchExtAttachedFileEvents;
-    }  
   else
     hr = E_NOINTERFACE;
   
   /* On success we need to bump up the reference counter for the
-   requested object. */
+     requested object. */
   if (*ppvObj)
     ((LPUNKNOWN)*ppvObj)->AddRef();
   
-  /*log_debug("QueryInterface %d\n", __LINE__);*/
-    return hr;
+  return hr;
 }
 
 
@@ -679,7 +380,7 @@ CGPGExchExt::QueryInterface(REFIID riid, LPVOID *ppvObj)
    indicate whether the extension should be installed modal.
 */
 STDMETHODIMP 
-CGPGExchExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
+GpgolExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
 {
   ULONG lBuildVersion;
   ULONG lActualVersion;
@@ -688,41 +389,26 @@ CGPGExchExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
   /* Save the context in an instance variable. */
   m_lContext = lContext;
 
-  log_debug ("%s:%s: context=0x%lx (%s) flags=0x%lx\n", SRCNAME, __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);
+  log_debug ("%s:%s: context=%s flags=0x%lx\n", SRCNAME, __func__,
+             ext_context_name (lContext), lFlags);
   
   /* Check version. */
-  log_debug ("GPGol: this is %s\n", PACKAGE_STRING);
+  log_debug ("%s:%s: this is %s\n", SRCNAME, __func__, PACKAGE_STRING);
   pEECB->GetVersion (&lBuildVersion, EECBGV_GETBUILDVERSION);
   pEECB->GetVersion (&lActualVersion, EECBGV_GETACTUALVERSION);
   pEECB->GetVersion (&lVirtualVersion, EECBGV_GETVIRTUALVERSION);
-  log_debug ("GPGol: detected Outlook build version 0x%lx (%lu.%lu)\n",
-             lBuildVersion,
+  log_debug ("%s:%s: detected Outlook build version 0x%lx (%lu.%lu)\n",
+             SRCNAME, __func__, lBuildVersion,
              (lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK) >> 16,
              (lBuildVersion & EECBGV_BUILDVERSION_MINOR_MASK));
-  log_debug ("GPGol:                 actual version 0x%lx (%u.%u.%u.%u)\n",
-             lActualVersion, 
+  log_debug ("%s:%s:                 actual version 0x%lx (%u.%u.%u.%u)\n",
+             SRCNAME, __func__, lActualVersion, 
              (unsigned int)((lActualVersion >> 24) & 0xff),
              (unsigned int)((lActualVersion >> 16) & 0xff),
              (unsigned int)((lActualVersion >> 8) & 0xff),
              (unsigned int)(lActualVersion & 0xff));
-  log_debug ("GPGol:                virtual version 0x%lx (%u.%u.%u.%u)\n",
-             lVirtualVersion, 
+  log_debug ("%s:%s:                virtual version 0x%lx (%u.%u.%u.%u)\n",
+             SRCNAME, __func__, lVirtualVersion, 
              (unsigned int)((lVirtualVersion >> 24) & 0xff),
              (unsigned int)((lVirtualVersion >> 16) & 0xff),
              (unsigned int)((lVirtualVersion >> 8) & 0xff),
@@ -732,7 +418,7 @@ CGPGExchExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
       != (lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK))
     {
       log_debug ("%s:%s: invalid version 0x%lx\n",
-                   SRCNAME, __func__, lBuildVersion);
+                 SRCNAME, __func__, lBuildVersion);
       return S_FALSE;
     }
   if ((lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK) < 13
@@ -754,7 +440,7 @@ CGPGExchExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
                         "might get stuck in the outgoing queue.\n\n"
                         "Please update at least to SP2 before trying to send "
                         "a message"),
-                      "GPGol", MB_ICONSTOP|MB_OK);
+                      "GpgOL", MB_ICONSTOP|MB_OK);
         }
     }
   
@@ -767,7 +453,8 @@ CGPGExchExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
       || lContext == EECONTEXT_READNOTEMESSAGE
       || lContext == EECONTEXT_READPOSTMESSAGE
       || lContext == EECONTEXT_READREPORTMESSAGE
-      || lContext == EECONTEXT_VIEWER)
+      || lContext == EECONTEXT_VIEWER
+      || lContext == EECONTEXT_SESSION)
     {
 //       LPUNKNOWN pApplication = get_outlook_application_object (pEECB);
 //       log_debug ("%s:%s: pApplication=%p\n",
@@ -781,1095 +468,4 @@ CGPGExchExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
 
 
 
-CGPGExchExtMessageEvents::CGPGExchExtMessageEvents 
-                                              (CGPGExchExt *pParentInterface)
-{ 
-  m_pExchExt = pParentInterface;
-  m_lRef = 0; 
-  m_bOnSubmitActive = FALSE;
-  m_want_html = FALSE;
-}
-
-
-STDMETHODIMP 
-CGPGExchExtMessageEvents::QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
-{   
-    *ppvObj = NULL;
-    if (riid == IID_IExchExtMessageEvents) {
-        *ppvObj = (LPVOID)this;
-        AddRef();
-        return S_OK;
-    }
-    if (riid == IID_IUnknown) {
-        *ppvObj = (LPVOID)m_pExchExt;  
-        m_pExchExt->AddRef();
-        return S_OK;
-    }
-    return E_NOINTERFACE;
-}
-
-
-/* Called from 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) 
-{
-  LPMDB pMDB = NULL;
-  LPMESSAGE pMessage = NULL;
-
-  log_debug ("%s:%s: received\n", SRCNAME, __func__);
-  pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
-  show_mapi_property (pMessage, PR_CONVERSATION_INDEX,"PR_CONVERSATION_INDEX");
-  ul_release (pMessage);
-  ul_release (pMDB);
-
-  return S_FALSE;
-}
-
-
-/* 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)
-{
-  log_debug ("%s:%s: received\n", SRCNAME, __func__);
-
-  /* The preview_info stuff does not work because for some reasons we
-     can't update the window.  Thus disabled for now. */
-  if (opt.preview_decrypt /*|| !opt.compat.no_preview_info*/)
-    {
-      HRESULT hr;
-      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))
-        {
-          GpgMsg *m = CreateGpgMsg (pMessage);
-          m->setExchangeCallback ((void*)pEECB);
-          m->setPreview (1);
-          /* If preview decryption has been requested, do so.  If not,
-             pass true as the second arg to let the fucntion display a
-             hint on what kind of message this is. */
-          m->decrypt (hWnd, !opt.preview_decrypt);
-          delete m;
-       }
-      ul_release (pMessage);
-      ul_release (pMDB);
-    }
-
-
-#if 0
-    {
-      HWND hWnd = NULL;
-
-      if (FAILED (pEECB->GetWindow (&hWnd)))
-        hWnd = NULL;
-      else
-        show_window_hierarchy (hWnd, 0);
-    }
-#endif
-
-  return S_FALSE;
-}
-
-
-/* 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)
-{
-  log_debug ("%s:%s: received\n", SRCNAME, __func__);
-
-  HRESULT hr;
-  LPDISPATCH pDisp;
-  DISPID dispid;
-  VARIANT aVariant;
-  DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
-  HWND hWnd = NULL;
-
-
-  /* If we are going to encrypt, check that the BodyFormat is
-     something we support.  This helps avoiding surprise by sending
-     out unencrypted messages. */
-  if (m_pExchExt->m_gpgEncrypt || m_pExchExt->m_gpgSign)
-    {
-      pDisp = find_outlook_property (pEECB, "BodyFormat", &dispid);
-      if (!pDisp)
-        {
-          log_debug ("%s:%s: BodyFormat not found\n", SRCNAME, __func__);
-          m_bWriteFailed = TRUE;       
-          return E_FAIL;
-        }
-      
-      aVariant.bstrVal = NULL;
-      hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
-                          DISPATCH_PROPERTYGET, &dispparamsNoArgs,
-                          &aVariant, NULL, NULL);
-      if (hr != S_OK)
-        {
-          log_debug ("%s:%s: retrieving BodyFormat failed: %#lx",
-                     SRCNAME, __func__, hr);
-          m_bWriteFailed = TRUE;       
-          pDisp->Release();
-          return E_FAIL;
-        }
-  
-      if (aVariant.vt != VT_INT && aVariant.vt != VT_I4)
-        {
-          log_debug ("%s:%s: BodyFormat is not an integer (%d)",
-                     SRCNAME, __func__, aVariant.vt);
-          m_bWriteFailed = TRUE;       
-          pDisp->Release();
-          return E_FAIL;
-        }
-  
-      if (aVariant.intVal == 1)
-        m_want_html = 0;
-      else if (aVariant.intVal == 2)
-        m_want_html = 1;
-      else
-        {
-
-          log_debug ("%s:%s: BodyFormat is %d",
-                     SRCNAME, __func__, aVariant.intVal);
-          
-          if (FAILED(pEECB->GetWindow (&hWnd)))
-            hWnd = NULL;
-          MessageBox (hWnd,
-                      _("Sorry, we can only encrypt plain text messages and\n"
-                      "no RTF messages. Please make sure that only the text\n"
-                      "format has been selected."),
-                      "GPGol", MB_ICONERROR|MB_OK);
-
-          m_bWriteFailed = TRUE;       
-          pDisp->Release();
-          return E_FAIL;
-        }
-      pDisp->Release();
-      
-    }
-  
-  
-  return S_FALSE;
-}
-
-
-/* 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.  We return E_FAIL
-   to signals Exchange an error; the message will not be sent.  Note
-   that we don't return S_OK because this would mean that we rolled
-   back the write operation and that no further extensions should be
-   called. */
-STDMETHODIMP 
-CGPGExchExtMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB,
-                                           ULONG lFlags)
-{
-  log_debug ("%s:%s: received\n", SRCNAME, __func__);
-
-  HRESULT hrReturn = S_FALSE;
-  LPMESSAGE msg = NULL;
-  LPMDB pMDB = NULL;
-  HWND hWnd = NULL;
-  int rc;
-
-  if (lFlags & (EEME_FAILED|EEME_COMPLETE_FAILED))
-    return S_FALSE; /* We don't need to rollback anything in case
-                       other extensions flagged a failure. */
-          
-  if (!m_bOnSubmitActive) /* The user is just saving the message. */
-    return S_FALSE;
-  
-  if (m_bWriteFailed)     /* Operation failed already. */
-    return S_FALSE;
-  
-  if (FAILED(pEECB->GetWindow (&hWnd)))
-    hWnd = NULL;
-
-  HRESULT hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&msg);
-  if (SUCCEEDED (hr))
-    {
-//      SPropTagArray proparray;
-
-      GpgMsg *m = CreateGpgMsg (msg);
-      m->setExchangeCallback ((void*)pEECB);
-      if (m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
-        rc = m->signEncrypt (hWnd, m_want_html);
-      else if (m_pExchExt->m_gpgEncrypt && !m_pExchExt->m_gpgSign)
-        rc = m->encrypt (hWnd, m_want_html);
-      else if (!m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
-        rc = m->sign (hWnd, m_want_html);
-      else
-        rc = 0;
-      delete m;
-
-      /* If we are encrypting we need to make sure that the other
-         format gets deleted and is not actually sent in the clear.
-         Note that this other format is always HTML because we have
-         moved that into an attachment and kept PR_BODY.  It seems
-         that OL always creates text and HTML if HTML has been
-         selected. */
-      /* ARGHH: This seems to delete also the PR_BODY for some reasonh
-         - need to disable this safe net. */
-//       if (m_pExchExt->m_gpgEncrypt)
-//         {
-//           log_debug ("%s:%s: deleting possible extra property PR_BODY_HTML\n",
-//                      SRCNAME, __func__);
-//           proparray.cValues = 1;
-//           proparray.aulPropTag[0] = PR_BODY_HTML;
-//           msg->DeleteProps (&proparray, NULL);
-//         }
-     
-      if (rc)
-        {
-          hrReturn = E_FAIL;
-          m_bWriteFailed = TRUE;       
-
-         /* Outlook should now correctly react and do not deliver
-            the message in case of an error.
-          */
-         #if 0
-          if (m_pExchExt->m_gpgEncrypt)
-            {
-              log_debug ("%s:%s: deleting property PR_BODY due to error\n",
-                         SRCNAME, __func__);
-              proparray.cValues = 1;
-              proparray.aulPropTag[0] = PR_BODY;
-              hr = msg->DeleteProps (&proparray, NULL);
-              if (hr != S_OK)
-                log_debug ("%s:%s: DeleteProps failed: hr=%#lx\n",
-                           SRCNAME, __func__, hr);
-              /* FIXME: We should delete the attachments too. 
-                 We really, really should do this!!!          */
-            }
-          #endif
-        }
-    }
-
-  ul_release (msg);
-  ul_release (pMDB);
-
-  return hrReturn;
-}
-
-/* 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)
-{
-  log_debug ("%s:%s: received\n", SRCNAME, __func__);
-  return S_FALSE;
-}
-
-
-/* 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)
-{
-  log_debug ("%s:%s: received\n", SRCNAME, __func__);
-  return S_FALSE;
-}
-
-
-/* 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)
-{
-  log_debug ("%s:%s: received\n", SRCNAME, __func__);
-  m_bOnSubmitActive = TRUE;
-  m_bWriteFailed = FALSE;
-  return S_FALSE;
-}
-
-
-/* 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)
-{
-  log_debug ("%s:%s: received\n", SRCNAME, __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; 
-}
-
-
-
-STDMETHODIMP 
-CGPGExchExtCommands::QueryInterface (REFIID riid, LPVOID FAR * ppvObj)
-{
-    *ppvObj = NULL;
-    if ((riid == IID_IExchExtCommands) || (riid == IID_IUnknown)) {
-        *ppvObj = (LPVOID)this;
-        AddRef ();
-        return S_OK;
-    }
-    return E_NOINTERFACE;
-}
-
-
-static HWND
-show_window_hierarchy (HWND parent, int level)
-{
-  HWND child;
-
-  child = GetWindow (parent, GW_CHILD);
-  while (child)
-    {
-      char buf[1024+1];
-      char name[200];
-      int nname;
-      char *pname;
-      
-      memset (buf, 0, sizeof (buf));
-      GetWindowText (child, buf, sizeof (buf)-1);
-      nname = GetClassName (child, name, sizeof (name)-1);
-      if (nname)
-        pname = name;
-      else
-        pname = NULL;
-      log_debug ("XXX %*shwnd=%p (%s) `%s'", level*2, "", child,
-                 pname? pname:"", buf);
-      show_window_hierarchy (child, level+1);
-      child = GetNextWindow (child, GW_HWNDNEXT);      
-    }
-
-  return NULL;
-}
-
-
-/* Called by Exchange 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 the main window
-                                 // of context.
-       HMENU hMenu,             // The menu handle to main menu of context.
-       UINT FAR * pnCommandIDBase,  // The base command id.
-       LPTBENTRY pTBEArray,     // The array of toolbar button entries.
-       UINT nTBECnt,            // The count of button entries in array.
-       ULONG lFlags)            // reserved
-{
-  HRESULT hr;
-  HMENU hMenuTools;
-  m_hWnd = hWnd;
-  LPDISPATCH pDisp;
-  DISPID dispid;
-  DISPID dispid_put = DISPID_PROPERTYPUT;
-  DISPPARAMS dispparams;
-  VARIANT aVariant;
-  int force_encrypt = 0;
-  
-  log_debug ("%s:%s: context=0x%lx (%s) flags=0x%lx\n", SRCNAME, __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 size 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 ConversationIndex property.
-
-     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 because this would pop up the securiy window, telling the
-     user that someone is trying to read this data.
-  */
-  if (m_lContext == EECONTEXT_SENDNOTEMESSAGE)
-    {
-      LPMDB pMDB = NULL;
-      LPMESSAGE pMessage = NULL;
-      
-      /*  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))
-        log_debug ("%s:%s: getObject failed: hr=%#lx\n", SRCNAME,__func__,hr);
-      else if (!opt.compat.no_msgcache)
-        {
-          const char *body;
-          char *key = NULL;
-          size_t keylen = 0;
-          void *refhandle = NULL;
-     
-          pDisp = find_outlook_property (pEECB, "ConversationIndex", &dispid);
-          if (pDisp)
-            {
-              DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
-
-              aVariant.bstrVal = NULL;
-              hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
-                                  DISPATCH_PROPERTYGET, &dispparamsNoArgs,
-                                  &aVariant, NULL, NULL);
-              if (hr != S_OK)
-                log_debug ("%s:%s: retrieving ConversationIndex failed: %#lx",
-                           SRCNAME, __func__, hr);
-              else if (aVariant.vt != VT_BSTR)
-                log_debug ("%s:%s: ConversationIndex is not a string (%d)",
-                           SRCNAME, __func__, aVariant.vt);
-              else if (aVariant.bstrVal)
-                {
-                  char *p;
-
-                  key = wchar_to_utf8 (aVariant.bstrVal);
-                  log_debug ("%s:%s: ConversationIndex is `%s'",
-                           SRCNAME, __func__, key);
-                  /* The key is a hex string.  Convert it to binary. */
-                  for (keylen=0,p=key; hexdigitp(p) && hexdigitp(p+1); p += 2)
-                    ((unsigned char*)key)[keylen++] = xtoi_2 (p);
-                  
-                 SysFreeString (aVariant.bstrVal);
-                }
-
-              pDisp->Release();
-              pDisp = NULL;
-            }
-          
-          if (key && keylen
-              && (body = msgcache_get (key, keylen, &refhandle)) 
-              && (pDisp = find_outlook_property (pEECB, "Body", &dispid)))
-            {
-#if 1
-              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);
-              log_debug ("%s:%s: PROPERTYPUT(body) result -> %#lx\n",
-                         SRCNAME, __func__, hr);
-#else
-              log_debug ("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
-              show_window_hierarchy (hWnd, 0);
-#endif
-              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;
-            }
-          msgcache_unref (refhandle);
-          xfree (key);
-        }
-      
-      ul_release (pMessage);
-      ul_release (pMDB);
-    }
-
-
-
-  /* XXX: factor out common code */
-  if (m_lContext == EECONTEXT_READNOTEMESSAGE)
-    {
-      int nTBIndex;
-      HWND hwndToolbar = NULL;
-
-      if (opt.compat.auto_decrypt)
-        watcher_set_callback_ctx ((void *)pEECB);
-      pEECB->GetMenuPos (EECMDID_ToolsCustomizeToolbar, &hMenuTools,
-                         NULL, NULL, 0);
-      AppendMenu (hMenuTools, MF_SEPARATOR, 0, NULL);
-       
-      AppendMenu (hMenuTools, MF_BYPOSITION | MF_STRING,
-                  *pnCommandIDBase, _("&Decrypt and verify message"));
-
-      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_DECRYPT;
-          m_nToolbarBitmap1 = SendMessage(hwndToolbar, TB_ADDBITMAP,
-                                          1, (LPARAM)&tbab);
-          m_nToolbarButtonID2 = pTBEArray[nTBIndex].itbbBase;
-          pTBEArray[nTBIndex].itbbBase++;
-        }
-    }
-
-  if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) 
-    {
-      int nTBIndex;
-      HWND hwndToolbar = NULL;
-
-      pEECB->GetMenuPos(EECMDID_ToolsCustomizeToolbar, &hMenuTools,
-                        NULL, NULL, 0);
-      AppendMenu(hMenuTools, MF_SEPARATOR, 0, NULL);
-       
-      AppendMenu(hMenuTools, MF_STRING,
-                 *pnCommandIDBase, _("GPG &encrypt message"));
-
-      m_nCmdEncrypt = *pnCommandIDBase;
-      (*pnCommandIDBase)++;
-
-      AppendMenu(hMenuTools, MF_STRING,
-                 *pnCommandIDBase, _("GPG &sign message"));
-
-      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 = opt.encrypt_default;
-      m_pExchExt->m_gpgSign    = opt.sign_default;
-      if (force_encrypt)
-        m_pExchExt->m_gpgEncrypt = true;
-    }
-
-  if (m_lContext == EECONTEXT_VIEWER) 
-    {
-      int nTBIndex;
-      HWND hwndToolbar = NULL;
-      
-      pEECB->GetMenuPos (EECMDID_ToolsCustomizeToolbar, &hMenuTools,
-                         NULL, NULL, 0);
-      AppendMenu (hMenuTools, MF_SEPARATOR, 0, NULL);
-      
-      AppendMenu (hMenuTools, MF_BYPOSITION | MF_STRING,
-                  *pnCommandIDBase, _("GPG Key &Manager"));
-
-      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);
-        }      
-    }
-  return S_FALSE;
-}
-
-
-/* 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.
-{
-  HRESULT hr;
-
-  log_debug ("%s:%s: commandID=%u (%#x)\n",
-             SRCNAME, __func__, nCommandID, nCommandID);
-  if (nCommandID == SC_CLOSE && m_lContext == EECONTEXT_READNOTEMESSAGE)
-    {
-      /* This is the system close command. Replace it with our own to
-         avoid the "save changes" query, apparently induced by OL
-         internal syncronisation of our SetWindowText message with its
-         own OOM (in this case Body). */
-      LPDISPATCH pDisp;
-      DISPID dispid;
-      DISPPARAMS dispparams;
-      VARIANT aVariant;
-      
-      pDisp = find_outlook_property (pEECB, "Close", &dispid);
-      if (pDisp)
-        {
-          dispparams.rgvarg = &aVariant;
-          dispparams.rgvarg[0].vt = VT_INT;
-          dispparams.rgvarg[0].intVal = 1; /* olDiscard */
-          dispparams.cArgs = 1;
-          dispparams.cNamedArgs = 0;
-          hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
-                              DISPATCH_METHOD, &dispparams,
-                              NULL, NULL, NULL);
-          pDisp->Release();
-          pDisp = NULL;
-          if (hr == S_OK)
-            {
-              log_debug ("%s:%s: invoking Close succeeded", SRCNAME,__func__);
-              return S_OK; /* We handled the close command. */
-            }
-
-          log_debug ("%s:%s: invoking Close failed: %#lx",
-                     SRCNAME, __func__, hr);
-        }
-
-      /* We are not interested in the close command - pass it on. */
-      return S_FALSE; 
-    }
-  else if (nCommandID == 154)
-    {
-      log_debug ("%s:%s: command Reply called\n", SRCNAME, __func__);
-      /* What we might want to do is to call Reply, then GetInspector
-         and then Activate - this allows us to get full control over
-         the quoted message and avoids the ugly msgcache. */
-    }
-  else if (nCommandID == 155)
-    {
-      log_debug ("%s:%s: command ReplyAll called\n", SRCNAME, __func__);
-    }
-  else if (nCommandID == 156)
-    {
-      log_debug ("%s:%s: command Forward called\n", SRCNAME, __func__);
-    }
-  
-
-  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;
-//       else
-//         show_window_hierarchy (hWnd, 0);
-
-      hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
-      if (SUCCEEDED (hr))
-        {
-          if (nCommandID == m_nCmdEncrypt)
-            {
-              GpgMsg *m = CreateGpgMsg (pMessage);
-              m->setExchangeCallback ((void*)pEECB);
-              m->decrypt (hWnd, 0);
-              delete m;
-           }
-       }
-      ul_release (pMessage);
-      ul_release (pMDB);
-    }
-  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;
-    }
-  else if (m_lContext == EECONTEXT_VIEWER)
-    {
-      if (start_key_manager ())
-        MessageBox (NULL, _("Could not start Key-Manager"),
-                    "GPGol", MB_ICONERROR|MB_OK);
-    }
-
-  return S_OK; 
-}
-
-/* Called by Exchange when it receives a WM_INITMENU message, allowing
-   the extension object to enable, disable, or update its menu
-   commands before the user sees them. This method is called
-   frequently and should be written in a very efficient manner. */
-STDMETHODIMP_(VOID) 
-CGPGExchExtCommands::InitMenu(LPEXCHEXTCALLBACK pEECB) 
-{
-#if 0
-  log_debug ("%s:%s: context=0x%lx (%s)\n", SRCNAME, __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" : ""));
-#endif
-}
-
-
-/* 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.
-{
-    if (m_lContext == EECONTEXT_READNOTEMESSAGE) {
-       if (nCommandID == m_nCmdEncrypt) {
-           MessageBox (m_hWnd,
-                        _("Decrypt and verify the message."),
-                        "GPGol", MB_OK);
-           return S_OK;
-       }
-    }
-    if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) {
-       if (nCommandID == m_nCmdEncrypt) {
-           MessageBox(m_hWnd,
-                       _("Select this option to encrypt the message."),
-                       "GPGol", MB_OK);        
-           return S_OK;
-       } 
-       else if (nCommandID == m_nCmdSign) {
-           MessageBox(m_hWnd,
-                       _("Select this option to sign the message."),
-                       "GPGol", MB_OK);        
-           return S_OK;
-       } 
-    }
-
-    if (m_lContext == EECONTEXT_VIEWER) {
-       if (nCommandID == m_nCmdEncrypt) {
-               MessageBox(m_hWnd, 
-                           _("Open GPG Key Manager"),
-                           "GPGol", MB_OK);
-               return S_OK;
-       } 
-    }
-
-    return S_FALSE;
-}
-
-
-/* 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)
-               lstrcpyn (pszText, ".", nCharCnt);
-           if (lFlags == EECQHT_TOOLTIP)
-               lstrcpyn (pszText,
-                          _("Decrypt message and verify signature"),
-                          nCharCnt);
-           return S_OK;
-       }
-    }
-    if (m_lContext == EECONTEXT_SENDNOTEMESSAGE) {
-       if (nCommandID == m_nCmdEncrypt) {
-           if (lFlags == EECQHT_STATUS)
-               lstrcpyn (pszText, ".", nCharCnt);
-           if (lFlags == EECQHT_TOOLTIP)
-               lstrcpyn (pszText,
-                          _("Encrypt message with GPG"),
-                          nCharCnt);
-           return S_OK;
-       }
-       if (nCommandID == m_nCmdSign) {
-           if (lFlags == EECQHT_STATUS)
-               lstrcpyn (pszText, ".", nCharCnt);
-           if (lFlags == EECQHT_TOOLTIP)
-               lstrcpyn (pszText,
-                          _("Sign message with GPG"),
-                          nCharCnt);
-           return S_OK;
-       }
-    }
-    if (m_lContext == EECONTEXT_VIEWER) {
-       if (nCommandID == m_nCmdEncrypt) {
-           if (lFlags == EECQHT_STATUS)
-               lstrcpyn (pszText, ".", nCharCnt);
-           if (lFlags == EECQHT_TOOLTIP)
-               lstrcpyn (pszText,
-                          _("Open GPG Key Manager"),
-                          nCharCnt);
-           return S_OK;
-       }       
-    }
-    return S_FALSE;
-}
-
-
-/* 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).
-       LPTSTR lpszDescription, // A pointer to string describing button.
-       UINT nCharCnt,          // The maximum size of lpsz buffer.
-        ULONG lFlags)           // EXCHEXT_UNICODE may be specified
-{
-       if (m_lContext == EECONTEXT_READNOTEMESSAGE)
-       {
-               if (nToolbarButtonID == m_nToolbarButtonID1)
-               {
-                       pTBB->iBitmap = m_nToolbarBitmap1;             
-                       pTBB->idCommand = m_nCmdEncrypt;
-                       pTBB->fsState = TBSTATE_ENABLED;
-                       pTBB->fsStyle = TBSTYLE_BUTTON;
-                       pTBB->dwData = 0;
-                       pTBB->iString = -1;
-                       lstrcpyn (lpszDescription,
-                                  _("Decrypt message and verify signature"),
-                                  nCharCnt);
-                       return S_OK;
-               }
-       }
-       if (m_lContext == EECONTEXT_SENDNOTEMESSAGE)
-       {
-               if (nToolbarButtonID == m_nToolbarButtonID1)
-               {
-                       pTBB->iBitmap = m_nToolbarBitmap1;             
-                       pTBB->idCommand = m_nCmdEncrypt;
-                       pTBB->fsState = TBSTATE_ENABLED;
-                       if (m_pExchExt->m_gpgEncrypt)
-                               pTBB->fsState |= TBSTATE_CHECKED;
-                       pTBB->fsStyle = TBSTYLE_BUTTON | TBSTYLE_CHECK;
-                       pTBB->dwData = 0;
-                       pTBB->iString = -1;
-                       lstrcpyn (lpszDescription,
-                                  _("Encrypt message with GPG"),
-                                  nCharCnt);
-                       return S_OK;
-               }
-               if (nToolbarButtonID == m_nToolbarButtonID2)
-               {
-                       pTBB->iBitmap = m_nToolbarBitmap2;             
-                       pTBB->idCommand = m_nCmdSign;
-                       pTBB->fsState = TBSTATE_ENABLED;
-                       if (m_pExchExt->m_gpgSign)
-                               pTBB->fsState |= TBSTATE_CHECKED;
-                       pTBB->fsStyle = TBSTYLE_BUTTON | TBSTYLE_CHECK;
-                       pTBB->dwData = 0;
-                       pTBB->iString = -1;
-                       lstrcpyn (lpszDescription,
-                                  _("Sign message with GPG"),
-                                  nCharCnt);
-                       return S_OK;
-               }
-       }
-       if (m_lContext == EECONTEXT_VIEWER)
-       {
-               if (nToolbarButtonID == m_nToolbarButtonID1)
-               {
-                       pTBB->iBitmap = m_nToolbarBitmap1;             
-                       pTBB->idCommand = m_nCmdEncrypt;
-                       pTBB->fsState = TBSTATE_ENABLED;
-                       pTBB->fsStyle = TBSTYLE_BUTTON;
-                       pTBB->dwData = 0;
-                       pTBB->iString = -1;
-                       lstrcpyn (lpszDescription,
-                                  _("Open GPG Key Manager"),
-                                  nCharCnt);
-                       return S_OK;
-               }
-       }
-
-       return S_FALSE;
-}
-
-
-
-STDMETHODIMP 
-CGPGExchExtCommands::ResetToolbar (ULONG lToolbarID, ULONG lFlags)
-{      
-    return S_OK;
-}
-
-
-CGPGExchExtPropertySheets::CGPGExchExtPropertySheets (
-                                    CGPGExchExt* pParentInterface)
-{ 
-    m_pExchExt = pParentInterface;
-    m_lRef = 0; 
-}
-
-
-STDMETHODIMP 
-CGPGExchExtPropertySheets::QueryInterface(REFIID riid, LPVOID FAR * ppvObj)
-{   
-    *ppvObj = NULL;
-    if (riid == IID_IExchExtPropertySheets) {
-        *ppvObj = (LPVOID)this;
-        AddRef();
-        return S_OK;
-    }
-    if (riid == IID_IUnknown) {
-        *ppvObj = (LPVOID)m_pExchExt;
-        m_pExchExt->AddRef();
-        return S_OK;
-    }
-
-    return E_NOINTERFACE;
-}
-
-
-/* Called 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)
-{
-    if (lFlags == EEPS_TOOLSOPTIONS)
-       return 1;       
-    return 0;
-}
-
-
-/* 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 
-                                 //  containing the number of property 
-                                 //  sheets actually used.
-{
-  int resid ;
-
-  if (!strncmp (gettext_localename (), "de", 2))
-    resid = IDD_GPG_OPTIONS_DE;
-  else
-    resid = IDD_GPG_OPTIONS;
-
-  pPSP[0].dwSize = sizeof (PROPSHEETPAGE);
-  pPSP[0].dwFlags = PSP_DEFAULT | PSP_HASHELP;
-  pPSP[0].hInstance = glob_hinst;
-  pPSP[0].pszTemplate = MAKEINTRESOURCE (resid);
-  pPSP[0].hIcon = NULL;     
-  pPSP[0].pszTitle = NULL;  
-  pPSP[0].pfnDlgProc = (DLGPROC) GPGOptionsDlgProc;
-  pPSP[0].lParam = 0;     
-  pPSP[0].pfnCallback = NULL;
-  pPSP[0].pcRefParent = NULL; 
-
-  *plPSP = 1;
-
-  return S_OK;
-}
-
-
-STDMETHODIMP_ (VOID) 
-CGPGExchExtPropertySheets::FreePages (LPPROPSHEETPAGE pPSP,
-                                      ULONG lFlags, ULONG lPSP)
-{
-}
-
-
-
 
index 3cb5666..ab166d0 100644 (file)
@@ -1,15 +1,14 @@
 /* olflange.h - Flange between Outlook and the MapiGPGME class
- *     Copyright (C) 2001 G Data Software AG, http://www.gdata.de
- *     Copyright (C) 2005 g10 Code GmbH
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
  * 
- * This file is part of GPGol.
+ * This file is part of GpgOL.
  * 
- * GPGol is free software; you can redistribute it and/or
+ * GpgOL is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  * 
- * GPGol is distributed in the hope that it will be useful,
+ * GpgOL is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU Lesser General Public License for more details.
 
 
 /*
CGPGExchExt 
GpgolExt 
 
- The CGPGExchExt class is the main exchange extension class. The other 
+ The GpgolExt class is the main exchange extension class. The other 
  extensions will be created in the constructor of this class.
 */
-class CGPGExchExt : public IExchExt
+class GpgolExt : public IExchExt
 {
 public:
-  CGPGExchExt();
-  virtual ~CGPGExchExt();
+  GpgolExt();
+  virtual ~GpgolExt();
 
 public:        
   HWND m_hWndExchange;  /* Handle of the exchange window. */
-  /* parameter for sending mails */
+
+  /* Parameters for sending mails.  */
   BOOL  m_gpgEncrypt;
   BOOL  m_gpgSign;
   
@@ -46,11 +46,12 @@ private:
   ULONG m_lRef;
   ULONG m_lContext;
   
-  /* pointer to the other extension objects */
-  CGPGExchExtMessageEvents* m_pExchExtMessageEvents;
-  CGPGExchExtCommands* m_pExchExtCommands;
-  CGPGExchExtPropertySheets* m_pExchExtPropertySheets;
-  CGPGExchExtAttachedFileEvents *m_pExchExtAttachedFileEvents;
+  /* Pointer to the other extension objects.  */
+  GpgolExtCommands           *m_pExchExtCommands;
+  GpgolSessionEvents            *m_pExchExtSessionEvents;
+  GpgolMessageEvents      *m_pExchExtMessageEvents;
+  GpgolPropertySheets     *m_pExchExtPropertySheets;
+  GpgolAttachedFileEvents *m_pExchExtAttachedFileEvents;
 
 public:
   STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObj);
@@ -65,158 +66,7 @@ public:
   STDMETHODIMP Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags);
 };
 
-/*
-   CGPGExchExtMessageEvents 
-   The CGPGExchExtMessageEvents class implements the reaction of the exchange 
-   message events.
- */
-class CGPGExchExtMessageEvents : public IExchExtMessageEvents
-{
-  /* constructor */
-public:
-  CGPGExchExtMessageEvents (CGPGExchExt* pParentInterface);
-
-  /* attributes */
-private:
-  ULONG   m_lRef;
-  ULONG   m_lContext;
-  BOOL    m_bOnSubmitActive;
-  CGPGExchExt* m_pExchExt;
-  BOOL    m_bWriteFailed;
-  BOOL    m_want_html;       /* Encryption of HTML is desired. */
-  
-public:
-  STDMETHODIMP QueryInterface (REFIID riid, LPVOID *ppvObj);
-  inline STDMETHODIMP_(ULONG) AddRef (void)
-  {
-    ++m_lRef; 
-    return m_lRef; 
-  };
-  inline STDMETHODIMP_(ULONG) Release (void) 
-  {
-    ULONG lCount = --m_lRef;
-    if (!lCount) 
-      delete this;
-    return lCount;     
-  };
-
-  STDMETHODIMP OnRead (LPEXCHEXTCALLBACK pEECB);
-  STDMETHODIMP OnReadComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags);
-  STDMETHODIMP OnWrite (LPEXCHEXTCALLBACK pEECB);
-  STDMETHODIMP OnWriteComplete (LPEXCHEXTCALLBACK pEECB, ULONG lFlags);
-  STDMETHODIMP OnCheckNames (LPEXCHEXTCALLBACK pEECB);
-  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;
-  };
-};
-
-/*
-   CGPGExchExtCommands 
 
-   Makes the menu and toolbar extensions. Implements the own commands.
- */
-class CGPGExchExtCommands : public IExchExtCommands
-{
-public:
-  CGPGExchExtCommands (CGPGExchExt* pParentInterface);
-  
-private:
-  ULONG m_lRef;
-  ULONG m_lContext;
-  
-  UINT  m_nCmdEncrypt;
-  UINT  m_nCmdSign;
-
-  UINT  m_nToolbarButtonID1;
-  UINT  m_nToolbarButtonID2;     
-  UINT  m_nToolbarBitmap1;
-  UINT  m_nToolbarBitmap2;
-  
-  HWND  m_hWnd;
-  
-  CGPGExchExt* m_pExchExt;
-  
-public:
-  STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
-  inline STDMETHODIMP_(ULONG) AddRef (void)
-  { 
-    ++m_lRef;
-    return m_lRef; 
-  };
-  inline STDMETHODIMP_(ULONG) Release (void) 
-  {
-    ULONG lCount = --m_lRef;
-    if (!lCount) 
-      delete this;
-    return lCount;     
-  };
-
-  STDMETHODIMP InstallCommands (LPEXCHEXTCALLBACK pEECB, HWND hWnd,
-                                HMENU hMenu, UINT FAR * pnCommandIDBase,
-                                LPTBENTRY pTBEArray,
-                                UINT nTBECnt, ULONG lFlags);
-  STDMETHODIMP DoCommand (LPEXCHEXTCALLBACK pEECB, UINT nCommandID);
-  STDMETHODIMP_(void) InitMenu (LPEXCHEXTCALLBACK pEECB);
-  STDMETHODIMP Help (LPEXCHEXTCALLBACK pEECB, UINT nCommandID);
-  STDMETHODIMP QueryHelpText (UINT nCommandID, ULONG lFlags,
-                              LPTSTR szText, UINT nCharCnt);
-  STDMETHODIMP QueryButtonInfo (ULONG lToolbarID, UINT nToolbarButtonID, 
-                                LPTBBUTTON pTBB, LPTSTR lpszDescription,
-                                UINT nCharCnt, ULONG lFlags);
-  STDMETHODIMP ResetToolbar (ULONG nToolbarID, ULONG lFlags);
-
-  inline void SetContext (ULONG lContext)
-  { 
-    m_lContext = lContext;
-  };
-};
-
-
-/*
-   CGPGExchExtPropertySheets 
-   The CGPGExchExtPropertySheets implements the exchange property
-   sheet extension to put the GPG options page in the exchanges
-   options property sheet.
- */
-class CGPGExchExtPropertySheets : public IExchExtPropertySheets
-{
-  // constructor
-public:
-  CGPGExchExtPropertySheets(CGPGExchExt* pParentInterface);
-
-  // attibutes
-private:
-  ULONG m_lRef;
-  CGPGExchExt* m_pExchExt;
-  
-public:        
-  STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
-  inline STDMETHODIMP_(ULONG) AddRef()
-  { 
-    ++m_lRef;
-    return m_lRef; 
-  };
-  inline STDMETHODIMP_(ULONG) Release() 
-  {
-    ULONG lCount = --m_lRef;
-    if (!lCount)
-      delete this;
-    return lCount;     
-  };
-
-  STDMETHODIMP_ (ULONG) GetMaxPageCount(ULONG lFlags);          
-  STDMETHODIMP  GetPages(LPEXCHEXTCALLBACK pEECB, ULONG lFlags,
-                         LPPROPSHEETPAGE pPSP, ULONG FAR * pcpsp);
-  STDMETHODIMP_ (void) FreePages(LPPROPSHEETPAGE pPSP, 
-                                 ULONG lFlags, ULONG cpsp);          
-
-};
+const char *ext_context_name (unsigned long no);
 
 #endif /*OLFLANGE_H*/
diff --git a/src/property-sheets.cpp b/src/property-sheets.cpp
new file mode 100644 (file)
index 0000000..6e35c3f
--- /dev/null
@@ -0,0 +1,132 @@
+/* property-sheets.cpp - Subclass impl of IExchExtPropertySheets
+ *     Copyright (C) 2004, 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+#include "myexchext.h"
+#include "display.h"
+#include "intern.h"
+#include "gpgmsg.hh"
+#include "msgcache.h"
+#include "engine.h"
+#include "mapihelp.h"
+
+#include "olflange-ids.h"
+#include "olflange-def.h"
+#include "olflange.h"
+#include "property-sheets.h"
+
+
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     SRCNAME, __func__, __LINE__); \
+                        } while (0)
+
+
+
+
+GpgolPropertySheets::GpgolPropertySheets (GpgolExt* pParentInterface)
+{ 
+    m_pExchExt = pParentInterface;
+    m_lRef = 0; 
+}
+
+
+STDMETHODIMP 
+GpgolPropertySheets::QueryInterface(REFIID riid, LPVOID FAR * ppvObj)
+{   
+    *ppvObj = NULL;
+    if (riid == IID_IExchExtPropertySheets) {
+        *ppvObj = (LPVOID)this;
+        AddRef();
+        return S_OK;
+    }
+    if (riid == IID_IUnknown) {
+        *ppvObj = (LPVOID)m_pExchExt;
+        m_pExchExt->AddRef();
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+
+/* Called 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) 
+GpgolPropertySheets::GetMaxPageCount(ULONG lFlags)
+{
+    if (lFlags == EEPS_TOOLSOPTIONS)
+       return 1;       
+    return 0;
+}
+
+
+/* Called by Exchange to request information about the property page.
+   Return value: S_OK to signal Echange to use the pPSP
+   information. */
+STDMETHODIMP 
+GpgolPropertySheets::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 
+                                 //  containing the number of property 
+                                 //  sheets actually used.
+{
+  int resid ;
+
+  if (!strncmp (gettext_localename (), "de", 2))
+    resid = IDD_GPG_OPTIONS_DE;
+  else
+    resid = IDD_GPG_OPTIONS;
+
+  pPSP[0].dwSize = sizeof (PROPSHEETPAGE);
+  pPSP[0].dwFlags = PSP_DEFAULT | PSP_HASHELP;
+  pPSP[0].hInstance = glob_hinst;
+  pPSP[0].pszTemplate = MAKEINTRESOURCE (resid);
+  pPSP[0].hIcon = NULL;     
+  pPSP[0].pszTitle = NULL;  
+  pPSP[0].pfnDlgProc = (DLGPROC) GPGOptionsDlgProc;
+  pPSP[0].lParam = 0;     
+  pPSP[0].pfnCallback = NULL;
+  pPSP[0].pcRefParent = NULL; 
+
+  *plPSP = 1;
+
+  return S_OK;
+}
+
+
+STDMETHODIMP_ (VOID) 
+GpgolPropertySheets::FreePages (LPPROPSHEETPAGE pPSP,
+                                      ULONG lFlags, ULONG lPSP)
+{
+}
diff --git a/src/property-sheets.h b/src/property-sheets.h
new file mode 100644 (file)
index 0000000..071b291
--- /dev/null
@@ -0,0 +1,69 @@
+/* property-sheets.h - Definitions for our subclass of IExchExtPropertySheets
+ *     Copyright (C) 2005, 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef PROPERTY_SHEETS_H
+#define PROPERTY_SHEETS_H
+
+
+/*
+   GpgolPropertySheets 
+   The GpgolPropertySheets implements the exchange property
+   sheet extension to put the GPG options page in the exchanges
+   options property sheet.
+ */
+class GpgolPropertySheets : public IExchExtPropertySheets
+{
+  // constructor
+public:
+  GpgolPropertySheets(GpgolExt* pParentInterface);
+
+  // attibutes
+private:
+  ULONG m_lRef;
+  GpgolExt* m_pExchExt;
+  
+public:        
+  STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
+  inline STDMETHODIMP_(ULONG) AddRef()
+  { 
+    ++m_lRef;
+    return m_lRef; 
+  };
+  inline STDMETHODIMP_(ULONG) Release() 
+  {
+    ULONG lCount = --m_lRef;
+    if (!lCount)
+      delete this;
+    return lCount;     
+  };
+
+  STDMETHODIMP_ (ULONG) GetMaxPageCount(ULONG lFlags);          
+  STDMETHODIMP  GetPages(LPEXCHEXTCALLBACK pEECB, ULONG lFlags,
+                         LPPROPSHEETPAGE pPSP, ULONG FAR * pcpsp);
+  STDMETHODIMP_ (void) FreePages(LPPROPSHEETPAGE pPSP, 
+                                 ULONG lFlags, ULONG cpsp);          
+
+};
+
+
+
+#endif /*PROPERTY_SHEETS_H*/
diff --git a/src/session-events.cpp b/src/session-events.cpp
new file mode 100644 (file)
index 0000000..ade5c64
--- /dev/null
@@ -0,0 +1,117 @@
+/* session-events.cpp - Subclass impl of IExchExtSessionEvents
+ *     Copyright (C) 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+
+#include "mymapi.h"
+#include "mymapitags.h"
+#include "myexchext.h"
+#include "display.h"
+#include "intern.h"
+#include "gpgmsg.hh"
+#include "msgcache.h"
+#include "engine.h"
+#include "mapihelp.h"
+
+#include "olflange-def.h"
+#include "olflange.h"
+#include "session-events.h"
+
+
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     SRCNAME, __func__, __LINE__); \
+                        } while (0)
+
+
+
+/* Wrapper around UlRelease with error checking. */
+/* FIXME: Duplicated code.  */
+static void 
+ul_release (LPVOID punk)
+{
+  ULONG res;
+  
+  if (!punk)
+    return;
+  res = UlRelease (punk);
+//   log_debug ("%s UlRelease(%p) had %lu references\n", __func__, punk, res);
+}
+
+
+
+
+
+
+
+/* Our constructor.  */
+GpgolSessionEvents::GpgolSessionEvents (GpgolExt *pParentInterface)
+{ 
+  m_pExchExt = pParentInterface;
+  m_lRef = 0; 
+}
+
+
+/* The QueryInterface which does the actual subclassing.  */
+STDMETHODIMP 
+GpgolSessionEvents::QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
+{   
+  *ppvObj = NULL;
+  if (riid == IID_IExchExtSessionEvents)
+    {
+      *ppvObj = (LPVOID)this;
+      AddRef();
+      return S_OK;
+    }
+  if (riid == IID_IUnknown)
+    {
+      *ppvObj = (LPVOID)m_pExchExt;  
+      m_pExchExt->AddRef();
+      return S_OK;
+    }
+  return E_NOINTERFACE;
+}
+
+
+
+/* Called from Exchange when a new message arrives.  Returns: S_FALSE
+   to signal Exchange to continue calling extensions.  PEECB is a
+   pointer to the IExchExtCallback interface. */
+STDMETHODIMP 
+GpgolSessionEvents::OnDelivery (LPEXCHEXTCALLBACK pEECB) 
+{
+  LPMDB pMDB = NULL;
+  LPMESSAGE pMessage = NULL;
+
+  log_debug ("%s:%s: received\n", SRCNAME, __func__);
+  pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
+  log_mapi_property (pMessage, PR_MESSAGE_CLASS,"PR_MESSAGE_CLASS");
+  mapi_change_message_class (pMessage);
+  log_mapi_property (pMessage, PR_MESSAGE_CLASS,"PR_MESSAGE_CLASS");
+  ul_release (pMessage);
+  ul_release (pMDB);
+
+  return S_FALSE;
+}
+
diff --git a/src/session-events.h b/src/session-events.h
new file mode 100644 (file)
index 0000000..92bc4c4
--- /dev/null
@@ -0,0 +1,68 @@
+/* session-events.h - Definitions for out subclass of IExchExtSessionEvents
+ *     Copyright (C) 2007 g10 Code GmbH
+ * 
+ * This file is part of GpgOL.
+ * 
+ * GpgOL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * GpgOL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef SESSION_EVENTS_H
+#define SESSION_EVENTS_H
+
+/*
+   GpgolSessionEvents 
+   The GpgolSessionEvents class implements the reaction on the certain
+   session events.
+ */
+class GpgolSessionEvents : public IExchExtSessionEvents
+{
+  /* Constructor. */
+public:
+  GpgolSessionEvents (GpgolExt *pParentInterface);
+
+  /* Attributes. */
+private:
+  ULONG   m_lRef;
+  ULONG   m_lContext;
+  GpgolExt *m_pExchExt;
+  
+public:
+  STDMETHODIMP QueryInterface (REFIID riid, LPVOID *ppvObj);
+  inline STDMETHODIMP_(ULONG) AddRef (void)
+  {
+    ++m_lRef; 
+    return m_lRef; 
+  };
+  inline STDMETHODIMP_(ULONG) Release (void) 
+  {
+    ULONG lCount = --m_lRef;
+    if (!lCount) 
+      delete this;
+    return lCount;     
+  };
+
+  STDMETHODIMP OnDelivery (LPEXCHEXTCALLBACK pEECB);
+
+
+  inline void SetContext (ULONG lContext)
+  { 
+    m_lContext = lContext;
+  };
+};
+
+
+#endif /*SESSION_EVENTS_H*/
index a7ff9f4..8e993cd 100644 (file)
@@ -72,6 +72,9 @@ void log_error_w32 (int w32err, const char *fmt,
                     ...) __attribute__ ((format (printf,2,3)));
 void log_hexdump (const void *buf, size_t buflen, const char *fmt, 
                   ...)  __attribute__ ((format (printf,3,4)));
+void log_window_hierarchy (HWND window, const char *fmt, 
+                           ...) __attribute__ ((format (printf,2,3)));
+
 const char *log_srcname (const char *s);
 #define SRCNAME log_srcname (__FILE__)