[git] GpgOL - branch, nomapi, updated. gpgol-1.4.0-21-g553db6b

by Andre Heinecke cvs at cvs.gnupg.org
Mon Aug 22 15:51:46 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 updated
       via  553db6ba3cfaca7275669abbc5024037363630be (commit)
       via  7f9f7bf99de356d794df06852bc12faf9c6e99ba (commit)
       via  3b27162dcb06c99aa62ab12403312854871e2214 (commit)
       via  87d57374bbe502b121d68874e9e807e89a20f358 (commit)
      from  c1398da89a56f4c2cad743af8eb687d33e7f3246 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 553db6ba3cfaca7275669abbc5024037363630be
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Mon Aug 22 15:40:37 2016 +0200

    Add GPGME based async decryption
    
    * src/Makefile.am (gpgol_SOURCES): Add Mimedataprovider.
    * src/mail.cpp (Mail::m_moss_position): Store moss pos.
    (Mail::is_mail_valid): Helper to check for orphaned mail pointer.
    (Mail::pre_process_message): Store moss position.
    (get_cipherstream): Use stored moss position.
    (use_body): Removed. Always use MOSS.
    (do_parsing): Helper to run in different thread.
    (Mail::decrypt_verify): Insert placehoder, create parser,
    start parser thread.
    (Mail::parsing_done): Helper to insert plaintext in UI Thread.
    (Mail::revert_all_mails): Fix typo.
    (Mail::wipe_all_mails): Init err.
    (Mail::close_inspector): Helper to close current inspector
    with discard changes.
    * src/mail.h: Update accordingly.
    * src/mailparser.cpp (MailParser::MailParser): Use MimeDataProvider.
    (operation_for_type): Helper to figure out type of work and protocol.
    (MailParser::parse): Enable a fist version of decrypt.
    * src/mailparser.h: Update accordingly.
    * src/main.c (DllMain): Set w32-inst-dir for GpgME.
    * src/mimedataprovider.cpp: New. Copy stream into GpgME Data.
    * src/mimedataprovider.h: New.
    * src/util.h (log_mime_parser): New helper for logging.
    * src/windowmessages.cpp (gpgol_window_proc): Handle parsing
    done signal.
    * src/windowmessages.h (PARSING_DONE): New.
    * src/attachment.cpp: Implement DataProvider interface.
    * src/attachment.h: Update accordingly.
    
    --
    The idea is that DataProvider classes will take and recieve
    Data from GpgOL, copy it into internal buffers (to avoid working
    with the OOM from a background thread) and then provide the
    data as needed to GpgOL. On Read they shall parse the MIME e.g.
    into a signature part, and on Write they shall deliver useful
    objects (e.g. attachments) for Outlook to work with.
    
    The Close / Wipe changes are a bit unrelated as they were created
    for experiments to avoid "save your changes" message boxes.

diff --git a/src/Makefile.am b/src/Makefile.am
index 65e4f7b..fd91691 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -88,7 +88,8 @@ gpgol_SOURCES = \
 	gmime-table-private.h \
 	exechelp.c exechelp.h \
 	addin-options.cpp addin-options.h \
-	mailparser.cpp mailparser.h
+	mailparser.cpp mailparser.h \
+	mimedataprovider.cpp mimedataprovider.h
 
 
 #treeview_SOURCES = treeview.c
diff --git a/src/attachment.cpp b/src/attachment.cpp
index a9ad736..b052d00 100644
--- a/src/attachment.cpp
+++ b/src/attachment.cpp
@@ -25,7 +25,9 @@
 #include "mapihelp.h"
 #include "gpgolstr.h"
 
+#include <climits>
 #include <gpg-error.h>
+#include <gpgme++/error.h>
 
 Attachment::Attachment()
 {
@@ -42,6 +44,15 @@ Attachment::Attachment()
     }
 }
 
+Attachment::Attachment(LPSTREAM stream)
+{
+  if (stream)
+    {
+      stream->AddRef ();
+    }
+  m_stream = stream;
+}
+
 Attachment::~Attachment()
 {
   log_debug ("%s:%s", SRCNAME, __func__);
@@ -60,12 +71,6 @@ Attachment::get_display_name() const
   return m_utf8DisplayName;
 }
 
-std::string
-Attachment::get_tmp_file_name() const
-{
-  return m_utf8FileName;
-}
-
 void
 Attachment::set_display_name(const char *name)
 {
@@ -78,26 +83,129 @@ Attachment::set_attach_type(attachtype_t type)
   m_type = type;
 }
 
-void
-Attachment::set_hidden(bool value)
+bool
+Attachment::isSupported(GpgME::DataProvider::Operation op) const
 {
-  m_hidden = value;
+  return op == GpgME::DataProvider::Read ||
+         op == GpgME::DataProvider::Write ||
+         op == GpgME::DataProvider::Seek ||
+         op == GpgME::DataProvider::Release;
+}
+
+ssize_t
+Attachment::read(void *buffer, size_t bufSize)
+{
+  if (!bufSize)
+    {
+      return 0;
+    }
+  if (!buffer || bufSize >= ULONG_MAX)
+    {
+      log_error ("%s:%s: Read invalid",
+                 SRCNAME, __func__);
+      GpgME::Error::setSystemError (GPG_ERR_EINVAL);
+      return -1;
+    }
+  if (!m_stream)
+    {
+      log_error ("%s:%s: Read on null stream.",
+                 SRCNAME, __func__);
+      GpgME::Error::setSystemError (GPG_ERR_EIO);
+      return -1;
+    }
+
+  ULONG cb = static_cast<size_t> (bufSize);
+  ULONG bRead = 0;
+  HRESULT hr = m_stream->Read (buffer, cb, &bRead);
+  if (hr != S_OK && hr != S_FALSE)
+    {
+      log_error ("%s:%s: Read failed",
+                 SRCNAME, __func__);
+      GpgME::Error::setSystemError (GPG_ERR_EIO);
+      return -1;
+    }
+  return static_cast<size_t>(bRead);
 }
 
-int
-Attachment::write(const char *data, size_t size)
+ssize_t
+Attachment::write(const void *data, size_t size)
 {
-  if (!data || !size)
+  if (!size)
     {
       return 0;
     }
-  if (!m_stream && m_stream->Write (data, size, NULL) != S_OK)
+  if (!data || size >= ULONG_MAX)
+    {
+      GpgME::Error::setSystemError (GPG_ERR_EINVAL);
+      return -1;
+    }
+  if (!m_stream)
     {
-      return 1;
+      log_error ("%s:%s: Write on NULL stream. ",
+                 SRCNAME, __func__);
+      GpgME::Error::setSystemError (GPG_ERR_EIO);
+      return -1;
+    }
+  ULONG written = 0;
+  if (m_stream->Write (data, static_cast<ULONG>(size), &written) != S_OK)
+    {
+      GpgME::Error::setSystemError (GPG_ERR_EIO);
+      log_error ("%s:%s: Write failed.",
+                 SRCNAME, __func__);
+      return -1;
     }
   if (m_stream->Commit (0) != S_OK)
     {
-      return 1;
+      log_error ("%s:%s: Commit failed. ",
+                 SRCNAME, __func__);
+      GpgME::Error::setSystemError (GPG_ERR_EIO);
+      return -1;
+    }
+  return static_cast<ssize_t> (written);
+}
+
+off_t Attachment::seek(off_t offset, int whence)
+{
+  DWORD dwOrigin;
+  switch (whence)
+    {
+      case SEEK_SET:
+          dwOrigin = STREAM_SEEK_SET;
+          break;
+      case SEEK_CUR:
+          dwOrigin = STREAM_SEEK_CUR;
+          break;
+      case SEEK_END:
+          dwOrigin = STREAM_SEEK_END;
+          break;
+      default:
+          GpgME::Error::setSystemError (GPG_ERR_EINVAL);
+          return (off_t) - 1;
+   }
+  if (!m_stream)
+    {
+      log_error ("%s:%s: Seek on null stream.",
+                 SRCNAME, __func__);
+      GpgME::Error::setSystemError (GPG_ERR_EIO);
+      return (off_t) - 1;
+    }
+  LARGE_INTEGER move = {0, 0};
+  move.QuadPart = offset;
+  ULARGE_INTEGER result;
+  HRESULT hr = m_stream->Seek (move, dwOrigin, &result);
+
+  if (hr != S_OK)
+    {
+      log_error ("%s:%s: Seek failed. ",
+                 SRCNAME, __func__);
+      GpgME::Error::setSystemError (GPG_ERR_EINVAL);
+      return (off_t) - 1;
     }
-  return 0;
+  return result.QuadPart;
+}
+
+void Attachment::release()
+{
+  /* No op. */
+  log_debug ("%s:%s", SRCNAME, __func__);
 }
diff --git a/src/attachment.h b/src/attachment.h
index 68821ff..ae1fb49 100644
--- a/src/attachment.h
+++ b/src/attachment.h
@@ -1,6 +1,6 @@
-/* attachment.h - Functions for attachment handling
+/* attachment.h - Wrapper class for attachments
  *    Copyright (C) 2005, 2007 g10 Code GmbH
- *    Copyright (C) 2015 Intevation GmbH
+ *    Copyright (C) 2015, 2016 Intevation GmbH
  *
  * This file is part of GpgOL.
  *
@@ -25,40 +25,41 @@
 #include "mapihelp.h"
 #include <string>
 
+#include <gpgme++/interfaces/dataprovider.h>
+
 /** Helper class for attachment actions. */
-class Attachment
+class Attachment : public GpgME::DataProvider
 {
 public:
   /** Creates and opens a new temporary stream. */
   Attachment();
 
+  /** Creates the attachment wrapper for an existing stream. */
+  Attachment(LPSTREAM stream);
+
   /** Deletes the attachment and the underlying temporary file. */
   ~Attachment();
 
   /** Get an assoicated ISteam ptr or NULL. */
   LPSTREAM get_stream();
 
-  /** 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);
-
   /** Set the display name */
   void set_display_name(const char *name);
   std::string get_display_name() const;
 
-  std::string get_tmp_file_name() const;
-
   void set_attach_type(attachtype_t type);
 
-  void set_hidden(bool value);
+  /* Dataprovider interface */
+  bool isSupported(Operation) const;
+  ssize_t read(void *buffer, size_t bufSize);
+  ssize_t write(const void *buffer, size_t bufSize);
+  off_t seek(off_t offset, int whence);
+  void release();
+
 private:
   LPSTREAM m_stream;
-  std::string m_utf8FileName;
   std::string m_utf8DisplayName;
   attachtype_t m_type;
-  bool m_hidden;
 };
 
 #endif // ATTACHMENT_H
diff --git a/src/mail.cpp b/src/mail.cpp
index 4c16852..6043ed1 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -31,6 +31,7 @@
 #include "mymapitags.h"
 #include "mailparser.h"
 #include "gpgolstr.h"
+#include "windowmessages.h"
 
 #include <map>
 #include <vector>
@@ -87,6 +88,7 @@ Mail::Mail (LPDISPATCH mailitem) :
     m_crypt_successful(false),
     m_is_smime(false),
     m_is_smime_checked(false),
+    m_moss_position(0),
     m_sender(NULL),
     m_type(MSGTYPE_UNKNOWN)
 {
@@ -142,6 +144,19 @@ Mail::get_mail_for_item (LPDISPATCH mailitem)
   return it->second;
 }
 
+bool
+Mail::is_mail_valid (const Mail *mail)
+{
+  auto it = g_mail_map.begin();
+  while (it != g_mail_map.end())
+    {
+      if (it->second == mail)
+        return true;
+      ++it;
+    }
+  return false;
+}
+
 int
 Mail::pre_process_message ()
 {
@@ -168,7 +183,8 @@ Mail::pre_process_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))
+  m_moss_position = mapi_mark_or_create_moss_attach (message, m_type);
+  if (!m_moss_position)
     {
       log_error ("%s:%s: Failed to find moss attachment.",
                  SRCNAME, __func__);
@@ -181,7 +197,7 @@ Mail::pre_process_message ()
 
 /** Get the cipherstream of the mailitem. */
 static LPSTREAM
-get_cipherstream (LPDISPATCH mailitem)
+get_cipherstream (LPDISPATCH mailitem, int pos)
 {
   LPDISPATCH attachments = get_oom_object (mailitem, "Attachments");
   LPDISPATCH attachment = NULL;
@@ -203,13 +219,9 @@ get_cipherstream (LPDISPATCH mailitem)
       gpgol_release (attachments);
       return NULL;
     }
-  if (count > 1)
-    {
-      log_debug ("%s:%s: More then one attachment count: %i. Continuing anway.",
-                 SRCNAME, __func__, count);
-    }
   /* We assume the crypto attachment is the second item. */
-  attachment = get_oom_object (attachments, "Item(2)");
+  const auto item_str = std::string("Item(") + std::to_string(pos) + ")";
+  attachment = get_oom_object (attachments, item_str.c_str());
   gpgol_release (attachments);
   attachments = NULL;
 
@@ -231,21 +243,6 @@ get_cipherstream (LPDISPATCH mailitem)
   return stream;
 }
 
-/** 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)
-{
-  switch (type)
-    {
-      case MSGTYPE_GPGOL_PGP_MESSAGE:
-      case MSGTYPE_GPGOL_CLEAR_SIGNED:
-        return true;
-      default:
-        return false;
-    }
-}
-
 /** Helper to update the attachments of a mail object in oom.
   does not modify the underlying mapi structure. */
 static bool
@@ -270,6 +267,19 @@ add_attachments(LPDISPATCH mail,
   return false;
 }
 
+static DWORD WINAPI
+do_parsing (LPVOID arg)
+{
+  log_debug ("%s:%s: starting parsing for: %p",
+             SRCNAME, __func__, arg);
+
+  Mail *mail = (Mail *)arg;
+  auto parser = mail->parser();
+  parser->parse();
+  do_in_ui_thread (PARSING_DONE, arg);
+  return 0;
+}
+
 int
 Mail::decrypt_verify()
 {
@@ -282,75 +292,75 @@ Mail::decrypt_verify()
     {
       log_error ("%s:%s: Decrypt verify called for msg that needs wipe: %p",
                  SRCNAME, __func__, m_mailitem);
-      return 0;
+      return 1;
     }
 
   m_processed = true;
-  /* Do the actual parsing */
-  std::unique_ptr<MailParser> parser;
-  if (!use_body (m_type))
-    {
-      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
+  /* Inser placeholder */
+  if (put_oom_string (m_mailitem, "HTMLBody", WAIT_TEMPLATE))
     {
-      parser = std::unique_ptr<MailParser>();
+      log_error ("%s:%s: Failed to modify html body of item.",
+                 SRCNAME, __func__);
+      return 1;
     }
 
-  const std::string err = parser->parse();
-  if (!err.empty())
+  /* Do the actual parsing */
+  auto cipherstream = get_cipherstream (m_mailitem, m_moss_position);
+
+  if (!cipherstream)
     {
-      /* TODO Show error message. */
-      log_error ("%s:%s: Failed to parse message: %s",
-                 SRCNAME, __func__, err.c_str());
+      /* TODO Error message? */
+      log_debug ("%s:%s: Failed to get cipherstream.",
+                 SRCNAME, __func__);
       return 1;
     }
 
+  m_parser = new MailParser (cipherstream, m_type);
+  gpgol_release (cipherstream);
+
+  CreateThread (NULL, 0, do_parsing, (LPVOID) this, 0,
+                NULL);
+  return 0;
+}
+
+void Mail::parsing_done()
+{
   m_needs_wipe = true;
   /* Update the body */
-  const auto html = parser->get_utf8_html_body();
+  const auto html = m_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;
+          return;
         }
     }
   else
     {
-      const auto body = parser->get_utf8_text_body();
+      const auto body = m_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;
+          return;
         }
     }
 
   /* Update attachments */
-  if (add_attachments (m_mailitem, parser->get_attachments()))
+  if (add_attachments (m_mailitem, m_parser->get_attachments()))
     {
       log_error ("%s:%s: Failed to update attachments.",
                  SRCNAME, __func__);
-      return 1;
+      return;
     }
 
   /* Invalidate UI to set the correct sig status. */
+  delete m_parser;
+  m_parser = nullptr;
   gpgoladdin_invalidate_ui ();
-  return 0;
+  return;
 }
 
 int
@@ -493,7 +503,7 @@ Mail::revert_all_mails ()
     {
       if (it->second->revert ())
         {
-          log_error ("Failed to wipe mail: %p ", it->first);
+          log_error ("Failed to revert mail: %p ", it->first);
           err++;
         }
     }
@@ -519,14 +529,13 @@ Mail::wipe_all_mails ()
 int
 Mail::revert ()
 {
-  int err;
+  int err = 0;
   if (!m_processed)
     {
       return 0;
     }
 
   err = gpgol_mailitem_revert (m_mailitem);
-
   if (err == -1)
     {
       log_error ("%s:%s: Message revert failed falling back to wipe.",
@@ -590,3 +599,41 @@ Mail::get_subject()
 {
   return std::string(get_oom_string (m_mailitem, "Subject"));
 }
+
+int
+Mail::close_inspector ()
+{
+  LPDISPATCH inspector = get_oom_object (m_mailitem, "GetInspector");
+  HRESULT hr;
+  DISPID dispid;
+  if (!inspector)
+    {
+      log_debug ("%s:%s: No inspector.",
+                 SRCNAME, __func__);
+      return -1;
+    }
+
+  dispid = lookup_oom_dispid (inspector, "Close");
+  if (dispid != DISPID_UNKNOWN)
+    {
+      VARIANT aVariant[1];
+      DISPPARAMS dispparams;
+
+      dispparams.rgvarg = aVariant;
+      dispparams.rgvarg[0].vt = VT_INT;
+      dispparams.rgvarg[0].intVal = 1;
+      dispparams.cArgs = 1;
+      dispparams.cNamedArgs = 0;
+
+      hr = inspector->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                              DISPATCH_METHOD, &dispparams,
+                              NULL, NULL, NULL);
+      if (hr != S_OK)
+        {
+          log_debug ("%s:%s: Failed to close inspector: %#lx",
+                     SRCNAME, __func__, hr);
+          return -1;
+        }
+    }
+  return 0;
+}
diff --git a/src/mail.h b/src/mail.h
index 1bbc789..0dc96d4 100644
--- a/src/mail.h
+++ b/src/mail.h
@@ -25,6 +25,9 @@
 #include "mapihelp.h"
 
 #include <string>
+#include <future>
+
+class MailParser;
 
 /** @brief Data wrapper around a mailitem.
  *
@@ -57,6 +60,13 @@ public:
   */
   static Mail* get_mail_for_item (LPDISPATCH mailitem);
 
+  /** @brief looks for existing Mail objects.
+
+    @returns A reference to an existing mailitem or NULL in case none
+    could be found. Can be used to check if a mail object was destroyed.
+  */
+  static bool is_mail_valid (const Mail *mail);
+
   /** @brief wipe the plaintext from all known Mail objects.
     *
     * This is intended as a "cleanup" call to be done on unload
@@ -168,6 +178,22 @@ public:
     */
   bool is_smime ();
 
+  /** @brief closes the inspector for this mail
+    *
+    * @returns true on success.
+  */
+  int close_inspector ();
+
+  /** @brief get the associated parser.
+    only valid while the actual parsing happens. */
+  MailParser *parser () { return m_parser; }
+
+  /** To be called from outside once the paser was done.
+   In Qt this would be a slot that is called once it is finished
+   we hack around that a bit by calling it from our windowmessages
+   handler.
+  */
+  void parsing_done ();
 private:
   LPDISPATCH m_mailitem;
   LPDISPATCH m_event_sink;
@@ -177,7 +203,9 @@ private:
        m_crypt_successful, /* We successfuly performed crypto on the item. */
        m_is_smime, /* This is an smime mail. */
        m_is_smime_checked; /* it was checked if this is an smime mail */
+  int m_moss_position; /* The number of the original message attachment. */
   char *m_sender;
   msgtype_t m_type; /* Our messagetype as set in mapi */
+  MailParser *m_parser;
 };
 #endif // MAIL_H
diff --git a/src/mailparser.cpp b/src/mailparser.cpp
index 500a383..c73de1f 100644
--- a/src/mailparser.cpp
+++ b/src/mailparser.cpp
@@ -23,31 +23,104 @@
 
 #include "mailparser.h"
 #include "attachment.h"
+#include "mimedataprovider.h"
+
+#include <gpgme++/context.h>
+#include <gpgme++/decryptionresult.h>
+
+#include <sstream>
+
+using namespace GpgME;
 
 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_input (Data(new MimeDataProvider(instream))),
     m_type (type),
-    m_error (false),
-    m_in_data (false),
-    signed_data (nullptr),
-    sig_data (nullptr)
+    m_error (false)
 {
-  log_debug ("%s:%s: Creating parser for stream: %p",
-             SRCNAME, __func__, instream);
-  instream->AddRef();
+  log_mime_parser ("%s:%s: Creating parser for stream: %p",
+                   SRCNAME, __func__, instream);
 }
 
 MailParser::~MailParser()
 {
-  gpgol_release(m_stream);
+  log_debug ("%s:%s", SRCNAME, __func__);
+}
+
+static void
+operation_for_type(msgtype_t type, bool *decrypt,
+                   bool *verify, Protocol *protocol)
+{
+  *decrypt = false;
+  *verify = false;
+  *protocol = Protocol::UnknownProtocol;
+  switch (type)
+    {
+      case MSGTYPE_GPGOL_MULTIPART_ENCRYPTED:
+      case MSGTYPE_GPGOL_PGP_MESSAGE:
+        *decrypt = true;
+        *protocol = Protocol::OpenPGP;
+        break;
+      case MSGTYPE_GPGOL_MULTIPART_SIGNED:
+      case MSGTYPE_GPGOL_CLEAR_SIGNED:
+        *verify = true;
+        *protocol = Protocol::OpenPGP;
+        break;
+      case MSGTYPE_GPGOL_OPAQUE_SIGNED:
+        *protocol = Protocol::CMS;
+        *verify = true;
+        break;
+      case MSGTYPE_GPGOL_OPAQUE_ENCRYPTED:
+        *protocol = Protocol::CMS;
+        *decrypt = true;
+        break;
+      default:
+        log_error ("%s:%s: Unknown data type: %i",
+                   SRCNAME, __func__, type);
+    }
 }
 
 std::string
 MailParser::parse()
 {
-  m_body = std::shared_ptr<std::string>(new std::string("Hello world"));
+  // Wrap the input stream in an attachment / GpgME Data
+  Protocol protocol;
+  bool decrypt, verify;
+  operation_for_type (m_type, &decrypt, &verify, &protocol);
+  auto ctx = Context::createForProtocol (protocol);
+  ctx->setArmor(true);
+
+  if (decrypt)
+    {
+      Data output;
+      log_debug ("%s:%s: Decrypting with protocol: %s",
+                 SRCNAME, __func__,
+                 protocol == OpenPGP ? "OpenPGP" :
+                 protocol == CMS ? "CMS" : "Unknown");
+      auto combined_result = ctx->decryptAndVerify(m_input, output);
+      m_decrypt_result = combined_result.first;
+      m_verify_result = combined_result.second;
+      if (m_decrypt_result.error())
+        {
+          MessageBox (NULL, "Decryption failed.", "Failed", MB_OK);
+        }
+      char buf[2048];
+      size_t bRead;
+      output.seek (0, SEEK_SET);
+      while ((bRead = output.read (buf, 2048)) > 0)
+        {
+          (*m_body).append(buf, bRead);
+        }
+      log_debug ("Body is: %s", m_body->c_str());
+    }
+
+  if (opt.enable_debug)
+    {
+       std::stringstream ss;
+       ss << m_decrypt_result << '\n' << m_verify_result;
+       log_debug ("Decrypt / Verify result: %s", ss.str().c_str());
+    }
   Attachment *att = new Attachment ();
   att->write ("Hello attachment", strlen ("Hello attachment"));
   att->set_display_name ("The Attachment.txt");
@@ -55,17 +128,20 @@ MailParser::parse()
   return std::string();
 }
 
-std::shared_ptr<std::string> MailParser::get_utf8_html_body()
+std::shared_ptr<std::string>
+MailParser::get_utf8_html_body()
 {
   return m_htmlbody;
 }
 
-std::shared_ptr<std::string> MailParser::get_utf8_text_body()
+std::shared_ptr<std::string>
+MailParser::get_utf8_text_body()
 {
   return m_body;
 }
 
-std::vector<std::shared_ptr<Attachment> > MailParser::get_attachments()
+std::vector<std::shared_ptr<Attachment> >
+MailParser::get_attachments()
 {
   return m_attachments;
 }
diff --git a/src/mailparser.h b/src/mailparser.h
index 1e03139..f92c313 100644
--- a/src/mailparser.h
+++ b/src/mailparser.h
@@ -24,12 +24,15 @@
 
 #include "oomhelp.h"
 #include "mapihelp.h"
-#include "gpgme.h"
 
 #include <string>
 #include <vector>
 #include <memory>
 
+#include <gpgme++/decryptionresult.h>
+#include <gpgme++/verificationresult.h>
+#include <gpgme++/data.h>
+
 class Attachment;
 
 class MailParser
@@ -65,17 +68,11 @@ private:
   std::shared_ptr<std::string> m_htmlbody;
 
   /* State variables */
-  LPSTREAM m_stream;
+  GpgME::Data m_input;
   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.  */
+  GpgME::DecryptionResult m_decrypt_result;
+  GpgME::VerificationResult m_verify_result;
 };
 
 #endif /* MAILPARSER_H */
diff --git a/src/main.c b/src/main.c
index 12321f3..fdff49c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -162,6 +162,13 @@ DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
 
       gpg_err_init ();
 
+      /* Set the installation directory for GpgME so that
+         it can find tools like gpgme-w32-spawn correctly. */
+      char *instdir;
+      gpgrt_asprintf (&instdir, "%s\\bin", get_gpg4win_dir ());
+      gpgme_set_global_flag ("w32-inst-dir", instdir);
+      xfree (instdir);
+
       /* The next call initializes subsystems of gpgme and should be
          done as early as possible.  The actual return value (the
          version string) is not used here.  It may be called at any
diff --git a/src/mimedataprovider.cpp b/src/mimedataprovider.cpp
new file mode 100644
index 0000000..d6628f3
--- /dev/null
+++ b/src/mimedataprovider.cpp
@@ -0,0 +1,213 @@
+/* mimedataprover.cpp - GpgME dataprovider for mime data
+ *    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 "mimedataprovider.h"
+
+/* The maximum length of a line we are able to process.  RFC822 allows
+   only for 1000 bytes; thus 2000 seems to be a reasonable value. */
+#define LINEBUFSIZE 2000
+
+/* How much data is read from the underlying stream in a collect
+   call. */
+#define BUFSIZE 8192
+
+#include <gpgme++/error.h>
+
+static int
+message_cb (void *opaque, rfc822parse_event_t event,
+            rfc822parse_t msg)
+{
+  (void) opaque;
+  (void) event;
+  (void) msg;
+  return 0;
+}
+
+MimeDataProvider::MimeDataProvider(LPSTREAM stream):
+  m_collect(true),
+  m_parser(rfc822parse_open (message_cb, this)),
+  m_current_encoding(None)
+{
+  if (stream)
+    {
+      stream->AddRef ();
+    }
+  else
+    {
+      log_error ("%s:%s called without stream ", SRCNAME, __func__);
+      return;
+    }
+  b64_init (&m_base64_context);
+  log_mime_parser ("%s:%s Collecting data.", SRCNAME, __func__);
+  collect_data (stream);
+  log_mime_parser ("%s:%s Data collected.", SRCNAME, __func__);
+  gpgol_release (stream);
+}
+
+MimeDataProvider::~MimeDataProvider()
+{
+  log_debug ("%s:%s", SRCNAME, __func__);
+}
+
+bool
+MimeDataProvider::isSupported(GpgME::DataProvider::Operation op) const
+{
+  return op == GpgME::DataProvider::Read ||
+         op == GpgME::DataProvider::Seek ||
+         op == GpgME::DataProvider::Release;
+}
+
+ssize_t
+MimeDataProvider::read(void *buffer, size_t size)
+{
+  log_mime_parser ("%s:%s: Reading: " SIZE_T_FORMAT "Bytes",
+                 SRCNAME, __func__, size);
+  ssize_t bRead = m_data.read (buffer, size);
+  if (opt.enable_debug & DBG_MIME_PARSER)
+    {
+      std::string buf ((char *)buffer, bRead);
+      log_mime_parser ("%s:%s: Data: \"%s\"",
+                     SRCNAME, __func__, buf.c_str());
+    }
+  return bRead;
+}
+
+void
+MimeDataProvider::decode_and_collect(char *line, size_t pos)
+{
+  /* We are inside the data.  That should be the actual
+     ciphertext in the given encoding. Add it to our internal
+     cache. */
+  int slbrk = 0;
+  size_t len;
+
+  if (m_current_encoding == Quoted)
+    len = qp_decode (line, pos, &slbrk);
+  else if (m_current_encoding == Base64)
+    len = b64_decode (&m_base64_context, line, pos);
+  else
+    len = pos;
+  m_data.write (line, len);
+  if (m_current_encoding != Encoding::Base64 && !slbrk)
+    {
+      m_data.write ("\r\n", 2);
+    }
+  return;
+}
+
+/* Split some raw data into lines and handle them accordingly.
+   returns the amount of bytes not taken from the input buffer.
+*/
+size_t
+MimeDataProvider::collect_input_lines(const char *input, size_t insize)
+{
+  char linebuf[LINEBUFSIZE];
+  const char *s = input;
+  size_t pos = 0;
+  size_t nleft = insize;
+  size_t not_taken = nleft;
+
+  /* Split the raw data into lines */
+  for (; nleft; nleft--, s++)
+    {
+      if (pos >= LINEBUFSIZE)
+        {
+          log_error ("%s:%s: rfc822 parser failed: line too long\n",
+                     SRCNAME, __func__);
+          GpgME::Error::setSystemError (GPG_ERR_EIO);
+          return not_taken;
+        }
+      if (*s != '\n')
+        linebuf[pos++] = *s;
+      else
+        {
+          /* Got a complete line.  Remove the last CR.  */
+          not_taken -= pos + 1; /* Pos starts at 0 so + 1 for it */
+          if (pos && linebuf[pos-1] == '\r')
+            {
+              pos--;
+            }
+
+          if (rfc822parse_insert (m_parser,
+                                  (unsigned char*) linebuf,
+                                  pos))
+            {
+              log_error ("%s:%s: rfc822 parser failed: %s\n",
+                         SRCNAME, __func__, strerror (errno));
+              return not_taken;
+            }
+          /* If we are currently in a collecting state actually
+             collect that line */
+          if (m_collect)
+            {
+              decode_and_collect (linebuf, pos);
+            }
+          /* Continue with next line. */
+          pos = 0;
+        }
+    }
+  return not_taken;
+}
+
+void
+MimeDataProvider::collect_data(LPSTREAM stream)
+{
+  if (!stream)
+    {
+      return;
+    }
+  HRESULT hr;
+  char buf[BUFSIZE];
+  ULONG bRead;
+  while ((hr = stream->Read (buf, BUFSIZE, &bRead)) == S_OK ||
+         hr == S_FALSE)
+    {
+      if (!bRead)
+        {
+          log_mime_parser ("%s:%s: Input stream at EOF.",
+                           SRCNAME, __func__);
+          return;
+        }
+      log_mime_parser ("%s:%s: Read %lu bytes.",
+                       SRCNAME, __func__, bRead);
+
+      m_rawbuf += std::string (buf, bRead);
+      size_t not_taken = collect_input_lines (m_rawbuf.c_str(),
+                                              m_rawbuf.size());
+
+      if (not_taken == m_rawbuf.size())
+        {
+          log_error ("%s:%s: Collect failed to consume anything.\n"
+                     "Buffer too small?",
+                     SRCNAME, __func__);
+          return;
+        }
+      log_mime_parser ("%s:%s: Consumed: " SIZE_T_FORMAT " bytes",
+                       SRCNAME, __func__, m_rawbuf.size() - not_taken);
+      m_rawbuf.erase (0, m_rawbuf.size() - not_taken);
+    }
+}
+
+off_t
+MimeDataProvider::seek(off_t offset, int whence)
+{
+  return m_data.seek (offset, whence);
+}
diff --git a/src/mimedataprovider.h b/src/mimedataprovider.h
new file mode 100644
index 0000000..8b9d8ee
--- /dev/null
+++ b/src/mimedataprovider.h
@@ -0,0 +1,83 @@
+/* mimedataprover.h - GpgME dataprovider for mime data
+ *    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 MIMEDATAPROVIDER_H
+#define MIMEDATAPROVIDER_H
+
+#include <gpgme++/interfaces/dataprovider.h>
+#include <gpgme++/data.h>
+#include "oomhelp.h"
+#include "mapihelp.h"
+#include "rfc822parse.h"
+
+#include <string>
+
+/** This class does simple one level mime parsing to find crypto
+  data.
+
+  Use the mimedataprovider on a body or attachment stream. It
+  will do the conversion from MIME to PGP / CMS data on the fly.
+
+  The raw mime data from the underlying stream is "collected" and
+  parsed into Crypto data which is then buffered in "databuf".
+*/
+class MimeDataProvider : public GpgME::DataProvider
+{
+public:
+  /* Read and parse the stream. Does not hold a reference
+     to the stream but releases it after read. */
+  MimeDataProvider(LPSTREAM stream);
+  ~MimeDataProvider();
+
+  /* Dataprovider interface */
+  bool isSupported(Operation) const;
+
+  /** Read some data from the stream. This triggers
+    the conversion code interanally to convert mime
+    data into PGP/CMS Data that GpgME can work with. */
+  ssize_t read(void *buffer, size_t bufSize);
+  ssize_t write(const void *buffer, size_t bufSize) {
+      (void)buffer; (void)bufSize; return -1;
+  }
+  /* Seek the underlying stream. This discards the internal
+     buffers as the offset is not mapped. Should not really
+     be used but can be used to reset the DataProvider. */
+  off_t seek(off_t offset, int whence);
+  /* Noop */
+  void release() {}
+
+  /* The the data of the signature part. */
+  const GpgME::Data &get_signature_data();
+private:
+  /* Collect the crypto data from mime. */
+  void collect_data(LPSTREAM stream);
+  /* Collect a single line. */
+  size_t collect_input_lines(const char *input, size_t size);
+  /* Move actual data into the databuffer. */
+  void decode_and_collect(char *line, size_t pos);
+  enum Encoding {None, Base64, Quoted};
+  std::string m_sig_data;
+  GpgME::Data m_data;
+  GpgME::Data m_signature;
+  std::string m_rawbuf;
+  bool m_collect;
+  rfc822parse_t m_parser;
+  Encoding m_current_encoding;
+  b64_state_t m_base64_context;
+};
+#endif // MIMEDATAPROVIDER_H
diff --git a/src/util.h b/src/util.h
index b20f0bc..0b78332 100644
--- a/src/util.h
+++ b/src/util.h
@@ -96,6 +96,8 @@ void log_window_hierarchy (HWND window, const char *fmt,
 
 #define log_oom if (opt.enable_debug & DBG_OOM) log_debug
 #define log_oom_extra if (opt.enable_debug & DBG_OOM_EXTRA) log_debug
+#define log_mime_parser if (opt.enable_debug & DBG_MIME_PARSER) log_debug
+
 #define gpgol_release(X) \
 { \
   if (X && opt.enable_debug & DBG_OOM_EXTRA) \
diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp
index e0c95cd..d850a8c 100644
--- a/src/windowmessages.cpp
+++ b/src/windowmessages.cpp
@@ -1,7 +1,28 @@
+/* @file windowmessages.h
+ * @brief Helper class to work with the windowmessage handler thread.
+ *
+ *    Copyright (C) 2015, 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 "windowmessages.h"
 
 #include "util.h"
 #include "oomhelp.h"
+#include "mail.h"
 
 #include <stdio.h>
 
@@ -39,10 +60,21 @@ gpgol_window_proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
               ctx->err = request_send_mail ((LPDISPATCH) ctx->data);
               break;
             }
+          case (PARSING_DONE):
+            {
+              auto mail = (Mail*) ctx->data;
+              if (!Mail::is_mail_valid (mail))
+                {
+                  log_debug ("%s:%s: Parsing done for mail which is gone.",
+                             SRCNAME, __func__);
+                }
+              mail->parsing_done();
+            }
+          break;
           default:
             log_debug ("Unknown msg");
         }
-        return 0;
+        return DefWindowProc(hWnd, message, wParam, lParam);
     }
 
   return DefWindowProc(hWnd, message, wParam, lParam);
diff --git a/src/windowmessages.h b/src/windowmessages.h
index c9355d5..ec66f7b 100644
--- a/src/windowmessages.h
+++ b/src/windowmessages.h
@@ -38,8 +38,10 @@
 typedef enum _gpgol_wmsg_type
 {
   UNKNOWN = 0,
-  REQUEST_SEND_MAIL = 1 /* Request to send a mail.
-                           Data should be LPMAILITEM */
+  REQUEST_SEND_MAIL = 1, /* Request to send a mail.
+                            Data should be LPMAILITEM */
+  PARSING_DONE = 2 /* A mail was parsed. Data should be a pointer
+                      to the mail object. */
 } gpgol_wmsg_type;
 
 typedef struct

commit 7f9f7bf99de356d794df06852bc12faf9c6e99ba
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Mon Aug 22 15:38:58 2016 +0200

    Return MOSS attachment positon from mapihelp
    
    * src/mapihelp.cpp (mapi_mark_or_create_moss_attach): Return
    MOSS position.
    * src/mapihelp.h (mapi_mark_or_create_moss_attach): Update doc.
    
    --
    Returning the attachment position here makes sense as we can
    then store it in the mail object and won't have search it
    again later.

diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp
index 76213cb..854e6f4 100644
--- a/src/mapihelp.cpp
+++ b/src/mapihelp.cpp
@@ -3505,30 +3505,52 @@ mapi_mark_or_create_moss_attach (LPMESSAGE message, msgtype_t msgtype)
 
   /* First check if we already have one marked. */
   mapi_attach_item_t *table = mapi_create_attach_table (message, 0);
+  int part1 = 0,
+      part2 = 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 (!part1)
+            {
+              part1 = i + 1;
+            }
+          else if (!part2)
+            {
+              /* If we have two MOSS attachments we use
+                 the second one. */
+              part2 = i + 1;
+              break;
+            }
         }
     }
+  if (part1 || part2)
+    {
+      /* Found existing moss attachment */
+      mapi_release_attach_table (table);
+      return part2;
+    }
 
   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 (mapi_body_to_attachment (message))
+        {
+          log_error ("%s:%s: Failed to create body attachment.",
+                     SRCNAME, __func__);
+          return 0;
+        }
+      return 1;
     }
   if (!table)
     {
       log_debug ("%s:%s: Neither pgp inline nor an attachment table.",
                  SRCNAME, __func__);
-      return -1;
+      return 0;
     }
 
   /* MIME Mails check for S/MIME first. */
@@ -3546,7 +3568,7 @@ mapi_mark_or_create_moss_attach (LPMESSAGE message, msgtype_t msgtype)
     {
       mapi_mark_moss_attach (message, table + i);
       mapi_release_attach_table (table);
-      return 0;
+      return i + 1;
     }
 
   /* PGP/MIME or S/MIME stuff.  */
@@ -3579,7 +3601,7 @@ mapi_mark_or_create_moss_attach (LPMESSAGE message, msgtype_t msgtype)
           mapi_mark_moss_attach (message, table+part1_idx);
           mapi_mark_moss_attach (message, table+part2_idx);
           mapi_release_attach_table (table);
-          return 0;
+          return 2;
         }
     }
 
@@ -3593,9 +3615,9 @@ mapi_mark_or_create_moss_attach (LPMESSAGE message, msgtype_t msgtype)
          we have a mean to find it again (see above).  */
       mapi_mark_moss_attach (message, table + 0);
       mapi_release_attach_table (table);
-      return 0;
+      return 1;
     }
 
    mapi_release_attach_table (table);
-   return -1; /* No original attachment - this should not happen.  */
+   return 0; /* No original attachment - this should not happen.  */
 }
diff --git a/src/mapihelp.h b/src/mapihelp.h
index 3f22538..da60531 100644
--- a/src/mapihelp.h
+++ b/src/mapihelp.h
@@ -179,7 +179,8 @@ 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. */
+ attachment for later use. Returns the attachments position
+ (1 is the first attachment) or 0 in case no attachment was found. */
 int mapi_mark_or_create_moss_attach (LPMESSAGE message, msgtype_t msgtype);
 
 /* Copy the MAPI body to a PGPBODY type attachment. */

commit 3b27162dcb06c99aa62ab12403312854871e2214
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Mon Aug 22 15:33:24 2016 +0200

    Check for and depend on GpgMEpp
    
    * configure.ac: Check for GpgMEpp.
    * m4/gpgme.m4 (AM_PATH_GPGMEPP): New.
    * src/Makefile.am: Link GpgMEpp.
    (AM_CXXFLAGS): Add GpgMEpp flags.

diff --git a/configure.ac b/configure.ac
index d6e79d9..340df73 100644
--- a/configure.ac
+++ b/configure.ac
@@ -166,6 +166,7 @@ AM_CONDITIONAL(BUILD_W64, test "$host" = "x86_64-w64-mingw32")
 
 AM_PATH_GPGME("$NEED_GPGME_API:$NEED_GPGME_VERSION",
                have_gpgme=yes,have_gpgme=no)
+AM_PATH_GPGMEPP(have_gpgmepp=yes,have_gpgmepp=no)
 AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
                   have_gpg_error=yes,have_gpg_error=no)
 AC_DEFINE(GPG_ERR_SOURCE_DEFAULT, GPG_ERR_SOURCE_USER_2,
@@ -272,6 +273,14 @@ if test "$have_gpgme" = "no"; then
 *** (at least version $NEED_GPGME_VERSION is required.)
 ***]])
 fi
+if test "$have_gpgmepp" = "no"; then
+   die=yes
+   AC_MSG_NOTICE([[
+***
+*** You need the C++ language binding for gpgme to build this program.
+** Ensure that GPGME was compiled with --enabled-languages=cpp
+***]])
+fi
 if test "$have_libassuan" = "no"; then
    die=yes
    AC_MSG_NOTICE([[
diff --git a/m4/gpgme.m4 b/m4/gpgme.m4
index 44bf43c..4bea719 100644
--- a/m4/gpgme.m4
+++ b/m4/gpgme.m4
@@ -98,6 +98,31 @@ AC_DEFUN([AM_PATH_GPGME],
   AC_SUBST(GPGME_LIBS)
 ])
 
+dnl AM_PATH_GPGMEPP([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgpgme and define GPGME_CFLAGS and GPGME_LIBS.
+dnl
+AC_DEFUN([AM_PATH_GPGMEPP],
+[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl
+  AC_MSG_CHECKING(for GPGME C++ Bindings)
+  ok=no
+  if $GPGME_CONFIG --have-lang=cpp 2>/dev/null ; then
+     ok=yes
+  fi
+  if test $ok = yes; then
+    GPGMEPP_CXXFLAGS="-I `$GPGME_CONFIG --prefix`/include/gpgme++"
+    GPGMEPP_CXXFLAGS="${GPGMEPP_CXXFLAGS} -DGPGMEPP_STATIC_DEFINE"
+    AC_MSG_RESULT(yes)
+    ifelse([$1], , :, [$1])
+  else
+    GPGMEPP_CFLAGS=""
+    GPGMEPP_LIBS=""
+    AC_MSG_RESULT(no)
+    ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(GPGMEPP_CXXFLAGS)
+  AC_SUBST(GPGMEPP_LIBS)
+])
+
 dnl AM_PATH_GPGME_PTH([MINIMUM-VERSION,
 dnl                   [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
 dnl Test for libgpgme and define GPGME_PTH_CFLAGS and GPGME_PTH_LIBS.
diff --git a/src/Makefile.am b/src/Makefile.am
index f9507f4..65e4f7b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,6 +34,7 @@ EXEEXT = .dll
 
 AM_CFLAGS = $(GPGME_CFLAGS) $(LIBASSUAN_CFLAGS) -shared
 AM_CXXFLAGS = $(GPGME_CFLAGS) $(LIBASSUAN_CFLAGS) -shared -std=c++11
+AM_CXXFLAGS += $(GPGMEPP_CXXFLAGS)
 
 gpgol_SOURCES = \
 	main.c  gpgol.def           \
@@ -98,7 +99,7 @@ gpgol_SOURCES = \
 # versions of GPGME and gpg-error, because we want to link to them
 # statically, and not dynamically (otherwise Outlook would not find
 # them).
-gpgol_DEPENDENCIES = libmapi32.a libgpg-error.a libgpgme.a libassuan.a
+gpgol_DEPENDENCIES = libmapi32.a libgpg-error.a libgpgme.a libassuan.a libgpgmepp.a
 
 if BUILD_W64
   DLLTOOLFLAGS64=--as-flags=--64 -m i386:x86-64
@@ -116,13 +117,16 @@ libgpgme.a:
 libassuan.a:
 	ln -s $$($(LIBASSUAN_CONFIG) --prefix)/lib/libassuan.a .
 
+libgpgmepp.a:
+	ln -s $$($(LIBASSUAN_CONFIG) --prefix)/lib/libgpgmepp.a .
+
 clean-local:
-	rm -f libmapi32.a libgpg-error.a libgpgme.a libassuan.a
+	rm -f libmapi32.a libgpg-error.a libgpgme.a libassuan.a libgpgmepp.a
 
 gpgol_LDFLAGS = -static-libgcc -static-libstdc++
 
 gpgol_LDADD = $(srcdir)/gpgol.def  \
-	-L . -lgpgme -lassuan -lgpg-error \
+	-L . -lgpgmepp -lgpgme -lassuan -lgpg-error \
 	-lmapi32 -lshell32 -lgdi32 -lcomdlg32 \
 	-lole32 -loleaut32 -lws2_32 -ladvapi32 \
 	-luuid -lgdiplus

commit 87d57374bbe502b121d68874e9e807e89a20f358
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Mon Aug 22 15:32:32 2016 +0200

    Bump required gpgme version to 1.7.0
    
    * configure.ac (NEED_GPGME_VERSION): 1.7.0

diff --git a/configure.ac b/configure.ac
index 709e427..d6e79d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,7 +40,7 @@ GPGOL_FORMS_REVISION=335
 
 NEED_GPG_ERROR_VERSION=1.9
 NEED_GPGME_API=1
-NEED_GPGME_VERSION=1.1.0
+NEED_GPGME_VERSION=1.7.0
 NEED_LIBASSUAN_API=2
 NEED_LIBASSUAN_VERSION=2.0.0
 

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

Summary of changes:
 configure.ac             |  11 ++-
 m4/gpgme.m4              |  25 ++++++
 src/Makefile.am          |  13 ++-
 src/attachment.cpp       | 140 +++++++++++++++++++++++++++----
 src/attachment.h         |  29 +++----
 src/mail.cpp             | 163 +++++++++++++++++++++++-------------
 src/mail.h               |  28 +++++++
 src/mailparser.cpp       | 102 ++++++++++++++++++++---
 src/mailparser.h         |  17 ++--
 src/main.c               |   7 ++
 src/mapihelp.cpp         |  40 +++++++--
 src/mapihelp.h           |   3 +-
 src/mimedataprovider.cpp | 213 +++++++++++++++++++++++++++++++++++++++++++++++
 src/mimedataprovider.h   |  83 ++++++++++++++++++
 src/util.h               |   2 +
 src/windowmessages.cpp   |  34 +++++++-
 src/windowmessages.h     |   6 +-
 17 files changed, 787 insertions(+), 129 deletions(-)
 create mode 100644 src/mimedataprovider.cpp
 create mode 100644 src/mimedataprovider.h


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




More information about the Gnupg-commits mailing list