Made debugging configurable.
[gpgol.git] / src / message-events.cpp
1 /* message-events.cpp - Subclass impl of IExchExtMessageEvents
2  *      Copyright (C) 2004, 2005, 2007, 2008 g10 Code GmbH
3  * 
4  * This file is part of GpgOL.
5  * 
6  * GpgOL is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  * 
11  * GpgOL is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  * 
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <windows.h>
24
25 #include "mymapi.h"
26 #include "mymapitags.h"
27 #include "myexchext.h"
28 #include "display.h"
29 #include "common.h"
30 #include "msgcache.h"
31 #include "mapihelp.h"
32
33 #include "olflange-def.h"
34 #include "olflange.h"
35 #include "ol-ext-callback.h"
36 #include "mimeparser.h"
37 #include "mimemaker.h"
38 #include "message.h"
39 #include "message-events.h"
40
41
42 #define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
43                                      SRCNAME, __func__, __LINE__); \
44                         } while (0)
45
46
47
48 /* Wrapper around UlRelease with error checking. */
49 static void 
50 ul_release (LPVOID punk, const char *func, int lnr)
51 {
52   ULONG res;
53   
54   if (!punk)
55     return;
56   res = UlRelease (punk);
57   log_debug ("%s:%s:%d: UlRelease(%p) had %lu references\n", 
58              SRCNAME, func, lnr, punk, res);
59 }
60
61
62
63
64
65
66 /* Our constructor.  */
67 GpgolMessageEvents::GpgolMessageEvents (GpgolExt *pParentInterface)
68
69   m_pExchExt = pParentInterface;
70   m_lRef = 0; 
71   m_bOnSubmitActive = false;
72   m_want_html = false;
73   m_processed = false;
74   m_wasencrypted = false;
75 }
76
77
78 /* The QueryInterfac.  */
79 STDMETHODIMP 
80 GpgolMessageEvents::QueryInterface (REFIID riid, LPVOID FAR *ppvObj)
81 {   
82   *ppvObj = NULL;
83   if (riid == IID_IExchExtMessageEvents)
84     {
85       *ppvObj = (LPVOID)this;
86       AddRef();
87       return S_OK;
88     }
89   if (riid == IID_IUnknown)
90     {
91       *ppvObj = (LPVOID)m_pExchExt;  
92       m_pExchExt->AddRef();
93       return S_OK;
94     }
95   return E_NOINTERFACE;
96 }
97
98
99
100 /* Called from Exchange on reading a message.  Returns: S_FALSE to
101    signal Exchange to continue calling extensions.  EECB is a pointer
102    to the IExchExtCallback interface. */
103 STDMETHODIMP 
104 GpgolMessageEvents::OnRead (LPEXCHEXTCALLBACK eecb) 
105 {
106   LPMDB mdb = NULL;
107   LPMESSAGE message = NULL;
108   
109   log_debug ("%s:%s: received\n", SRCNAME, __func__);
110
111   m_wasencrypted = false;
112   if (1 /*opt.preview_decrypt*/)
113     {
114       HWND hwnd = NULL;
115
116       if (FAILED (eecb->GetWindow (&hwnd)))
117         hwnd = NULL;
118       eecb->GetObject (&mdb, (LPMAPIPROP *)&message);
119       if (message_incoming_handler (message, m_pExchExt->getMsgtype (eecb),
120                                     hwnd))
121         m_processed = true;
122       ul_release (message, __func__, __LINE__);
123       ul_release (mdb, __func__, __LINE__);
124     }
125   
126   return S_FALSE;
127 }
128
129
130 /* Called by Exchange after a message has been read.  Returns: S_FALSE
131    to signal Exchange to continue calling extensions.  EECB is a
132    pointer to the IExchExtCallback interface. FLAGS are some flags. */
133 STDMETHODIMP 
134 GpgolMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK eecb, ULONG flags)
135 {
136   log_debug ("%s:%s: received; flags=%#lx m_processed=%d\n",
137              SRCNAME, __func__, flags, m_processed);
138
139   /* If the message has been processed by us (i.e. in OnRead), we now
140      use our own display code.  */
141   if (!flags && m_processed)
142     {
143       HWND hwnd = NULL;
144
145       if (FAILED (eecb->GetWindow (&hwnd)))
146         hwnd = NULL;
147       if (message_display_handler (eecb, hwnd))
148         m_wasencrypted = true;
149     }
150   
151
152   return S_FALSE;
153 }
154
155
156 /* Called by Exchange when a message will be written. Returns: S_FALSE
157    to signal Exchange to continue calling extensions.  EECB is a
158    pointer to the IExchExtCallback interface. */
159 STDMETHODIMP 
160 GpgolMessageEvents::OnWrite (LPEXCHEXTCALLBACK eecb)
161 {
162   log_debug ("%s:%s: received\n", SRCNAME, __func__);
163
164   HRESULT hr;
165   LPDISPATCH pDisp;
166   DISPID dispid;
167   VARIANT aVariant;
168   DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
169   HWND hWnd = NULL;
170
171
172   /* If we are going to encrypt, check that the BodyFormat is
173      something we support.  This helps avoiding surprise by sending
174      out unencrypted messages. */
175   if (m_pExchExt->m_gpgEncrypt || m_pExchExt->m_gpgSign)
176     {
177       pDisp = find_outlook_property (eecb, "BodyFormat", &dispid);
178       if (!pDisp)
179         {
180           log_debug ("%s:%s: BodyFormat not found\n", SRCNAME, __func__);
181           m_bWriteFailed = TRUE;        
182           return E_FAIL;
183         }
184       
185       aVariant.bstrVal = NULL;
186       hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
187                           DISPATCH_PROPERTYGET, &dispparamsNoArgs,
188                           &aVariant, NULL, NULL);
189       if (hr != S_OK)
190         {
191           log_debug ("%s:%s: retrieving BodyFormat failed: %#lx",
192                      SRCNAME, __func__, hr);
193           m_bWriteFailed = TRUE;        
194           pDisp->Release();
195           return E_FAIL;
196         }
197   
198       if (aVariant.vt != VT_INT && aVariant.vt != VT_I4)
199         {
200           log_debug ("%s:%s: BodyFormat is not an integer (%d)",
201                      SRCNAME, __func__, aVariant.vt);
202           m_bWriteFailed = TRUE;        
203           pDisp->Release();
204           return E_FAIL;
205         }
206   
207       if (aVariant.intVal == 1)
208         m_want_html = 0;
209       else if (aVariant.intVal == 2)
210         m_want_html = 1;
211       else
212         {
213
214           log_debug ("%s:%s: BodyFormat is %d",
215                      SRCNAME, __func__, aVariant.intVal);
216           
217           if (FAILED(eecb->GetWindow (&hWnd)))
218             hWnd = NULL;
219           MessageBox (hWnd,
220                       _("Sorry, we can only encrypt plain text messages and\n"
221                       "no RTF messages. Please make sure that only the text\n"
222                       "format has been selected."),
223                       "GpgOL", MB_ICONERROR|MB_OK);
224
225           m_bWriteFailed = TRUE;        
226           pDisp->Release();
227           return E_FAIL;
228         }
229       pDisp->Release();
230       
231     }
232   
233   
234   return S_FALSE;
235 }
236
237
238
239
240 /* Called by Exchange when the data has been written to the message.
241    Encrypts and signs the message if the options are set.  EECB is a
242    pointer to the IExchExtCallback interface.  Returns: S_FALSE to
243    signal Exchange to continue calling extensions.  We return E_FAIL
244    to signals Exchange an error; the message will not be sent.  Note
245    that we don't return S_OK because this would mean that we rolled
246    back the write operation and that no further extensions should be
247    called. */
248 STDMETHODIMP 
249 GpgolMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK eecb, ULONG flags)
250 {
251   HRESULT hrReturn = S_FALSE;
252   LPMESSAGE msg = NULL;
253   LPMDB pMDB = NULL;
254   HWND hWnd = NULL;
255   int rc;
256
257   log_debug ("%s:%s: received\n", SRCNAME, __func__);
258
259
260   if (flags & (EEME_FAILED|EEME_COMPLETE_FAILED))
261     return S_FALSE; /* We don't need to rollback anything in case
262                        other extensions flagged a failure. */
263           
264   if (!m_bOnSubmitActive) /* The user is just saving the message. */
265     return S_FALSE;
266   
267   if (m_bWriteFailed)     /* Operation failed already. */
268     return S_FALSE;
269
270   /* Try to get the current window. */
271   if (FAILED(eecb->GetWindow (&hWnd)))
272     hWnd = NULL;
273
274   /* Get the object and call the encryption or signing function.  */
275   HRESULT hr = eecb->GetObject (&pMDB, (LPMAPIPROP *)&msg);
276   if (SUCCEEDED (hr))
277     {
278       protocol_t proto = m_pExchExt->m_protoSelection;
279       
280       if (m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
281         rc = message_sign_encrypt (msg, proto, hWnd);
282       else if (m_pExchExt->m_gpgEncrypt && !m_pExchExt->m_gpgSign)
283         rc = message_encrypt (msg, proto, hWnd);
284       else if (!m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
285         rc = message_sign (msg, proto, hWnd);
286       else
287         rc = 0;
288       
289       if (rc)
290         {
291           hrReturn = E_FAIL;
292           m_bWriteFailed = TRUE;        
293         }
294     }
295   
296   ul_release (msg, __func__, __LINE__);
297   ul_release (pMDB, __func__, __LINE__);
298   
299   return hrReturn;
300 }
301
302
303 /* Called by Exchange when the user selects the "check names" command.
304    EECB is a pointer to the IExchExtCallback interface.  Returns
305    S_FALSE to signal Exchange to continue calling extensions. */
306 STDMETHODIMP 
307 GpgolMessageEvents::OnCheckNames(LPEXCHEXTCALLBACK eecb)
308 {
309   log_debug ("%s:%s: received\n", SRCNAME, __func__);
310   return S_FALSE;
311 }
312
313
314 /* Called by Exchange when "check names" command is complete.
315    EECB is a pointer to the IExchExtCallback interface.  Returns
316    S_FALSE to signal Exchange to continue calling extensions. */
317 STDMETHODIMP 
318 GpgolMessageEvents::OnCheckNamesComplete (LPEXCHEXTCALLBACK eecb,ULONG flags)
319 {
320   log_debug ("%s:%s: received\n", SRCNAME, __func__);
321   return S_FALSE;
322 }
323
324
325 /* Called by Exchange before the message data will be written and
326    submitted to MAPI.  EECB is a pointer to the IExchExtCallback
327    interface.  Returns S_FALSE to signal Exchange to continue calling
328    extensions. */
329 STDMETHODIMP 
330 GpgolMessageEvents::OnSubmit (LPEXCHEXTCALLBACK eecb)
331 {
332   log_debug ("%s:%s: received\n", SRCNAME, __func__);
333   m_bOnSubmitActive = TRUE;
334   m_bWriteFailed = FALSE;
335   return S_FALSE;
336 }
337
338
339 /* Called by Exchange after the message has been submitted to MAPI.
340    EECB is a pointer to the IExchExtCallback interface. */
341 STDMETHODIMP_ (VOID) 
342 GpgolMessageEvents::OnSubmitComplete (LPEXCHEXTCALLBACK eecb, ULONG flags)
343 {
344   log_debug ("%s:%s: received\n", SRCNAME, __func__);
345   m_bOnSubmitActive = FALSE; 
346 }
347
348