Added translation framework and translated a few strings.
[gpgol.git] / src / gpgmsg.cpp
index 9d029ea..b4edf31 100644 (file)
@@ -1,14 +1,14 @@
 /* gpgmsg.cpp - Implementation ofthe GpgMsg class
  *     Copyright (C) 2005 g10 Code GmbH
  *
- * This file is part of OutlGPG.
+ * This file is part of GPGol.
  * 
- * OutlGPG 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.
  * 
- * OutlGPG 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.
@@ -34,6 +34,7 @@
 #include "gpgmsg.hh"
 #include "util.h"
 #include "msgcache.h"
+#include "pgpmime.h"
 #include "engine.h"
 #include "display.h"
 
@@ -42,13 +43,29 @@ static const char oid_mimetag[] =
 
 
 #define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
-                                       __FILE__, __func__, __LINE__); \
+                                       SRCNAME, __func__, __LINE__); \
                         } while (0)
 
+/* Constants to describe the PGP armor types. */
+typedef enum 
+  {
+    ARMOR_NONE = 0,
+    ARMOR_MESSAGE,
+    ARMOR_SIGNATURE,
+    ARMOR_SIGNED,
+    ARMOR_FILE,     
+    ARMOR_PUBKEY,
+    ARMOR_SECKEY
+  }
+armor_t;
+
+
 struct attach_info
 {
   int end_of_table;  /* True if this is the last plus one entry of the
                         table. */
+  int invalid;       /* Invalid table entry - usally ignored. */
+   
   int is_encrypted;  /* This is an encrypted attchment. */
   int is_signed;     /* This is a signed attachment. */
   unsigned int sig_pos; /* For signed attachments the index of the
@@ -61,7 +78,7 @@ struct attach_info
                         against "type/subtype" is sufficient. */
   const char *content_type_parms; /* If not NULL the parameters of the
                                      content_type. */
-
+  armor_t armor_type;   /* 0 or the type of the PGP armor. */
 };
 typedef struct attach_info *attach_info_t;
 
@@ -72,7 +89,7 @@ static bool set_x_header (LPMESSAGE msg, const char *name, const char *val);
 
 
 /*
-   The implementation class of MapiGPGME.  
+   The implementation class of GpgMsg.  
  */
 class GpgMsgImpl : public GpgMsg
 {
@@ -84,7 +101,10 @@ public:
     body = NULL;
     body_plain = NULL;
     is_pgpmime = false;
-    
+    has_attestation = false;
+    silent = false;
+
+    attestation = NULL;
 
     attach.att_table = NULL;
     attach.rows = NULL;
@@ -97,6 +117,9 @@ public:
     xfree (body);
     xfree (body_plain);
 
+    if (attestation)
+      gpgme_data_release (attestation);
+
     if (attach.att_table)
       {
         attach.att_table->Release ();
@@ -139,23 +162,26 @@ public:
     exchange_cb = cb;
   }
   
+  void setSilent (bool value)
+  {
+    silent = value;
+  }
+
   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);
-  bool matchesString (const char *string);
 
   int decrypt (HWND hwnd);
-  int verify (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);
 
@@ -177,6 +203,13 @@ 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.  */
+
+  /* If not NULL, collect attestation information here. */
+  gpgme_data_t attestation;
+  
 
   /* This structure collects the information about attachments. */
   struct 
@@ -185,10 +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);
 };
 
 
@@ -217,17 +251,15 @@ free_key_array (gpgme_key_t *keys)
     }
 }
 
-/* Release an array of strings with recipient names. */
+/* Release an array of strings. */
 static void
-free_recipient_array (char **recipients)
+free_string_array (char **strings)
 {
-  int i;
-
-  if (recipients)
+  if (strings)
     {
-      for (i=0; recipients[i]; i++) 
-       xfree (recipients[i]);  
-      xfree (recipients);
+      for (int i=0; strings[i]; i++) 
+       xfree (strings[i]);     
+      xfree (strings);
     }
 }
 
@@ -248,13 +280,23 @@ release_attach_info (attach_info_t table)
 }
 
 
-/* Return the number of recipients in the array RECIPIENTS. */
-static int 
-count_recipients (char **recipients)
+/* Return the number of strings in the array STRINGS. */
+static size_t
+count_strings (char **strings)
 {
-  int i;
+  size_t i;
+  
+  for (i=0; strings[i]; i++)
+    ;
+  return i;
+}
+
+static size_t
+count_keys (gpgme_key_t *keys)
+{
+  size_t i;
   
-  for (i=0; recipients[i] != NULL; i++)
+  for (i=0; keys[i]; i++)
     ;
   return i;
 }
@@ -324,19 +366,20 @@ 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;
   LPSTREAM stream;
-  SPropValue prop;
+//   SPropValue prop;
   STATSTG statInfo;
   ULONG nread;
 
   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) )
@@ -360,19 +403,28 @@ 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",
-                     __FILE__, __func__, hr);
+                     SRCNAME, __func__, hr);
+          if (want_html)
+            {
+              log_debug ("%s:%s: trying to read it from the OOM\n",
+                         SRCNAME, __func__);
+              body = get_outlook_property (exchange_cb, "HTMLBody");
+              if (body)
+                goto ready;
+            }
+          
           return;
         }
       
       hr = stream->Stat (&statInfo, STATFLAG_NONAME);
       if ( hr != S_OK )
         {
-          log_debug ("%s:%s: Stat failed: hr=%#lx", __FILE__, __func__, hr);
+          log_debug ("%s:%s: Stat failed: hr=%#lx", SRCNAME, __func__, hr);
           stream->Release ();
           return;
         }
@@ -385,7 +437,7 @@ GpgMsgImpl::loadBody (void)
       hr = stream->Read (body, (size_t)statInfo.cbSize.QuadPart, &nread);
       if ( hr != S_OK )
         {
-          log_debug ("%s:%s: Read failed: hr=%#lx", __FILE__, __func__, hr);
+          log_debug ("%s:%s: Read failed: hr=%#lx", SRCNAME, __func__, hr);
           xfree (body);
           body = NULL;
           stream->Release ();
@@ -395,7 +447,7 @@ GpgMsgImpl::loadBody (void)
       body[nread+1] = 0;
       if (nread != statInfo.cbSize.QuadPart)
         {
-          log_debug ("%s:%s: not enough bytes returned\n", __FILE__, __func__);
+          log_debug ("%s:%s: not enough bytes returned\n", SRCNAME, __func__);
           xfree (body);
           body = NULL;
           stream->Release ();
@@ -417,9 +469,10 @@ GpgMsgImpl::loadBody (void)
       }
     }
 
+ ready:
   if (body)
     log_debug ("%s:%s: loaded body `%s' at %p\n",
-               __FILE__, __func__, body, body);
+               SRCNAME, __func__, body, body);
   
 
 //   prop.ulPropTag = PR_ACCESS;
@@ -427,12 +480,13 @@ GpgMsgImpl::loadBody (void)
 //   hr = HrSetOneProp (message, &prop);
 //   if (FAILED (hr))
 //     log_debug ("%s:%s: updating message access to 0x%08lx failed: hr=%#lx",
-//                    __FILE__, __func__, prop.Value.l, hr);
+//                    SRCNAME, __func__, prop.Value.l, hr);
 }
 
 
 /* Return the subject of the message or NULL if it does not
    exists.  Caller must free. */
+#if 0
 static char *
 get_subject (LPMESSAGE obj)
 {
@@ -444,7 +498,7 @@ get_subject (LPMESSAGE obj)
   if (FAILED (hr))
     {
       log_error ("%s:%s: error getting the subject: hr=%#lx",
-                 __FILE__, __func__, hr);
+                 SRCNAME, __func__, hr);
       return NULL; 
     }
   switch ( PROP_TYPE (propval->ulPropTag) )
@@ -452,7 +506,7 @@ get_subject (LPMESSAGE obj)
     case PT_UNICODE:
       name = wchar_to_utf8 (propval->Value.lpszW);
       if (!name)
-        log_debug ("%s:%s: error converting to utf8\n", __FILE__, __func__);
+        log_debug ("%s:%s: error converting to utf8\n", SRCNAME, __func__);
       break;
       
     case PT_STRING8:
@@ -460,17 +514,19 @@ get_subject (LPMESSAGE obj)
       break;
       
     default:
-      log_debug ("%s:%s: proptag=%xlx not supported\n",
-                 __FILE__, __func__, propval->ulPropTag);
+      log_debug ("%s:%s: proptag=%#lx not supported\n",
+                 SRCNAME, __func__, propval->ulPropTag);
       name = NULL;
       break;
     }
   MAPIFreeBuffer (propval);
   return name;
 }
+#endif
 
 /* Set the subject of the message OBJ to STRING. Returns 0 on
    success. */
+#if 0
 static int
 set_subject (LPMESSAGE obj, const char *string)
 {
@@ -497,12 +553,12 @@ set_subject (LPMESSAGE obj, const char *string)
   if (hr != S_OK)
     {
       log_debug ("%s:%s: HrSetOneProp failed: hr=%#lx\n",
-                 __FILE__, __func__, hr); 
+                 SRCNAME, __func__, hr); 
       return gpg_error (GPG_ERR_GENERAL);
     }
   return 0;
 }
-
+#endif
 
 
 /* Return the type of a message. */
@@ -511,7 +567,7 @@ GpgMsgImpl::getMessageType (void)
 {
   const char *s;
   
-  loadBody ();
+  loadBody (false);
   
   if (!body || !(s = strstr (body, "BEGIN PGP ")))
     return OPENPGP_NONE;
@@ -535,9 +591,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 : "";
 }
@@ -548,7 +604,7 @@ GpgMsgImpl::getOrigText ()
 const char *
 GpgMsgImpl::getDisplayText (void)
 {
-  loadBody ();
+  loadBody (false);
 
   if (body_plain)
     return body_plain;
@@ -559,17 +615,6 @@ GpgMsgImpl::getDisplayText (void)
 }
 
 
-/* Returns true if STRING matches the actual message. */ 
-bool
-GpgMsgImpl::matchesString (const char *string)
-{
-  /* FIXME:  This is a too simple implementation. */
-  if (string && strstr (string, "BEGIN PGP ") )
-    return true;
-  return false;
-}
-
-
 
 /* Return an array of strings with the recipients of the message. On
    success a malloced array is returned containing allocated strings
@@ -584,7 +629,6 @@ GpgMsgImpl::getRecipients ()
   LPMAPITABLE lpRecipientTable = NULL;
   LPSRowSet lpRecipientRows = NULL;
   char **rset;
-  const char *s;
   int i, j;
 
   if (!message)
@@ -594,7 +638,7 @@ GpgMsgImpl::getRecipients ()
   if (FAILED (hr)) 
     {
       log_debug_w32 (-1, "%s:%s: GetRecipientTable failed",
-                     __FILE__, __func__);
+                     SRCNAME, __func__);
       return NULL;
     }
 
@@ -602,7 +646,7 @@ GpgMsgImpl::getRecipients ()
                        NULL, NULL, 0L, &lpRecipientRows);
   if (FAILED (hr)) 
     {
-      log_debug_w32 (-1, "%s:%s: GHrQueryAllRows failed", __FILE__, __func__);
+      log_debug_w32 (-1, "%s:%s: GHrQueryAllRows failed", SRCNAME, __func__);
       if (lpRecipientTable)
         lpRecipientTable->Release();
       return NULL;
@@ -610,7 +654,7 @@ GpgMsgImpl::getRecipients ()
 
   rset = (char**)xcalloc (lpRecipientRows->cRows+1, sizeof *rset);
 
-  for (i = j = 0; i < lpRecipientRows->cRows; i++)
+  for (i = j = 0; (unsigned int)i < lpRecipientRows->cRows; i++)
     {
       LPSPropValue row;
 
@@ -626,7 +670,7 @@ GpgMsgImpl::getRecipients ()
             j++;
           else
             log_debug ("%s:%s: error converting recipient to utf8\n",
-                       __FILE__, __func__);
+                       SRCNAME, __func__);
           break;
       
         case PT_STRING8: /* Assume Ascii. */
@@ -635,7 +679,7 @@ GpgMsgImpl::getRecipients ()
           
         default:
           log_debug ("%s:%s: proptag=0x%08lx not supported\n",
-                     __FILE__, __func__, row->ulPropTag);
+                     SRCNAME, __func__, row->ulPropTag);
           break;
         }
     }
@@ -647,14 +691,169 @@ GpgMsgImpl::getRecipients ()
     FreeProws(lpRecipientRows);        
   
   log_debug ("%s:%s: got %d recipients:\n",
-             __FILE__, __func__, j);
+             SRCNAME, __func__, j);
   for (i=0; rset[i]; i++)
-    log_debug ("%s:%s: \t`%s'\n", __FILE__, __func__, rset[i]);
+    log_debug ("%s:%s: \t`%s'\n", SRCNAME, __func__, rset[i]);
 
   return rset;
 }
 
 
+/* Write an Attestation to the current message. */
+void
+GpgMsgImpl::writeAttestation (void)
+{
+  HRESULT hr;
+  ULONG newpos;
+  SPropValue prop;
+  LPATTACH newatt = NULL;
+  LPSTREAM to = NULL;
+  char *buffer = NULL;
+  char *p, *pend;
+  ULONG nwritten;
+
+  if (!message || !attestation)
+    return;
+
+  hr = message->CreateAttach (NULL, 0, &newpos, &newatt);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: can't create attachment: hr=%#lx\n",
+                 SRCNAME, __func__, hr); 
+      goto leave;
+    }
+          
+  prop.ulPropTag = PR_ATTACH_METHOD;
+  prop.Value.ul = ATTACH_BY_VALUE;
+  hr = HrSetOneProp (newatt, &prop);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: can't set attach method: hr=%#lx\n",
+                 SRCNAME, __func__, hr); 
+      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",
+                 SRCNAME, __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);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: can't set attach filename: hr=%#lx\n",
+                 SRCNAME, __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",
+                 SRCNAME, __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",
+                 SRCNAME, __func__, hr); 
+      goto leave;
+    }
+
+  hr = newatt->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 0,
+                             MAPI_CREATE|MAPI_MODIFY, (LPUNKNOWN*)&to);
+  if (FAILED (hr)) 
+    {
+      log_error ("%s:%s: can't create output stream: hr=%#lx\n",
+                 SRCNAME, __func__, hr); 
+      goto leave;
+    }
+  
+
+  if (gpgme_data_write (attestation, "", 1) != 1
+      || !(buffer = gpgme_data_release_and_get_mem (attestation, NULL)))
+    {
+      attestation = NULL;
+      log_error ("%s:%s: gpgme_data_write failed\n", SRCNAME, __func__); 
+      goto leave;
+    }
+  attestation = NULL;
+
+  log_debug ("writing attestation `%s'\n", buffer);
+  hr = S_OK;
+  if (!*buffer)
+    {
+      const char *s = _("[No attestation computed "
+                        "(e.g. messages was not signed)");
+      hr = to->Write (s, strlen (s), &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", SRCNAME, __func__, hr);
+      goto leave;
+    }
+      
+  
+  to->Commit (0);
+  to->Release ();
+  to = NULL;
+  
+  hr = newatt->SaveChanges (0);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: SaveChanges(attachment) failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr); 
+      goto leave;
+    }
+  hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: SaveChanges(message) failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr); 
+      goto leave;
+    }
+
+
+ leave:
+  if (to)
+    {
+      to->Revert ();
+      to->Release ();
+    }
+  if (newatt)
+    newatt->Release ();
+  gpgme_free (buffer);
+}
+
 
 
 /* Decrypt the message MSG and update the window.  HWND identifies the
@@ -662,7 +861,7 @@ GpgMsgImpl::getRecipients ()
 int 
 GpgMsgImpl::decrypt (HWND hwnd)
 {
-  log_debug ("%s:%s: enter\n", __FILE__, __func__);
+  log_debug ("%s:%s: enter\n", SRCNAME, __func__);
   openpgp_t mtype;
   char *plaintext = NULL;
   attach_info_t table = NULL;
@@ -675,11 +874,6 @@ GpgMsgImpl::decrypt (HWND hwnd)
   int pgpmime_succeeded = 0;
 
   mtype = getMessageType ();
-  if (mtype == OPENPGP_CLEARSIG)
-    {
-      log_debug ("%s:%s: leave (passing on to verify)\n", __FILE__, __func__);
-      return verify (hwnd);
-    }
 
   /* Check whether this possibly encrypted message has encrypted
      attachments.  We check right now because we need to get into the
@@ -697,18 +891,62 @@ GpgMsgImpl::decrypt (HWND hwnd)
     }
   log_debug ("%s:%s: message has %u attachments with "
              "%u signed and %d encrypted\n",
-             __FILE__, __func__, n_attach, n_signed, n_encrypted);
+             SRCNAME, __func__, n_attach, n_signed, n_encrypted);
   if (mtype == OPENPGP_NONE && !n_encrypted && !n_signed) 
     {
-      /* Fixme: we should display the messsage box only if decryption
-         has explicity be requested. */
-      MessageBox (hwnd, "No valid OpenPGP data found.",
-                  "GPG Decryption", MB_ICONWARNING|MB_OK);
-      log_debug ("%s:%s: leave (no OpenPGP data)\n", __FILE__, __func__);
+      /* Because we usually work around the OL object model, it can't
+         notice that we changed the windows's text behind its back (by
+         means of update_display and the SetWindowText API).  Thus it
+         happens sometimes that the ciphertext is still displayed
+         although the MAPI calls in loadBody returned the plaintext
+         (because we once used set_message_body).  The effect is that
+         when clicking the decrypt button, we won't have any
+         ciphertext to decrypt and thus get to here.  We try solving
+         this by updating the window if we also have a cached entry.
+
+         Another solution would be to always update the windows's text
+         using a cached plaintext (in OnRead). I have some fear that
+         this might lead to unexpected behaviour in certain cases, so
+         we better only do it on demand and only if the old reply hack
+         has been enabled. */
+      void *refhandle;
+      const char *s;
+
+      if (!opt.compat.old_reply_hack
+          && (s = msgcache_get_from_mapi (message, &refhandle)))
+        {
+          xfree (body_plain);
+          body_plain = xstrdup (s);
+          update_display (hwnd, this, exchange_cb, is_html_body (s));
+          msgcache_unref (refhandle);
+          log_debug ("%s:%s: leave (already decrypted)\n", SRCNAME, __func__);
+        }
+      else
+        {
+          MessageBox (hwnd, "No valid OpenPGP data found.",
+                      "GPG Decryption", MB_ICONWARNING|MB_OK);
+          log_debug ("%s:%s: leave (no OpenPGP data)\n", SRCNAME, __func__);
+        }
+      
       release_attach_info (table);
       return 0;
     }
 
+  /* 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 (has_attestation)
+    {
+      if (attestation)
+        gpgme_data_release (attestation);
+      log_debug ("%s:%s: we already have an attestation\n",
+                 SRCNAME, __func__);
+    }
+  else if (!attestation && !opt.compat.no_attestation)
+    gpgme_data_new (&attestation);
+  
+
+  /* Process according to type of message. */
   if (is_pgpmime)
     {
       LPATTACH att;
@@ -719,10 +957,10 @@ GpgMsgImpl::decrypt (HWND hwnd)
       if (FAILED (hr))
         {
           log_error ("%s:%s: can't open PGP/MIME attachment 2: hr=%#lx",
-                     __FILE__, __func__, hr);
+                     SRCNAME, __func__, hr);
           MessageBox (hwnd, "Problem decrypting PGP/MIME message",
                       "GPG Decryption", MB_ICONERROR|MB_OK);
-          log_debug ("%s:%s: leave (PGP/MIME problem)\n", __FILE__, __func__);
+          log_debug ("%s:%s: leave (PGP/MIME problem)\n", SRCNAME, __func__);
           release_attach_info (table);
           return gpg_error (GPG_ERR_GENERAL);
         }
@@ -731,10 +969,10 @@ GpgMsgImpl::decrypt (HWND hwnd)
       if (method != ATTACH_BY_VALUE)
         {
           log_error ("%s:%s: unsupported method %d for PGP/MIME attachment 2",
-                     __FILE__, __func__, method);
+                     SRCNAME, __func__, method);
           MessageBox (hwnd, "Problem decrypting PGP/MIME message",
                       "GPG Decryption", MB_ICONERROR|MB_OK);
-          log_debug ("%s:%s: leave (bad PGP/MIME method)\n",__FILE__,__func__);
+          log_debug ("%s:%s: leave (bad PGP/MIME method)\n",SRCNAME,__func__);
           att->Release ();
           release_attach_info (table);
           return gpg_error (GPG_ERR_GENERAL);
@@ -745,30 +983,37 @@ GpgMsgImpl::decrypt (HWND hwnd)
       if (FAILED (hr))
         {
           log_error ("%s:%s: can't open data of attachment 2: hr=%#lx",
-                     __FILE__, __func__, pos, hr);
+                     SRCNAME, __func__, hr);
           MessageBox (hwnd, "Problem decrypting PGP/MIME message",
                       "GPG Decryption", MB_ICONERROR|MB_OK);
-          log_debug ("%s:%s: leave (OpenProperty failed)\n",__FILE__,__func__);
+          log_debug ("%s:%s: leave (OpenProperty failed)\n",SRCNAME,__func__);
           att->Release ();
           release_attach_info (table);
           return gpg_error (GPG_ERR_GENERAL);
         }
 
-      err = op_decrypt_stream_to_buffer (from, &plaintext,
-                                         opt.passwd_ttl, NULL);
+      err = pgpmime_decrypt (from, opt.passwd_ttl, &plaintext, attestation,
+                             hwnd);
+      
       from->Release ();
       att->Release ();
       if (!err)
         pgpmime_succeeded = 1;
     }
-  else if (*getOrigText())
-    err = op_decrypt (getOrigText (), &plaintext, opt.passwd_ttl, NULL);
+  else if (mtype == OPENPGP_CLEARSIG)
+    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);
   if (err)
     {
       if (!is_pgpmime && n_attach && gpg_err_code (err) == GPG_ERR_NO_DATA)
         ;
+      else if (mtype == OPENPGP_CLEARSIG)
+        MessageBox (hwnd, op_strerror (err),
+                    "GPG verification failed", MB_ICONERROR|MB_OK);
       else
         MessageBox (hwnd, op_strerror (err),
                     "GPG decryption failed", MB_ICONERROR|MB_OK);
@@ -777,24 +1022,37 @@ GpgMsgImpl::decrypt (HWND hwnd)
     {  
       int is_html = is_html_body (plaintext);
 
-      set_message_body (message, plaintext);
+      log_debug ("decrypt isHtml=%d\n", is_html);
+
+      /* Do we really need to set the body?  update_display below
+         should be sufficient.  The problem with this is that we did
+         changes in the MAPI and OL will later ask whether to save
+         them.  The original reason for this kludge was to get the
+         plaintext into the reply (by setting the property without
+         calling SaveChanges) - with OL2003 it didn't worked reliable
+         and thus we implemented the trick with the msgcache. For now
+         we will disable it but add a compatibility flag to re-enable
+         it. */
+      if (opt.compat.old_reply_hack)
+        set_message_body (message, plaintext, is_html);
+
       xfree (body_plain);
       body_plain = plaintext;
       plaintext = NULL;
       msgcache_put (body_plain, 0, message);
 
-      /* Also set PR_BODY but do not use 'SaveChanges' to make it
-         permanently.  This way the user can reply with the
-         plaintext but the ciphertext is still stored. 
-
-         NOTE: That does not work for OL2003!  This is the reason we
-         implemented the (not fully working) msgcache system. */
-      log_debug ("decrypt isHtml=%d\n", is_html);
-
-      /* XXX: find a way to handle text/html message in a better way! */
-      /* I have disabled the kludge to see what happens to a html
-         message. */
-      if (/*is_html ||*/ update_display (hwnd, this, exchange_cb)) 
+      if (opt.save_decrypted_attach)
+        {
+          /* User wants us to replace the encrypted message with the
+             plaintext version. */
+          hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
+          if (FAILED (hr))
+            log_debug ("%s:%s: SaveChanges failed: hr=%#lx",
+                       SRCNAME, __func__, hr);
+          update_display (hwnd, this, exchange_cb, is_html);
+          
+        }
+      else if (!silent && update_display (hwnd, this, exchange_cb, is_html)) 
         {
           const char s[] = 
             "The message text cannot be displayed.\n"
@@ -811,7 +1069,7 @@ GpgMsgImpl::decrypt (HWND hwnd)
               hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
               if (FAILED (hr))
                 log_debug ("%s:%s: SaveChanges failed: hr=%#lx",
-                           __FILE__, __func__, hr);
+                           SRCNAME, __func__, hr);
             }
        }
     }
@@ -820,7 +1078,7 @@ GpgMsgImpl::decrypt (HWND hwnd)
   /* If we have signed attachments.  Ask whether the signatures should
      be verified; we do this is case of large attachments where
      verification might take long. */
-  if (n_signed && !pgpmime_succeeded)
+  if (!silent && n_signed && !pgpmime_succeeded)
     {
       const char s[] = 
         "Signed attachments found.\n\n"
@@ -845,7 +1103,7 @@ GpgMsgImpl::decrypt (HWND hwnd)
         }
     }
 
-  if (n_encrypted && !pgpmime_succeeded)
+  if (!silent && n_encrypted && !pgpmime_succeeded)
     {
       const char s[] = 
         "Encrypted attachments found.\n\n"
@@ -867,35 +1125,10 @@ GpgMsgImpl::decrypt (HWND hwnd)
         }
     }
 
-  release_attach_info (table);
-  log_debug ("%s:%s: leave (rc=%d)\n", __FILE__, __func__, err);
-  return err;
-}
-
-
-/* Verify the message and display the verification result. */
-int 
-GpgMsgImpl::verify (HWND hwnd)
-{
-  log_debug ("%s:%s: enter\n", __FILE__, __func__);
-  openpgp_t mtype;
-  int err, has_attach;
-  
-  mtype = getMessageType ();
-  has_attach = hasAttachments ();
-  if (mtype == OPENPGP_NONE && !has_attach ) 
-    {
-      log_debug ("%s:%s: leave (no OpenPGP data)\n", __FILE__, __func__);
-      return 0;
-    }
-
-  err = op_verify (getOrigText (), NULL, NULL);
-  if (err)
-    MessageBox (hwnd, op_strerror (err), "GPG Verify", MB_ICONERROR|MB_OK);
-  else
-    update_display (hwnd, this, NULL);
+  writeAttestation ();
 
-  log_debug ("%s:%s: leave (rc=%d)\n", __FILE__, __func__, err);
+  release_attach_info (table);
+  log_debug ("%s:%s: leave (rc=%d)\n", SRCNAME, __func__, err);
   return err;
 }
 
@@ -907,25 +1140,27 @@ GpgMsgImpl::verify (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);
+  log_debug ("%s:%s: enter message=%p\n", SRCNAME, __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__);
+      log_debug ("%s:%s: leave (empty)", SRCNAME, __func__);
       return 0; 
     }
 
   /* Pop up a dialog box to ask for the signer of the message. */
-  if (signer_dialog_box (&sign_key, NULL) == -1)
+  if (signer_dialog_box (&sign_key, NULL, 0) == -1)
     {
-      log_debug ("%s.%s: leave (dialog failed)\n", __FILE__, __func__);
+      log_debug ("%s.%s: leave (dialog failed)\n", SRCNAME, __func__);
       return gpg_error (GPG_ERR_CANCELED);  
     }
 
@@ -946,91 +1181,114 @@ GpgMsgImpl::sign (HWND hwnd)
       unsigned int n;
       
       n = getAttachments ();
-      log_debug ("%s:%s: message has %u attachments\n", __FILE__, __func__, n);
-      for (int i=0; i < n; i++) 
+      log_debug ("%s:%s: message has %u attachments\n", SRCNAME, __func__, n);
+      for (unsigned int i=0; i < n; i++) 
         signAttachment (hwnd, i, sign_key, opt.passwd_ttl);
       /* FIXME: we should throw an error if signing of any attachment
          failed. */
     }
 
-  set_x_header (message, "Outlgpg-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",
+                     SRCNAME, __func__, hr);
+        }
+    }
+  
+  hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: SaveChanges(message) failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr); 
+      err = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
+    }
 
  leave:
   xfree (signedtext);
   gpgme_key_release (sign_key);
-  log_debug ("%s:%s: leave (err=%s)\n", __FILE__, __func__, op_strerror (err));
+  log_debug ("%s:%s: leave (err=%s)\n", SRCNAME, __func__, op_strerror (err));
   return err;
 }
 
 
 \f
-/* Encrypt and optionally sign (if SIGN 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)
+GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool want_html, bool sign_flag)
 {
-  log_debug ("%s:%s: enter\n", __FILE__, __func__);
+  log_debug ("%s:%s: enter\n", SRCNAME, __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;
   char **unknown = NULL;
   int err = 0;
-  size_t all = 0;
-  int n_keys;
+  size_t n_keys, n_unknown, n_recp;
+  SPropValue prop;
     
   
-  if (!*(plaintext = getOrigText ()) && !hasAttachments ()) 
+  if (!*(plaintext = getOrigText (want_html)) && !hasAttachments ()) 
     {
-      log_debug ("%s:%s: leave (empty)", __FILE__, __func__);
+      log_debug ("%s:%s: leave (empty)", SRCNAME, __func__);
       return 0; 
     }
 
   /* Pop up a dialog box to ask for the signer of the message. */
-  if (sign)
+  if (sign_flag)
     {
-      if (signer_dialog_box (&sign_key, NULL) == -1)
+      if (signer_dialog_box (&sign_key, NULL, 1) == -1)
         {
-          log_debug ("%s.%s: leave (dialog failed)\n", __FILE__, __func__);
+          log_debug ("%s.%s: leave (dialog failed)\n", SRCNAME, __func__);
           return gpg_error (GPG_ERR_CANCELED);  
         }
     }
 
   /* Gather the keys for the recipients. */
   recipients = getRecipients ();
-  n_keys = op_lookup_keys (recipients, &keys, &unknown, &all);
+  if ( op_lookup_keys (recipients, &keys, &unknown) )
+    {
+      log_debug ("%s.%s: leave (lookup keys failed)\n", SRCNAME, __func__);
+      return gpg_error (GPG_ERR_GENERAL);  
+    }
+  n_recp = count_strings (recipients);
+  n_keys = count_keys (keys);
+  n_unknown = count_strings (unknown);
 
-  log_debug ("%s:%s: found %d recipients, need %d, unknown=%p\n",
-             __FILE__, __func__, n_keys, all, unknown);
   
-  if (n_keys != count_recipients (recipients))
+  log_debug ("%s:%s: found %d recipients, need %d, unknown=%d\n",
+             SRCNAME, __func__, (int)n_keys, (int)n_recp, (int)n_unknown);
+  
+  if (n_keys != n_recp)
     {
-      int opts = 0;
-      gpgme_key_t *keys2 = NULL;
+      unsigned int opts;
+      gpgme_key_t *keys2;
 
-      /* FIXME: The implementation is not correct: op_lookup_keys
-         returns the number of missing keys but we compare against the
-         total number of keys; thus the box would pop up even when all
-         have been found. */
-      log_debug ("%s:%s: calling recipient_dialog_box2", __FILE__, __func__);
-      recipient_dialog_box2 (keys, unknown, all, &keys2, &opts);
-      xfree (keys);
+      log_debug ("%s:%s: calling recipient_dialog_box2", SRCNAME, __func__);
+      opts = recipient_dialog_box2 (keys, unknown, &keys2);
+      free_key_array (keys);
       keys = keys2;
       if (opts & OPT_FLAG_CANCEL) 
         {
@@ -1040,22 +1298,21 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign)
     }
 
   if (sign_key)
-    log_debug ("%s:%s: signer: 0x%s %s\n",  __FILE__, __func__,
+    log_debug ("%s:%s: signer: 0x%s %s\n",  SRCNAME, __func__,
                keyid_from_key (sign_key), userid_from_key (sign_key));
   else
-    log_debug ("%s:%s: no signer\n", __FILE__, __func__);
+    log_debug ("%s:%s: no signer\n", SRCNAME, __func__);
   if (keys)
     {
       for (int i=0; keys[i] != NULL; i++)
-        log_debug ("%s.%s: recp.%d 0x%s %s\n", __FILE__, __func__,
+        log_debug ("%s.%s: recp.%d 0x%s %s\n", SRCNAME, __func__,
                    i, keyid_from_key (keys[i]), userid_from_key (keys[i]));
     }
 
   if (*plaintext)
     {
-      is_html = is_html_body (plaintext);
-
-      err = op_encrypt (plaintext, &ciphertext, keys, NULL, 0);
+      err = op_encrypt (plaintext, &ciphertext, 
+                        keys, sign_key, opt.passwd_ttl);
       if (err)
         {
           MessageBox (hwnd, op_strerror (err),
@@ -1063,7 +1320,7 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign)
           goto leave;
         }
 
-      if (is_html) 
+      if (want_html) 
         {
           char *tmp = add_html_line_endings (ciphertext);
           xfree (ciphertext);
@@ -1072,23 +1329,13 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign)
 
 //       {
 //         SPropValue prop;
-
 //         prop.ulPropTag=PR_MESSAGE_CLASS_A;
 //         prop.Value.lpszA="IPM.Note.OPENPGP";
 //         hr = HrSetOneProp (message, &prop);
 //         if (hr != S_OK)
 //           {
 //             log_error ("%s:%s: can't set message class: hr=%#lx\n",
-//                        __FILE__, __func__, hr); 
-//           }
-
-//         prop.ulPropTag=PR_CONTENT_TYPE_A;
-//         prop.Value.lpszA="application/encrypted;foo=bar;type=mytype";
-//         hr = HrSetOneProp (message, &prop);
-//         if (hr != S_OK)
-//           {
-//             log_error ("%s:%s: can't set content type: hr=%#lx\n",
-//                        __FILE__, __func__, hr); 
+//                        SRCNAME, __func__, hr); 
 //           }
 //       }
 
@@ -1099,8 +1346,8 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign)
       unsigned int n;
       
       n = getAttachments ();
-      log_debug ("%s:%s: message has %u attachments\n", __FILE__, __func__, n);
-      for (int i=0; !err && i < n; i++) 
+      log_debug ("%s:%s: message has %u attachments\n", SRCNAME, __func__, n);
+      for (unsigned int i=0; !err && i < n; i++) 
         err = encryptAttachment (hwnd, i, keys, NULL, 0);
       if (err)
         {
@@ -1110,34 +1357,63 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign)
         }
     }
 
-  set_x_header (message, "Outlgpg-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, ciphertext);
+      if (want_html)
+        {
+          /* We better update the body of the OOM too. */
+          if (put_outlook_property (exchange_cb, "Body", ciphertext))
+            log_error ("%s:%s: put OOM property Body failed\n",
+                       SRCNAME, __func__);
+          /* And set the format to plain text. */
+          if (put_outlook_property_int (exchange_cb, "BodyFormat", 1))
+            log_error ("%s:%s: put OOM property BodyFormat failed\n",
+                       SRCNAME, __func__);
+        }
+
+
+      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.  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);
+      if (hr != S_OK)
+        {
+          log_error ("%s:%s: can't set content type: hr=%#lx\n",
+                     SRCNAME, __func__, hr);
+        }
+
+    }
+  
+  hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: SaveChanges(message) failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr); 
+      err = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
+    }
 
  leave:
   /* FIXME: What to do with already encrypted attachments if some of
      the encrypted (or other operations) failed? */
 
-  for (int i=0; i < n_keys; i++)
-    xfree (unknown[i]);
-  if (n_keys)
-    xfree (unknown);
-
   free_key_array (keys);
-  free_recipient_array (recipients);
+  free_string_array (recipients);
+  free_string_array (unknown);
   xfree (ciphertext);
-  log_debug ("%s:%s: leave (err=%s)\n", __FILE__, __func__, op_strerror (err));
+  log_debug ("%s:%s: leave (err=%s)\n", SRCNAME, __func__, op_strerror (err));
   return err;
 }
 
@@ -1209,7 +1485,7 @@ GpgMsgImpl::getAttachments (void)
       if (FAILED (hr))
         {
           log_debug ("%s:%s: GetAttachmentTable failed: hr=%#lx",
-                     __FILE__, __func__, hr);
+                     SRCNAME, __func__, hr);
           return 0;
         }
       
@@ -1218,7 +1494,7 @@ GpgMsgImpl::getAttachments (void)
       if (FAILED (hr))
         {
           log_debug ("%s:%s: HrQueryAllRows failed: hr=%#lx",
-                     __FILE__, __func__, hr);
+                     SRCNAME, __func__, hr);
           table->Release ();
           return 0;
         }
@@ -1244,7 +1520,7 @@ get_attach_method (LPATTACH obj)
   if (FAILED (hr))
     {
       log_error ("%s:%s: error getting attachment method: hr=%#lx",
-                 __FILE__, __func__, hr);
+                 SRCNAME, __func__, hr);
       return 0; 
     }
   /* We don't bother checking whether we really get a PT_LONG ulong
@@ -1256,21 +1532,20 @@ get_attach_method (LPATTACH obj)
 }
 
 
-/* Return the content-type of the attachment OBJ or NULL if it dow not
+/* Return the content-type of the attachment OBJ or NULL if it does not
    exists.  Caller must free. */
 static char *
 get_attach_mime_tag (LPATTACH obj)
 {
   HRESULT hr;
   LPSPropValue propval = NULL;
-  int method ;
   char *name;
 
   hr = HrGetOneProp ((LPMAPIPROP)obj, PR_ATTACH_MIME_TAG_A, &propval);
   if (FAILED (hr))
     {
       log_error ("%s:%s: error getting attachment's MIME tag: hr=%#lx",
-                 __FILE__, __func__, hr);
+                 SRCNAME, __func__, hr);
       return NULL; 
     }
   switch ( PROP_TYPE (propval->ulPropTag) )
@@ -1278,7 +1553,7 @@ get_attach_mime_tag (LPATTACH obj)
     case PT_UNICODE:
       name = wchar_to_utf8 (propval->Value.lpszW);
       if (!name)
-        log_debug ("%s:%s: error converting to utf8\n", __FILE__, __func__);
+        log_debug ("%s:%s: error converting to utf8\n", SRCNAME, __func__);
       break;
       
     case PT_STRING8:
@@ -1286,8 +1561,8 @@ get_attach_mime_tag (LPATTACH obj)
       break;
       
     default:
-      log_debug ("%s:%s: proptag=%xlx not supported\n",
-                 __FILE__, __func__, propval->ulPropTag);
+      log_debug ("%s:%s: proptag=%#lx not supported\n",
+                 SRCNAME, __func__, propval->ulPropTag);
       name = NULL;
       break;
     }
@@ -1304,14 +1579,13 @@ get_short_attach_data (LPATTACH obj)
 {
   HRESULT hr;
   LPSPropValue propval = NULL;
-  int method ;
   char *data;
 
   hr = HrGetOneProp ((LPMAPIPROP)obj, PR_ATTACH_DATA_BIN, &propval);
   if (FAILED (hr))
     {
       log_error ("%s:%s: error getting attachment's data: hr=%#lx",
-                 __FILE__, __func__, hr);
+                 SRCNAME, __func__, hr);
       return NULL; 
     }
   switch ( PROP_TYPE (propval->ulPropTag) )
@@ -1326,7 +1600,7 @@ get_short_attach_data (LPATTACH obj)
       
     default:
       log_debug ("%s:%s: proptag=%#lx not supported\n",
-                 __FILE__, __func__, propval->ulPropTag);
+                 SRCNAME, __func__, propval->ulPropTag);
       data = NULL;
       break;
     }
@@ -1391,7 +1665,6 @@ static bool
 set_x_header (LPMESSAGE msg, const char *name, const char *val)
 {  
   HRESULT hr;
-  LPMDB lpMdb = NULL;
   LPSPropTagArray pProps = NULL;
   SPropValue pv;
   MAPINAMEID mnid, *pmnid;     
@@ -1412,7 +1685,7 @@ set_x_header (LPMESSAGE msg, const char *name, const char *val)
   if (FAILED (hr)) 
     {
       log_error ("%s:%s: can't get mapping for header `%s': hr=%#lx\n",
-                 __FILE__, __func__, name, hr); 
+                 SRCNAME, __func__, name, hr); 
       return false;
     }
     
@@ -1422,7 +1695,7 @@ set_x_header (LPMESSAGE msg, const char *name, const char *val)
   if (hr != S_OK)
     {
       log_error ("%s:%s: can't set header `%s': hr=%#lx\n",
-                 __FILE__, __func__, name, hr); 
+                 SRCNAME, __func__, name, hr); 
       return false;
     }
   return true;
@@ -1448,7 +1721,7 @@ get_attach_filename (LPATTACH obj)
     hr = HrGetOneProp ((LPMAPIPROP)obj, PR_ATTACH_FILENAME, &propval);
   if (FAILED(hr))
     {
-      log_debug ("%s:%s: no filename property found", __FILE__, __func__);
+      log_debug ("%s:%s: no filename property found", SRCNAME, __func__);
       return NULL;
     }
 
@@ -1457,7 +1730,7 @@ get_attach_filename (LPATTACH obj)
     case PT_UNICODE:
       name = wchar_to_utf8 (propval->Value.lpszW);
       if (!name)
-        log_debug ("%s:%s: error converting to utf8\n", __FILE__, __func__);
+        log_debug ("%s:%s: error converting to utf8\n", SRCNAME, __func__);
       break;
       
     case PT_STRING8:
@@ -1465,8 +1738,8 @@ get_attach_filename (LPATTACH obj)
       break;
       
     default:
-      log_debug ("%s:%s: proptag=%xlx not supported\n",
-                 __FILE__, __func__, propval->ulPropTag);
+      log_debug ("%s:%s: proptag=%#lx not supported\n",
+                 SRCNAME, __func__, propval->ulPropTag);
       name = NULL;
       break;
     }
@@ -1476,42 +1749,64 @@ get_attach_filename (LPATTACH obj)
 
 
 
-
-/* Return a filename to be used for saving an attachment. Returns an
-   malloced string on success. HWND is the current Window and SRCNAME
-   the filename to be used as suggestion.  On error; i.e. cancel NULL
-   is returned. */
-static char *
-get_save_filename (HWND root, const char *srcname)
-                                    
+\f
+/* Read the attachment ATT and try to detect whether this is a PGP
+   Armored message.  METHOD is the attach method of ATT.  Returns 0 if
+   it is not a PGP attachment. */
+static armor_t
+get_pgp_armor_type (LPATTACH att, int method)
 {
-  char filter[] = "All Files (*.*)\0*.*\0\0";
-  char fname[MAX_PATH+1];
+  HRESULT hr;
+  LPSTREAM stream;
+  char buffer [128];
+  ULONG nread;
   const char *s;
-  OPENFILENAME ofn;
 
-  memset (fname, 0, sizeof (fname));
-  strncpy (fname, srcname, MAX_PATH-1);
-  fname[MAX_PATH] = 0;  
+  if (method != ATTACH_BY_VALUE)
+    return ARMOR_NONE;
   
+  hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 
+                          0, 0, (LPUNKNOWN*) &stream);
+  if (FAILED (hr))
+    {
+      log_debug ("%s:%s: can't attachment data: hr=%#lx",
+                 SRCNAME, __func__,  hr);
+      return ARMOR_NONE;
+    }
 
-  memset (&ofn, 0, sizeof (ofn));
-  ofn.lStructSize = sizeof (ofn);
-  ofn.hwndOwner = root;
-  ofn.lpstrFile = fname;
-  ofn.nMaxFile = MAX_PATH;
-  ofn.lpstrFileTitle = NULL;
-  ofn.nMaxFileTitle = 0;
-  ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
-  ofn.lpstrTitle = "GPG - Save decrypted attachment";
-  ofn.lpstrFilter = filter;
-
-  if (GetSaveFileName (&ofn))
-    return xstrdup (fname);
-  return NULL;
+  hr = stream->Read (buffer, sizeof buffer -1, &nread);
+  if ( hr != S_OK )
+    {
+      log_debug ("%s:%s: Read failed: hr=%#lx", SRCNAME, __func__, hr);
+      stream->Release ();
+      return ARMOR_NONE;
+    }
+  buffer[nread] = 0;
+  stream->Release ();
+
+  s = strstr (buffer, "-----BEGIN PGP ");
+  if (!s)
+    return ARMOR_NONE;
+  s += 15;
+  if (!strncmp (s, "MESSAGE-----", 12))
+    return ARMOR_MESSAGE;
+  else if (!strncmp (s, "SIGNATURE-----", 14))
+    return ARMOR_SIGNATURE;
+  else if (!strncmp (s, "SIGNED MESSAGE-----", 19))
+    return ARMOR_SIGNED;
+  else if (!strncmp (s, "ARMORED FILE-----", 17))
+    return ARMOR_FILE;
+  else if (!strncmp (s, "PUBLIC KEY BLOCK-----", 21))
+    return ARMOR_PUBKEY;
+  else if (!strncmp (s, "PRIVATE KEY BLOCK-----", 22))
+    return ARMOR_SECKEY;
+  else if (!strncmp (s, "SECRET KEY BLOCK-----", 21))
+    return ARMOR_SECKEY;
+  else
+    return ARMOR_NONE;
 }
 
-\f
+
 /* Gather information about attachments and return a new object with
    these information.  Caller must release the returned information.
    The routine will return NULL in case of an error or if no
@@ -1522,13 +1817,15 @@ GpgMsgImpl::gatherAttachmentInfo (void)
   HRESULT hr;
   attach_info_t table;
   unsigned int pos, n_attach;
-  int method, err;
   const char *s;
+  unsigned int attestation_count = 0;
+  unsigned int invalid_count = 0;
 
   is_pgpmime = false;
+  has_attestation = false;
   n_attach = getAttachments ();
   log_debug ("%s:%s: message has %u attachments\n",
-             __FILE__, __func__, n_attach);
+             SRCNAME, __func__, n_attach);
   if (!n_attach)
       return NULL;
 
@@ -1541,7 +1838,9 @@ GpgMsgImpl::gatherAttachmentInfo (void)
       if (FAILED (hr))
         {
           log_error ("%s:%s: can't open attachment %d: hr=%#lx",
-                     __FILE__, __func__, pos, hr);
+                     SRCNAME, __func__, pos, hr);
+          table[pos].invalid = 1;
+          invalid_count++;
           continue;
         }
 
@@ -1560,7 +1859,21 @@ GpgMsgImpl::gatherAttachmentInfo (void)
               trim_trailing_spaces (p);
               table[pos].content_type_parms = p;
             }
+          if (!stricmp (table[pos].content_type, "text/plain")
+              && table[pos].filename 
+              && (s = strrchr (table[pos].filename, '.'))
+              && !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;
+          attestation_count++;
+        }
+
       att->Release ();
     }
   table[pos].end_of_table = 1;
@@ -1568,8 +1881,12 @@ GpgMsgImpl::gatherAttachmentInfo (void)
   /* Figure out whether there are encrypted attachments. */
   for (pos=0; !table[pos].end_of_table; pos++)
     {
-      if (table[pos].filename && (s = strrchr (table[pos].filename, '.'))
-          &&  (!stricmp (s, ".pgp") || !stricmp (s, ".gpg")))
+      if (table[pos].invalid)
+        continue;
+      if (table[pos].armor_type == ARMOR_MESSAGE)
+        table[pos].is_encrypted = 1;
+      else if (table[pos].filename && (s = strrchr (table[pos].filename, '.'))
+               &&  (!stricmp (s, ".pgp") || !stricmp (s, ".gpg")))
         table[pos].is_encrypted = 1;
       else if (table[pos].content_type  
                && ( !stricmp (table[pos].content_type,
@@ -1578,13 +1895,20 @@ GpgMsgImpl::gatherAttachmentInfo (void)
                                  "multipart/encrypted")
                        && table[pos].content_type_parms
                        && strstr (table[pos].content_type_parms,
-                                  "application/pgp-encrypted"))))
+                                  "application/pgp-encrypted"))
+                   || (!stricmp (table[pos].content_type,
+                                 "application/pgp")
+                       && table[pos].content_type_parms
+                       && strstr (table[pos].content_type_parms,
+                                  "x-action=encrypt"))))
         table[pos].is_encrypted = 1;
     }
      
   /* Figure out what attachments are signed. */
   for (pos=0; !table[pos].end_of_table; pos++)
     {
+      if (table[pos].invalid)
+        continue;
       if (table[pos].filename && (s = strrchr (table[pos].filename, '.'))
           &&  !stricmp (s, ".asc")
           && table[pos].content_type  
@@ -1595,36 +1919,53 @@ GpgMsgImpl::gatherAttachmentInfo (void)
           /* We mark the actual file, assuming that the .asc is a
              detached signature.  To correlate the data file and the
              signature we keep track of the POS. */
-          for (int i=0; !table[i].end_of_table; i++)
-            if (i != pos && table[i].filename 
-                && strlen (table[i].filename) == len
-                && !strncmp (table[i].filename, table[pos].filename, len))
-              {
-                table[i].is_signed = 1;
-                table[i].sig_pos = pos;
-              }
+          for (unsigned int i=0; !table[i].end_of_table; i++)
+            {
+              if (table[i].invalid)
+                continue;
+              if (i != pos && table[i].filename 
+                  && strlen (table[i].filename) == len
+                  && !strncmp (table[i].filename, table[pos].filename, len))
+                {
+                  table[i].is_signed = 1;
+                  table[i].sig_pos = pos;
+                }
+            }
+          
         }
+      else if (table[pos].content_type  
+               && (!stricmp (table[pos].content_type, "application/pgp")
+                   && table[pos].content_type_parms
+                   && strstr (table[pos].content_type_parms,"x-action=sign")))
+        table[pos].is_signed = 1;
     }
 
-  log_debug ("%s:%s: attachment info:\n", __FILE__, __func__);
+  log_debug ("%s:%s: attachment info:\n", SRCNAME, __func__);
   for (pos=0; !table[pos].end_of_table; pos++)
     {
-      log_debug ("\t%d %d %d %u `%s' `%s' `%s'\n",
+      if (table[pos].invalid)
+        continue;
+      log_debug ("\t%d %d %d %u %d `%s' `%s' `%s'\n",
                  pos, table[pos].is_encrypted,
                  table[pos].is_signed, table[pos].sig_pos,
+                 table[pos].armor_type,
                  table[pos].filename, table[pos].content_type,
                  table[pos].content_type_parms);
     }
 
   /* 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
-      && pos == 2 && table[0].content_type && table[1].content_type
-      && !stricmp (table[0].content_type, "application/pgp-encrypted")
-      && !stricmp (table[1].content_type, "application/octet-stream")
-      && isPgpmimeVersionPart (0))
+     for other storage providers.  We use a hack to ignore extra
+     attesttation attachments: Those are assumed to come after the
+     both PGP/MIME parts. */
+  if (opt.compat.no_pgpmime)
+    ;
+  else if (pos == 2 + attestation_count + invalid_count
+           && table[0].content_type && table[1].content_type
+           && !stricmp (table[0].content_type, "application/pgp-encrypted")
+           && !stricmp (table[1].content_type, "application/octet-stream")
+           && isPgpmimeVersionPart (0))
     {
       log_debug ("\tThis is a PGP/MIME encrypted message - table adjusted");
       table[0].is_encrypted = 0;
@@ -1638,9 +1979,9 @@ GpgMsgImpl::gatherAttachmentInfo (void)
 
 
 \f
-/* Verify the ATTachment at attachments and table position POS_DATA
-   agains the signature at position POS_SIG.  Display the status for
-   each signature. */
+/* Verify the attachment as recorded in TABLE and at table position
+   POS_DATA against the signature at position POS_SIG.  Display the
+   status for each signature. */
 void
 GpgMsgImpl::verifyAttachment (HWND hwnd, attach_info_t table,
                               unsigned int pos_data,
@@ -1653,7 +1994,7 @@ GpgMsgImpl::verifyAttachment (HWND hwnd, attach_info_t table,
   char *sig_data;
 
   log_debug ("%s:%s: verifying attachment %d/%d",
-             __FILE__, __func__, pos_data, pos_sig);
+             SRCNAME, __func__, pos_data, pos_sig);
 
   assert (table);
   assert (message);
@@ -1665,7 +2006,7 @@ GpgMsgImpl::verifyAttachment (HWND hwnd, attach_info_t table,
   if (FAILED (hr))
     {
       log_error ("%s:%s: can't open attachment %d (sig): hr=%#lx",
-                 __FILE__, __func__, pos_sig, hr);
+                 SRCNAME, __func__, pos_sig, hr);
       return;
     }
 
@@ -1674,7 +2015,7 @@ GpgMsgImpl::verifyAttachment (HWND hwnd, attach_info_t table,
   else
     {
       log_error ("%s:%s: attachment %d (sig): method %d not supported",
-                 __FILE__, __func__, pos_sig, table[pos_sig].method);
+                 SRCNAME, __func__, pos_sig, table[pos_sig].method);
       att->Release ();
       return;
     }
@@ -1688,7 +2029,7 @@ GpgMsgImpl::verifyAttachment (HWND hwnd, attach_info_t table,
   if (FAILED (hr))
     {
       log_error ("%s:%s: can't open attachment %d (data): hr=%#lx",
-                 __FILE__, __func__, pos_data, hr);
+                 SRCNAME, __func__, pos_data, hr);
       xfree (sig_data);
       return;
     }
@@ -1702,15 +2043,15 @@ GpgMsgImpl::verifyAttachment (HWND hwnd, attach_info_t table,
       if (FAILED (hr))
         {
           log_error ("%s:%s: can't open data of attachment %d: hr=%#lx",
-                     __FILE__, __func__, pos_data, hr);
+                     SRCNAME, __func__, pos_data, hr);
           goto leave;
         }
       err = op_verify_detached_sig (stream, sig_data,
-                                    table[pos_data].filename);
+                                    table[pos_data].filename, attestation);
       if (err)
         {
           log_debug ("%s:%s: verify detached signature failed: %s",
-                     __FILE__, __func__, op_strerror (err)); 
+                     SRCNAME, __func__, op_strerror (err)); 
           MessageBox (hwnd, op_strerror (err),
                       "GPG Attachment Verification", MB_ICONERROR|MB_OK);
         }
@@ -1719,7 +2060,7 @@ GpgMsgImpl::verifyAttachment (HWND hwnd, attach_info_t table,
   else
     {
       log_error ("%s:%s: attachment %d (data): method %d not supported",
-                 __FILE__, __func__, pos_data, table[pos_data].method);
+                 SRCNAME, __func__, pos_data, table[pos_data].method);
     }
 
  leave:
@@ -1740,19 +2081,22 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
   HRESULT hr;
   LPATTACH att;
   int method, err;
+  LPATTACH newatt = NULL;
+  char *outname = NULL;
+  
 
-  log_debug ("%s:%s: processing attachment %d", __FILE__, __func__, pos);
+  log_debug ("%s:%s: processing attachment %d", SRCNAME, __func__, pos);
 
   /* Make sure that we can access the attachment table. */
   if (!message || !getAttachments ())
     {
-      log_debug ("%s:%s: no attachemnts at all", __FILE__, __func__);
+      log_debug ("%s:%s: no attachemnts at all", SRCNAME, __func__);
       return;
     }
 
   if (!save_plaintext)
     {
-      log_error ("%s:%s: save_plaintext not requested", __FILE__, __func__);
+      log_error ("%s:%s: save_plaintext not requested", SRCNAME, __func__);
       return;
     }
 
@@ -1760,7 +2104,7 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
   if (FAILED (hr))
     {
       log_debug ("%s:%s: can't open attachment %d: hr=%#lx",
-                 __FILE__, __func__, pos, hr);
+                 SRCNAME, __func__, pos, hr);
       return;
     }
 
@@ -1781,7 +2125,7 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
       if (FAILED (hr))
         {
           log_error ("%s:%s: can't open data obj of attachment %d: hr=%#lx",
-                     __FILE__, __func__, pos, hr);
+                     SRCNAME, __func__, pos, hr);
           goto leave;
         }
 
@@ -1798,14 +2142,13 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
   else if (method == ATTACH_BY_VALUE)
     {
       char *s;
-      char *outname;
       char *suggested_name;
       LPSTREAM from, to;
 
       suggested_name = get_attach_filename (att);
       if (suggested_name)
         log_debug ("%s:%s: attachment %d, filename `%s'", 
-                  __FILE__, __func__, pos, suggested_name);
+                   SRCNAME, __func__, pos, suggested_name);
       /* Strip of know extensions or use a default name. */
       if (!suggested_name)
         {
@@ -1820,72 +2163,155 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
         {
           *s = 0;
         }
-      outname = get_save_filename (hwnd, suggested_name);
-      xfree (suggested_name);
-
+      if (opt.save_decrypted_attach)
+        outname = suggested_name;
+      else
+        {
+          outname = get_save_filename (hwnd, suggested_name);
+          xfree (suggested_name);
+        }
+      
       hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 
                               0, 0, (LPUNKNOWN*) &from);
       if (FAILED (hr))
         {
           log_error ("%s:%s: can't open data of attachment %d: hr=%#lx",
-                     __FILE__, __func__, pos, hr);
-          xfree (outname);
+                     SRCNAME, __func__, pos, hr);
           goto leave;
         }
 
-      hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
-                             (STGM_CREATE | STGM_READWRITE),
-                             outname, NULL, &to); 
-      if (FAILED (hr)) 
+
+      if (opt.save_decrypted_attach) /* Decrypt and save in the MAPI. */
         {
-          log_error ("%s:%s: can't create stream for `%s': hr=%#lx\n",
-                     __FILE__, __func__, outname, hr); 
+          ULONG newpos;
+          SPropValue prop;
+
+          hr = message->CreateAttach (NULL, 0, &newpos, &newatt);
+          if (hr != S_OK)
+            {
+              log_error ("%s:%s: can't create attachment: hr=%#lx\n",
+                         SRCNAME, __func__, hr); 
+              goto leave;
+            }
+          
+          prop.ulPropTag = PR_ATTACH_METHOD;
+          prop.Value.ul = ATTACH_BY_VALUE;
+          hr = HrSetOneProp (newatt, &prop);
+          if (hr != S_OK)
+            {
+              log_error ("%s:%s: can't set attach method: hr=%#lx\n",
+                         SRCNAME, __func__, hr); 
+              goto leave;
+            }
+          
+          prop.ulPropTag = PR_ATTACH_LONG_FILENAME_A;
+          prop.Value.lpszA = outname;   
+          hr = HrSetOneProp (newatt, &prop);
+          if (hr != S_OK)
+            {
+              log_error ("%s:%s: can't set attach filename: hr=%#lx\n",
+                         SRCNAME, __func__, hr); 
+              goto leave;
+            }
+          log_debug ("%s:%s: setting filename of attachment %d/%ld to `%s'",
+                     SRCNAME, __func__, pos, newpos, outname);
+          
+
+          hr = newatt->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 0,
+                                     MAPI_CREATE|MAPI_MODIFY, (LPUNKNOWN*)&to);
+          if (FAILED (hr)) 
+            {
+              log_error ("%s:%s: can't create output stream: hr=%#lx\n",
+                         SRCNAME, __func__, hr); 
+              goto leave;
+            }
+      
+          err = op_decrypt_stream (from, to, ttl, filename, attestation);
+          if (err)
+            {
+              log_debug ("%s:%s: decrypt stream failed: %s",
+                         SRCNAME, __func__, op_strerror (err)); 
+              to->Revert ();
+              to->Release ();
+              from->Release ();
+              MessageBox (hwnd, op_strerror (err),
+                          "GPG Attachment Decryption", MB_ICONERROR|MB_OK);
+              goto leave;
+            }
+        
+          to->Commit (0);
+          to->Release ();
           from->Release ();
-          xfree (outname);
-          goto leave;
+
+          hr = newatt->SaveChanges (0);
+          if (hr != S_OK)
+            {
+              log_error ("%s:%s: SaveChanges failed: hr=%#lx\n",
+                         SRCNAME, __func__, hr); 
+              goto leave;
+            }
+
+          /* Delete the orginal attachment. FIXME: Should we really do
+             that or better just mark it in the table and delete
+             later? */
+          att->Release ();
+          att = NULL;
+          if (message->DeleteAttach (pos, 0, NULL, 0) == S_OK)
+            log_error ("%s:%s: failed to delete attachment %d: %s",
+                       SRCNAME, __func__, pos, op_strerror (err)); 
+          
         }
-      
-      err = op_decrypt_stream (from, to, ttl, filename);
-      if (err)
+      else  /* Save attachment to a file. */
         {
-          log_debug ("%s:%s: decrypt stream failed: %s",
-                     __FILE__, __func__, op_strerror (err)); 
-          to->Revert ();
+          hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
+                                 (STGM_CREATE | STGM_READWRITE),
+                                 outname, NULL, &to); 
+          if (FAILED (hr)) 
+            {
+              log_error ("%s:%s: can't create stream for `%s': hr=%#lx\n",
+                         SRCNAME, __func__, outname, hr); 
+              from->Release ();
+              goto leave;
+            }
+      
+          err = op_decrypt_stream (from, to, ttl, filename, attestation);
+          if (err)
+            {
+              log_debug ("%s:%s: decrypt stream failed: %s",
+                         SRCNAME, __func__, op_strerror (err)); 
+              to->Revert ();
+              to->Release ();
+              from->Release ();
+              MessageBox (hwnd, op_strerror (err),
+                          "GPG Attachment Decryption", MB_ICONERROR|MB_OK);
+              /* FIXME: We might need to delete outname now.  However a
+                 sensible implementation of the stream object should have
+                 done it through the Revert call. */
+              goto leave;
+            }
+        
+          to->Commit (0);
           to->Release ();
           from->Release ();
-          MessageBox (hwnd, op_strerror (err),
-                      "GPG Attachment Decryption", MB_ICONERROR|MB_OK);
-          /* FIXME: We might need to delete outname now.  However a
-             sensible implementation of the stream object should have
-             done it trhough the Revert call. */
-          xfree (outname);
-          goto leave;
         }
-        
-      to->Commit (0);
-      to->Release ();
-      from->Release ();
-
-      /*  Hmmm: Why are we deleting the attachment now????? 
-          Disabled until clarified.   FIXME */
-      //if (message->DeleteAttach (pos, 0, NULL, 0) == S_OK)
-      //   show error;
-
-      xfree (outname);
+      
     }
   else
     {
       log_error ("%s:%s: attachment %d: method %d not supported",
-                 __FILE__, __func__, pos, method);
+                 SRCNAME, __func__, pos, method);
     }
 
  leave:
-  /* Close this attachment. */
-  att->Release ();
+  xfree (outname);
+  if (newatt)
+    newatt->Release ();
+  if (att)
+    att->Release ();
 }
 
 
-/* Sign the attachment with the internal number POS.  TTL is caching
+/* Sign the attachment with the internal number POS.  TTL is the caching
    time for a required passphrase. */
 void
 GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
@@ -1901,7 +2327,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
   /* Make sure that we can access the attachment table. */
   if (!message || !getAttachments ())
     {
-      log_debug ("%s:%s: no attachemnts at all", __FILE__, __func__);
+      log_debug ("%s:%s: no attachemnts at all", SRCNAME, __func__);
       return;
     }
 
@@ -1909,7 +2335,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
   if (FAILED (hr))
     {
       log_debug ("%s:%s: can't open attachment %d: hr=%#lx",
-                 __FILE__, __func__, pos, hr);
+                 SRCNAME, __func__, pos, hr);
       return;
     }
 
@@ -1933,7 +2359,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
   if (method == ATTACH_EMBEDDED_MSG)
     {
       log_debug ("%s:%s: signing embedded attachments is not supported",
-                 __FILE__, __func__);
+                 SRCNAME, __func__);
     }
   else if (method == ATTACH_BY_VALUE)
     {
@@ -1945,7 +2371,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (FAILED (hr))
         {
           log_error ("%s:%s: can't open data of attachment %d: hr=%#lx",
-                     __FILE__, __func__, pos, hr);
+                     SRCNAME, __func__, pos, hr);
           goto leave;
         }
 
@@ -1953,7 +2379,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't create attachment: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           goto leave;
         }
 
@@ -1963,7 +2389,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach method: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           goto leave;
         }
       
@@ -1973,11 +2399,11 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach filename: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           goto leave;
         }
       log_debug ("%s:%s: setting filename of attachment %d/%ld to `%s'",
-                 __FILE__, __func__, pos, newpos, signame);
+                 SRCNAME, __func__, pos, newpos, signame);
 
       prop.ulPropTag = PR_ATTACH_EXTENSION_A;
       prop.Value.lpszA = ".pgpsig";   
@@ -1985,7 +2411,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach extension: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           goto leave;
         }
 
@@ -1996,7 +2422,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach tag: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           goto leave;
         }
 
@@ -2006,7 +2432,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach mime tag: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           goto leave;
         }
 
@@ -2015,7 +2441,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (FAILED (hr)) 
         {
           log_error ("%s:%s: can't create output stream: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           goto leave;
         }
       
@@ -2023,7 +2449,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (err)
         {
           log_debug ("%s:%s: sign stream failed: %s",
-                     __FILE__, __func__, op_strerror (err)); 
+                     SRCNAME, __func__, op_strerror (err)); 
           to->Revert ();
           MessageBox (hwnd, op_strerror (err),
                       "GPG Attachment Signing", MB_ICONERROR|MB_OK);
@@ -2039,7 +2465,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
       if (hr != S_OK)
         {
           log_error ("%s:%s: SaveChanges failed: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           goto leave;
         }
 
@@ -2047,7 +2473,7 @@ GpgMsgImpl::signAttachment (HWND hwnd, int pos, gpgme_key_t sign_key, int ttl)
   else
     {
       log_error ("%s:%s: attachment %d: method %d not supported",
-                 __FILE__, __func__, pos, method);
+                 SRCNAME, __func__, pos, method);
     }
 
  leave:
@@ -2082,7 +2508,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
   /* Make sure that we can access the attachment table. */
   if (!message || !getAttachments ())
     {
-      log_debug ("%s:%s: no attachemnts at all", __FILE__, __func__);
+      log_debug ("%s:%s: no attachemnts at all", SRCNAME, __func__);
       return 0;
     }
 
@@ -2090,7 +2516,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
   if (FAILED (hr))
     {
       log_debug ("%s:%s: can't open attachment %d: hr=%#lx",
-                 __FILE__, __func__, pos, hr);
+                 SRCNAME, __func__, pos, hr);
       err = gpg_error (GPG_ERR_GENERAL);
       return err;
     }
@@ -2115,7 +2541,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
   if (method == ATTACH_EMBEDDED_MSG)
     {
       log_debug ("%s:%s: encrypting embedded attachments is not supported",
-                 __FILE__, __func__);
+                 SRCNAME, __func__);
       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
   else if (method == ATTACH_BY_VALUE)
@@ -2128,7 +2554,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (FAILED (hr))
         {
           log_error ("%s:%s: can't open data of attachment %d: hr=%#lx",
-                     __FILE__, __func__, pos, hr);
+                     SRCNAME, __func__, pos, hr);
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2137,7 +2563,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't create attachment: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2148,7 +2574,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach method: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2159,12 +2585,12 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach filename: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
       log_debug ("%s:%s: setting filename of attachment %d/%ld to `%s'",
-                 __FILE__, __func__, pos, newpos, filename);
+                 SRCNAME, __func__, pos, newpos, filename);
 
       prop.ulPropTag = PR_ATTACH_EXTENSION_A;
       prop.Value.lpszA = ".pgpenc";   
@@ -2172,7 +2598,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach extension: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2184,7 +2610,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach tag: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2195,7 +2621,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (hr != S_OK)
         {
           log_error ("%s:%s: can't set attach mime tag: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2205,7 +2631,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (FAILED (hr)) 
         {
           log_error ("%s:%s: can't create output stream: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2214,7 +2640,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (err)
         {
           log_debug ("%s:%s: encrypt stream failed: %s",
-                     __FILE__, __func__, op_strerror (err)); 
+                     SRCNAME, __func__, op_strerror (err)); 
           to->Revert ();
           MessageBox (hwnd, op_strerror (err),
                       "GPG Attachment Encryption", MB_ICONERROR|MB_OK);
@@ -2230,7 +2656,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (hr != S_OK)
         {
           log_error ("%s:%s: SaveChanges failed: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2239,7 +2665,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
       if (hr != S_OK)
         {
           log_error ("%s:%s: DeleteAtatch failed: hr=%#lx\n",
-                     __FILE__, __func__, hr); 
+                     SRCNAME, __func__, hr); 
           err = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -2248,7 +2674,7 @@ GpgMsgImpl::encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
   else
     {
       log_error ("%s:%s: attachment %d: method %d not supported",
-                 __FILE__, __func__, pos, method);
+                 SRCNAME, __func__, pos, method);
       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
     }