b53aeb70807cd73afc638205afe2bbd80a4f5673
[gpgol.git] / src / olflange.cpp
1 /* olflange.cpp - Connect GpgOL to Outlook
2  *      Copyright (C) 2001 G Data Software AG, http://www.gdata.de
3  *      Copyright (C) 2004, 2005, 2007 g10 Code GmbH
4  * 
5  * This file is part of GpgOL.
6  * 
7  * GpgOL is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  * 
12  * GpgOL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU Lesser General Public License for more details.
16  * 
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <windows.h>
26
27 #ifndef INITGUID
28 #define INITGUID
29 #endif
30
31 #include <initguid.h>
32 #include "mymapi.h"
33 #include "mymapitags.h"
34 #include "myexchext.h"
35
36 #include "common.h"
37 #include "display.h"
38 #include "msgcache.h"
39 #include "engine.h"
40 #include "mapihelp.h"
41
42 #include "olflange-def.h"
43 #include "olflange.h"
44 #include "ext-commands.h"
45 #include "user-events.h"
46 #include "session-events.h"
47 #include "message-events.h"
48 #include "property-sheets.h"
49 #include "attached-file-events.h"
50 #include "item-events.h"
51 #include "ol-ext-callback.h"
52
53 /* The GUID for this plugin.  */
54 #define CLSIDSTR_GPGOL   "{42d30988-1a3a-11da-c687-000d6080e735}"
55 DEFINE_GUID(CLSID_GPGOL, 0x42d30988, 0x1a3a, 0x11da, 
56             0xc6, 0x87, 0x00, 0x0d, 0x60, 0x80, 0xe7, 0x35);
57
58 /* For documentation: The GUID used for our custom properties: 
59    {31805ab8-3e92-11dc-879c-00061b031004}
60  */
61
62
63 #define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
64                                      SRCNAME, __func__, __LINE__); \
65                         } while (0)
66
67
68 static bool g_initdll = FALSE;
69
70
71
72 \f
73 /* Return a string for the context NO.  This never return NULL. */
74 const char *
75 ext_context_name (unsigned long no)
76 {
77   switch (no)
78     {
79     case EECONTEXT_SESSION:           return "Session";
80     case EECONTEXT_VIEWER:            return "Viewer";
81     case EECONTEXT_REMOTEVIEWER:      return "RemoteViewer";
82     case EECONTEXT_SEARCHVIEWER:      return "SearchViewer";
83     case EECONTEXT_ADDRBOOK:          return "AddrBook";
84     case EECONTEXT_SENDNOTEMESSAGE:   return "SendNoteMessage";
85     case EECONTEXT_READNOTEMESSAGE:   return "ReadNoteMessage";
86     case EECONTEXT_SENDPOSTMESSAGE:   return "SendPostMessage";
87     case EECONTEXT_READPOSTMESSAGE:   return "ReadPostMessage";
88     case EECONTEXT_READREPORTMESSAGE: return "ReadReportMessage";
89     case EECONTEXT_SENDRESENDMESSAGE: return "SendResendMessage";
90     case EECONTEXT_PROPERTYSHEETS:    return "PropertySheets";
91     case EECONTEXT_ADVANCEDCRITERIA:  return "AdvancedCriteria";
92     case EECONTEXT_TASK:              return "Task";
93     default: return "?";
94     }
95 }
96
97
98 /* Wrapper around UlRelease with error checking. */
99 // static void 
100 // ul_release (LPVOID punk, const char *func)
101 // {
102 //   ULONG res;
103   
104 //   if (!punk)
105 //     return;
106 //   res = UlRelease (punk);
107 //   if (opt.enable_debug & DBG_MEMORY)
108 //     log_debug ("%s:%s: UlRelease(%p) had %lu references\n", 
109 //                SRCNAME, func, punk, res);
110 // }
111
112
113 \f
114 /* Registers this module as an Exchange extension. This basically updates
115    some Registry entries. */
116 STDAPI 
117 DllRegisterServer (void)
118 {    
119   HKEY hkey, hkey2;
120   CHAR szKeyBuf[MAX_PATH+1024];
121   CHAR szEntry[MAX_PATH+512];
122   TCHAR szModuleFileName[MAX_PATH];
123   DWORD dwTemp = 0;
124   long ec;
125
126   /* Get server location. */
127   if (!GetModuleFileName(glob_hinst, szModuleFileName, MAX_PATH))
128     return E_FAIL;
129
130   lstrcpy (szKeyBuf, "Software\\Microsoft\\Exchange\\Client\\Extensions");
131   lstrcpy (szEntry, "4.0;");
132   lstrcat (szEntry, szModuleFileName);
133   lstrcat (szEntry, ";1"); /* Entry point ordinal. */
134   /* Context information string:
135      pos       context
136      1  EECONTEXT_SESSION
137      2  EECONTEXT_VIEWER
138      3  EECONTEXT_REMOTEVIEWER
139      4  EECONTEXT_SEARCHVIEWER
140      5  EECONTEXT_ADDRBOOK
141      6  EECONTEXT_SENDNOTEMESSAGE
142      7  EECONTEXT_READNOTEMESSAGE
143      8  EECONTEXT_SENDPOSTMESSAGE
144      9  EECONTEXT_READPOSTMESSAGE
145      a  EECONTEXT_READREPORTMESSAGE
146      b  EECONTEXT_SENDRESENDMESSAGE
147      c  EECONTEXT_PROPERTYSHEETS
148      d  EECONTEXT_ADVANCEDCRITERIA
149      e  EECONTEXT_TASK
150                    ___123456789abcde___ */                 
151   lstrcat (szEntry, ";11000111111100"); 
152   /* Interfaces to we want to hook into:
153      pos  interface
154      1    IExchExtCommands            
155      2    IExchExtUserEvents          
156      3    IExchExtSessionEvents       
157      4    IExchExtMessageEvents       
158      5    IExchExtAttachedFileEvents  
159      6    IExchExtPropertySheets      
160      7    IExchExtAdvancedCriteria    
161      -    IExchExt              
162      -    IExchExtModeless
163      -    IExchExtModelessCallback
164                    ___1234567___ */
165   lstrcat (szEntry, ";11111101"); 
166   ec = RegCreateKeyEx (HKEY_LOCAL_MACHINE, szKeyBuf, 0, NULL, 
167                        REG_OPTION_NON_VOLATILE,
168                        KEY_ALL_ACCESS, NULL, &hkey, NULL);
169   if (ec != ERROR_SUCCESS) 
170     {
171       log_debug ("DllRegisterServer failed\n");
172       return E_ACCESSDENIED;
173     }
174     
175   dwTemp = lstrlen (szEntry) + 1;
176   RegSetValueEx (hkey, "GpgOL", 0, REG_SZ, (BYTE*) szEntry, dwTemp);
177
178   /* To avoid conflicts with the old G-DATA plugin and older versions
179      of this Plugin, we remove the key used by these versions. */
180   RegDeleteValue (hkey, "GPG Exchange");
181
182   /* Set outlook update flag. */
183   /* Fixme: We have not yet implemented this hint from Microsoft:
184
185        In order for .ecf-based ECEs to be detected by Outlook on Vista,
186        one needs to delete if present:
187
188        [HKEY_CURRENT_USER\Software\Microsoft\Office\[Office Version]\Outlook]
189        "Exchange Client Extension"=
190              "4.0;Outxxx.dll;7;000000000000000;0000000000;OutXXX"
191
192        [Office Version] is 11.0 ( for OL 03 ), 12.0 ( OL 07 )...
193
194      Obviously due to HKCU, that also requires to run this code at
195      startup.  However, we don't use an ECF right now.  */
196   strcpy (szEntry, "4.0;Outxxx.dll;7;000000000000000;0000000000;OutXXX");
197   dwTemp = lstrlen (szEntry) + 1;
198   RegSetValueEx (hkey, "Outlook Setup Extension",
199                  0, REG_SZ, (BYTE*) szEntry, dwTemp);
200   RegCloseKey (hkey);
201     
202   hkey = NULL;
203   lstrcpy (szKeyBuf, "Software\\GNU\\GpgOL");
204   RegCreateKeyEx (HKEY_CURRENT_USER, szKeyBuf, 0, NULL,
205                   REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL);
206   if (hkey != NULL)
207     RegCloseKey (hkey);
208
209   hkey = NULL;
210   strcpy (szKeyBuf, "CLSID\\" CLSIDSTR_GPGOL );
211   ec = RegCreateKeyEx (HKEY_CLASSES_ROOT, szKeyBuf, 0, NULL,
212                   REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL);
213   if (ec != ERROR_SUCCESS) 
214     {
215       fprintf (stderr, "creating key `%s' failed: ec=%#lx\n", szKeyBuf, ec);
216       return E_ACCESSDENIED;
217     }
218
219   strcpy (szEntry, "GpgOL - The GnuPG Outlook Plugin");
220   dwTemp = strlen (szEntry) + 1;
221   RegSetValueEx (hkey, NULL, 0, REG_SZ, (BYTE*)szEntry, dwTemp);
222
223   strcpy (szKeyBuf, "InprocServer32");
224   ec = RegCreateKeyEx (hkey, szKeyBuf, 0, NULL, REG_OPTION_NON_VOLATILE,
225                        KEY_ALL_ACCESS, NULL, &hkey2, NULL);
226   if (ec != ERROR_SUCCESS) 
227     {
228       fprintf (stderr, "creating key `%s' failed: ec=%#lx\n", szKeyBuf, ec);
229       RegCloseKey (hkey);
230       return E_ACCESSDENIED;
231     }
232   strcpy (szEntry, szModuleFileName);
233   dwTemp = strlen (szEntry) + 1;
234   RegSetValueEx (hkey2, NULL, 0, REG_SZ, (BYTE*)szEntry, dwTemp);
235
236   strcpy (szEntry, "Neutral");
237   dwTemp = strlen (szEntry) + 1;
238   RegSetValueEx (hkey2, "ThreadingModel", 0, REG_SZ, (BYTE*)szEntry, dwTemp);
239
240   RegCloseKey (hkey2);
241   RegCloseKey (hkey);
242
243
244   log_debug ("DllRegisterServer succeeded\n");
245   return S_OK;
246 }
247
248
249 /* Unregisters this module as an Exchange extension. */
250 STDAPI 
251 DllUnregisterServer (void)
252 {
253   HKEY hkey;
254   CHAR buf[MAX_PATH+1024];
255   DWORD ntemp;
256   long res;
257
258   strcpy (buf, "Software\\Microsoft\\Exchange\\Client\\Extensions");
259   /* Create and open key and subkey. */
260   res = RegCreateKeyEx (HKEY_LOCAL_MACHINE, buf, 0, NULL, 
261                         REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 
262                         NULL, &hkey, NULL);
263   if (res != ERROR_SUCCESS) 
264     {
265       log_debug ("DllUnregisterServer: access denied.\n");
266       return E_ACCESSDENIED;
267     }
268   RegDeleteValue (hkey, "GpgOL");
269   
270   /* Set outlook update flag.  */  
271   strcpy (buf, "4.0;Outxxx.dll;7;000000000000000;0000000000;OutXXX");
272   ntemp = strlen (buf) + 1;
273   RegSetValueEx (hkey, "Outlook Setup Extension", 0, 
274                  REG_SZ, (BYTE*) buf, ntemp);
275   RegCloseKey (hkey);
276
277   /* Delete CLSIDs. */
278   strcpy (buf, "CLSID\\" CLSIDSTR_GPGOL "\\InprocServer32");
279   RegDeleteKey (HKEY_CLASSES_ROOT, buf);
280   strcpy (buf, "CLSID\\" CLSIDSTR_GPGOL);
281   RegDeleteKey (HKEY_CLASSES_ROOT, buf);
282   
283   return S_OK;
284 }
285
286
287 static const char*
288 parse_version_number (const char *s, int *number)
289 {
290   int val = 0;
291
292   if (*s == '0' && digitp (s+1))
293     return NULL;  /* Leading zeros are not allowed.  */
294   for (; digitp (s); s++)
295     {
296       val *= 10;
297       val += *s - '0';
298     }
299   *number = val;
300   return val < 0 ? NULL : s;
301 }
302
303 static const char *
304 parse_version_string (const char *s, int *major, int *minor, int *micro)
305 {
306   s = parse_version_number (s, major);
307   if (!s || *s != '.')
308     return NULL;
309   s++;
310   s = parse_version_number (s, minor);
311   if (!s || *s != '.')
312     return NULL;
313   s++;
314   s = parse_version_number (s, micro);
315   if (!s)
316     return NULL;
317   return s;  /* Patchlevel.  */
318 }
319
320 static const char *
321 compare_versions (const char *my_version, const char *req_version)
322 {
323   int my_major, my_minor, my_micro;
324   int rq_major, rq_minor, rq_micro;
325   const char *my_plvl, *rq_plvl;
326
327   if (!req_version)
328     return my_version;
329   if (!my_version)
330     return NULL;
331
332   my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
333   if (!my_plvl)
334     return NULL;        /* Very strange: our own version is bogus.  */
335   rq_plvl = parse_version_string(req_version,
336                                  &rq_major, &rq_minor, &rq_micro);
337   if (!rq_plvl)
338     return NULL;        /* Requested version string is invalid.  */
339
340   if (my_major > rq_major
341         || (my_major == rq_major && my_minor > rq_minor)
342       || (my_major == rq_major && my_minor == rq_minor 
343           && my_micro > rq_micro)
344       || (my_major == rq_major && my_minor == rq_minor
345           && my_micro == rq_micro
346           && strcmp( my_plvl, rq_plvl ) >= 0))
347     {
348       return my_version;
349     }
350   return NULL;
351 }
352
353 /* Check that the the version of GpgOL is at minimum the requested one
354  * and return GpgOL's version string; return NULL if that condition is
355  * not met.  If a NULL is passed to this function, no check is done
356  * and the version string is simply returned.  */
357 EXTERN_C const char * __stdcall
358 gpgol_check_version (const char *req_version)
359 {
360   return compare_versions (PACKAGE_VERSION, req_version);
361 }
362
363
364
365 \f
366 /* The entry point which Exchange/Outlook calls.  This is called for
367    each context entry.  Creates a new GpgolExt object every time so
368    each context will get its own GpgolExt interface. */
369 EXTERN_C LPEXCHEXT __stdcall
370 ExchEntryPoint (void)
371 {
372   log_debug ("%s:%s: creating new GpgolExt object\n", SRCNAME, __func__);
373   return new GpgolExt;
374 }
375
376
377
378 /* Constructor of GpgolExt
379
380    Initializes members and creates the interface objects for the new
381    context.  Does the DLL initialization if it has not been done
382    before. */
383 GpgolExt::GpgolExt (void)
384
385   m_lRef = 1;
386   m_lContext = 0;
387   m_hWndExchange = 0;
388   m_protoSelection = PROTOCOL_UNKNOWN;
389   m_gpgEncrypt = FALSE;
390   m_gpgSign = FALSE;
391
392   m_pExchExtCommands           = new GpgolExtCommands (this);
393   m_pExchExtUserEvents         = new GpgolUserEvents (this);
394   m_pExchExtSessionEvents      = new GpgolSessionEvents (this);
395   m_pExchExtMessageEvents      = new GpgolMessageEvents (this);
396   m_pExchExtAttachedFileEvents = new GpgolAttachedFileEvents (this);
397   m_pExchExtPropertySheets     = new GpgolPropertySheets (this);
398 //   m_pOutlookExtItemEvents      = new GpgolItemEvents (this);
399   if (!m_pExchExtCommands
400       || !m_pExchExtUserEvents
401       || !m_pExchExtSessionEvents
402       || !m_pExchExtMessageEvents
403       || !m_pExchExtAttachedFileEvents
404       || !m_pExchExtPropertySheets
405       /*|| !m_pOutlookExtItemEvents*/)
406     out_of_core ();
407
408   /* For this class we need to bump the reference counter intially.
409      The question is why it works at all with the other stuff.  */
410 //   m_pOutlookExtItemEvents->AddRef ();
411
412   if (!g_initdll)
413     {
414       read_options ();
415       log_debug ("%s:%s: this is GpgOL %s\n", 
416                  SRCNAME, __func__, PACKAGE_VERSION);
417       log_debug ("%s:%s:   using GPGME %s\n", 
418                  SRCNAME, __func__, gpgme_check_version (NULL));
419       engine_init ();
420       g_initdll = TRUE;
421       log_debug ("%s:%s: first time initialization done\n",
422                  SRCNAME, __func__);
423       if ( SVN_REVISION > opt.svn_revision )
424         MessageBox (NULL,
425                     _("You have installed a new version of GpgOL.\n"
426                       "\n"
427                       "Please open the option dialog and confirm that"
428                       " the settings are correct for your needs.  The option"
429                       " dialog can be found in the main menu at:"
430                       " Extras->Options->GpgOL.\n"),
431                       "GpgOL", MB_ICONINFORMATION|MB_OK);
432     }
433 }
434
435
436 /*  Uninitializes the DLL in the session context. */
437 GpgolExt::~GpgolExt (void) 
438 {
439   log_debug ("%s:%s: cleaning up GpgolExt object; context=%s\n",
440              SRCNAME, __func__, ext_context_name (m_lContext));
441     
442 //   if (m_pOutlookExtItemEvents)
443 //     m_pOutlookExtItemEvents->Release ();
444   
445   if (m_lContext == EECONTEXT_SESSION)
446     {
447       if (g_initdll)
448         {
449           engine_deinit ();
450           write_options ();
451           g_initdll = FALSE;
452           log_debug ("%s:%s: DLL closed down\n", SRCNAME, __func__);
453         }       
454     }
455   
456
457 }
458
459
460 /* Called by Exchange to retrieve an object pointer for a named
461    interface.  This is a standard COM method.  REFIID is the ID of the
462    interface and PPVOBJ will get the address of the object pointer if
463    this class defines the requested interface.  Return value: S_OK if
464    the interface is supported, otherwise E_NOINTERFACE. */
465 STDMETHODIMP 
466 GpgolExt::QueryInterface(REFIID riid, LPVOID *ppvObj)
467 {
468   HRESULT hr = S_OK;
469   
470   *ppvObj = NULL;
471   
472   if ((riid == IID_IUnknown) || (riid == IID_IExchExt)) 
473     {
474       *ppvObj = (LPUNKNOWN) this;
475     }
476   else if (riid == IID_IExchExtCommands) 
477     {
478       *ppvObj = (LPUNKNOWN)m_pExchExtCommands;
479       m_pExchExtCommands->SetContext (m_lContext);
480     }
481   else if (riid == IID_IExchExtUserEvents) 
482     {
483       *ppvObj = (LPUNKNOWN) m_pExchExtUserEvents;
484       m_pExchExtUserEvents->SetContext (m_lContext);
485     }
486   else if (riid == IID_IExchExtSessionEvents) 
487     {
488       *ppvObj = (LPUNKNOWN) m_pExchExtSessionEvents;
489       m_pExchExtSessionEvents->SetContext (m_lContext);
490     }
491   else if (riid == IID_IExchExtMessageEvents) 
492     {
493       *ppvObj = (LPUNKNOWN) m_pExchExtMessageEvents;
494       m_pExchExtMessageEvents->SetContext (m_lContext);
495     }
496   else if (riid == IID_IExchExtAttachedFileEvents)
497     {
498       *ppvObj = (LPUNKNOWN)m_pExchExtAttachedFileEvents;
499     }  
500   else if (riid == IID_IExchExtPropertySheets) 
501     {
502       if (m_lContext != EECONTEXT_PROPERTYSHEETS)
503         return E_NOINTERFACE;
504       *ppvObj = (LPUNKNOWN) m_pExchExtPropertySheets;
505     }
506 //   else if (riid == IID_IOutlookExtItemEvents)
507 //     {
508 //       *ppvObj = (LPUNKNOWN)m_pOutlookExtItemEvents;
509 //     }  
510   else
511     hr = E_NOINTERFACE;
512   
513   /* On success we need to bump up the reference counter for the
514      requested object. */
515   if (*ppvObj)
516     ((LPUNKNOWN)*ppvObj)->AddRef();
517   
518   return hr;
519 }
520
521
522 /* Called once for each new context. Checks the Exchange extension
523    version number and the context.  Returns: S_OK if the extension
524    should used in the requested context, otherwise S_FALSE.  PEECB is
525    a pointer to Exchange extension callback function.  LCONTEXT is the
526    context code at time of being called. LFLAGS carries flags to
527    indicate whether the extension should be installed modal.
528 */
529 STDMETHODIMP 
530 GpgolExt::Install(LPEXCHEXTCALLBACK pEECB, ULONG lContext, ULONG lFlags)
531 {
532   static int version_shown;
533   static char *olversion;
534   ULONG lBuildVersion;
535   ULONG lActualVersion;
536   ULONG lVirtualVersion;
537
538
539   /* Save the context in an instance variable. */
540   m_lContext = lContext;
541
542   log_debug ("%s:%s: context=%s flags=0x%lx\n", SRCNAME, __func__,
543              ext_context_name (lContext), lFlags);
544   
545   /* Check version.  This install method is called by Outlook even
546      before the OOM interface is available, thus we need to keep on
547      checking for the olversion until we get one.  Only then we can
548      display the complete version and do a final test to see whether
549      this is a supported version. */
550   if (!olversion)
551     olversion = get_outlook_property (pEECB, "Application.Version");
552   pEECB->GetVersion (&lBuildVersion, EECBGV_GETBUILDVERSION);
553   pEECB->GetVersion (&lActualVersion, EECBGV_GETACTUALVERSION);
554   pEECB->GetVersion (&lVirtualVersion, EECBGV_GETVIRTUALVERSION);
555   if (!version_shown)
556     {
557       log_debug ("%s:%s: detected Outlook build version 0x%lx (%lu.%lu)\n",
558                  SRCNAME, __func__, lBuildVersion,
559                  (lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK) >> 16,
560                  (lBuildVersion & EECBGV_BUILDVERSION_MINOR_MASK));
561       log_debug ("%s:%s:                 actual version 0x%lx (%u.%u.%u.%u)\n",
562                  SRCNAME, __func__, lActualVersion, 
563                  (unsigned int)((lActualVersion >> 24) & 0xff),
564                  (unsigned int)((lActualVersion >> 16) & 0xff),
565              (unsigned int)((lActualVersion >> 8) & 0xff),
566                  (unsigned int)(lActualVersion & 0xff));
567       log_debug ("%s:%s:                virtual version 0x%lx (%u.%u.%u.%u)\n",
568                  SRCNAME, __func__, lVirtualVersion, 
569                  (unsigned int)((lVirtualVersion >> 24) & 0xff),
570                  (unsigned int)((lVirtualVersion >> 16) & 0xff),
571              (unsigned int)((lVirtualVersion >> 8) & 0xff),
572                  (unsigned int)(lVirtualVersion & 0xff));
573       if (olversion)
574         {
575           log_debug ("%s:%s:                    OOM version %s\n",
576                      SRCNAME, __func__, olversion);
577           version_shown = 1;
578         }
579     }
580   
581   if (EECBGV_BUILDVERSION_MAJOR
582       != (lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK))
583     {
584       log_debug ("%s:%s: invalid version 0x%lx\n",
585                  SRCNAME, __func__, lBuildVersion);
586       return S_FALSE;
587     }
588   
589   /* The version numbers as returned by GetVersion are the same for
590      OL2003 as well as for recent OL2002.  My guess is that this
591      version comes from the Exchange Client Extension API and that has
592      been updated in all version of OL.  Thus we also need to check
593      the version number as taken from the Outlook Object Model.  */
594   if ( (lBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK) < 13
595        || (lBuildVersion & EECBGV_BUILDVERSION_MINOR_MASK) < 1573
596        || (olversion && atoi (olversion) < 11) )
597     {
598       static int shown;
599       HWND hwnd;
600       
601       if (!shown)
602         {
603           shown = 1;
604           
605           if (FAILED(pEECB->GetWindow (&hwnd)))
606             hwnd = NULL;
607           MessageBox (hwnd,
608                       _("This version of Outlook is too old!\n\n"
609                         "At least versions of Outlook 2003 older than SP2 "
610                         "exhibit crashes when sending messages and messages "
611                         "might get stuck in the outgoing queue.\n\n"
612                         "Please update at least to SP2 before trying to send "
613                         "a message"),
614                       "GpgOL", MB_ICONSTOP|MB_OK);
615         }
616     }
617   
618
619   /* Check context. */
620   if (   lContext == EECONTEXT_PROPERTYSHEETS
621       || lContext == EECONTEXT_SENDNOTEMESSAGE
622       || lContext == EECONTEXT_SENDPOSTMESSAGE
623       || lContext == EECONTEXT_SENDRESENDMESSAGE
624       || lContext == EECONTEXT_READNOTEMESSAGE
625       || lContext == EECONTEXT_READPOSTMESSAGE
626       || lContext == EECONTEXT_READREPORTMESSAGE
627       || lContext == EECONTEXT_VIEWER
628       || lContext == EECONTEXT_SESSION)
629     {
630       return S_OK;
631     }
632   
633   log_debug ("%s:%s: can't handle this context\n", SRCNAME, __func__);
634   return S_FALSE;
635 }
636
637