[git] GpgOL - branch, master, updated. gpgol-2.3.0-9-g4384758

by Andre Heinecke cvs at cvs.gnupg.org
Wed Sep 5 16:33:48 CEST 2018


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, master has been updated
       via  4384758e839e816033c07e78bbec1842af076793 (commit)
       via  062279e5e69ef00d61aac6fddc9fb9ccf1201d9d (commit)
       via  7ebcc2dc0925864d352935ebe642a8b675cca018 (commit)
       via  abe308f5ce366fc0f9e2e5545676728ac7818085 (commit)
       via  3b770f928eb17fd876a00e85e7b384d566de2175 (commit)
       via  a507d8bdfb9e31814abf21ad5a9915abd66c96c1 (commit)
       via  164d89131534bf28ceb0f554bf50d1672445d33f (commit)
      from  7b5d671c020b32f3d147bcac3585448ea2e65bb0 (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 4384758e839e816033c07e78bbec1842af076793
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Wed Sep 5 16:24:54 2018 +0200

    Add Address Book integration
    
    * src/Makefile.am: Add new files.
    * src/addressbook.cpp, src/addressbook.h: New. Code for
    Address Book handling.
    * src/gpgoladdin.cpp (GpgolRibbonExtender::GetIDsOfNames),
    (GpgolRibbonExtender::Invoke),
    (GetCustomUI_MIME): Add Button to configure PGP Key.
    * src/mail.cpp (m_locate_in_progress): Make static
    locate_in_progress a proper member.
    (Mail::locateKeys_o): Trigger address book check.
    (Mail::locateAllCryptoRecipients_o): Don't abort
    if autoresolve is false.
    * src/mail.h: Update accordingly.
    * src/mailitem-events.cpp (PropertyChange): Trigger
    locate even if autoresolve is off.
    * src/ribbon-callbacks.cpp (open_contact_key): New.
    * src/ribbon-callbacks.h: Add id and protoype.
    * src/windowmessages.cpp (gpgol_window_proc): Handle
    config key done.
    * src/windowmessages.h (CONFIG_KEY_DONE): New.
    
    --
    We do the now usual dance with an external process and
    windowmessage callback to configure a PGP Key in the
    Address book.
    This key or keys override any other key and will
    be used regardless of validity or user ids.
    This should allow a power user or administrator to centrally
    manage keys in a shared address book and enable such
    use cases as delegateing one mail address to
    a different key.
    
    GnuPG-Bug-Id: T4122

diff --git a/src/Makefile.am b/src/Makefile.am
index 7906794..9abce23 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,6 +28,7 @@ AM_CXXFLAGS += $(GPGMEPP_CXXFLAGS) -D_FILE_OFFSET_BITS=64
 
 gpgol_SOURCES = \
     addin-options.cpp addin-options.h \
+    addressbook.cpp addressbook.h \
     application-events.cpp \
     attachment.h attachment.cpp \
     common.h common.cpp \
diff --git a/src/addressbook.cpp b/src/addressbook.cpp
new file mode 100644
index 0000000..a61c192
--- /dev/null
+++ b/src/addressbook.cpp
@@ -0,0 +1,300 @@
+/* addressbook.cpp - Functions for the Addressbook
+ * Copyright (C) 2018 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 "addressbook.h"
+
+#include "oomhelp.h"
+#include "keycache.h"
+#include "mail.h"
+#include "cpphelp.h"
+#include "windowmessages.h"
+
+#include <gpgme++/context.h>
+#include <gpgme++/data.h>
+
+#include <set>
+
+typedef struct
+{
+  std::string name;
+  std::string data;
+  HWND hwnd;
+  shared_disp_t contact;
+} keyadder_args_t;
+
+static DWORD WINAPI
+open_keyadder (LPVOID arg)
+{
+  auto adder_args = std::unique_ptr<keyadder_args_t> ((keyadder_args_t*) arg);
+
+  std::vector<std::string> args;
+
+  // Collect the arguments
+  char *gpg4win_dir = get_gpg4win_dir ();
+  if (!gpg4win_dir)
+    {
+      TRACEPOINT;
+      return -1;
+    }
+  const auto keyadder = std::string (gpg4win_dir) + "\\bin\\gpgolkeyadder.exe";
+  args.push_back (keyadder);
+
+  args.push_back (std::string ("--hwnd"));
+  args.push_back (std::to_string ((int) (intptr_t) adder_args->hwnd));
+
+  args.push_back (std::string ("--username"));
+  args.push_back (adder_args->name);
+
+  auto ctx = GpgME::Context::createForEngine (GpgME::SpawnEngine);
+  if (!ctx)
+    {
+      // can't happen
+      TRACEPOINT;
+      return -1;
+    }
+
+  GpgME::Data mystdin (adder_args->data.c_str(), adder_args->data.size(),
+                       false);
+  GpgME::Data mystdout, mystderr;
+
+  char **cargs = vector_to_cArray (args);
+  log_debug ("%s:%s: launching keyadder args:", SRCNAME, __func__);
+  for (size_t i = 0; cargs && cargs[i]; i++)
+    {
+      log_debug (SIZE_T_FORMAT ": '%s'", i, cargs[i]);
+    }
+
+  GpgME::Error err = ctx->spawn (cargs[0], const_cast <const char**> (cargs),
+                                 mystdin, mystdout, mystderr,
+                                 (GpgME::Context::SpawnFlags) (
+                                  GpgME::Context::SpawnAllowSetFg |
+                                  GpgME::Context::SpawnShowWindow));
+  release_cArray (cargs);
+  if (err)
+    {
+      log_error ("%s:%s: Err code: %i asString: %s",
+                 SRCNAME, __func__, err.code(), err.asString());
+      return 0;
+    }
+
+  auto newKey = mystdout.toString ();
+
+  rtrim(newKey);
+
+  if (newKey.empty())
+    {
+      log_debug ("%s:%s: keyadder canceled.", SRCNAME, __func__);
+      return 0;
+    }
+  if (newKey == "empty")
+    {
+      log_debug ("%s:%s: keyadder empty.", SRCNAME, __func__);
+      newKey = "";
+    }
+
+  Addressbook::callback_args_t cb_args;
+
+  /* cb args are valid in the same scope as newKey */
+  cb_args.data = newKey.c_str();
+  cb_args.contact = adder_args->contact;
+
+  do_in_ui_thread (CONFIG_KEY_DONE, (void*) &cb_args);
+  return 0;
+}
+
+void
+Addressbook::update_key_o (void *callback_args)
+{
+  if (!callback_args)
+    {
+      TRACEPOINT;
+      return;
+    }
+  callback_args_t *cb_args = static_cast<callback_args_t *> (callback_args);
+  LPDISPATCH contact = cb_args->contact.get();
+
+  LPDISPATCH user_props = get_oom_object (contact, "UserProperties");
+  if (!user_props)
+    {
+      TRACEPOINT;
+      return;
+    }
+
+  LPDISPATCH pgp_key = find_or_add_text_prop (user_props, "OpenPGP Key");
+  if (!pgp_key)
+    {
+      TRACEPOINT;
+      return;
+    }
+  put_oom_string (pgp_key, "Value", cb_args->data);
+
+  log_debug ("%s:%s: PGP key data updated",
+             SRCNAME, __func__);
+
+  gpgol_release (pgp_key);
+  return;
+}
+
+void
+Addressbook::edit_key_o (LPDISPATCH contact)
+{
+  if (!contact)
+    {
+      TRACEPOINT;
+      return;
+    }
+
+  LPDISPATCH user_props = get_oom_object (contact, "UserProperties");
+  if (!user_props)
+    {
+      TRACEPOINT;
+      return;
+    }
+
+  auto pgp_key = MAKE_SHARED (
+                      find_or_add_text_prop (user_props, "OpenPGP Key"));
+  gpgol_release (user_props);
+
+  if (!pgp_key)
+    {
+      TRACEPOINT;
+      return;
+    }
+
+  char *key_data = get_oom_string (pgp_key.get(), "Value");
+  if (!key_data)
+    {
+      TRACEPOINT;
+      return;
+    }
+
+  char *name = get_oom_string (contact, "Subject");
+  if (!name)
+    {
+      TRACEPOINT;
+      name = get_oom_string (contact, "Email1Address");
+      if (!name)
+        {
+          name = xstrdup (/* TRANSLATORS: Placeholder for a contact without
+                             a configured name */ _("Unknown contact"));
+        }
+    }
+
+  keyadder_args_t *args = new keyadder_args_t;
+  args->name = name;
+  args->data = key_data;
+  args->hwnd = get_active_hwnd ();
+  contact->AddRef ();
+  memdbg_addRef (contact);
+  args->contact = MAKE_SHARED (contact);
+
+  CloseHandle (CreateThread (NULL, 0, open_keyadder, (LPVOID) args, 0,
+                             NULL));
+  xfree (name);
+  xfree (key_data);
+
+  return;
+}
+
+static std::set <std::string> s_checked_entries;
+/* For each new recipient check the address book to look for a potentially
+   configured key for this recipient and import / register
+   it into the keycache.
+*/
+void
+Addressbook::check_o (Mail *mail)
+{
+  if (!mail)
+    {
+      TRACEPOINT;
+      return;
+    }
+  LPDISPATCH mailitem = mail->item ();
+  if (!mailitem)
+    {
+      TRACEPOINT;
+      return;
+    }
+  auto recipients_obj = MAKE_SHARED (get_oom_object (mailitem, "Recipients"));
+
+  if (!recipients_obj)
+    {
+      TRACEPOINT;
+      return;
+    }
+
+  bool err = false;
+  const auto recipient_entries = get_oom_recipients_with_addrEntry (recipients_obj.get(),
+                                                                    &err);
+  for (const auto pair: recipient_entries)
+    {
+      if (s_checked_entries.find (pair.first) != s_checked_entries.end ())
+        {
+          continue;
+        }
+      s_checked_entries.insert (pair.first);
+
+      if (!pair.second)
+        {
+          TRACEPOINT;
+          continue;
+        }
+
+      auto contact = MAKE_SHARED (get_oom_object (pair.second.get (), "GetContact"));
+      if (!contact)
+        {
+          log_debug ("%s:%s: failed to resolve contact for %s",
+                     SRCNAME, __func__,
+                     (opt.enable_debug & DBG_MIME_PARSER) ?
+                     pair.first.c_str() : "omitted");
+          continue;
+        }
+
+      LPDISPATCH user_props = get_oom_object (contact.get (), "UserProperties");
+      if (!user_props)
+        {
+          TRACEPOINT;
+          continue;
+        }
+
+      LPDISPATCH pgp_key = find_or_add_text_prop (user_props, "OpenPGP Key");
+      gpgol_release (user_props);
+
+      if (!pgp_key)
+        {
+          continue;
+        }
+
+      log_debug ("%s:%s: found configured pgp key for %s",
+                 SRCNAME, __func__,
+                 (opt.enable_debug & DBG_MIME_PARSER) ?
+                 pair.first.c_str() : "omitted");
+
+      char *key_data = get_oom_string (pgp_key, "Value");
+      if (!key_data || !strlen (key_data))
+        {
+          log_debug ("%s:%s: No key data",
+                     SRCNAME, __func__);
+        }
+      KeyCache::instance ()->importFromAddrBook (pair.first, key_data,
+                                                 mail);
+      xfree (key_data);
+      gpgol_release (pgp_key);
+    }
+}
diff --git a/src/addressbook.h b/src/addressbook.h
new file mode 100644
index 0000000..c175bb8
--- /dev/null
+++ b/src/addressbook.h
@@ -0,0 +1,48 @@
+#ifndef SRC_ADDRESSBOOK_H
+#define SRC_ADDRESSBOOK_H
+/* addressbook.h - Functions for the Addressbook
+ * Copyright (C) 2018 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 "common.h"
+#include <map>
+#include <string>
+#include <vector>
+#include "oomhelp.h"
+
+class Mail;
+
+namespace Addressbook
+{
+typedef struct
+{
+  shared_disp_t contact;
+  const char *data;
+} callback_args_t;
+
+/* Configure the OpenPGP Key for this contact. */
+void edit_key_o (LPDISPATCH contact);
+
+/* Check the address book for keys to import. */
+void check_o (Mail *mail);
+
+/* Update the key information for a contact. */
+void update_key_o (void *callback_args);
+} // namespace Addressbook
+
+#endif // SRC_ADDRESSBOOK_H
diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp
index e331b86..6ab5919 100644
--- a/src/gpgoladdin.cpp
+++ b/src/gpgoladdin.cpp
@@ -714,6 +714,7 @@ GpgolRibbonExtender::GetIDsOfNames (REFIID riid, LPOLESTR *rgszNames,
       ID_MAPPER (L"getIsDetailsEnabled", ID_GET_IS_DETAILS_ENABLED)
       ID_MAPPER (L"getIsCrypto", ID_GET_IS_CRYPTO_MAIL)
       ID_MAPPER (L"printDecrypted", ID_CMD_PRINT_DECRYPTED)
+      ID_MAPPER (L"openContactKey", ID_CMD_OPEN_CONTACT_KEY)
     }
 
   if (cNames > 1)
@@ -803,6 +804,8 @@ GpgolRibbonExtender::Invoke (DISPID dispid, REFIID riid, LCID lcid,
         return print_decrypted (parms->rgvarg[0].pdispVal);
       case ID_GET_IS_CRYPTO_MAIL:
         return get_is_crypto_mail (parms->rgvarg[0].pdispVal, result);
+      case ID_CMD_OPEN_CONTACT_KEY:
+        return open_contact_key (parms->rgvarg[0].pdispVal);
       case ID_BTN_ENCRYPT:
       case ID_BTN_DECRYPT:
       case ID_BTN_DECRYPT_LARGE:
@@ -1069,6 +1072,43 @@ GetCustomUI_MIME (BSTR RibbonID, BSTR * RibbonXml)
         optsSTip
         );
     }
+  else if (!wcscmp (RibbonID, L"Microsoft.Outlook.Contact"))
+    {
+      gpgrt_asprintf (&buffer,
+        "<customUI xmlns=\"http://schemas.microsoft.com/office/2009/07/customui\""
+        " onLoad=\"ribbonLoaded\">"
+        " <ribbon>"
+        "   <tabs>"
+        "    <tab idMso=\"TabContact\">"
+        "     <group id=\"gpgol_contact\""
+        "            label=\"%s\">"
+        "       <button id=\"idContactAddkey\""
+        "               getImage=\"btnSignEncryptLarge\""
+        "               size=\"large\""
+        "               label=\"%s\""
+        "               screentip=\"%s\""
+        "               supertip=\"%s\""
+        "               onAction=\"openContactKey\"/>"
+        "       <dialogBoxLauncher>"
+        "         <button id=\"optsBtn_contact\""
+        "                 onAction=\"openOptions\""
+        "                 screentip=\"%s\"/>"
+        "       </dialogBoxLauncher>"
+        "     </group>"
+        "    </tab>"
+        "   </tabs>"
+        " </ribbon>"
+        "</customUI>",
+        _("GpgOL"),
+        _("OpenPGP Key"),
+        _(/* TRANSLATORS: Tooltip caption */
+          "Configure the OpenPGP key for this contact."),
+        _(/* TRANSLATORS: Tooltip content */
+          "The configured key or keys will be used for this contact even "
+          "if they are not certified."),
+        optsSTip
+        );
+    }
 
   if (buffer)
     {
diff --git a/src/mail.cpp b/src/mail.cpp
index 06f58cd..7cd887a 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -38,6 +38,7 @@
 #include "wks-helper.h"
 #include "keycache.h"
 #include "cpphelp.h"
+#include "addressbook.h"
 
 #include <gpgme++/configuration.h>
 #include <gpgme++/tofuinfo.h>
@@ -102,7 +103,8 @@ Mail::Mail (LPDISPATCH mailitem) :
     m_manual_crypto_opts(false),
     m_first_autosecure_check(true),
     m_locate_count(0),
-    m_is_about_to_be_moved(false)
+    m_is_about_to_be_moved(false),
+    m_locate_in_progress(false)
 {
   if (getMailForItem (mailitem))
     {
@@ -2772,9 +2774,7 @@ Mail::getSigFpr () const
 void
 Mail::locateKeys_o ()
 {
-  static bool locate_in_progress;
-
-  if (locate_in_progress)
+  if (m_locate_in_progress)
     {
       /** XXX
         The strangest thing seems to happen here:
@@ -2800,16 +2800,22 @@ Mail::locateKeys_o ()
                  SRCNAME, __func__, this);
       return;
     }
-  locate_in_progress = true;
+  m_locate_in_progress = true;
+
+  Addressbook::check_o (this);
+
+  if (opt.autoresolve)
+    {
+      // First update oom data to have recipients and sender updated.
+      updateOOMData_o ();
+      KeyCache::instance()->startLocateSecret (getSender_o ().c_str (), this);
+      KeyCache::instance()->startLocate (getSender_o ().c_str (), this);
+      KeyCache::instance()->startLocate (getCachedRecipients (), this);
+    }
 
-  // First update oom data to have recipients and sender updated.
-  updateOOMData_o ();
-  KeyCache::instance()->startLocateSecret (getSender_o ().c_str (), this);
-  KeyCache::instance()->startLocate (getSender_o ().c_str (), this);
-  KeyCache::instance()->startLocate (getCachedRecipients (), this);
   autosecureCheck ();
 
-  locate_in_progress = false;
+  m_locate_in_progress = false;
 }
 
 bool
@@ -3137,11 +3143,6 @@ Mail::clearLastMail ()
 void
 Mail::locateAllCryptoRecipients_o ()
 {
-  if (!opt.autoresolve)
-    {
-      return;
-    }
-
   gpgrt_lock_lock (&mail_map_lock);
   std::map<LPDISPATCH, Mail *>::iterator it;
   for (it = s_mail_map.begin(); it != s_mail_map.end(); ++it)
diff --git a/src/mail.h b/src/mail.h
index 44c15da..c4f2369 100644
--- a/src/mail.h
+++ b/src/mail.h
@@ -394,7 +394,9 @@ public:
   /** Get the recipients. */
   std::vector<std::string> getRecipients_o () const;
 
-  /** Try to locate the keys for all recipients */
+  /** Try to locate the keys for all recipients.
+      This also triggers the Addressbook integration, which we
+      treat as locate jobs. */
   void locateKeys_o ();
 
   /** State variable to check if a close was triggerd by us. */
@@ -646,5 +648,6 @@ private:
   bool m_first_autosecure_check; /* This is the first autoresolve check */
   int m_locate_count; /* The number of key locates pending for this mail. */
   bool m_is_about_to_be_moved;
+  bool m_locate_in_progress; /* Simplified state variable for locate */
 };
 #endif // MAIL_H
diff --git a/src/mailitem-events.cpp b/src/mailitem-events.cpp
index 26cbbdd..2d91cc8 100644
--- a/src/mailitem-events.cpp
+++ b/src/mailitem-events.cpp
@@ -228,10 +228,6 @@ EVENT_SINK_INVOKE(MailItemEvents)
           const wchar_t *prop_name = parms->rgvarg[0].bstrVal;
           if (!m_mail->isCryptoMail ())
             {
-              if (!opt.autoresolve)
-                {
-                  break;
-                }
               if (m_mail->hasOverrideMimeData())
                 {
                   /* This is a mail created by us. Ignore propchanges. */
diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp
index e9f8a5e..dac67b5 100644
--- a/src/ribbon-callbacks.cpp
+++ b/src/ribbon-callbacks.cpp
@@ -43,6 +43,7 @@
 #include "filetype.h"
 #include "mail.h"
 #include "dispcache.h"
+#include "addressbook.h"
 
 #include <gpgme++/context.h>
 #include <gpgme++/data.h>
@@ -795,3 +796,36 @@ HRESULT print_decrypted (LPDISPATCH ctrl)
   invoke_oom_method (mail->item(), "PrintOut", NULL);
   return S_OK;
 }
+
+HRESULT open_contact_key (LPDISPATCH ctrl)
+{
+  if (!ctrl)
+    {
+      log_error ("%s:%s:%i", SRCNAME, __func__, __LINE__);
+      return E_FAIL;
+    }
+  LPDISPATCH inspector = NULL;
+  HRESULT hr = getContext (ctrl, &inspector);
+
+  if (hr)
+    {
+      log_error ("%s:%s:%i : hresult %lx", SRCNAME, __func__, __LINE__,
+                 hr);
+      return S_OK;
+    }
+
+  /* Context is assumed to be the Insepector */
+  LPDISPATCH contact = get_oom_object (inspector, "CurrentItem");
+  gpgol_release (inspector);
+
+  if (!contact)
+    {
+      TRACEPOINT;
+      return S_OK;
+    }
+
+  Addressbook::edit_key_o (contact);
+
+  gpgol_release (contact);
+  return S_OK;
+}
diff --git a/src/ribbon-callbacks.h b/src/ribbon-callbacks.h
index e4658a1..ce71c1a 100644
--- a/src/ribbon-callbacks.h
+++ b/src/ribbon-callbacks.h
@@ -49,6 +49,7 @@
 #define ID_CMD_SIGN_ENCRYPT_MIME_EX 33
 #define ID_CMD_PRINT_DECRYPTED 34
 #define ID_GET_IS_CRYPTO_MAIL 35
+#define ID_CMD_OPEN_CONTACT_KEY 36
 
 #define ID_BTN_DECRYPT           IDI_DECRYPT_16_PNG
 #define ID_BTN_DECRYPT_LARGE     IDI_DECRYPT_48_PNG
@@ -85,4 +86,6 @@ HRESULT ribbon_loaded (LPDISPATCH ctrl);
 HRESULT get_is_crypto_mail (LPDISPATCH ctrl, VARIANT *result);
 /* Print out the decrypted mail */
 HRESULT print_decrypted (LPDISPATCH ctrl);
+/* Open key configuration for a contact */
+HRESULT open_contact_key (LPDISPATCH ctrl);
 #endif
diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp
index e9ec1e5..c99806a 100644
--- a/src/windowmessages.cpp
+++ b/src/windowmessages.cpp
@@ -26,6 +26,7 @@
 #include "mail.h"
 #include "gpgoladdin.h"
 #include "wks-helper.h"
+#include "addressbook.h"
 
 #include <stdio.h>
 
@@ -228,6 +229,14 @@ gpgol_window_proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
               mail->setDoAutosecure_m (false);
               break;
             }
+          case (CONFIG_KEY_DONE):
+            {
+              log_debug ("%s:%s: Key configuration done.",
+                         SRCNAME, __func__);
+
+              Addressbook::update_key_o (ctx->data);
+              break;
+            }
           default:
             log_debug ("%s:%s: Unknown msg %x",
                        SRCNAME, __func__, ctx->wmsg_type);
diff --git a/src/windowmessages.h b/src/windowmessages.h
index 1730a25..599a90c 100644
--- a/src/windowmessages.h
+++ b/src/windowmessages.h
@@ -55,6 +55,7 @@ typedef enum _gpgol_wmsg_type
   CLEAR_REPLY_FORWARD,
   DO_AUTO_SECURE,
   DONT_AUTO_SECURE,
+  CONFIG_KEY_DONE,
 } gpgol_wmsg_type;
 
 typedef struct

commit 062279e5e69ef00d61aac6fddc9fb9ccf1201d9d
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Wed Sep 5 16:23:35 2018 +0200

    Fix find user prop
    
    * src/oomhelp.cpp (find_user_prop): Set cNamedArgs so it
    is not unitialized.

diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp
index 680ecc3..0f832d8 100644
--- a/src/oomhelp.cpp
+++ b/src/oomhelp.cpp
@@ -2536,6 +2536,7 @@ find_user_prop (LPDISPATCH user_props, const char *name)
   argvars[0].vt = VT_BOOL;
   argvars[0].boolVal = VARIANT_TRUE;
   args.cArgs = 2;
+  args.cNamedArgs = 0;
   args.rgvarg = argvars;
 
   int res = invoke_oom_method_with_parms (user_props, "Find", &var, &args);

commit 7ebcc2dc0925864d352935ebe642a8b675cca018
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Wed Sep 5 14:17:24 2018 +0200

    Add l10n strings for the keyadder
    
    * src/addin-options.cpp (i18n_noops): Extend with strings
    for the key adder dialog.

diff --git a/src/addin-options.cpp b/src/addin-options.cpp
index 05848a6..7b56491 100644
--- a/src/addin-options.cpp
+++ b/src/addin-options.cpp
@@ -70,8 +70,48 @@ i18n_noops[] = {
        "the deprecated PGP/Inline is used.\n"
        "This can be required for compatibility but should generally not "
        "be used."),
+
+    /* Not options but strings for the key adder */
+    /* TRANSLATORS: Part of address book key configuration dialog.
+       The contacts name follows. */
+    N_("Configure key for:"),
+    /* TRANSLATORS: Part of address book key configuration dialog.
+       An example for a public key follows. */
+    N_("Paste a public key export here. It should look like:"),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("Failed to parse any public key."),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("Error"),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("Secret key detected."),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("You can only configure public keys in Outlook."
+       " Import secret keys with Kleopatra."),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("The key is unusable for Outlook."
+       " Please check Kleopatra for more information."),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("Invalid key detected."),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("Created:"),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("User Ids:"),
+    /* TRANSLATORS: Part of address book key configuration dialog. %1 is
+        a placeholder for the plual for key / keys. */
+    N_("You are about to configure the following %1 for:"),
+    /* TRANSLATORS: Part of address book key configuration dialog.
+       used in a sentence as plural form. */
+    N_("keys"),
+    /* TRANSLATORS: Part of address book key configuration dialog.
+       used in a sentence as singular form. */
+    N_("key"),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("Continue?"),
+    /* TRANSLATORS: Part of address book key configuration dialog. */
+    N_("Confirm keys"),
 };
 
+
 static bool dlg_open;
 
 static DWORD WINAPI

commit abe308f5ce366fc0f9e2e5545676728ac7818085
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Wed Sep 5 08:54:39 2018 +0200

    Add import / override functions to keycache
    
    * src/keycache.cpp (KeyCache::importFromAddrBook): New.
    (KeyCache::onAddrBookImportJobDone): New internal helper.
    (KeyCache::Private::importFromAddrBook): New.
    (KeyCache::Private::getPGPOverrides): Access imported overrides.
    (KeyCache::Private::getEncryptionKeys): Respect overrides.
    (do_import): New thread function to do the actual import.
    * src/keycache.h: Update accordingly and add comments which
    functions are async.
    
    --
    This adds support to the keycache to import keys to override
    existing keys / force their usage regardless of validity.
    
    GnuPG-Bug-Id: T4122

diff --git a/src/keycache.cpp b/src/keycache.cpp
index 2331c89..14afd01 100644
--- a/src/keycache.cpp
+++ b/src/keycache.cpp
@@ -28,6 +28,8 @@
 #include <gpg-error.h>
 #include <gpgme++/context.h>
 #include <gpgme++/key.h>
+#include <gpgme++/data.h>
+#include <gpgme++/importresult.h>
 
 #include <windows.h>
 
@@ -38,6 +40,7 @@
 GPGRT_LOCK_DEFINE (keycache_lock);
 GPGRT_LOCK_DEFINE (fpr_map_lock);
 GPGRT_LOCK_DEFINE (update_lock);
+GPGRT_LOCK_DEFINE (import_lock);
 static KeyCache* singleton = nullptr;
 
 /** At some point we need to set a limit. There
@@ -89,6 +92,8 @@ namespace
 
 typedef std::pair<std::string, GpgME::Protocol> update_arg_t;
 
+typedef std::pair<std::unique_ptr<LocateArgs>, std::string> import_arg_t;
+
 static DWORD WINAPI
 do_update (LPVOID arg)
 {
@@ -134,6 +139,76 @@ do_update (LPVOID arg)
   return 0;
 }
 
+static DWORD WINAPI
+do_import (LPVOID arg)
+{
+  auto args = std::unique_ptr<import_arg_t> ((import_arg_t*) arg);
+
+  const std::string mbox = args->first->m_mbox;
+
+  log_mime_parser ("%s:%s importing for: \"%s\" with data \n%s",
+                   SRCNAME, __func__, mbox.c_str (),
+                   args->second.c_str ());
+  auto ctx = std::unique_ptr<GpgME::Context> (GpgME::Context::createForProtocol
+                                              (GpgME::OpenPGP));
+
+  if (!ctx)
+    {
+      TRACEPOINT;
+      return 0;
+    }
+  // We want to avoid unneccessary copies. The c_str will be valid
+  // until args goes out of scope.
+  const char *keyStr = args->second.c_str ();
+  GpgME::Data data (keyStr, strlen (keyStr), /* copy */ false);
+
+  if (data.type () != GpgME::Data::PGPKey)
+    {
+      log_debug ("%s:%s Data for: %s is not a PGP Key",
+                 SRCNAME, __func__, mbox.c_str ());
+      return 0;
+    }
+  data.rewind ();
+
+  const auto result = ctx->importKeys (data);
+
+  std::vector<std::string> fingerprints;
+  for (const auto import: result.imports())
+    {
+      if (import.error())
+        {
+          log_debug ("%s:%s Error importing: %s",
+                     SRCNAME, __func__, import.error().asString());
+          continue;
+        }
+      const char *fpr = import.fingerprint ();
+      if (!fpr)
+        {
+          TRACEPOINT;
+          continue;
+        }
+
+      update_arg_t * update_args = new update_arg_t;
+      update_args->first = std::string (fpr);
+      update_args->second = GpgME::OpenPGP;
+
+      // We do it blocking to be sure that when all imports
+      // are done they are also part of the keycache.
+      do_update ((LPVOID) update_args);
+
+      fingerprints.push_back (fpr);
+      log_debug ("%s:%s Imported: %s from addressbook.",
+                 SRCNAME, __func__, fpr);
+    }
+
+  KeyCache::instance ()->onAddrBookImportJobDone (mbox, fingerprints);
+
+  log_debug ("%s:%s Import job done for: %s",
+             SRCNAME, __func__, mbox.c_str ());
+  return 0;
+}
+
+
 class KeyCache::Private
 {
 public:
@@ -210,6 +285,39 @@ public:
     gpgrt_lock_unlock (&keycache_lock);
   }
 
+  std::vector<GpgME::Key> getPGPOverrides (const char *addr)
+  {
+    std::vector<GpgME::Key> ret;
+
+    if (!addr)
+      {
+        return ret;
+      }
+    auto mbox = GpgME::UserID::addrSpecFromString (addr);
+
+    gpgrt_lock_lock (&keycache_lock);
+    const auto it = m_addr_book_overrides.find (mbox);
+    if (it == m_addr_book_overrides.end ())
+      {
+        gpgrt_lock_unlock (&keycache_lock);
+        return ret;
+      }
+    for (const auto fpr: it->second)
+      {
+        const auto key = getByFpr (fpr.c_str (), false);
+        if (key.isNull())
+          {
+            log_debug ("%s:%s: No key for %s in the cache?!",
+                       SRCNAME, __func__, fpr.c_str());
+            continue;
+          }
+        ret.push_back (key);
+      }
+
+    gpgrt_lock_unlock (&keycache_lock);
+    return ret;
+  }
+
   GpgME::Key getKey (const char *addr, GpgME::Protocol proto)
   {
     if (!addr)
@@ -326,6 +434,18 @@ public:
       }
     for (const auto &recip: recipients)
       {
+        if (proto == GpgME::OpenPGP)
+          {
+            const auto overrides = getPGPOverrides (recip.c_str ());
+
+            if (!overrides.empty())
+              {
+                ret.insert (ret.end (), overrides.begin (), overrides.end ());
+                log_mime_parser ("%s:%s: Using overides for %s",
+                                 SRCNAME, __func__, recip.c_str ());
+                continue;
+              }
+          }
         const auto key = getKey (recip.c_str (), proto);
         if (key.isNull())
           {
@@ -579,13 +699,73 @@ public:
       return;
     }
 
+  void importFromAddrBook (const std::string &mbox, const char *data,
+                           Mail *mail)
+    {
+      if (!data || mbox.empty() || !mail)
+        {
+          TRACEPOINT;
+          return;
+        }
+       gpgrt_lock_lock (&import_lock);
+       if (m_import_jobs.find (mbox) != m_import_jobs.end ())
+         {
+           log_debug ("%s:%s import for \"%s\" already in progress.",
+                      SRCNAME, __func__, mbox.c_str ());
+           gpgrt_lock_unlock (&import_lock);
+         }
+       m_import_jobs.insert (mbox);
+       gpgrt_lock_unlock (&import_lock);
+
+       import_arg_t * args = new import_arg_t;
+       args->first = std::unique_ptr<LocateArgs> (new LocateArgs (mbox, mail));
+       args->second = std::string (data);
+       CloseHandle (CreateThread (NULL, 0, do_import,
+                                  (LPVOID) args, 0,
+                                  NULL));
+
+    }
+
+  void onAddrBookImportJobDone (const std::string &mbox,
+                                const std::vector<std::string> &result_fprs)
+    {
+      gpgrt_lock_lock (&keycache_lock);
+      auto it = m_addr_book_overrides.find (mbox);
+      if (it != m_addr_book_overrides.end ())
+        {
+          it->second = result_fprs;
+        }
+      else
+        {
+          m_addr_book_overrides.insert (
+                std::make_pair (mbox, result_fprs));
+        }
+      gpgrt_lock_unlock (&keycache_lock);
+      gpgrt_lock_lock (&import_lock);
+      const auto job_it = m_import_jobs.find(mbox);
+
+      if (job_it == m_import_jobs.end())
+        {
+          log_error ("%s:%s import for \"%s\" already finished.",
+                     SRCNAME, __func__, mbox.c_str ());
+          gpgrt_lock_unlock (&import_lock);
+          return;
+        }
+      m_import_jobs.erase (job_it);
+      gpgrt_lock_unlock (&import_lock);
+      return;
+    }
+
   std::unordered_map<std::string, GpgME::Key> m_pgp_key_map;
   std::unordered_map<std::string, GpgME::Key> m_smime_key_map;
   std::unordered_map<std::string, GpgME::Key> m_pgp_skey_map;
   std::unordered_map<std::string, GpgME::Key> m_smime_skey_map;
   std::unordered_map<std::string, GpgME::Key> m_fpr_map;
   std::unordered_map<std::string, std::string> m_sub_fpr_map;
+  std::unordered_map<std::string, std::vector<std::string> >
+    m_addr_book_overrides;
   std::set<std::string> m_update_jobs;
+  std::set<std::string> m_import_jobs;
 };
 
 KeyCache::KeyCache():
@@ -941,3 +1121,17 @@ KeyCache::onUpdateJobDone (const char *fpr, const GpgME::Key &key)
 {
   return d->onUpdateJobDone (fpr, key);
 }
+
+void
+KeyCache::importFromAddrBook (const std::string &mbox, const char *key_data,
+                              Mail *mail) const
+{
+  return d->importFromAddrBook (mbox, key_data, mail);
+}
+
+void
+KeyCache::onAddrBookImportJobDone (const std::string &mbox,
+                                   const std::vector<std::string> &result_fprs)
+{
+  return d->onAddrBookImportJobDone (mbox, result_fprs);
+}
diff --git a/src/keycache.h b/src/keycache.h
index ea90863..e67bcf4 100644
--- a/src/keycache.h
+++ b/src/keycache.h
@@ -54,7 +54,8 @@ public:
     /* Get the keys for recipents. The keys
        are taken from the internal cache. If
        one recipient can't be resolved an empty
-       list is returned. */
+       list is returned.
+       */
     std::vector<GpgME::Key> getEncryptionKeys (const std::vector<std::string> &recipients,
                                                GpgME::Protocol proto) const;
 
@@ -63,14 +64,22 @@ public:
 
        The mail argument is used to add / remove the
        locator thread counter.
+
+       async
        */
     void startLocate (const std::vector<std::string> &addrs, Mail *mail) const;
 
-    /* Look for a secret key for the addr. */
+    /* Look for a secret key for the addr.
+
+       async
+    */
     void startLocateSecret (const char *addr, Mail *mail) const;
 
     /* Start a key location in a background thread filling
-       the key cache. */
+       the key cache.
+
+       async
+       */
     void startLocate (const char *addr, Mail *mail) const;
 
     /* Check that a mail is resolvable through the keycache.
@@ -83,6 +92,8 @@ public:
     /* Search / Update a key in the cache. This is meant to be
        called e.g. after a verify to update the key.
 
+       async
+
        A known issue is that a get right after it might
        still return an outdated key but the get after that
        would return the updated one. This is acceptable as
@@ -97,12 +108,27 @@ public:
        to insert keys into the cache */
     GpgME::Key getByFpr (const char *fpr, bool block = true) const;
 
+    /* Import key data from the address book for the address mbox.
+       Keys imported this way take precedence over other keys for
+       this mail address regardless of validity.
+
+       The mail argument is used to add / remove the
+       locator thread counter.
+
+       async
+    */
+    void importFromAddrBook (const std::string &mbox,
+                             const char *key_data,
+                             Mail *mail) const;
+
     // Internal for thread
     void setSmimeKey(const std::string &mbox, const GpgME::Key &key);
     void setPgpKey(const std::string &mbox, const GpgME::Key &key);
     void setSmimeKeySecret(const std::string &mbox, const GpgME::Key &key);
     void setPgpKeySecret(const std::string &mbox, const GpgME::Key &key);
-    void onUpdateJobDone (const char *fpr, const GpgME::Key &key);
+    void onUpdateJobDone(const char *fpr, const GpgME::Key &key);
+    void onAddrBookImportJobDone (const std::string &fpr,
+                                  const std::vector<std::string> &result_fprs);
 
 private:
 

commit 3b770f928eb17fd876a00e85e7b384d566de2175
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Sep 4 13:50:28 2018 +0200

    Rename autoresolveCheck to autosecureCheck
    
    * src/mail.cpp, src/mail.h (Mail::autoresolveCheck): Rename
    to autosecureCheck.
    (Mail::autsecureCheck): Also check for opt.autosecure.
    
    --
    This reduces confusing naming and ensures that when opt.autosecure
    is not set auto secure won't happen.
    
    GnuPG-Bug-Id: T4126

diff --git a/src/mail.cpp b/src/mail.cpp
index d25b9d2..06f58cd 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -2807,7 +2807,7 @@ Mail::locateKeys_o ()
   KeyCache::instance()->startLocateSecret (getSender_o ().c_str (), this);
   KeyCache::instance()->startLocate (getSender_o ().c_str (), this);
   KeyCache::instance()->startLocate (getCachedRecipients (), this);
-  autoresolveCheck ();
+  autosecureCheck ();
 
   locate_in_progress = false;
 }
@@ -3374,14 +3374,14 @@ Mail::decrementLocateCount ()
     }
   if (!m_locate_count)
     {
-      autoresolveCheck ();
+      autosecureCheck ();
     }
 }
 
 void
-Mail::autoresolveCheck ()
+Mail::autosecureCheck ()
 {
-  if (!opt.autoresolve || m_manual_crypto_opts ||
+  if (!opt.autosecure || !opt.autoresolve || m_manual_crypto_opts ||
       m_locate_count)
     {
       return;
diff --git a/src/mail.h b/src/mail.h
index 7865336..44c15da 100644
--- a/src/mail.h
+++ b/src/mail.h
@@ -576,7 +576,7 @@ public:
   /* Check if the keys can be resolved automatically and trigger
    * setting the crypto flags accordingly.
    */
-  void autoresolveCheck ();
+  void autosecureCheck ();
 
   /* Set if a mail should be secured (encrypted and signed)
    *

commit a507d8bdfb9e31814abf21ad5a9915abd66c96c1
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Sep 4 13:47:04 2018 +0200

    Fix Mail::needs_crypto_m
    
    * src/mail.cpp (Mail::needs_crypto_m): Fix function.
    
    --
    It would always return 1 if any crypto was required. This
    had a side effect like:
    
    GnuPG-Bug-Id: T4126

diff --git a/src/mail.cpp b/src/mail.cpp
index 04d0b8e..d25b9d2 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -1519,7 +1519,7 @@ int
 Mail::needs_crypto_m () const
 {
   LPMESSAGE message = get_oom_message (m_mailitem);
-  bool ret;
+  int ret;
   if (!message)
     {
       log_error ("%s:%s: Failed to get message.",

commit 164d89131534bf28ceb0f554bf50d1672445d33f
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Sep 4 10:37:36 2018 +0200

    Extend oomhelp for address book integration
    
    * src/oomhelp.h (shared_disp_t, MAKE_SHARED, release_disp):
    New. Automatically releasing IDispatch pointer.
    * src/oomhelp.cpp, src/oomhelp.h (release_disp),
    (get_oom_recipients_with_addrEntry, find_user_prop),
    (find_or_add_text_prop): New.
    
    --
    This adds a way to get the recipients with their addresentry
    objects. For more complex IDispatch handling we now
    have shared_disp_t and MAKE_SHARED to wrap the IDispatch
    in an automatically releasing shared pointer.
    
    find_user_prop and find_or_add_text_prop are new
    functions to interact with Contact properties.

diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp
index 0870b34..680ecc3 100644
--- a/src/oomhelp.cpp
+++ b/src/oomhelp.cpp
@@ -2,19 +2,20 @@
  * Copyright (C) 2009 g10 Code GmbH
  * Copyright (C) 2015 by Bundesamt für Sicherheit in der Informationstechnik
  * Software engineering by Intevation GmbH
- * 
+ * Copyright (C) 2018 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/>.
  */
@@ -1220,7 +1221,8 @@ get_recipient_addr_fallbacks (LPDISPATCH recipient)
    returns true on success.
 */
 static bool
-try_resolve_group (LPDISPATCH addrEntry, std::vector<std::string> &ret)
+try_resolve_group (LPDISPATCH addrEntry,
+                   std::vector<std::pair<std::string, shared_disp_t> > &ret)
 {
   /* Get the name for debugging */
   std::string name;
@@ -1262,21 +1264,21 @@ try_resolve_group (LPDISPATCH addrEntry, std::vector<std::string> &ret)
   for (int i = 1; i <= count; i++)
     {
       auto item_str = std::string("Item(") + std::to_string (i) + ")";
-      LPDISPATCH entry = get_oom_object (members, item_str.c_str());
+      auto entry = MAKE_SHARED (get_oom_object (members, item_str.c_str()));
       if (!entry)
         {
           TRACEPOINT;
           continue;
         }
       std::string entryName;
-      char *entry_name = get_oom_string (entry, "Name");
+      char *entry_name = get_oom_string (entry.get(), "Name");
       if (entry_name)
         {
           entryName = entry_name;
           xfree (entry_name);
         }
 
-      int subType = get_oom_int (entry, "AddressEntryUserType");
+      int subType = get_oom_int (entry.get(), "AddressEntryUserType");
       /* Resolve recursively, yeah fun. */
       if (subType == DISTRIBUTION_LIST_ADDRESS_ENTRY_TYPE)
         {
@@ -1284,41 +1286,42 @@ try_resolve_group (LPDISPATCH addrEntry, std::vector<std::string> &ret)
                      SRCNAME, __func__,
                      (opt.enable_debug & DBG_MIME_PARSER) ?
                      entryName.c_str() : "omitted");
-          if (try_resolve_group (entry, ret))
+          if (try_resolve_group (entry.get(), ret))
             {
               foundOne = true;
-              gpgol_release (entry);
               continue;
             }
         }
 
+      std::pair<std::string, shared_disp_t> element;
+      element.second = entry;
+
       /* Resolve directly ? */
-      char *addrtype = get_pa_string (entry, PR_ADDRTYPE_DASL);
+      char *addrtype = get_pa_string (entry.get(), PR_ADDRTYPE_DASL);
       if (addrtype && !strcmp (addrtype, "SMTP"))
         {
           xfree (addrtype);
-          char *resolved = get_pa_string (entry, PR_EMAIL_ADDRESS_DASL);
+          char *resolved = get_pa_string (entry.get(), PR_EMAIL_ADDRESS_DASL);
           if (resolved)
             {
-              ret.push_back(resolved);
+              element.first = resolved;
+              ret.push_back (element);
               foundOne = true;
-              gpgol_release (entry);
               continue;
             }
         }
       xfree (addrtype);
 
       /* Resolve through Exchange API */
-      char *ex_resolved = get_recipient_addr_entry_fallbacks_ex (entry);
+      char *ex_resolved = get_recipient_addr_entry_fallbacks_ex (entry.get());
       if (ex_resolved)
         {
-          ret.push_back (ex_resolved);
+          element.first = ex_resolved;
+          ret.push_back (element);
           foundOne = true;
-          gpgol_release (entry);
           continue;
         }
 
-      gpgol_release (entry);
       log_debug ("%s:%s: failed to resolve name %s",
                  SRCNAME, __func__,
                  (opt.enable_debug & DBG_MIME_PARSER) ?
@@ -1335,12 +1338,13 @@ try_resolve_group (LPDISPATCH addrEntry, std::vector<std::string> &ret)
   return foundOne;
 }
 
-/* Gets the resolved smtp addresses of the recpients. */
-std::vector<std::string>
-get_oom_recipients (LPDISPATCH recipients, bool *r_err)
+/* Get the recipient mbox addresses with the addrEntry
+   object corresponding to the resolved address. */
+std::vector<std::pair<std::string, shared_disp_t> >
+get_oom_recipients_with_addrEntry (LPDISPATCH recipients, bool *r_err)
 {
   int recipientsCnt = get_oom_int (recipients, "Count");
-  std::vector<std::string> ret;
+  std::vector<std::pair<std::string, shared_disp_t> > ret;
   int i;
 
   if (!recipientsCnt)
@@ -1367,42 +1371,47 @@ get_oom_recipients (LPDISPATCH recipients, bool *r_err)
           break;
         }
 
-      LPDISPATCH addrEntry = get_oom_object (recipient, "AddressEntry");
-      if (addrEntry && try_resolve_group (addrEntry, ret))
+      auto addrEntry = MAKE_SHARED (get_oom_object (recipient, "AddressEntry"));
+      if (addrEntry && try_resolve_group (addrEntry.get (), ret))
         {
           log_debug ("%s:%s: Resolved recipient group",
                      SRCNAME, __func__);
           gpgol_release (recipient);
-          gpgol_release (addrEntry);
           continue;
         }
-      gpgol_release (addrEntry);
+
+      std::pair<std::string, shared_disp_t> entry;
+      entry.second = addrEntry;
 
       char *resolved = get_pa_string (recipient, PR_SMTP_ADDRESS_DASL);
       if (resolved)
         {
-          ret.push_back (resolved);
+          entry.first = resolved;
           xfree (resolved);
           gpgol_release (recipient);
+          ret.push_back (entry);
           continue;
         }
       /* No PR_SMTP_ADDRESS first fallback */
       resolved = get_recipient_addr_fallbacks (recipient);
       if (resolved)
         {
-          ret.push_back (resolved);
+          entry.first = resolved;
           xfree (resolved);
           gpgol_release (recipient);
+          ret.push_back (entry);
           continue;
         }
 
       char *address = get_oom_string (recipient, "Address");
       gpgol_release (recipient);
-      log_debug ("%s:%s: Failed to look up Address probably EX addr is returned",
+      log_debug ("%s:%s: Failed to look up Address probably "
+                 "EX addr is returned",
                  SRCNAME, __func__);
       if (address)
         {
-          ret.push_back (address);
+          entry.first = address;
+          ret.push_back (entry);
           xfree (address);
         }
       else if (r_err)
@@ -1410,7 +1419,18 @@ get_oom_recipients (LPDISPATCH recipients, bool *r_err)
           *r_err = true;
         }
     }
+  return ret;
+}
 
+/* Gets the resolved smtp addresses of the recpients. */
+std::vector<std::string>
+get_oom_recipients (LPDISPATCH recipients, bool *r_err)
+{
+  std::vector<std::string> ret;
+  for (const auto pair: get_oom_recipients_with_addrEntry (recipients, r_err))
+    {
+      ret.push_back (pair.first);
+    }
   return ret;
 }
 
@@ -2422,3 +2442,143 @@ is_preview_pane_visible (LPDISPATCH explorer)
     }
   return !!var.boolVal;
 }
+
+static LPDISPATCH
+add_user_prop (LPDISPATCH user_props, const char *name)
+{
+  if (!user_props || !name)
+    {
+      TRACEPOINT;
+      return nullptr;
+    }
+
+  wchar_t *w_name = utf8_to_wchar (name);
+  BSTR b_name = SysAllocString (w_name);
+  xfree (w_name);
+
+  /* Args:
+    0: DisplayFormat int OlUserPropertyType
+    1: AddToFolderFields Bool Should the filed be added to the folder.
+    2: Type int OlUserPropertyType Type of the field.
+    3: Name Bstr Name of the field.
+
+    Returns the added Property.
+  */
+  VARIANT var;
+  VariantInit (&var);
+  DISPPARAMS args;
+  VARIANT argvars[4];
+  VariantInit (&argvars[0]);
+  VariantInit (&argvars[1]);
+  VariantInit (&argvars[2]);
+  VariantInit (&argvars[3]);
+  argvars[0].vt = VT_INT;
+  argvars[0].intVal = 1; // 1 means text.
+  argvars[1].vt = VT_BOOL;
+  argvars[1].boolVal = VARIANT_FALSE;
+  argvars[2].vt = VT_INT;
+  argvars[2].intVal = 1;
+  argvars[3].vt = VT_BSTR;
+  argvars[3].bstrVal = b_name;
+  args.cArgs = 4;
+  args.cNamedArgs = 0;
+  args.rgvarg = argvars;
+
+  int res = invoke_oom_method_with_parms (user_props, "Add", &var, &args);
+  VariantClear (&argvars[0]);
+  VariantClear (&argvars[1]);
+  VariantClear (&argvars[2]);
+  VariantClear (&argvars[3]);
+
+  if (res)
+    {
+      log_oom ("%s:%s: Failed to add property %s.",
+               SRCNAME, __func__, name);
+      return nullptr;
+    }
+
+  if (var.vt != VT_DISPATCH)
+    {
+      TRACEPOINT;
+      return nullptr;
+    }
+
+  LPDISPATCH ret = var.pdispVal;
+  memdbg_addRef (ret);
+
+  return ret;
+}
+
+LPDISPATCH
+find_user_prop (LPDISPATCH user_props, const char *name)
+{
+  if (!user_props || !name)
+    {
+      TRACEPOINT;
+      return nullptr;
+    }
+  VARIANT var;
+  VariantInit (&var);
+
+  wchar_t *w_name = utf8_to_wchar (name);
+  BSTR b_name = SysAllocString (w_name);
+  xfree (w_name);
+
+  /* Name -> 1 / Bstr
+     Custom 0 -> Bool True for search in custom properties. False
+                 for builtin properties. */
+  DISPPARAMS args;
+  VARIANT argvars[2];
+  VariantInit (&argvars[0]);
+  VariantInit (&argvars[1]);
+  argvars[1].vt = VT_BSTR;
+  argvars[1].bstrVal = b_name;
+  argvars[0].vt = VT_BOOL;
+  argvars[0].boolVal = VARIANT_TRUE;
+  args.cArgs = 2;
+  args.rgvarg = argvars;
+
+  int res = invoke_oom_method_with_parms (user_props, "Find", &var, &args);
+  VariantClear (&argvars[0]);
+  VariantClear (&argvars[1]);
+  if (res)
+    {
+      log_oom ("%s:%s: Failed to find property %s.",
+               SRCNAME, __func__, name);
+      return nullptr;
+    }
+  if (var.vt != VT_DISPATCH)
+    {
+      TRACEPOINT;
+      return nullptr;
+    }
+
+  LPDISPATCH ret = var.pdispVal;
+  memdbg_addRef (ret);
+
+  return ret;
+}
+
+LPDISPATCH
+find_or_add_text_prop (LPDISPATCH user_props, const char *name)
+{
+  TRACEPOINT;
+  LPDISPATCH ret = find_user_prop (user_props, name);
+
+  TRACEPOINT;
+  if (ret)
+    {
+      return ret;
+    }
+
+  ret = add_user_prop (user_props, name);
+  TRACEPOINT;
+
+  return ret;
+}
+
+void
+release_disp (LPDISPATCH obj)
+{
+  gpgol_release (obj);
+}
diff --git a/src/oomhelp.h b/src/oomhelp.h
index 0ef2c01..1882057 100644
--- a/src/oomhelp.h
+++ b/src/oomhelp.h
@@ -24,9 +24,11 @@
 
 #include <unknwn.h>
 #include "mymapi.h"
+#include "common.h"
 
 #include <vector>
 #include <string>
+#include <memory>
 
 #define MSOCONTROLBUTTON    1
 #define MSOCONTROLEDIT      2
@@ -140,6 +142,13 @@ DEFINE_OLEGUID(IID_IOleWindow,                0x00000114, 0, 0);
 
 #define DISTRIBUTION_LIST_ADDRESS_ENTRY_TYPE 11
 
+typedef std::shared_ptr<IDispatch> shared_disp_t;
+
+/* Function to contain the gpgol_release macro */
+void release_disp (LPDISPATCH obj);
+
+#define MAKE_SHARED(X) shared_disp_t (X, &release_disp)
+
 /* Return the malloced name of an COM+ object.  */
 char *get_object_name (LPUNKNOWN obj);
 
@@ -194,6 +203,12 @@ HWND get_oom_context_window (LPDISPATCH context);
 std::vector<std::string> get_oom_recipients (LPDISPATCH recipients,
                                              bool *r_err = nullptr);
 
+/* Same as above but include the AddrEntry object in the result.
+   Caller needs to release the AddrEntry. */
+std::vector<std::pair<std::string, shared_disp_t> >
+get_oom_recipients_with_addrEntry (LPDISPATCH recipients,
+                                   bool *r_err = nullptr);
+
 /* Add an attachment to a dispatcher */
 int
 add_oom_attachment (LPDISPATCH disp, const wchar_t* inFile,
@@ -385,4 +400,10 @@ HRESULT gpgol_openProperty (LPMAPIPROP obj, ULONG ulPropTag, LPCIID lpiid,
 
 /* Check if the preview pane in the explorer is visible */
 bool is_preview_pane_visible (LPDISPATCH explorer);
+
+/* Find or add a text user property with that name. */
+LPDISPATCH find_or_add_text_prop (LPDISPATCH props, const char *name);
+
+/* Find a user property and return it if found. */
+LPDISPATCH find_user_prop (LPDISPATCH props, const char *name);
 #endif /*OOMHELP_H*/

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

Summary of changes:
 src/Makefile.am                  |   1 +
 src/addin-options.cpp            |  40 ++++++
 src/addressbook.cpp              | 300 +++++++++++++++++++++++++++++++++++++++
 src/{overlay.h => addressbook.h} |  45 +++---
 src/gpgoladdin.cpp               |  40 ++++++
 src/keycache.cpp                 | 194 +++++++++++++++++++++++++
 src/keycache.h                   |  34 ++++-
 src/mail.cpp                     |  43 +++---
 src/mail.h                       |   7 +-
 src/mailitem-events.cpp          |   4 -
 src/oomhelp.cpp                  | 221 ++++++++++++++++++++++++----
 src/oomhelp.h                    |  21 +++
 src/ribbon-callbacks.cpp         |  34 +++++
 src/ribbon-callbacks.h           |   3 +
 src/windowmessages.cpp           |   9 ++
 src/windowmessages.h             |   1 +
 16 files changed, 914 insertions(+), 83 deletions(-)
 create mode 100644 src/addressbook.cpp
 copy src/{overlay.h => addressbook.h} (56%)


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




More information about the Gnupg-commits mailing list