[git] GpgOL - branch, nomapi, created. gpgol-1.4.0-17-gc1398da

by Andre Heinecke cvs at cvs.gnupg.org
Tue Aug 16 16:51:14 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG extension for MS Outlook".

The branch, nomapi has been created
        at  c1398da89a56f4c2cad743af8eb687d33e7f3246 (commit)

- Log -----------------------------------------------------------------
commit c1398da89a56f4c2cad743af8eb687d33e7f3246
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 16 16:45:49 2016 +0200

    Add first (dummy) version of C++ MailParser
    
    * src/mail.cpp (get_cipherstream): Use second
    attachment for now.
    (use_body): Small helper to detect if the body
    should be used.
    (Mail::decrypt_mime): Removed.
    (Mail::decrypt): Removed.
    (add_attachments): New helper to create OOM
    attachments from Attachment Objects.
    (Mail::decrypt_verify): Use MailParser.
    (Mail::get_subject): New helper.
    * src/mailparser.cpp, src/mailparser.h: New.
    
    --
    Instead of refactoring the mimeparser to work without MAPI
    structures I'm not incrementally factoring things out from
    there into a new MailParser class which will replace both
    message.cpp and mimeparser.c and should work without writing
    directly to MAPI so that in the future the MailParser can
    be moved into a different thread and we avoid chaning
    underlying MAPI Stores without going through oom.

diff --git a/src/Makefile.am b/src/Makefile.am
index 8834497..f9507f4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -86,7 +86,8 @@ gpgol_SOURCES = \
 	mlang-charset.cpp mlang-charset.h \
 	gmime-table-private.h \
 	exechelp.c exechelp.h \
-	addin-options.cpp addin-options.h
+	addin-options.cpp addin-options.h \
+	mailparser.cpp mailparser.h
 
 
 #treeview_SOURCES = treeview.c
diff --git a/src/mail.cpp b/src/mail.cpp
index ba1f23f..4c16852 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -29,8 +29,12 @@
 #include "revert.h"
 #include "gpgoladdin.h"
 #include "mymapitags.h"
+#include "mailparser.h"
+#include "gpgolstr.h"
 
 #include <map>
+#include <vector>
+#include <memory>
 
 static std::map<LPDISPATCH, Mail*> g_mail_map;
 
@@ -204,8 +208,8 @@ get_cipherstream (LPDISPATCH mailitem)
       log_debug ("%s:%s: More then one attachment count: %i. Continuing anway.",
                  SRCNAME, __func__, count);
     }
-  /* We assume the crypto attachment is the first item. */
-  attachment = get_oom_object (attachments, "Item(1)");
+  /* We assume the crypto attachment is the second item. */
+  attachment = get_oom_object (attachments, "Item(2)");
   gpgol_release (attachments);
   attachments = NULL;
 
@@ -227,41 +231,53 @@ get_cipherstream (LPDISPATCH mailitem)
   return stream;
 }
 
-/** The decryption for mime messages.
-  We get the original attachment table and decrypt the first
-  attachment. Then we replace the body and attachment table
-  with the new contents. */
-int
-Mail::decrypt_mime()
+/** Helper to check if the body should be used for decrypt verify
+  or if the mime Attachment should be used. */
+static bool
+use_body(msgtype_t type)
 {
-  LPSTREAM cipherstream = get_cipherstream(m_mailitem);
-
-  if (!cipherstream)
+  switch (type)
     {
-      log_debug ("%s:%s: Failed to get cipherstream.",
-                 SRCNAME, __func__);
-      return 1;
-    }
-
-  char tmpbuf[33];
-
-  if (put_oom_string (m_mailitem, "HTMLBody", WAIT_TEMPLATE))
-    {
-      log_error ("%s:%s: Failed to modify body of item.",
-                 SRCNAME, __func__);
+      case MSGTYPE_GPGOL_PGP_MESSAGE:
+      case MSGTYPE_GPGOL_CLEAR_SIGNED:
+        return true;
+      default:
+        return false;
     }
-  return 0;
 }
 
-int
-Mail::decrypt()
+/** Helper to update the attachments of a mail object in oom.
+  does not modify the underlying mapi structure. */
+static bool
+add_attachments(LPDISPATCH mail,
+                std::vector<std::shared_ptr<Attachment> > attachments)
 {
-  return 0;
+  for (auto att: attachments)
+    {
+      wchar_t* wchar_name = utf8_to_wchar (att->get_display_name().c_str());
+      log_debug("DisplayName %s", att->get_display_name().c_str());
+      HANDLE hFile;
+      wchar_t* wchar_file = get_tmp_outfile (GpgOLStr("gpgol-attach-"), &hFile);
+      if (add_oom_attachment (mail, wchar_file, wchar_name))
+        {
+          log_debug ("Failed to add attachment.");
+        }
+      CloseHandle (hFile);
+      DeleteFileW (wchar_file);
+      xfree (wchar_file);
+      xfree (wchar_name);
+    }
+  return false;
 }
 
 int
 Mail::decrypt_verify()
 {
+  if (m_type == MSGTYPE_UNKNOWN || m_type == MSGTYPE_GPGOL)
+    {
+      /* Not a message for us. */
+      return 0;
+    }
   if (m_needs_wipe)
     {
       log_error ("%s:%s: Decrypt verify called for msg that needs wipe: %p",
@@ -269,21 +285,69 @@ Mail::decrypt_verify()
       return 0;
     }
 
-  switch (m_type)
+  m_processed = true;
+  /* Do the actual parsing */
+  std::unique_ptr<MailParser> parser;
+  if (!use_body (m_type))
     {
-      case MSGTYPE_UNKNOWN:
-        /* Not a message for us. Ignore. */
-        return 0;
-      case MSGTYPE_GPGOL:
-        log_debug ("%s:%s: ignoring unknown message of original SMIME class\n",
-                   SRCNAME, __func__);
-        break;
-      case MSGTYPE_GPGOL_MULTIPART_ENCRYPTED:
-        return decrypt_mime();
-      default:
-        log_debug ("%s:%s: Unhandled message class. \n",
-                   SRCNAME, __func__);
+      auto cipherstream = get_cipherstream (m_mailitem);
+
+      if (!cipherstream)
+        {
+          /* TODO Error message? */
+          log_debug ("%s:%s: Failed to get cipherstream.",
+                     SRCNAME, __func__);
+          return 1;
+        }
+
+      parser = std::unique_ptr<MailParser>(new MailParser (cipherstream, m_type));
+      gpgol_release (cipherstream);
     }
+  else
+    {
+      parser = std::unique_ptr<MailParser>();
+    }
+
+  const std::string err = parser->parse();
+  if (!err.empty())
+    {
+      /* TODO Show error message. */
+      log_error ("%s:%s: Failed to parse message: %s",
+                 SRCNAME, __func__, err.c_str());
+      return 1;
+    }
+
+  m_needs_wipe = true;
+  /* Update the body */
+  const auto html = parser->get_utf8_html_body();
+  if (!html->empty())
+    {
+      if (put_oom_string (m_mailitem, "HTMLBody", html->c_str()))
+        {
+          log_error ("%s:%s: Failed to modify html body of item.",
+                     SRCNAME, __func__);
+          return 1;
+        }
+    }
+  else
+    {
+      const auto body = parser->get_utf8_text_body();
+      if (put_oom_string (m_mailitem, "Body", body->c_str()))
+        {
+          log_error ("%s:%s: Failed to modify body of item.",
+                     SRCNAME, __func__);
+          return 1;
+        }
+    }
+
+  /* Update attachments */
+  if (add_attachments (m_mailitem, parser->get_attachments()))
+    {
+      log_error ("%s:%s: Failed to update attachments.",
+                 SRCNAME, __func__);
+      return 1;
+    }
+
   /* Invalidate UI to set the correct sig status. */
   gpgoladdin_invalidate_ui ();
   return 0;
@@ -520,3 +584,9 @@ Mail::is_smime ()
   m_is_smime_checked  = true;
   return m_is_smime;
 }
+
+std::string
+Mail::get_subject()
+{
+  return std::string(get_oom_string (m_mailitem, "Subject"));
+}
diff --git a/src/mail.h b/src/mail.h
index 5b75f79..1bbc789 100644
--- a/src/mail.h
+++ b/src/mail.h
@@ -24,6 +24,8 @@
 #include "oomhelp.h"
 #include "mapihelp.h"
 
+#include <string>
+
 /** @brief Data wrapper around a mailitem.
  *
  * This class is intended to bundle all that we know about
@@ -136,6 +138,11 @@ public:
    * @returns A reference to the utf8 sender address. Or NULL. */
   const char *get_sender ();
 
+  /** @brief get the subject string (UTF-8 encoded).
+    *
+    * @returns the subject or an empty string. */
+  std::string get_subject ();
+
   /** @brief Is this a crypto mail handled by gpgol.
   *
   * Calling this is only valid after a message has been processed.
@@ -161,15 +168,6 @@ public:
     */
   bool is_smime ();
 
-protected:
-  /** @brief do the actual decryption for mime messages.
-    *
-    * @returns true on error. */
-  int decrypt_mime();
-
-  /** @brief decryption helper. */
-  int decrypt();
-
 private:
   LPDISPATCH m_mailitem;
   LPDISPATCH m_event_sink;
diff --git a/src/mailparser.cpp b/src/mailparser.cpp
new file mode 100644
index 0000000..500a383
--- /dev/null
+++ b/src/mailparser.cpp
@@ -0,0 +1,71 @@
+/* @file mailparser.cpp
+ * @brief Parse a mail and decrypt / verify accordingly
+ *
+ *    Copyright (C) 2016 Intevation GmbH
+ *
+ * This file is part of GpgOL.
+ *
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+#include "common.h"
+
+#include "mailparser.h"
+#include "attachment.h"
+
+MailParser::MailParser(LPSTREAM instream, msgtype_t type):
+    m_body (std::shared_ptr<std::string>(new std::string())),
+    m_htmlbody (std::shared_ptr<std::string>(new std::string())),
+    m_stream (instream),
+    m_type (type),
+    m_error (false),
+    m_in_data (false),
+    signed_data (nullptr),
+    sig_data (nullptr)
+{
+  log_debug ("%s:%s: Creating parser for stream: %p",
+             SRCNAME, __func__, instream);
+  instream->AddRef();
+}
+
+MailParser::~MailParser()
+{
+  gpgol_release(m_stream);
+}
+
+std::string
+MailParser::parse()
+{
+  m_body = std::shared_ptr<std::string>(new std::string("Hello world"));
+  Attachment *att = new Attachment ();
+  att->write ("Hello attachment", strlen ("Hello attachment"));
+  att->set_display_name ("The Attachment.txt");
+  m_attachments.push_back (std::shared_ptr<Attachment>(att));
+  return std::string();
+}
+
+std::shared_ptr<std::string> MailParser::get_utf8_html_body()
+{
+  return m_htmlbody;
+}
+
+std::shared_ptr<std::string> MailParser::get_utf8_text_body()
+{
+  return m_body;
+}
+
+std::vector<std::shared_ptr<Attachment> > MailParser::get_attachments()
+{
+  return m_attachments;
+}
diff --git a/src/mailparser.h b/src/mailparser.h
new file mode 100644
index 0000000..1e03139
--- /dev/null
+++ b/src/mailparser.h
@@ -0,0 +1,81 @@
+/* @file mailparser.h
+ * @brief Parse a mail and decrypt / verify accordingly
+ *
+ *    Copyright (C) 2016 Intevation GmbH
+ *
+ * This file is part of GpgOL.
+ *
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAILPARSER_H
+#define MAILPARSER_H
+
+#include "oomhelp.h"
+#include "mapihelp.h"
+#include "gpgme.h"
+
+#include <string>
+#include <vector>
+#include <memory>
+
+class Attachment;
+
+class MailParser
+{
+public:
+  /** Construct a new MailParser for the stream instream.
+    instream is expected to point to a mime mail.
+    Adds a reference to the stream and releases it on
+    destruction. */
+  MailParser(LPSTREAM instream, msgtype_t type);
+  ~MailParser();
+
+  /** Construct a new MailParser for an inline message where
+    the content is pointet to by body.
+  MailParser(const char *body, msgtype_t type);
+  */
+  /** Main entry point. Parses the Mail returns an
+    * empty string on success or an error message on failure. */
+  std::string parse();
+
+  /** Get the Body converted to utf8. Call parse first. */
+  std::shared_ptr<std::string> get_utf8_text_body();
+
+  /** Get an alternative? HTML Body converted to utf8. Call parse first. */
+  std::shared_ptr<std::string> get_utf8_html_body();
+
+  /** Get the decrypted / verified attachments. Call parse first.
+  */
+  std::vector<std::shared_ptr<Attachment> > get_attachments();
+private:
+  std::vector<std::shared_ptr<Attachment> > m_attachments;
+  std::shared_ptr<std::string> m_body;
+  std::shared_ptr<std::string> m_htmlbody;
+
+  /* State variables */
+  LPSTREAM m_stream;
+  msgtype_t m_type;
+  bool m_error;
+  bool m_in_data;
+  gpgme_data_t signed_data;/* NULL or the data object used to collect
+                              the signed data. It would be better to
+                              just hash it but there is no support in
+                              gpgme for this yet. */
+  gpgme_data_t sig_data;  /* NULL or data object to collect the
+                             signature attachment which should be a
+                             signature then.  */
+};
+
+#endif /* MAILPARSER_H */

commit 2bdf9f9b3afabfe5ce039ba61b72cfcd20ef2da8
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 16 16:44:52 2016 +0200

    Mark / create MOSS attachment in BeforeRead
    
    * src/mail.cpp (Mail::pre_process_message): Mark moss attach.
    
    --
    This hides the MOSS attachments from the user and allows us
    to later find them again.

diff --git a/src/mail.cpp b/src/mail.cpp
index 7da636c..ba1f23f 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -161,6 +161,16 @@ Mail::pre_process_message ()
   /* TODO: Unify this so mapi_change_message_class returns
      a useful value already. */
   m_type = mapi_get_message_type (message);
+
+  /* Create moss attachments here so that they are properly
+     hidden when the item is read into the model. */
+  if (mapi_mark_or_create_moss_attach (message, m_type))
+    {
+      log_error ("%s:%s: Failed to find moss attachment.",
+                 SRCNAME, __func__);
+      m_type = MSGTYPE_UNKNOWN;
+    }
+
   gpgol_release (message);
   return 0;
 }

commit 78b87db761b72e8c7f9fad3f0c8ba1f44de71bb9
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 16 16:39:19 2016 +0200

    Add Attachment helper class
    
    * src/attachment.cpp (Attachment): New helper class.
    * src/attachment.h (Attachment): Declare class.
    * src/mail.cpp (Mail::wipe): No longer encrypt attachments.
    
    --
    The Attachment class is similar to the Mail class in that
    it is a wrapper around some Attachment related data. The
    Attachment uses a temporary stream internally which ideally
    is never even created as a file.

diff --git a/src/attachment.cpp b/src/attachment.cpp
index 6f31510..a9ad736 100644
--- a/src/attachment.cpp
+++ b/src/attachment.cpp
@@ -21,320 +21,83 @@
 #include "config.h"
 #include "common.h"
 #include "attachment.h"
-#include "serpent.h"
-#include "oomhelp.h"
 #include "mymapitags.h"
 #include "mapihelp.h"
+#include "gpgolstr.h"
 
 #include <gpg-error.h>
 
-#define COPYBUFFERSIZE 4096
-
-#define IV_DEFAULT_LEN 16
-
-/** Decrypt the first 16 bytes of stream and check that it contains
-  our header. Return 0 on success. */
-static int
-check_header (LPSTREAM stream, symenc_t symenc)
+Attachment::Attachment()
 {
   HRESULT hr;
-  char tmpbuf[16];
-  ULONG nread;
-  hr = stream->Read (tmpbuf, 16, &nread);
-  if (hr || nread != 16)
-    {
-      log_error ("%s:%s: Read failed: hr=%#lx", SRCNAME, __func__, hr);
-      return -1;
-    }
-  symenc_cfb_decrypt (symenc, tmpbuf, tmpbuf, 16);
-  if (memcmp (tmpbuf, "GpgOL attachment", 16))
+  hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
+                        (SOF_UNIQUEFILENAME | STGM_DELETEONRELEASE
+                         | STGM_CREATE | STGM_READWRITE),
+                        NULL, GpgOLStr("GPG"), &m_stream);
+  if (FAILED (hr))
     {
-      log_error ("%s:%s: Invalid header.",
-                 SRCNAME, __func__);
-      char buf2 [17];
-      snprintf (buf2, 17, "%s", tmpbuf);
-      log_error("Buf2: %s", buf2);
-      return -1;
+      log_error ("%s:%s: can't create attachment: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      m_stream = NULL;
     }
-  return 0;
 }
 
-/** Encrypts or decrypts a stream in place using the symenc context.
-  Returns 0 on success. */
-static int
-do_crypt_stream (LPSTREAM stream, symenc_t symenc, bool encrypt)
+Attachment::~Attachment()
 {
-  char *buf = NULL;
-  HRESULT hr;
-  ULONG nread;
-  bool fixed_str_written = false;
-  int rc = -1;
-  ULONG written = 0;
-  /* The original intention was to use IStream::Clone to have
-     an independent read / write stream. But the MAPI attachment
-     stream returns E_NOT_IMPLMENTED for that :-)
-     So we manually track the read and writepos. Read is offset
-     at 16 because of the GpgOL message. */
-  LARGE_INTEGER readpos = {0, 0},
-                writepos = {0, 0};
-  ULARGE_INTEGER new_size = {0, 0};
-
-  if (!encrypt)
-    {
-      readpos.QuadPart = 16;
-    }
-
-  buf = (char*)xmalloc (COPYBUFFERSIZE);
-  do
-    {
-      hr = stream->Read (buf, COPYBUFFERSIZE, &nread);
-      if (hr)
-        {
-          log_error ("%s:%s: Read failed: hr=%#lx", SRCNAME, __func__, hr);
-          goto done;
-        }
-      if (!nread)
-        {
-          break;
-        }
-      readpos.QuadPart += nread;
-      stream->Seek(writepos, STREAM_SEEK_SET, NULL);
-      if (nread && encrypt && !fixed_str_written)
-        {
-          char tmpbuf[16];
-          /* Write an encrypted fixed 16 byte string which we need to
-             check at decryption time to see whether we have actually
-             encrypted it using this session key.  */
-          symenc_cfb_encrypt (symenc, tmpbuf, "GpgOL attachment", 16);
-          stream->Write (tmpbuf, 16, NULL);
-          fixed_str_written = true;
-          writepos.QuadPart = 16;
-        }
-      if (encrypt)
-        {
-          symenc_cfb_encrypt (symenc, buf, buf, nread);
-        }
-      else
-        {
-          symenc_cfb_decrypt (symenc, buf, buf, nread);
-        }
-
-        hr = stream->Write (buf, nread, &written);
-        if (FAILED (hr) || written != nread)
-          {
-            log_error ("%s:%s: Write failed: %i", SRCNAME, __func__, __LINE__);
-            goto done;
-          }
-        writepos.QuadPart += written;
-        stream->Seek(readpos, STREAM_SEEK_SET, NULL);
-      }
-    while (nread == COPYBUFFERSIZE);
-
-  new_size.QuadPart = writepos.QuadPart;
-  hr = stream->SetSize (new_size);
-  if (FAILED (hr))
-    {
-      log_error ("%s:%s: Failed to update size", SRCNAME, __func__);
-      goto done;
-    }
-  rc = 0;
-
-done:
-  xfree (buf);
-
-  if (rc)
-    {
-      stream->Revert ();
-    }
-  else
-    {
-      stream->Commit (0);
-    }
-
-  return rc;
+  log_debug ("%s:%s", SRCNAME, __func__);
+  gpgol_release (m_stream);
 }
 
-/** If encrypt is set to true this will encrypt the attachment
-  data with serpent otherwiese it will decrypt.
-  This function handles the mapi side of things.
-  */
-static int
-do_crypt_mapi (LPATTACH att, bool encrypt)
+LPSTREAM
+Attachment::get_stream()
 {
-  char *iv;
-  ULONG tag;
-  size_t ivlen = IV_DEFAULT_LEN;
-  symenc_t symenc = NULL;
-  HRESULT hr;
-  LPSTREAM stream = NULL;
-  int rc = -1;
-
-  if (!att)
-    {
-      log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
-      return -1;
-    }
-
-  /* Get or create a new IV */
-  if (get_gpgolprotectiv_tag ((LPMESSAGE)att, &tag) )
-    {
-      log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
-      return -1;
-    }
-  if (encrypt)
-    {
-      iv = (char*)create_initialization_vector (IV_DEFAULT_LEN);
-    }
-  else
-    {
-      iv = mapi_get_binary_prop ((LPMESSAGE)att, tag, &ivlen);
-    }
-  if (!iv)
-    {
-      log_error ("%s:%s: Error creating / getting IV: %i", SRCNAME,
-                 __func__, __LINE__);
-      goto done;
-    }
-
-  symenc = symenc_open (get_128bit_session_key (), 16, iv, ivlen);
-  xfree (iv);
-  if (!symenc)
-    {
-      log_error ("%s:%s: can't open encryption context", SRCNAME, __func__);
-      goto done;
-    }
-
-  hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream,
-                          0, MAPI_MODIFY, (LPUNKNOWN*) &stream);
-  if (FAILED (hr))
-    {
-      log_error ("%s:%s: can't open data stream of attachment: hr=%#lx",
-                 SRCNAME, __func__, hr);
-      goto done;
-    }
-
-  /* When decrypting check the first 16 bytes for the header */
-  if (!encrypt && check_header (stream, symenc))
-    {
-      goto done;
-    }
-
-  if (FAILED (hr))
-    {
-      log_error ("%s:%s: can't create temp file: hr=%#lx",
-                 SRCNAME, __func__, hr);
-      goto done;
-    }
+  return m_stream;
+}
 
-  if (do_crypt_stream (stream, symenc, encrypt))
-    {
-      log_error ("%s:%s: stream handling failed",
-                 SRCNAME, __func__);
-      goto done;
-    }
-  rc = 0;
+std::string
+Attachment::get_display_name() const
+{
+  return m_utf8DisplayName;
+}
 
-done:
-  if (symenc)
-    symenc_close (symenc);
-  gpgol_release (stream);
+std::string
+Attachment::get_tmp_file_name() const
+{
+  return m_utf8FileName;
+}
 
-  return rc;
+void
+Attachment::set_display_name(const char *name)
+{
+  m_utf8DisplayName = std::string(name);
 }
 
-/** Protect or unprotect attachments.*/
-static int
-do_crypt (LPDISPATCH mailitem, bool protect)
+void
+Attachment::set_attach_type(attachtype_t type)
 {
-  LPDISPATCH attachments = get_oom_object (mailitem, "Attachments");
-  LPMESSAGE message = get_oom_base_message (mailitem);
-  int count = 0;
-  int err = -1;
-  char *item_str;
-  int i;
-  ULONG tag_id;
+  m_type = type;
+}
 
-  if (!attachments || !message)
-    {
-      log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
-      return -1;
-    }
-  count = get_oom_int (attachments, "Count");
+void
+Attachment::set_hidden(bool value)
+{
+  m_hidden = value;
+}
 
-  if (get_gpgolattachtype_tag (message, &tag_id))
+int
+Attachment::write(const char *data, size_t size)
+{
+  if (!data || !size)
     {
-      log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
-      goto done;
+      return 0;
     }
-
-  if (count < 1)
+  if (!m_stream && m_stream->Write (data, size, NULL) != S_OK)
     {
-      log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
-      goto done;
+      return 1;
     }
-
-  /* Yes the items start at 1! */
-  for (i = 1; i <= count; i++)
+  if (m_stream->Commit (0) != S_OK)
     {
-      LPDISPATCH attachment;
-      LPATTACH mapi_attachment;
-      attachtype_t att_type;
-
-      if (gpgrt_asprintf (&item_str, "Item(%i)", i) == -1)
-        {
-          log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
-          goto done;
-        }
-
-      attachment = get_oom_object (attachments, item_str);
-      xfree (item_str);
-      if (!attachment)
-        {
-          log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
-        }
-      mapi_attachment = (LPATTACH) get_oom_iunknown (attachment,
-                                                     "MapiObject");
-      if (!mapi_attachment)
-        {
-          log_debug ("%s:%s: Failed to get MapiObject of attachment: %p",
-                     SRCNAME, __func__, attachment);
-          gpgol_release (attachment);
-          continue;
-        }
-
-      att_type = get_gpgolattachtype (mapi_attachment, tag_id);
-      if ((protect && att_type == ATTACHTYPE_FROMMOSS_DEC) ||
-          (!protect && att_type == ATTACHTYPE_FROMMOSS))
-        {
-          if (do_crypt_mapi (mapi_attachment, protect))
-            {
-              log_error ("%s:%s: Error: Session crypto failed.",
-                         SRCNAME, __func__);
-              gpgol_release (mapi_attachment);
-              gpgol_release (attachment);
-              goto done;
-            }
-        }
-      gpgol_release (mapi_attachment);
-      gpgol_release (attachment);
+      return 1;
     }
-  err = 0;
-
-done:
-
-  gpgol_release (message);
-  gpgol_release (attachments);
-  return err;
-}
-
-int
-protect_attachments (LPDISPATCH mailitem)
-{
-  return do_crypt (mailitem, true);
-}
-
-int
-unprotect_attachments (LPDISPATCH mailitem)
-{
-  return do_crypt (mailitem, false);
+  return 0;
 }
diff --git a/src/attachment.h b/src/attachment.h
index 932a21a..68821ff 100644
--- a/src/attachment.h
+++ b/src/attachment.h
@@ -21,32 +21,44 @@
 #define ATTACHMENT_H
 
 #include <windows.h>
+#include "oomhelp.h"
+#include "mapihelp.h"
+#include <string>
 
-/** Protect attachments so that it can be stored
-  by outlook. This means to symetrically encrypt the
-  data with the session key.
+/** Helper class for attachment actions. */
+class Attachment
+{
+public:
+  /** Creates and opens a new temporary stream. */
+  Attachment();
 
-  This will change the messagetype back to
-  ATTACHTYPE_FROMMOSS it is only supposed to be
-  called on attachments with the Attachmentype
-  ATTACHTYPE_FROMMOSS_DEC.
+  /** Deletes the attachment and the underlying temporary file. */
+  ~Attachment();
 
-  The dispatch paramenter should be a mailitem.
+  /** Get an assoicated ISteam ptr or NULL. */
+  LPSTREAM get_stream();
 
-  Returns 0 on success.
-*/
-int
-protect_attachments (LPDISPATCH mailitem);
+  /** Writes data to the attachment stream.
+   * Calling this method automatically commits the stream.
+   *
+   * Returns 0 on success. */
+  int write(const char *data, size_t size);
 
-/** Remove the symetric session encryption of the attachments.
+  /** Set the display name */
+  void set_display_name(const char *name);
+  std::string get_display_name() const;
 
-  The dispatch paramenter should be a mailitem.
+  std::string get_tmp_file_name() const;
 
-  This will change the messsagetype to
-  ATTACHTYPE_FROMMOSS_DEC it should only be called
-  with attachments of the type ATTACHTYPE_FROMMOSS.
+  void set_attach_type(attachtype_t type);
+
+  void set_hidden(bool value);
+private:
+  LPSTREAM m_stream;
+  std::string m_utf8FileName;
+  std::string m_utf8DisplayName;
+  attachtype_t m_type;
+  bool m_hidden;
+};
 
-  Returns 0 on success. */
-int
-unprotect_attachments (LPDISPATCH mailitem);
 #endif // ATTACHMENT_H
diff --git a/src/mail.cpp b/src/mail.cpp
index 0559c93..7da636c 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -352,8 +352,7 @@ Mail::wipe ()
   log_debug ("%s:%s: Removing plaintext from mailitem: %p.",
              SRCNAME, __func__, m_mailitem);
   if (put_oom_string (m_mailitem, "HTMLBody",
-                      HTML_TEMPLATE) ||
-      protect_attachments (m_mailitem))
+                      HTML_TEMPLATE))
     {
       log_debug ("%s:%s: Failed to wipe mailitem: %p.",
                  SRCNAME, __func__, m_mailitem);

commit edb74e9f77e294d0aa9f29d8daf89d7149cfada6
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 16 16:37:37 2016 +0200

    Extend add_oom_attachment with display name
    
    * src/oomhelp.cpp (add_oom_attachment): Add display name-
    * src/oomhelp.h (add_oom_attachment): Update prototype.
    * src/ribbon-callbacks.cpp: Use new function.

diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp
index 3191c91..2a286e9 100644
--- a/src/oomhelp.cpp
+++ b/src/oomhelp.cpp
@@ -1052,7 +1052,8 @@ get_oom_recipients (LPDISPATCH recipients)
    inFile is the path to the attachment. Name is the
    name that should be used in outlook. */
 int
-add_oom_attachment (LPDISPATCH disp, wchar_t* inFileW)
+add_oom_attachment (LPDISPATCH disp, const wchar_t* inFileW,
+                    const wchar_t* displayName)
 {
   LPDISPATCH attachments = get_oom_object (disp, "Attachments");
 
@@ -1061,16 +1062,11 @@ add_oom_attachment (LPDISPATCH disp, wchar_t* inFileW)
   VARIANT vtResult;
   VARIANT aVariant[4];
   HRESULT hr;
-  BSTR inFileB = NULL;
+  BSTR inFileB = nullptr,
+       dispNameB = nullptr;
   unsigned int argErr = 0;
   EXCEPINFO execpinfo;
 
-  if (!inFileW || !wcslen (inFileW))
-    {
-      log_error ("%s:%s: no filename provided", SRCNAME, __func__);
-      return -1;
-    }
-
   dispid = lookup_oom_dispid (attachments, "Add");
 
   if (dispid == DISPID_UNKNOWN)
@@ -1080,7 +1076,14 @@ add_oom_attachment (LPDISPATCH disp, wchar_t* inFileW)
     return -1;
   }
 
-  inFileB = SysAllocString (inFileW);
+  if (inFileW)
+    {
+      inFileB = SysAllocString (inFileW);
+    }
+  if (displayName)
+    {
+      dispNameB = SysAllocString (displayName);
+    }
 
   dispparams.rgvarg = aVariant;
 
@@ -1088,9 +1091,8 @@ add_oom_attachment (LPDISPATCH disp, wchar_t* inFileW)
      parameter and not the first. Additionally DisplayName
      is documented but gets ignored by Outlook since Outlook
      2003 */
-
   dispparams.rgvarg[0].vt = VT_BSTR; /* DisplayName */
-  dispparams.rgvarg[0].bstrVal = NULL;
+  dispparams.rgvarg[0].bstrVal = dispNameB;
   dispparams.rgvarg[1].vt = VT_INT;  /* Position */
   dispparams.rgvarg[1].intVal = 1;
   dispparams.rgvarg[2].vt = VT_INT;  /* Type */
@@ -1112,7 +1114,10 @@ add_oom_attachment (LPDISPATCH disp, wchar_t* inFileW)
       dump_excepinfo (execpinfo);
     }
 
-  SysFreeString (inFileB);
+  if (inFileB)
+    SysFreeString (inFileB);
+  if (dispNameB)
+    SysFreeString (dispNameB);
   VariantClear (&vtResult);
   gpgol_release (attachments);
 
diff --git a/src/oomhelp.h b/src/oomhelp.h
index b069b31..d352a8f 100644
--- a/src/oomhelp.h
+++ b/src/oomhelp.h
@@ -151,7 +151,8 @@ char ** get_oom_recipients (LPDISPATCH recipients);
 
 /* Add an attachment to a dispatcher */
 int
-add_oom_attachment (LPDISPATCH disp, wchar_t* inFile);
+add_oom_attachment (LPDISPATCH disp, const wchar_t* inFile,
+                    const wchar_t *displayName);
 
 /* Look up a string with the propertyAccessor interface */
 char *
diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp
index 0b547f4..dccd3b2 100644
--- a/src/ribbon-callbacks.cpp
+++ b/src/ribbon-callbacks.cpp
@@ -160,7 +160,7 @@ attachSignature (LPDISPATCH mailItem, char *subject, HANDLE hFileToSign,
     }
 
   /* Now we have an encrypted file behind encryptedFile. Let's add it */
-  add_oom_attachment (mailItem, sigFileName);
+  add_oom_attachment (mailItem, sigFileName, nullptr);
 
 failure:
   xfree (sigFileName);
@@ -1182,7 +1182,7 @@ attachEncryptedFile (LPDISPATCH ctrl, int flags)
     }
 
   /* Now we have an encrypted file behind encryptedFile. Let's add it */
-  add_oom_attachment (mailItem, encryptedFile);
+  add_oom_attachment (mailItem, encryptedFile, nullptr);
 
   if (flags & OP_SIGN)
     {

commit 7e5e8e0ebc5e880beafb39d59319fbabb0241c11
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 16 16:27:20 2016 +0200

    * src/mapihelp.cpp: New.
    * src/mapihelp.h: New.
    * src/message.cpp: New.
    Factor out code from message.cpp to mapihelp
    
    * src/mapihelp.cpp (mapi_body_to_attachment): New
    moved from message.cpp.
    (mapi_mark_or_create_moss_attach): New. Combination
    of moss handling from message_decrypt and message_verify.
    * src/mapihelp.h: Add protoype
    * src/message.cpp (pgp_body_to_attachment): Remove.
    
    --
    Moving the moss handling out of the decryption functions means
    that we can just mark the attachments / hide them in beforeRead
    and then do the actual decryption work with them later.

diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp
index 64fe721..76213cb 100644
--- a/src/mapihelp.cpp
+++ b/src/mapihelp.cpp
@@ -3363,4 +3363,239 @@ mapi_attachment_to_body (LPMESSAGE message, mapi_attach_item_t *item)
   return result;
 }
 
+/* Copy the MAPI body to a PGPBODY type attachment. */
+int
+mapi_body_to_attachment (LPMESSAGE message)
+{
+  HRESULT hr;
+  LPSTREAM instream;
+  ULONG newpos;
+  LPATTACH newatt = NULL;
+  SPropValue prop;
+  LPSTREAM outstream = NULL;
+  LPUNKNOWN punk;
+  GpgOLStr body_filename (PGPBODYFILENAME);
+
+  instream = mapi_get_body_as_stream (message);
+  if (!instream)
+    return -1;
+
+  hr = message->CreateAttach (NULL, 0, &newpos, &newatt);
+  if (hr)
+    {
+      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 ((LPMAPIPROP)newatt, &prop);
+  if (hr)
+    {
+      log_error ("%s:%s: can't set attach method: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      goto leave;
+    }
+
+  /* Mark that attachment so that we know why it has been created.  */
+  if (get_gpgolattachtype_tag (message, &prop.ulPropTag) )
+    goto leave;
+  prop.Value.l = ATTACHTYPE_PGPBODY;
+  hr = HrSetOneProp ((LPMAPIPROP)newatt, &prop);
+  if (hr)
+    {
+      log_error ("%s:%s: can't set %s property: hr=%#lx\n",
+                 SRCNAME, __func__, "GpgOL Attach Type", hr);
+      goto leave;
+    }
+
+  prop.ulPropTag = PR_ATTACHMENT_HIDDEN;
+  prop.Value.b = TRUE;
+  hr = HrSetOneProp ((LPMAPIPROP)newatt, &prop);
+  if (hr)
+    {
+      log_error ("%s:%s: can't set hidden attach flag: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      goto leave;
+    }
+
+  prop.ulPropTag = PR_ATTACH_FILENAME_A;
+  prop.Value.lpszA = body_filename;
+  hr = HrSetOneProp ((LPMAPIPROP)newatt, &prop);
+  if (hr)
+    {
+      log_error ("%s:%s: can't set attach filename: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      goto leave;
+    }
+
+  punk = (LPUNKNOWN)outstream;
+  hr = newatt->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 0,
+                             MAPI_CREATE|MAPI_MODIFY, &punk);
+  if (FAILED (hr))
+    {
+      log_error ("%s:%s: can't create output stream: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      goto leave;
+    }
+  outstream = (LPSTREAM)punk;
+
+  /* Insert a blank line so that our mime parser skips over the mail
+     headers.  */
+  hr = outstream->Write ("\r\n", 2, NULL);
+  if (hr)
+    {
+      log_error ("%s:%s: Write failed: hr=%#lx", SRCNAME, __func__, hr);
+      goto leave;
+    }
+
+  {
+    ULARGE_INTEGER cb;
+    cb.QuadPart = 0xffffffffffffffffll;
+    hr = instream->CopyTo (outstream, cb, NULL, NULL);
+  }
+  if (hr)
+    {
+      log_error ("%s:%s: can't copy streams: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      goto leave;
+    }
+  hr = outstream->Commit (0);
+  if (hr)
+    {
+      log_error ("%s:%s: Commiting output stream failed: hr=%#lx",
+                 SRCNAME, __func__, hr);
+      goto leave;
+    }
+  gpgol_release (outstream);
+  outstream = NULL;
+  hr = newatt->SaveChanges (0);
+  if (hr)
+    {
+      log_error ("%s:%s: SaveChanges of the attachment failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      goto leave;
+    }
+  gpgol_release (newatt);
+  newatt = NULL;
+  hr = mapi_save_changes (message, KEEP_OPEN_READWRITE);
+
+ leave:
+  if (outstream)
+    {
+      outstream->Revert ();
+      gpgol_release (outstream);
+    }
+  if (newatt)
+    gpgol_release (newatt);
+  gpgol_release (instream);
+  return hr? -1:0;
+}
+
+int
+mapi_mark_or_create_moss_attach (LPMESSAGE message, msgtype_t msgtype)
+{
+  int i;
+  if (msgtype == MSGTYPE_UNKNOWN ||
+      msgtype == MSGTYPE_GPGOL)
+    {
+      return 0;
+    }
 
+  /* First check if we already have one marked. */
+  mapi_attach_item_t *table = mapi_create_attach_table (message, 0);
+  for (i = 0; table && !table[i].end_of_table; i++)
+    {
+      if (table[i].attach_type == ATTACHTYPE_PGPBODY ||
+          table[i].attach_type == ATTACHTYPE_MOSS ||
+          table[i].attach_type == ATTACHTYPE_MOSSTEMPL)
+        {
+          /* Found existing moss attachment */
+          mapi_release_attach_table (table);
+          return 0;
+        }
+    }
+
+  if (msgtype == MSGTYPE_GPGOL_CLEAR_SIGNED ||
+      msgtype == MSGTYPE_GPGOL_PGP_MESSAGE)
+    {
+      /* Inline message we need to create body attachment so that we
+         are able to restore the content. */
+      return mapi_body_to_attachment (message);
+    }
+  if (!table)
+    {
+      log_debug ("%s:%s: Neither pgp inline nor an attachment table.",
+                 SRCNAME, __func__);
+      return -1;
+    }
+
+  /* MIME Mails check for S/MIME first. */
+  for (i = 0; !table[i].end_of_table; i++)
+    {
+      if (table[i].content_type
+          && (!strcmp (table[i].content_type, "application/pkcs7-mime")
+              || !strcmp (table[i].content_type,
+                          "application/x-pkcs7-mime"))
+          && table[i].filename
+          && !strcmp (table[i].filename, "smime.p7m"))
+        break;
+    }
+  if (!table[i].end_of_table)
+    {
+      mapi_mark_moss_attach (message, table + i);
+      mapi_release_attach_table (table);
+      return 0;
+    }
+
+  /* PGP/MIME or S/MIME stuff.  */
+  /* Multipart/encrypted message: We expect 2 attachments.
+     The first one with the version number and the second one
+     with the ciphertext.  As we don't know wether we are
+     called the first time, we first try to find these
+     attachments by looking at all attachments.  Only if this
+     fails we identify them by their order (i.e. the first 2
+     attachments) and mark them as part1 and part2.  */
+  for (i = 0; !table[i].end_of_table; i++); /* Count entries */
+  if (i >= 2)
+    {
+      int part1_idx = -1,
+          part2_idx = -1;
+      /* At least 2 attachments but none are marked.  Thus we
+         assume that this is the first time we see this
+         message and we will set the mark now if we see
+         appropriate content types. */
+      if (table[0].content_type
+          && !strcmp (table[0].content_type,
+                      "application/pgp-encrypted"))
+        part1_idx = 0;
+      if (table[1].content_type
+          && !strcmp (table[1].content_type,
+                      "application/octet-stream"))
+        part2_idx = 1;
+      if (part1_idx != -1 && part2_idx != -1)
+        {
+          mapi_mark_moss_attach (message, table+part1_idx);
+          mapi_mark_moss_attach (message, table+part2_idx);
+          mapi_release_attach_table (table);
+          return 0;
+        }
+    }
+
+  if (!table[0].end_of_table && table[1].end_of_table)
+    {
+      /* No MOSS flag found in the table but there is only one
+         attachment.  Due to the message type we know that this is
+         the original MOSS message.  We mark this attachment as
+         hidden, so that it won't get displayed.  We further mark
+         it as our original MOSS attachment so that after parsing
+         we have a mean to find it again (see above).  */
+      mapi_mark_moss_attach (message, table + 0);
+      mapi_release_attach_table (table);
+      return 0;
+    }
+
+   mapi_release_attach_table (table);
+   return -1; /* No original attachment - this should not happen.  */
+}
diff --git a/src/mapihelp.h b/src/mapihelp.h
index ad2ede1..3f22538 100644
--- a/src/mapihelp.h
+++ b/src/mapihelp.h
@@ -177,6 +177,13 @@ attachtype_t get_gpgolattachtype (LPATTACH obj, ULONG tag);
 int get_gpgol_draft_info_flags (LPMESSAGE message);
 
 int set_gpgol_draft_info_flags (LPMESSAGE message, int flags);
+
+/* Mark crypto attachments as hidden. And mark the moss
+ attachment for later use. Returns true on error. */
+int mapi_mark_or_create_moss_attach (LPMESSAGE message, msgtype_t msgtype);
+
+/* Copy the MAPI body to a PGPBODY type attachment. */
+int mapi_body_to_attachment (LPMESSAGE message);
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/message.cpp b/src/message.cpp
index 6fe6747..d04e919 100644
--- a/src/message.cpp
+++ b/src/message.cpp
@@ -673,137 +673,6 @@ message_verify (LPMESSAGE message, msgtype_t msgtype, int force, HWND hwnd)
 }
 
 
-/* Copy the MAPI body to a PGPBODY type attachment. */
-static int
-pgp_body_to_attachment (LPMESSAGE message)
-{
-  HRESULT hr;
-  LPSTREAM instream;
-  ULONG newpos;
-  LPATTACH newatt = NULL;
-  SPropValue prop;
-  LPSTREAM outstream = NULL;
-  LPUNKNOWN punk;
-  GpgOLStr body_filename (PGPBODYFILENAME);
-
-  instream = mapi_get_body_as_stream (message);
-  if (!instream)
-    return -1;
-  
-  hr = message->CreateAttach (NULL, 0, &newpos, &newatt);
-  if (hr)
-    {
-      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 ((LPMAPIPROP)newatt, &prop);
-  if (hr)
-    {
-      log_error ("%s:%s: can't set attach method: hr=%#lx\n",
-                 SRCNAME, __func__, hr); 
-      goto leave;
-    }
-
-  /* Mark that attachment so that we know why it has been created.  */
-  if (get_gpgolattachtype_tag (message, &prop.ulPropTag) )
-    goto leave;
-  prop.Value.l = ATTACHTYPE_PGPBODY;
-  hr = HrSetOneProp ((LPMAPIPROP)newatt, &prop);	
-  if (hr)
-    {
-      log_error ("%s:%s: can't set %s property: hr=%#lx\n",
-                 SRCNAME, __func__, "GpgOL Attach Type", hr); 
-      goto leave;
-    }
-
-  prop.ulPropTag = PR_ATTACHMENT_HIDDEN;
-  prop.Value.b = TRUE;
-  hr = HrSetOneProp ((LPMAPIPROP)newatt, &prop);
-  if (hr)
-    {
-      log_error ("%s:%s: can't set hidden attach flag: hr=%#lx\n",
-                 SRCNAME, __func__, hr); 
-      goto leave;
-    }
-
-  prop.ulPropTag = PR_ATTACH_FILENAME_A;
-  prop.Value.lpszA = body_filename;
-  hr = HrSetOneProp ((LPMAPIPROP)newatt, &prop);
-  if (hr)
-    {
-      log_error ("%s:%s: can't set attach filename: hr=%#lx\n",
-                 SRCNAME, __func__, hr); 
-      goto leave;
-    }
-
-  punk = (LPUNKNOWN)outstream;
-  hr = newatt->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 0,
-                             MAPI_CREATE|MAPI_MODIFY, &punk);
-  if (FAILED (hr)) 
-    {
-      log_error ("%s:%s: can't create output stream: hr=%#lx\n",
-                 SRCNAME, __func__, hr); 
-      goto leave;
-    }
-  outstream = (LPSTREAM)punk;
-
-  /* Insert a blank line so that our mime parser skips over the mail
-     headers.  */
-  hr = outstream->Write ("\r\n", 2, NULL);
-  if (hr)
-    {
-      log_error ("%s:%s: Write failed: hr=%#lx", SRCNAME, __func__, hr);
-      goto leave;
-    }
-
-  {
-    ULARGE_INTEGER cb;
-    cb.QuadPart = 0xffffffffffffffffll;
-    hr = instream->CopyTo (outstream, cb, NULL, NULL);
-  }
-  if (hr)
-    {
-      log_error ("%s:%s: can't copy streams: hr=%#lx\n",
-                 SRCNAME, __func__, hr); 
-      goto leave;
-    }
-  hr = outstream->Commit (0);
-  if (hr)
-    {
-      log_error ("%s:%s: Commiting output stream failed: hr=%#lx",
-                 SRCNAME, __func__, hr);
-      goto leave;
-    }
-  gpgol_release (outstream);
-  outstream = NULL;
-  hr = newatt->SaveChanges (0);
-  if (hr)
-    {
-      log_error ("%s:%s: SaveChanges of the attachment failed: hr=%#lx\n",
-                 SRCNAME, __func__, hr); 
-      goto leave;
-    }
-  gpgol_release (newatt);
-  newatt = NULL;
-  hr = mapi_save_changes (message, KEEP_OPEN_READWRITE);
-
- leave:
-  if (outstream)
-    {
-      outstream->Revert ();
-      gpgol_release (outstream);
-    }
-  if (newatt)
-    gpgol_release (newatt);
-  gpgol_release (instream);
-  return hr? -1:0;
-}
-
-
 /* Decrypt MESSAGE, check signature and update the attachments as
    required.  MSGTYPE should be the type of the message so that the
    function can decide what to do.  With FORCE set the decryption is
@@ -875,7 +744,7 @@ message_decrypt (LPMESSAGE message, msgtype_t msgtype, int force, HWND hwnd)
       if (part1_idx == -1)
         {
           mapi_release_attach_table (table);
-          if (pgp_body_to_attachment (message))
+          if (mapi_body_to_attachment (message))
             table = NULL;
           else
             table = mapi_create_attach_table (message, 0);

commit 5c8b946a694b9e856c5513a8c3f275272d9b445f
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 16 16:23:36 2016 +0200

    Enable c++11
    
    * src/Makefile.am: Enable c++11.
    * src/olflange-dlgs.cpp: Fix compile error with c++11.
    
    --
    The plan is to use a bit more c++ features in new code like
    shared / unique pointers and more objects for simplified data
    and memory handling.

diff --git a/src/Makefile.am b/src/Makefile.am
index f1c6856..8834497 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,7 +33,7 @@ EXTRA_DIST = \
 EXEEXT = .dll
 
 AM_CFLAGS = $(GPGME_CFLAGS) $(LIBASSUAN_CFLAGS) -shared
-AM_CXXFLAGS = $(GPGME_CFLAGS) $(LIBASSUAN_CFLAGS) -shared
+AM_CXXFLAGS = $(GPGME_CFLAGS) $(LIBASSUAN_CFLAGS) -shared -std=c++11
 
 gpgol_SOURCES = \
 	main.c  gpgol.def           \
diff --git a/src/olflange-dlgs.cpp b/src/olflange-dlgs.cpp
index 8bccbaa..0fed8a4 100644
--- a/src/olflange-dlgs.cpp
+++ b/src/olflange-dlgs.cpp
@@ -54,7 +54,7 @@ set_labels (HWND dlg)
 
     { IDC_GPG_OPTIONS,      "Debug..."},
     { IDC_GPG_CONF,         N_("Crypto Engine")},
-    { IDC_VERSION_INFO,  "Version "VERSION},
+    { IDC_VERSION_INFO,  "Version " VERSION},
     { 0, NULL}
   };
   int i;

commit 268212abb5f0403cc03f1127f2014cef780450ff
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Mon Aug 15 14:07:37 2016 +0200

    Start mail handing restructuring
    
    * src/mail.cpp (Mail::process_message): Split out beforeRead
    parts into pre_process_message.
    (get_cipherstream): New helper to get OOM level attachment.
    (Mail::decrypt_mime): New. OOM based mime decryption.
    (Mail::decrypt): Dummy.
    (Mail::do_crypto): Rename to encrypt_sign.
    (Mail::decrypt_verify): New. Entry point for Read event.
    * src/mail.h: Update accordingly.
    * src/mailitem-events.cpp: Call new functions.
    
    --
    First part of a series of commits that will rework the way
    decryption works without modifing the underlying mapi object.

diff --git a/src/mail.cpp b/src/mail.cpp
index 1030c77..0559c93 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -1,7 +1,7 @@
 /* @file mail.h
  * @brief High level class to work with Outlook Mailitems.
  *
- *    Copyright (C) 2015 Intevation GmbH
+ *    Copyright (C) 2015, 2016 Intevation GmbH
  *
  * This file is part of GpgOL.
  *
@@ -28,6 +28,7 @@
 #include "message.h"
 #include "revert.h"
 #include "gpgoladdin.h"
+#include "mymapitags.h"
 
 #include <map>
 
@@ -61,6 +62,19 @@ static std::map<LPDISPATCH, Mail*> g_mail_map;
 "</td></tr>" \
 "</table></body></html>"
 
+#define WAIT_TEMPLATE \
+"<html><head></head><body>" \
+"<table border=\"0\" width=\"100%\" cellspacing=\"1\" cellpadding=\"1\" bgcolor=\"#0069cc\">" \
+"<tr>" \
+"<td bgcolor=\"#0080ff\">" \
+"<p><span style=\"font-weight:600; background-color:#0080ff;\"><center>This message is encrypted</center><span></p></td></tr>" \
+"<tr>" \
+"<td bgcolor=\"#e0f0ff\">" \
+"<center>" \
+"<br/>Please wait while the message is decrypted by GpgOL..." \
+"</td></tr>" \
+"</table></body></html>"
+
 Mail::Mail (LPDISPATCH mailitem) :
     m_mailitem(mailitem),
     m_processed(false),
@@ -69,7 +83,8 @@ Mail::Mail (LPDISPATCH mailitem) :
     m_crypt_successful(false),
     m_is_smime(false),
     m_is_smime_checked(false),
-    m_sender(NULL)
+    m_sender(NULL),
+    m_type(MSGTYPE_UNKNOWN)
 {
   if (get_mail_for_item (mailitem))
     {
@@ -91,37 +106,6 @@ Mail::Mail (LPDISPATCH mailitem) :
   g_mail_map.insert (std::pair<LPDISPATCH, Mail *> (mailitem, this));
 }
 
-int
-Mail::process_message ()
-{
-  int err;
-  LPMESSAGE message = get_oom_base_message (m_mailitem);
-  if (!message)
-    {
-      log_error ("%s:%s: Failed to get base message.",
-                 SRCNAME, __func__);
-      return 0;
-    }
-  log_oom_extra ("%s:%s: GetBaseMessage OK.",
-                 SRCNAME, __func__);
-  /* Change the message class here. It is important that
-     we change the message class in the before read event
-     regardless if it is already set to one of GpgOL's message
-     classes. Changing the message class (even if we set it
-     to the same value again that it already has) causes
-     Outlook to reconsider what it "knows" about a message
-     and reread data from the underlying base message. */
-  mapi_change_message_class (message, 1);
-  err = message_incoming_handler (message, NULL,
-                                  false);
-  m_processed = (err == 1) || (err == 2);
-
-  log_debug ("%s:%s: incoming handler status: %i",
-             SRCNAME, __func__, err);
-  gpgol_release (message);
-  return 0;
-}
-
 Mail::~Mail()
 {
   std::map<LPDISPATCH, Mail *>::iterator it;
@@ -155,80 +139,148 @@ Mail::get_mail_for_item (LPDISPATCH mailitem)
 }
 
 int
-Mail::insert_plaintext ()
+Mail::pre_process_message ()
 {
-  int err = 0;
-  int is_html, was_protected = 0;
-  char *body = NULL;
-
-  if (!m_processed)
+  LPMESSAGE message = get_oom_base_message (m_mailitem);
+  if (!message)
     {
+      log_error ("%s:%s: Failed to get base message.",
+                 SRCNAME, __func__);
       return 0;
     }
+  log_oom_extra ("%s:%s: GetBaseMessage OK.",
+                 SRCNAME, __func__);
+  /* Change the message class here. It is important that
+     we change the message class in the before read event
+     regardless if it is already set to one of GpgOL's message
+     classes. Changing the message class (even if we set it
+     to the same value again that it already has) causes
+     Outlook to reconsider what it "knows" about a message
+     and reread data from the underlying base message. */
+  mapi_change_message_class (message, 1);
+  /* TODO: Unify this so mapi_change_message_class returns
+     a useful value already. */
+  m_type = mapi_get_message_type (message);
+  gpgol_release (message);
+  return 0;
+}
 
-  if (m_needs_wipe)
+/** Get the cipherstream of the mailitem. */
+static LPSTREAM
+get_cipherstream (LPDISPATCH mailitem)
+{
+  LPDISPATCH attachments = get_oom_object (mailitem, "Attachments");
+  LPDISPATCH attachment = NULL;
+  LPATTACH mapi_attachment = NULL;
+  LPSTREAM stream = NULL;
+
+  if (!attachments)
     {
-      log_error ("%s:%s: Insert plaintext called for msg that needs wipe: %p",
-                 SRCNAME, __func__, m_mailitem);
-      return 0;
+      log_debug ("%s:%s: Failed to get attachments.",
+                 SRCNAME, __func__);
+      return NULL;
     }
 
-  /* Outlook somehow is confused about the attachment
-     table of our sent mails. The securemessage interface
-     gives us access to the real attach table but the attachment
-     table of the message itself is broken. */
-  LPMESSAGE base_message = get_oom_base_message (m_mailitem);
-  if (!base_message)
+  int count = get_oom_int (attachments, "Count");
+  if (count < 1)
     {
-      log_error ("%s:%s: Failed to get base message",
-                 SRCNAME, __func__);
-      return 0;
+      log_debug ("%s:%s: Invalid attachment count: %i.",
+                 SRCNAME, __func__, count);
+      gpgol_release (attachments);
+      return NULL;
+    }
+  if (count > 1)
+    {
+      log_debug ("%s:%s: More then one attachment count: %i. Continuing anway.",
+                 SRCNAME, __func__, count);
     }
-  err = mapi_get_gpgol_body_attachment (base_message, &body, NULL,
-                                        &is_html, &was_protected);
-  m_needs_wipe = was_protected;
+  /* We assume the crypto attachment is the first item. */
+  attachment = get_oom_object (attachments, "Item(1)");
+  gpgol_release (attachments);
+  attachments = NULL;
 
-  log_debug ("%s:%s: Setting plaintext for msg: %p",
-             SRCNAME, __func__, m_mailitem);
-  if (err || !body)
+  mapi_attachment = (LPATTACH) get_oom_iunknown (attachment,
+                                                 "MapiObject");
+  gpgol_release (attachment);
+  if (!mapi_attachment)
     {
-      log_error ("%s:%s: Failed to get body attachment. Err: %i",
-                 SRCNAME, __func__, err);
-      put_oom_string (m_mailitem, "HTMLBody", HTML_TEMPLATE);
-      err = -1;
-      goto done;
+      log_debug ("%s:%s: Failed to get MapiObject of attachment: %p",
+                 SRCNAME, __func__, attachment);
     }
-  if (put_oom_string (m_mailitem, is_html ? "HTMLBody" : "Body", body))
+  if (FAILED (mapi_attachment->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream,
+                                             0, MAPI_MODIFY, (LPUNKNOWN*) &stream)))
     {
-      log_error ("%s:%s: Failed to modify body of item.",
+      log_debug ("%s:%s: Failed to open stream for mapi_attachment: %p",
+                 SRCNAME, __func__, mapi_attachment);
+      gpgol_release (mapi_attachment);
+    }
+  return stream;
+}
+
+/** The decryption for mime messages.
+  We get the original attachment table and decrypt the first
+  attachment. Then we replace the body and attachment table
+  with the new contents. */
+int
+Mail::decrypt_mime()
+{
+  LPSTREAM cipherstream = get_cipherstream(m_mailitem);
+
+  if (!cipherstream)
+    {
+      log_debug ("%s:%s: Failed to get cipherstream.",
                  SRCNAME, __func__);
-      err = -1;
+      return 1;
     }
 
-  xfree (body);
-  /* TODO: unprotect attachments does not work for sent mails
-     as the attachment table of the mapiitem is invalid.
-     We need to somehow get outlook to use the attachment table
-     of the base message and and then decrypt those.
-     This will probably mean removing all attachments for the
-     message and adding the attachments from the base message then
-     we can call unprotect_attachments as usual. */
-  if (unprotect_attachments (m_mailitem))
+  char tmpbuf[33];
+
+  if (put_oom_string (m_mailitem, "HTMLBody", WAIT_TEMPLATE))
     {
-      log_error ("%s:%s: Failed to unprotect attachments.",
+      log_error ("%s:%s: Failed to modify body of item.",
                  SRCNAME, __func__);
-      err = -1;
+    }
+  return 0;
+}
+
+int
+Mail::decrypt()
+{
+  return 0;
+}
+
+int
+Mail::decrypt_verify()
+{
+  if (m_needs_wipe)
+    {
+      log_error ("%s:%s: Decrypt verify called for msg that needs wipe: %p",
+                 SRCNAME, __func__, m_mailitem);
+      return 0;
     }
 
+  switch (m_type)
+    {
+      case MSGTYPE_UNKNOWN:
+        /* Not a message for us. Ignore. */
+        return 0;
+      case MSGTYPE_GPGOL:
+        log_debug ("%s:%s: ignoring unknown message of original SMIME class\n",
+                   SRCNAME, __func__);
+        break;
+      case MSGTYPE_GPGOL_MULTIPART_ENCRYPTED:
+        return decrypt_mime();
+      default:
+        log_debug ("%s:%s: Unhandled message class. \n",
+                   SRCNAME, __func__);
+    }
   /* Invalidate UI to set the correct sig status. */
   gpgoladdin_invalidate_ui ();
-done:
-  gpgol_release (base_message);
-  return err;
+  return 0;
 }
 
 int
-Mail::do_crypto ()
+Mail::encrypt_sign ()
 {
   int err = -1,
       flags = 0;
diff --git a/src/mail.h b/src/mail.h
index ff79567..5b75f79 100644
--- a/src/mail.h
+++ b/src/mail.h
@@ -1,7 +1,7 @@
 /* @file mail.h
  * @brief High level class to work with Outlook Mailitems.
  *
- *    Copyright (C) 2015 Intevation GmbH
+ *    Copyright (C) 2015, 2016 Intevation GmbH
  *
  * This file is part of GpgOL.
  *
@@ -22,6 +22,7 @@
 #define MAIL_H
 
 #include "oomhelp.h"
+#include "mapihelp.h"
 
 /** @brief Data wrapper around a mailitem.
  *
@@ -76,25 +77,22 @@ public:
   /** @brief Reference to the mailitem. Do not Release! */
   LPDISPATCH item () { return m_mailitem; }
 
-  /** @brief Process the message. Ususally to be called from BeforeRead.
+  /** @brief Pre process the message. Ususally to be called from BeforeRead.
    *
    * This function assumes that the base message interface can be accessed
-   * and calles the MAPI Message handling which creates the GpgOL style
-   * attachments and sets up the message class etc.
-   *
-   * Sets the was_encrypted / processed variables.
+   * and calles the MAPI Message handling which changes the message class
+   * to enable our own handling.
    *
    * @returns 0 on success.
    */
-  int process_message ();
+  int pre_process_message ();
 
-  /** @brief Replace the body with the plaintext and session decrypts
-   * attachments.
+  /** @brief Decrypt / Verify the mail.
    *
-   * Sets the needs_wipe variable.
+   * Sets the needs_wipe and was_encrypted variable.
    *
    * @returns 0 on success. */
-  int insert_plaintext ();
+  int decrypt_verify ();
 
   /** @brief do crypto operations as selected by the user.
    *
@@ -102,7 +100,7 @@ public:
    * draft info flags.
    *
    * @returns 0 on success. */
-  int do_crypto ();
+  int encrypt_sign ();
 
   /** @brief Necessary crypto operations were completed successfully. */
   bool crypto_successful () { return !needs_crypto() || m_crypt_successful; }
@@ -163,6 +161,15 @@ public:
     */
   bool is_smime ();
 
+protected:
+  /** @brief do the actual decryption for mime messages.
+    *
+    * @returns true on error. */
+  int decrypt_mime();
+
+  /** @brief decryption helper. */
+  int decrypt();
+
 private:
   LPDISPATCH m_mailitem;
   LPDISPATCH m_event_sink;
@@ -173,5 +180,6 @@ private:
        m_is_smime, /* This is an smime mail. */
        m_is_smime_checked; /* it was checked if this is an smime mail */
   char *m_sender;
+  msgtype_t m_type; /* Our messagetype as set in mapi */
 };
 #endif // MAIL_H
diff --git a/src/mailitem-events.cpp b/src/mailitem-events.cpp
index 5101610..e526124 100644
--- a/src/mailitem-events.cpp
+++ b/src/mailitem-events.cpp
@@ -160,18 +160,18 @@ EVENT_SINK_INVOKE(MailItemEvents)
         }
       case BeforeRead:
         {
-          if (m_mail->process_message ())
+          if (m_mail->pre_process_message ())
             {
-              log_error ("%s:%s: Process message failed.",
+              log_error ("%s:%s: Pre process message failed.",
                          SRCNAME, __func__);
             }
           break;
         }
       case Read:
         {
-          if (m_mail->insert_plaintext ())
+          if (m_mail->decrypt_verify ())
             {
-              log_error ("%s:%s: Failed to insert plaintext into oom.",
+              log_error ("%s:%s: Decrypt message failed.",
                          SRCNAME, __func__);
             }
           if (!opt.enable_smime && m_mail->is_smime ())
@@ -300,7 +300,7 @@ EVENT_SINK_INVOKE(MailItemEvents)
           if (m_send_seen)
             {
               m_send_seen = false;
-              m_mail->do_crypto ();
+              m_mail->encrypt_sign ();
               if (m_mail->crypto_successful ())
                 {
                   /* We can't trigger a Send event in the current state.

-----------------------------------------------------------------------


hooks/post-receive
-- 
GnuPG extension for MS Outlook
http://git.gnupg.org




More information about the Gnupg-commits mailing list