Basic HTMl support
authorWerner Koch <wk@gnupg.org>
Tue, 15 Nov 2005 16:06:38 +0000 (16:06 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 15 Nov 2005 16:06:38 +0000 (16:06 +0000)
15 files changed:
ChangeLog
NEWS
README
TODO
configure.ac
src/ChangeLog
src/config-dialog.c
src/display.cpp
src/display.h
src/engine-gpgme.c
src/gpgmsg.cpp
src/gpgmsg.hh
src/mymapitags.h
src/olflange.cpp
src/olflange.h

index a9b910e..15d1b90 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,16 @@
+2005-11-15  Werner Koch  <wk@g10code.com>
+
+       * configure.ac (BUILD_TIMESTAMP): Include SVN revision.
+
 2005-10-21  Marcus Brinkmann  <marcus@g10code.de>
 
        * m4/gpg-error.m4: New file.
        * configure.ac: Also check for gpg-error.
 
+2005-10-11  Werner Koch  <wk@g10code.com>
+
+       * configure.ac: Use MS style bitfields.
+
 2005-10-06  Marcus Brinkmann  <marcus@g10code.de>
 
        * configure.ac: Change AC_CONFIG_SRCDIR argument to src/gpgol.def.
diff --git a/NEWS b/NEWS
index 78a6c37..a311c55 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Noteworthy changes for version 0.9.4
+=================================================
+
+
 Noteworthy changes for version 0.9.3 (2005-09-29)
 =================================================
 
diff --git a/README b/README
index 5c5403e..2ed344d 100644 (file)
--- a/README
+++ b/README
@@ -16,14 +16,6 @@ available in a directory where Windows searches for DLLs
 gpgol.dll" and start Outlook. You should then find a new tab named
 "GnuPG" in Outlook's option menu.
 
-Note: For building in src/ you need to throw an original mapi32.dll
-into this directory.  This is due to a bug in the binutils: ld is not
-able to properly read a DEF file but will happily use the same
-information from an actual DLL.  The problem is that symbols like
-HrSetOneProp@8 are actually written without the "@8" into the import
-table when used with a DEF file and generated import lib.  Needs more
-debugging - any BFD cracks who can lend me a helping hand?  (wk).
-
 Bug reporting: First click on the logo on the GnuPG options tab to
 check whether a newer version has been released - try this first.  If
 this does not help, check out the mailing lists and also the bug
diff --git a/TODO b/TODO
index a1b8e03..583dea2 100644 (file)
--- a/TODO
+++ b/TODO
@@ -18,4 +18,3 @@
 
 * Allow for symmetric encryption.
 
-
index ebe5849..9f3d414 100644 (file)
@@ -14,8 +14,9 @@ AC_PREREQ(2.59)
 min_automake_version="1.9.4"
 
 # Version number: Remember to change it immediately *after* a release.
+#                 Make sure to run  "svn up" before a "make dist".
 #                 Add a "-cvs" prefix for non-released code.
-AC_INIT(gpgol, 0.9.3-cvs, bug-gpgol@g10code.com)
+AC_INIT(gpgol, 0.9.4-cvs, bug-gpgol@g10code.com)
 
 NEED_GPGME_API=1
 NEED_GPGME_VERSION=1.1.0
@@ -44,11 +45,15 @@ AC_DEFINE_UNQUOTED(PACKAGE_BUGREPORT, "$PACKAGE_BUGREPORT",
 AC_DEFINE_UNQUOTED(NEED_GPGME_VERSION, "$NEED_GPGME_VERSION",
                                        [Required version of GPGME])
 
+
 BUILD_TIMESTAMP=`date --iso-8601=minutes`
 AC_SUBST(BUILD_TIMESTAMP)
 changequote(,)dnl
-BUILD_FILEVERSION=`echo "$VERSION" | sed 's/\([0-9.]*\).*/\1.0/;s/\./,/g'`
+BUILD_FILEVERSION=`echo "$VERSION" | sed 's/\([0-9.]*\).*/\1./;s/\./,/g'`
+tmp="`echo '$Revision$' | sed 's/[^0-9]//g'`"
 changequote([,])dnl
+test -z "$tmp" && tmp="0"
+BUILD_FILEVERSION="${BUILD_FILEVERSION}$tmp"
 AC_SUBST(BUILD_FILEVERSION)
 
 
@@ -157,14 +162,13 @@ if test "$have_w32_system" = yes; then
 fi
 
 if test "$GCC" = yes; then
+    CFLAGS="$CFLAGS -Wall -mms-bitfields"
+    CXXFLAGS="$CXXFLAGS -Wall -mms-bitfields"
     if test "$USE_MAINTAINER_MODE" = "yes"; then
-        CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
+        CFLAGS="$CFLAGS -Wcast-align -Wshadow -Wstrict-prototypes"
         CFLAGS="$CFLAGS -Wno-format-y2k -Wformat-security"
-        CXXFLAGS="$CXXFLAGS -Wall -Wcast-align -Wshadow"
+        CXXFLAGS="$CXXFLAGS -Wcast-align -Wshadow"
         CXXFLAGS="$CXXFLAGS -Wno-format-y2k -Wformat-security"
-    else
-        CFLAGS="$CFLAGS -Wall"
-        CXXFLAGS="$CXXFLAGS -Wall"
     fi
 fi
 
index c100894..8e57f86 100644 (file)
@@ -1,3 +1,24 @@
+2005-11-15  Werner Koch  <wk@g10code.com>
+
+       * Makefile.am (gpgol_LDADD): Remove -lintl for now.
+
+       * olflange.cpp (OnWriteComplete): Make sure that we don't sent out
+       unencrypted stuff on error.
+       * display.cpp (set_message_body): Add arg IS_HTML.
+       (update_display): Ditto.
+
+       * gpgmsg.cpp (loadBody): New arg WANT_HTML.
+       (getOrigText): Ditto.
+
+       * olflange.h (class CGPGExchExtMessageEvents): Add M_WANT_HTML.
+       * olflange.cpp (OnWrite): Set it.
+       (OnWriteComplete): Pass its value to the encrypt functions.
+
+2005-11-10  Werner Koch  <wk@g10code.com>
+
+       * config-dialog.c (start_key_manager): Changed invocation of
+       default keymanager.
+
 2005-10-21  Marcus Brinkmann  <marcus@g10code.de>
 
        * Makefile.am (libgpgme.a, libgpgme.a): New targets.
        (gpgol_LDADD): Replace mapi32.dll with "-L . -lmapi32".
        (clean-local): New target.
 
+2005-10-19  Werner Koch  <wk@g10code.com>
+
+       * gpgmsg.cpp (sign, encrypt_and_sign): Don't set the body first to
+       empty. If this is really required we should do this in
+       set_message_body.
+       (sign): Save changes. Set content type to text/plain.
+       (encrypt_and_sign): Save changes also for empty bodies.
+
+2005-10-06  Werner Koch  <wk@g10code.com>
+
+       * gpgmsg.cpp (writeAttestation): Use gpgme_free for BUFFER.
+       * engine-gpgme.c (data_to_file): Ditto.
+
 2005-10-06  Marcus Brinkmann  <marcus@g10code.de>
 
        * Makefile.am (gpgol_DEPENDENCIES): New variable.
index f8ec0a1..ba45157 100644 (file)
@@ -390,7 +390,7 @@ start_key_manager (void)
         info = info->next;
       if (info && info->file_name && *info->file_name)
         {
-          keyman = xmalloc (strlen (info->file_name) + 10);
+          keyman = xmalloc (strlen (info->file_name) + 50);
           strcpy (keyman, info->file_name);
           for (p=keyman; *p; p++)
             if (*p == '/')
@@ -401,10 +401,10 @@ start_key_manager (void)
               xfree (keyman);
               return -1;
             }
-          strcpy (p+1, "winpt.exe");
+          strcpy (p+1, "winpt.exe --keymanager");
           if (access (keyman, F_OK))
             {
-              strcpy (p+1, "gpa.exe");
+              strcpy (p+1, "gpa.exe --keyring");
               if (access (keyman, F_OK))
                 {
                   xfree (keyman);
index 42a0256..aef5993 100644 (file)
@@ -131,7 +131,7 @@ find_message_window (HWND parent)
 
 /* Update the display using the message MSG.  Return 0 on success. */
 int
-update_display (HWND hwnd, GpgMsg *msg, void *exchange_cb)
+update_display (HWND hwnd, GpgMsg *msg, void *exchange_cb, bool is_html)
 {
   HWND window;
 
@@ -161,7 +161,7 @@ update_display (HWND hwnd, GpgMsg *msg, void *exchange_cb)
   else if (exchange_cb && !opt.compat.no_oom_write)
     {
       log_debug ("updating display using OOM");
-      return put_outlook_property (exchange_cb, "Body",
+      return put_outlook_property (exchange_cb, is_html? "HTMLBody":"Body",
                                    msg->getDisplayText ());
     }
   else
@@ -176,26 +176,28 @@ update_display (HWND hwnd, GpgMsg *msg, void *exchange_cb)
 /* Set the body of MESSAGE to STRING.  Returns 0 on success or an
    error code otherwise. */
 int
-set_message_body (LPMESSAGE message, const char *string)
+set_message_body (LPMESSAGE message, const char *string, bool is_html)
 {
   HRESULT hr;
   SPropValue prop;
-  //  BOOL dummy_bool;
+  SPropTagArray proparray;
   const char *s;
   
+  assert (message);
+  
   /* Decide whether we need to use the Unicode version. */
   for (s=string; *s && !(*s & 0x80); s++)
     ;
   if (*s)
     {
-      prop.ulPropTag = PR_BODY_W;
+      prop.ulPropTag = is_html? PR_BODY_HTML_W : PR_BODY_W;
       prop.Value.lpszW = utf8_to_wchar (string);
       hr = HrSetOneProp (message, &prop);
       xfree (prop.Value.lpszW);
     }
   else /* Only plain ASCII. */
     {
-      prop.ulPropTag = PR_BODY_A;
+      prop.ulPropTag = is_html? PR_BODY_HTML_A : PR_BODY_A;
       prop.Value.lpszA = (CHAR*)string;
       hr = HrSetOneProp (message, &prop);
     }
@@ -205,13 +207,14 @@ set_message_body (LPMESSAGE message, const char *string)
                  __FILE__, __func__, hr); 
       return gpg_error (GPG_ERR_GENERAL);
     }
-// When enabling the code below the result is that (under OL2003
-// standalone) the message is sent with an empty body.  Thus we don't
-// do it.  Note further that the specs say that when dummy_bool
-// returns true, SaveChanges must be called on the message.
-//   hr = RTFSync (message, RTF_SYNC_BODY_CHANGED, &dummy_bool);
-//   if (hr != S_OK)
-//     log_debug ("%s:%s: RTFSync failed: hr=%#lx - error ignored",
-//                __FILE__, __func__, hr); 
+
+  /* Instead of using RTF Sync, we simply delete any RTF property. */
+  proparray.cValues = 1;
+  proparray.aulPropTag[0] = PR_RTF_COMPRESSED;
+  hr = message->DeleteProps (&proparray, NULL);
+  if (hr != S_OK)
+    log_debug ("%s:%s: DeleteProps failed: hr=%#lx\n", __FILE__, __func__, hr);
+  
+    
   return 0;
 }
index 2a979d0..b051ffe 100644 (file)
@@ -28,9 +28,9 @@ int is_html_body (const char *body);
 
 char *add_html_line_endings (const char *body);
 
-int update_display (HWND hwnd, GpgMsg *msg, void *exchange_cb);
+int update_display (HWND hwnd, GpgMsg *msg, void *exchange_cb, bool is_html);
 
-int set_message_body (LPMESSAGE message, const char *string);
+int set_message_body (LPMESSAGE message, const char *string, bool is_html);
 
 
 /*-- olflange.cpp --*/
index 6cbfa49..3c08118 100644 (file)
@@ -218,9 +218,10 @@ check_encrypt_result (gpgme_ctx_t ctx, gpgme_error_t err)
 
 
 /* Encrypt the data in INBUF into a newly malloced buffer stored on
-   success at OUTBUF. The recipients are expected in the NULL
-   terminated array KEYS. If SIGN_KEY is not NULl, the data will also
-   be signed using this key.  TTL is the time the passphrase should be
+   success at OUTBUF.  The caller should release this buffer using
+   gpgme_free.  The recipients are expected in the NULL terminated
+   array KEYS. If SIGN_KEY is not NULl, the data will also be signed
+   using this key.  TTL is the time the passphrase should be
    cached. */
 int
 op_encrypt (const char *inbuf, char **outbuf, gpgme_key_t *keys,
@@ -355,7 +356,7 @@ op_encrypt_stream (LPSTREAM instream, LPSTREAM outstream, gpgme_key_t *keys,
 
 \f
 /* Sign and encrypt the data in INBUF into a newly allocated buffer at
-   OUTBUF. */
+   OUTBUF. Caller needs to free the returned buffer using gpgme_free. */
 int
 op_sign (const char *inbuf, char **outbuf, int mode,
          gpgme_key_t sign_key, int ttl)
@@ -477,11 +478,12 @@ op_sign_stream (LPSTREAM instream, LPSTREAM outstream, int mode,
 
 
 \f
-/* Run the decryption.  Decrypts INBUF to OUTBUF, caller must xfree
-   the result at OUTBUF.  TTL is the time in seconds to cache a
-   passphrase.  If FILENAME is not NULL it will be displayed along
-   with status outputs. If ATTESTATION is not NULL a text with the
-   result of the signature verification will get printed to it. */
+/* Run the decryption.  Decrypts INBUF to OUTBUF; caller needs to free
+   the returned result at OUTBUF using gpgme_free.  the result at
+   OUTBUF.  TTL is the time in seconds to cache a passphrase.  If
+   FILENAME is not NULL it will be displayed along with status
+   outputs. If ATTESTATION is not NULL a text with the result of the
+   signature verification will get printed to it. */
 int 
 op_decrypt (const char *inbuf, char **outbuf, int ttl, const char *filename,
             gpgme_data_t attestation)
@@ -664,7 +666,8 @@ op_decrypt_stream (LPSTREAM instream, LPSTREAM outstream, int ttl,
 }
 
 
-/* Decrypt the stream INSTREAM directly to the newly allocated buffer OUTBUF.
+/* Decrypt the stream INSTREAM directly to the newly allocated buffer
+   OUTBUF.  Caller needs to free the returned buffer using gpgme_free.
    Returns 0 on success or an gpgme error code on failure.  If
    FILENAME is not NULL it will be displayed along with status
    outputs. */
@@ -738,7 +741,8 @@ op_decrypt_stream_to_gpgme (LPSTREAM instream, gpgme_data_t out, int ttl,
    will show the result of the verification.  If FILENAME is not NULL
    it will be displayed along with status outputs.  If ATTESTATION is
    not NULL a text with the result of the signature verification will
-   get printed to it. */
+   get printed to it. Caller needs to free the returned buffer at
+   OUTBUF using gpgme_free. */
 int
 op_verify (const char *inbuf, char **outbuf, const char *filename,
            gpgme_data_t attestation)
@@ -1267,7 +1271,7 @@ data_to_file (gpgme_data_t *dat, const char *outfile)
   fwrite (buf, 1, n, out);
   fclose (out);
   /* FIXME: We have no error checking above. */
-  xfree (buf);
+  gpgme_free (buf);
   return 0;
 }
 
index 584dd26..d3a32fb 100644 (file)
@@ -169,19 +169,19 @@ public:
 
   openpgp_t getMessageType (void);
   bool hasAttachments (void);
-  const char *getOrigText (void);
+  const char *getOrigText (bool want_html);
   const char *GpgMsgImpl::getDisplayText (void);
   const char *getPlainText (void);
 
   int decrypt (HWND hwnd);
   int sign (HWND hwnd);
-  int encrypt (HWND hwnd)
+  int encrypt (HWND hwnd, bool want_html)
   {
-    return encrypt_and_sign (hwnd, false);
+    return encrypt_and_sign (hwnd, want_html, false);
   }
-  int signEncrypt (HWND hwnd)
+  int signEncrypt (HWND hwnd, bool want_html)
   {
-    return encrypt_and_sign (hwnd, true);
+    return encrypt_and_sign (hwnd, want_html, true);
   }
   int attachPublicKey (const char *keyid);
 
@@ -218,11 +218,11 @@ private:
     LPSRowSet   rows;     /* The retrieved set of rows from the table. */
   } attach;
   
-  void loadBody (void);
+  void loadBody (bool want_html);
   bool isPgpmimeVersionPart (int pos);
   void writeAttestation (void);
   attach_info_t gatherAttachmentInfo (void);
-  int encrypt_and_sign (HWND hwnd, bool sign);
+  int encrypt_and_sign (HWND hwnd, bool want_html, bool sign);
 };
 
 
@@ -366,7 +366,7 @@ text_from_attach_info (attach_info_t table, const char *format,
 /* Load the body and make it available as an UTF8 string in the
    instance variable BODY.  */
 void
-GpgMsgImpl::loadBody (void)
+GpgMsgImpl::loadBody (bool want_html)
 {
   HRESULT hr;
   LPSPropValue lpspvFEID = NULL;
@@ -378,7 +378,8 @@ GpgMsgImpl::loadBody (void)
   if (body || !message)
     return;
 
-  hr = HrGetOneProp ((LPMAPIPROP)message, PR_BODY, &lpspvFEID);
+  hr = HrGetOneProp ((LPMAPIPROP)message,
+                     want_html? PR_BODY_HTML : PR_BODY, &lpspvFEID);
   if (SUCCEEDED (hr))
     { /* Message is small enough to be retrieved this way. */
       switch ( PROP_TYPE (lpspvFEID->ulPropTag) )
@@ -402,8 +403,8 @@ GpgMsgImpl::loadBody (void)
     }
   else /* Message is large; Use a stream to read it. */
     {
-      hr = message->OpenProperty (PR_BODY, &IID_IStream,
-                                  0, 0, (LPUNKNOWN*)&stream);
+      hr = message->OpenProperty (want_html? PR_BODY_HTML : PR_BODY,
+                                  &IID_IStream, 0, 0, (LPUNKNOWN*)&stream);
       if ( hr != S_OK )
         {
           log_debug ("%s:%s: OpenProperty failed: hr=%#lx",
@@ -556,7 +557,7 @@ GpgMsgImpl::getMessageType (void)
 {
   const char *s;
   
-  loadBody ();
+  loadBody (false);
   
   if (!body || !(s = strstr (body, "BEGIN PGP ")))
     return OPENPGP_NONE;
@@ -580,9 +581,9 @@ GpgMsgImpl::getMessageType (void)
 /* Return the body text as received or composed.  This is guaranteed
    to never return NULL.  */
 const char *
-GpgMsgImpl::getOrigText ()
+GpgMsgImpl::getOrigText (bool want_html)
 {
-  loadBody ();
+  loadBody (want_html);
   
   return body? body : "";
 }
@@ -593,7 +594,7 @@ GpgMsgImpl::getOrigText ()
 const char *
 GpgMsgImpl::getDisplayText (void)
 {
-  loadBody ();
+  loadBody (false);
 
   if (body_plain)
     return body_plain;
@@ -839,7 +840,7 @@ GpgMsgImpl::writeAttestation (void)
     }
   if (newatt)
     newatt->Release ();
-  xfree (buffer);
+  gpgme_free (buffer);
 }
 
 
@@ -905,7 +906,7 @@ GpgMsgImpl::decrypt (HWND hwnd)
         {
           xfree (body_plain);
           body_plain = xstrdup (s);
-          update_display (hwnd, this, exchange_cb);
+          update_display (hwnd, this, exchange_cb, is_html_body (s));
           msgcache_unref (refhandle);
           log_debug ("%s:%s: leave (already decrypted)\n", __FILE__, __func__);
         }
@@ -989,9 +990,9 @@ GpgMsgImpl::decrypt (HWND hwnd)
         pgpmime_succeeded = 1;
     }
   else if (mtype == OPENPGP_CLEARSIG)
-    err = op_verify (getOrigText (), NULL, NULL, attestation);
-  else if (*getOrigText())
-    err = op_decrypt (getOrigText (), &plaintext, opt.passwd_ttl,
+    err = op_verify (getOrigText (false), NULL, NULL, attestation);
+  else if (*getOrigText(false))
+    err = op_decrypt (getOrigText (false), &plaintext, opt.passwd_ttl,
                       NULL, attestation);
   else
     err = gpg_error (GPG_ERR_NO_DATA);
@@ -1022,7 +1023,7 @@ GpgMsgImpl::decrypt (HWND hwnd)
          we will disable it but add a compatibility flag to re-enable
          it. */
       if (opt.compat.old_reply_hack)
-        set_message_body (message, plaintext);
+        set_message_body (message, plaintext, is_html);
 
       xfree (body_plain);
       body_plain = plaintext;
@@ -1037,10 +1038,10 @@ GpgMsgImpl::decrypt (HWND hwnd)
           if (FAILED (hr))
             log_debug ("%s:%s: SaveChanges failed: hr=%#lx",
                        __FILE__, __func__, hr);
-          update_display (hwnd, this, exchange_cb);
+          update_display (hwnd, this, exchange_cb, is_html);
           
         }
-      else if (!silent && update_display (hwnd, this, exchange_cb)) 
+      else if (!silent && update_display (hwnd, this, exchange_cb, is_html)) 
         {
           const char s[] = 
             "The message text cannot be displayed.\n"
@@ -1128,16 +1129,18 @@ GpgMsgImpl::decrypt (HWND hwnd)
 int
 GpgMsgImpl::sign (HWND hwnd)
 {
+  HRESULT hr;
   const char *plaintext;
   char *signedtext = NULL;
   int err = 0;
   gpgme_key_t sign_key = NULL;
+  SPropValue prop;
 
   log_debug ("%s:%s: enter message=%p\n", __FILE__, __func__, message);
   
   /* We don't sign an empty body - a signature on a zero length string
      is pretty much useless. */
-  if (!*(plaintext = getOrigText ()) && !hasAttachments ()) 
+  if (!*(plaintext = getOrigText (false)) && !hasAttachments ()) 
     {
       log_debug ("%s:%s: leave (empty)", __FILE__, __func__);
       return 0; 
@@ -1174,20 +1177,38 @@ GpgMsgImpl::sign (HWND hwnd)
          failed. */
     }
 
-  set_x_header (message, "Gpgol-Version", PACKAGE_VERSION);
+  set_x_header (message, "GPGOL-VERSION", PACKAGE_VERSION);
 
   /* Now that we successfully processed the attachments, we can save
-     the changes to the body.  For unknown reasons we need to set it
-     to empty first. */
+     the changes to the body.  */
   if (*plaintext)
     {
-      err = set_message_body (message, "");
-      if (!err)
-        err = set_message_body (message, signedtext);
+      err = set_message_body (message, signedtext, 0);
       if (err)
         goto leave;
-    }
 
+      /* In case we don't have attachments, Outlook will really insert
+         the following content type into the header.  We use this to
+         declare that the encrypted content of the message is utf-8
+         encoded. */
+      prop.ulPropTag=PR_CONTENT_TYPE_A;
+      prop.Value.lpszA="text/plain; charset=utf-8"; 
+      hr = HrSetOneProp (message, &prop);
+      if (hr != S_OK)
+        {
+          log_error ("%s:%s: can't set content type: hr=%#lx\n",
+                     __FILE__, __func__, hr);
+        }
+    }
+  
+  hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: SaveChanges(message) failed: hr=%#lx\n",
+                 __FILE__, __func__, hr); 
+      err = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
+    }
 
  leave:
   xfree (signedtext);
@@ -1198,16 +1219,17 @@ GpgMsgImpl::sign (HWND hwnd)
 
 
 \f
-/* Encrypt and optionally sign (if SIGN_FLAG is true) the entire message
-   including all attachments. Returns 0 on success. */
+/* Encrypt and optionally sign (if SIGN_FLAG is true) the entire
+   message including all attachments.  If WANT_HTML is true, the text
+   to encrypt will be taken from the html property. Returns 0 on
+   success. */
 int 
-GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
+GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool want_html, bool sign_flag)
 {
   log_debug ("%s:%s: enter\n", __FILE__, __func__);
   HRESULT hr;
   gpgme_key_t *keys = NULL;
   gpgme_key_t sign_key = NULL;
-  bool is_html;
   const char *plaintext;
   char *ciphertext = NULL;
   char **recipients = NULL;
@@ -1217,7 +1239,7 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
   SPropValue prop;
     
   
-  if (!*(plaintext = getOrigText ()) && !hasAttachments ()) 
+  if (!*(plaintext = getOrigText (want_html)) && !hasAttachments ()) 
     {
       log_debug ("%s:%s: leave (empty)", __FILE__, __func__);
       return 0; 
@@ -1278,8 +1300,6 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
 
   if (*plaintext)
     {
-      is_html = is_html_body (plaintext);
-
       err = op_encrypt (plaintext, &ciphertext, 
                         keys, sign_key, opt.passwd_ttl);
       if (err)
@@ -1289,7 +1309,7 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
           goto leave;
         }
 
-      if (is_html) 
+      if (want_html) 
         {
           char *tmp = add_html_line_endings (ciphertext);
           xfree (ciphertext);
@@ -1329,20 +1349,18 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
   set_x_header (message, "GPGOL-VERSION", PACKAGE_VERSION);
 
   /* Now that we successfully processed the attachments, we can save
-     the changes to the body.  For unknown reasons we need to set it
-     to empty first. */
+     the changes to the body.  */
   if (*plaintext)
     {
-      err = set_message_body (message, "");
-      if (!err)
-        err = set_message_body (message, ciphertext);
+      err = set_message_body (message, ciphertext, want_html);
       if (err)
         goto leave;
 
       /* In case we don't have attachments, Outlook will really insert
          the following content type into the header.  We use this to
          declare that the encrypted content of the message is utf-8
-         encoded. */
+         encoded.  Note that we use plain/text even for HTML because
+         it is base64 encoded. */
       prop.ulPropTag=PR_CONTENT_TYPE_A;
       prop.Value.lpszA="text/plain; charset=utf-8"; 
       hr = HrSetOneProp (message, &prop);
@@ -1351,15 +1369,15 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
           log_error ("%s:%s: can't set content type: hr=%#lx\n",
                      __FILE__, __func__, hr);
         }
-
-      hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
-      if (hr != S_OK)
-        {
-          log_error ("%s:%s: SaveChanges(message) failed: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
-          err = gpg_error (GPG_ERR_GENERAL);
-          goto leave;
-        }
+    }
+  
+  hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: SaveChanges(message) failed: hr=%#lx\n",
+                 __FILE__, __func__, hr); 
+      err = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
     }
 
  leave:
@@ -2214,7 +2232,7 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
           att->Release ();
           att = NULL;
           if (message->DeleteAttach (pos, 0, NULL, 0) == S_OK)
-            log_error ("%s:%s: failed to delete attacghment %d: %s",
+            log_error ("%s:%s: failed to delete attachment %d: %s",
                        __FILE__, __func__, pos, op_strerror (err)); 
           
         }
index b928782..782578b 100644 (file)
@@ -62,7 +62,7 @@ public:
   /* Return the body text as received or composed.  This is guaranteed
      to never return NULL.  Usually getMessageType is used to check
      whether there is a suitable message. */
-  virtual const char *getOrigText (void) = 0;
+  virtual const char *getOrigText (bool want_html) = 0;
 
   /* Return the text of the message to be used for the display.  The
      message objects has intrinsic knowledge about the correct
@@ -82,11 +82,11 @@ public:
 
   /* Encrypt the entire message including any attachments. Returns 0
      on success. */
-  virtual int encrypt (HWND hwnd) = 0;
+  virtual int encrypt (HWND hwnd, bool want_html) = 0;
 
   /* Encrypt and sign the entire message including any
      attachments. Return 0 on success. */
-  virtual int signEncrypt (HWND hwnd) = 0;
+  virtual int signEncrypt (HWND hwnd, bool want_html) = 0;
 
   /* Attach the key identified by KEYID to the message. */
   virtual int attachPublicKey (const char *keyid) = 0;
index a017861..609abc2 100644 (file)
 #define PR_YPOS                               PROP_TAG( PT_LONG,        0x3F06)
 #define PR_CONTROL_ID                         PROP_TAG( PT_BINARY,      0x3F07)
 #define PR_INITIAL_DETAILS_PANE               PROP_TAG( PT_LONG,        0x3F08)
+#define PR_MSG_EDITOR_FORMAT                  PROP_TAG( PT_LONG,        0x5903)
 
 #define PROP_ID_SECURE_MIN                0x67F0
 #define PROP_ID_SECURE_MAX                0x67FF
index 5de2d31..8a20baf 100644 (file)
@@ -641,6 +641,7 @@ CGPGExchExtMessageEvents::CGPGExchExtMessageEvents
   m_pExchExt = pParentInterface;
   m_lRef = 0; 
   m_bOnSubmitActive = FALSE;
+  m_want_html = FALSE;
 }
 
 
@@ -777,7 +778,11 @@ CGPGExchExtMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
           return E_FAIL;
         }
   
-      if (aVariant.intVal != 1)
+      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",
@@ -786,9 +791,9 @@ CGPGExchExtMessageEvents::OnWrite (LPEXCHEXTCALLBACK pEECB)
           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.",
+                      "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;       
@@ -826,7 +831,7 @@ CGPGExchExtMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB,
 
   if (lFlags & (EEME_FAILED|EEME_COMPLETE_FAILED))
     return S_FALSE; /* We don't need to rollback anything in case
-                       other extensions flagged a failire. */
+                       other extensions flagged a failure. */
           
   if (!m_bOnSubmitActive) /* The user is just saving the message. */
     return S_FALSE;
@@ -840,22 +845,48 @@ CGPGExchExtMessageEvents::OnWriteComplete (LPEXCHEXTCALLBACK pEECB,
   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);
+        rc = m->signEncrypt (hWnd, m_want_html);
       if (m_pExchExt->m_gpgEncrypt && !m_pExchExt->m_gpgSign)
-        rc = m->encrypt (hWnd);
+        rc = m->encrypt (hWnd, m_want_html);
       if (!m_pExchExt->m_gpgEncrypt && m_pExchExt->m_gpgSign)
         rc = m->sign (hWnd);
       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. */
+      if (m_pExchExt->m_gpgEncrypt)
+        {
+          proparray.cValues = 1;
+          proparray.aulPropTag[0] = m_want_html? PR_BODY : PR_BODY_HTML;
+          msg->DeleteProps (&proparray, NULL);
+        }
       
       if (rc)
         {
           hrReturn = E_FAIL;
           m_bWriteFailed = TRUE;       
+
+          /* Due to an error in Outlook the error is ignored and the
+             message sent out anyway.  Thus we better delete the stuff
+             now. */
+          if (m_pExchExt->m_gpgEncrypt)
+            {
+              proparray.cValues = 1;
+              proparray.aulPropTag[0] = m_want_html? PR_BODY_HTML : PR_BODY;
+              hr = msg->DeleteProps (&proparray, NULL);
+              if (hr != S_OK)
+                log_debug ("%s:%s: DeleteProps failed: hr=%#lx\n",
+                           __FILE__, __func__, hr);
+              /* FIXME: We should delete the atatchments too. */
+            }
+          
         }
     }
 
index 45ca1fb..3cb5666 100644 (file)
@@ -84,6 +84,7 @@ private:
   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);