Check that we only encrypt plain text bodies
authorWerner Koch <wk@gnupg.org>
Thu, 15 Sep 2005 09:36:29 +0000 (09:36 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 15 Sep 2005 09:36:29 +0000 (09:36 +0000)
TODO
src/ChangeLog
src/gpgmsg.cpp
src/myexchext.h
src/olflange.cpp

diff --git a/TODO b/TODO
index 3f9f49c..c622857 100644 (file)
--- a/TODO
+++ b/TODO
@@ -7,12 +7,11 @@
 * find out why sometimes the new body cannot set to a MAPI object. In
   this case the body is empty but the W32 API said it was correctly set.
   This might be due to the length of the object.  HrGetOneProp has
-  such limitations adn thus it owould be reasonable to assume that the
-  same holds true for HrSetOneProp.  We might want to use Openproperty
+  such limitations adn thus it would be reasonable to assume that the
+  same holds true for HrSetOneProp.  We might want to use OpenProperty
   for longer texts.
 
-* There is no verification status for attachments. What about
-  generating a new text attachemnts with the status information?  We
-  need to make sure that it can be identified as locally generated.
-
 * IMPORTANT: msgcache.c grows without limit - fix it.
+
+* Hook into OnDelivery and rename attachments named like the
+  Attestation attachment we generate locally.
index 114f6a3..41176c4 100644 (file)
@@ -1,3 +1,17 @@
+2005-09-15  Werner Koch  <wk@g10code.com>
+
+       * olflange.cpp (OnWriteComplete): Take care of EEME_FAILED.
+       (OnWrite): Check that we are encrypting only plain text messages.
+
+       * myexchext.h: Add flags used by OnReadComplete.
+
+2005-09-14  Werner Koch  <wk@g10code.com>
+
+       * gpgmsg.cpp (writeAttestation): Add a content type.
+       (gatherAttachmentInfo): Detect whether we already have an attestation.
+       (decrypt): Don't create duplicate attestations.
+       (writeAttestation): Translate LF to CRLF.
+
 2005-09-13  Werner Koch  <wk@g10code.com>
 
        * pgpmime.c (pgpmime_decrypt): New arg ATTESTATION.
index a2429ca..3b0ec29 100644 (file)
@@ -99,6 +99,7 @@ public:
     body = NULL;
     body_plain = NULL;
     is_pgpmime = false;
+    has_attestation = false;
     silent = false;
 
     attestation = NULL;
@@ -200,6 +201,7 @@ private:
   char *body;         /* utf-8 encoded body string or NULL. */
   char *body_plain;   /* Plaintext version of BODY or NULL. */
   bool is_pgpmime;    /* True if the message is a PGP/MIME encrypted one. */
+  bool has_attestation;/* True if we found an attestation attachment. */
   bool silent;        /* Don't pop up message boxes.  Currently this
                          is only used with decryption.  */
 
@@ -686,6 +688,7 @@ GpgMsgImpl::writeAttestation (void)
   LPATTACH newatt = NULL;
   LPSTREAM to = NULL;
   char *buffer = NULL;
+  char *p, *pend;
   ULONG nwritten;
 
   if (!message || !attestation)
@@ -709,6 +712,20 @@ GpgMsgImpl::writeAttestation (void)
       goto leave;
     }
   
+  /* It seem that we need to insert a short filename.  Without it the
+     _displayed_ list of attachments won't get updated although the
+     attachment has been created. */
+  prop.ulPropTag = PR_ATTACH_FILENAME_A;
+  prop.Value.lpszA = "gpgtstt0.txt";
+  hr = HrSetOneProp (newatt, &prop);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: can't set attach filename: hr=%#lx\n",
+                 __FILE__, __func__, hr); 
+      goto leave;
+    }
+
+  /* And not for the real name. */
   prop.ulPropTag = PR_ATTACH_LONG_FILENAME_A;
   prop.Value.lpszA = "GPGol-Attestation.txt";
   hr = HrSetOneProp (newatt, &prop);
@@ -718,7 +735,28 @@ GpgMsgImpl::writeAttestation (void)
                  __FILE__, __func__, hr); 
       goto leave;
     }
-  
+
+  prop.ulPropTag = PR_ATTACH_TAG;
+  prop.Value.bin.cb  = sizeof oid_mimetag;
+  prop.Value.bin.lpb = (LPBYTE)oid_mimetag;
+  hr = HrSetOneProp (newatt, &prop);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: can't set attach tag: hr=%#lx\n",
+                 __FILE__, __func__, hr); 
+      goto leave;
+    }
+
+  prop.ulPropTag = PR_ATTACH_MIME_TAG_A;
+  prop.Value.lpszA = "text/plain; charset=utf-8";
+  hr = HrSetOneProp (newatt, &prop);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: can't set attach mime tag: hr=%#lx\n",
+                 __FILE__, __func__, hr); 
+      goto leave;
+    }
+
   hr = newatt->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 0,
                              MAPI_CREATE|MAPI_MODIFY, (LPUNKNOWN*)&to);
   if (FAILED (hr)) 
@@ -739,13 +777,29 @@ GpgMsgImpl::writeAttestation (void)
   attestation = NULL;
 
   log_debug ("writing attestation `%s'\n", buffer);
-
-  hr = to->Write (buffer, strlen (buffer), &nwritten);
+  hr = S_OK;
+  if (!*buffer)
+    {
+      p = _("[No attestation computed (e.g. messages was not signed)");
+      hr = to->Write (p, strlen (p), &nwritten);
+    }
+  else
+    {
+      for (p=buffer; hr == S_OK && (pend = strchr (p, '\n')); p = pend+1)
+        {
+          hr = to->Write (p, pend - p, &nwritten);
+          if (hr == S_OK)
+            hr = to->Write ("\r\n", 2, &nwritten);
+        }
+      if (*p && hr == S_OK)
+        hr = to->Write (p, strlen (p), &nwritten);
+    }
   if (hr != S_OK)
     {
       log_debug ("%s:%s: Write failed: hr=%#lx", __FILE__, __func__, hr);
       goto leave;
     }
+      
   
   to->Commit (0);
   to->Release ();
@@ -859,7 +913,14 @@ GpgMsgImpl::decrypt (HWND hwnd)
   /* We always want an attestation.  Note that we ignore any error
      because that would anyway be a out of core situation and thus we
      can't do much about it. */
-  if (!attestation)
+  if (has_attestation)
+    {
+      if (attestation)
+        gpgme_data_release (attestation);
+      log_debug ("%s:%s: we already have an attestation\n",
+                 __FILE__, __func__);
+    }
+  else if (!attestation)
     gpgme_data_new (&attestation);
   
 
@@ -1726,6 +1787,7 @@ GpgMsgImpl::gatherAttachmentInfo (void)
   const char *s;
 
   is_pgpmime = false;
+  has_attestation = false;
   n_attach = getAttachments ();
   log_debug ("%s:%s: message has %u attachments\n",
              __FILE__, __func__, n_attach);
@@ -1766,6 +1828,12 @@ GpgMsgImpl::gatherAttachmentInfo (void)
               && !stricmp (s, ".asc"))
             table[pos].armor_type = get_pgp_armor_type (att,table[pos].method);
         }
+      if (table[pos].filename
+          && !stricmp (table[pos].filename, "GPGol-Attestation.txt")
+          && table[pos].content_type
+          && !stricmp (table[pos].content_type, "text/plain"))
+        has_attestation = true;
+
       att->Release ();
     }
   table[pos].end_of_table = 1;
@@ -1835,7 +1903,7 @@ GpgMsgImpl::gatherAttachmentInfo (void)
     }
 
   /* Simple check whether this is PGP/MIME encrypted.  At least with
-     OL2003 the conent-type of the body is also correctly set but we
+     OL2003 the content-type of the body is also correctly set but we
      don't make use of this as it is not clear whether this is true
      for othyer storage providers. */
   if (!opt.compat.no_pgpmime
index 2494285..9fa2822 100644 (file)
@@ -61,6 +61,10 @@ extern "C" {
 #define EEPS_STORE                      0x00000003
 #define EEPS_TOOLSOPTIONS               0x00000004
 
+/* Flags used by OnFooComplete. */
+#define EEME_FAILED                     0x00000001
+#define EEME_COMPLETE_FAILED            0x00000002
+
 
 /* Command IDs. */
 #define EECMDID_ToolsCustomizeToolbar          134
index 3c4de35..d489133 100644 (file)
@@ -691,16 +691,86 @@ CGPGExchExtMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK pEECB,
 STDMETHODIMP 
 CGPGExchExtMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
 {
-    log_debug ("%s:%s: received\n", __FILE__, __func__);
-    return S_FALSE;
+  log_debug ("%s:%s: received\n", __FILE__, __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)
+    {
+      pDisp = find_outlook_property (pEECB, "BodyFormat", &dispid);
+      if (!pDisp)
+        {
+          log_debug ("%s:%s: BodyFormat not found\n", __FILE__, __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",
+                     __FILE__, __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)",
+                     __FILE__, __func__, aVariant.vt);
+          m_bWriteFailed = TRUE;       
+          pDisp->Release();
+          return E_FAIL;
+        }
+  
+      if (aVariant.intVal != 1)
+        {
+
+          log_debug ("%s:%s: BodyFormat is %d",
+                     __FILE__, __func__, aVariant.intVal);
+          
+          if (FAILED(pEECB->GetWindow (&hWnd)))
+            hWnd = NULL;
+          MessageBox (hWnd,
+                      "Sorry, we can only encrypt plain text messages and no\n"
+                      "HTML or RTF messages. Please make sure that only the\n"
+                      "text 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.  E_FAIL to signals
-   Exchange an error; the message will not be sent */
+   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)
@@ -712,16 +782,20 @@ CGPGExchExtMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB,
   LPMDB pMDB = NULL;
   HWND hWnd = NULL;
   int rc;
-          
-  if (FAILED(pEECB->GetWindow (&hWnd)))
-    hWnd = NULL;
 
-  if (!m_bOnSubmitActive) /* the user is just saving the message */
+  if (lFlags & (EEME_FAILED|EEME_COMPLETE_FAILED))
+    return S_FALSE; /* We don't need to rollback anything in case
+                       other extensions flagged a failire. */
+          
+  if (!m_bOnSubmitActive) /* The user is just saving the message. */
     return S_FALSE;
   
-  if (m_bWriteFailed)     /* operation failed already */
+  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))
     {
@@ -954,7 +1028,7 @@ CGPGExchExtCommands::InstallCommands (
                     ((unsigned char*)key)[keylen++] = xtoi_2 (p);
                   
                   /* FIXME: Do we need to free the string returned in
-                     AVARIANT?  Check at other palces too. */
+                     AVARIANT?  Check at other places too. */
                 }
 
               pDisp->Release();