Make it possible to move decrypted mails
authorAndre Heinecke <aheinecke@intevation.de>
Tue, 26 Jun 2018 14:18:38 +0000 (16:18 +0200)
committerAndre Heinecke <aheinecke@intevation.de>
Tue, 26 Jun 2018 14:18:38 +0000 (16:18 +0200)
* src/Makefile.am: Add folder-events.cpp
* src/eventsinks.h (install_FolderEvents_sink),
(detach_FolderEvents_sink): New.
* src/folder-events.cpp: New event handler.
* src/mail.cpp (s_folder_events_map): New map to track
registered handlers.
(Mail::isAboutToBeMoved, Mail::setIsAboutToBeMoved): New.
(Mail::installFolderEventHandler_o): New.
(Mail::closeAllMails_o): detach folder handler.
* src/mail.h: Update accordingly.
* src/mailitem-events.cpp (Write): Pass if mail is about to
be moved.
* src/oomhelp.h (IID_FolderEvents): New.

--
Finally!
While the application has the item copy events the folder
has a before item move event. To catch this we register an
event handler for each folder in which a mail was decrypted.
If a crypto mail is then about to be moved we close it with
discard changes to discard the plaintext, then we pass
the write event to allow the move.

Works flawlessly in the first tests.

GnuPG-Bug-Id: T3459
GnuPG-Bug-Id: T3956
GnuPG-Bug-Id: T3418

src/Makefile.am
src/eventsinks.h
src/folder-events.cpp [new file with mode: 0644]
src/mail.cpp
src/mail.h
src/mailitem-events.cpp
src/oomhelp.h

index 2e6f529..161bd88 100644 (file)
@@ -42,6 +42,7 @@ gpgol_SOURCES = \
     explorer-events.cpp \
     explorers-events.cpp \
     filetype.c filetype.h \
+    folder-events.cpp \
     gmime-table-private.h \
     gpgoladdin.cpp gpgoladdin.h \
     gpgol.def \
index 96b067f..1508a62 100644 (file)
@@ -30,4 +30,6 @@ LPDISPATCH install_ExplorerEvents_sink (LPDISPATCH obj);
 void detach_ExplorerEvents_sink (LPDISPATCH obj);
 LPDISPATCH install_ExplorersEvents_sink (LPDISPATCH obj);
 void detach_ExplorersEvents_sink (LPDISPATCH obj);
+LPDISPATCH install_FolderEvents_sink (LPDISPATCH obj);
+void detach_FolderEvents_sink (LPDISPATCH obj);
 #endif // EVENTSINKS_H
diff --git a/src/folder-events.cpp b/src/folder-events.cpp
new file mode 100644 (file)
index 0000000..8c765c1
--- /dev/null
@@ -0,0 +1,135 @@
+/* folder-events.cpp - Event handling for a folder.
+ * 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/>.
+ */
+
+/* The event handler classes defined in this file follow the
+   general pattern that they implment the IDispatch interface
+   through the eventsink macros and handle event invocations
+   in their invoke methods.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eventsink.h"
+#include "ocidl.h"
+#include "common.h"
+#include "oomhelp.h"
+#include "mail.h"
+
+/* Folder Events */
+BEGIN_EVENT_SINK(FolderEvents, IDispatch)
+EVENT_SINK_DEFAULT_CTOR(FolderEvents)
+EVENT_SINK_DEFAULT_DTOR(FolderEvents)
+typedef enum
+  {
+    BeforeItemMove = 0xFBA9,
+    BeforeFolderMove = 0xFBA8,
+  } FolderEvent;
+
+EVENT_SINK_INVOKE(FolderEvents)
+{
+  USE_INVOKE_ARGS
+  switch(dispid)
+    {
+      case BeforeItemMove:
+        {
+          log_oom_extra ("%s:%s: Item Move in folder: %p",
+                         SRCNAME, __func__, this);
+
+          /* Parameters should be
+             disp item   Represents the Outlook item that is to be moved or deleted.
+             disp folder Represents the folder to which the item is being moved.
+                         If null the message will be deleted.
+             bool cancel Move should be canceled.
+
+             Remember that the order is inverted. */
+          if (!(parms->cArgs == 3 && parms->rgvarg[1].vt == (VT_DISPATCH) &&
+                parms->rgvarg[2].vt == (VT_DISPATCH) &&
+                parms->rgvarg[0].vt == (VT_BOOL | VT_BYREF)))
+            {
+              log_error ("%s:%s: Invalid args.",
+                         SRCNAME, __func__);
+              break;
+            }
+
+          if (!parms->rgvarg[1].pdispVal)
+            {
+              log_oom_extra ("%s:%s: Passing delete",
+                             SRCNAME, __func__);
+              break;
+            }
+
+          LPDISPATCH mailitem = parms->rgvarg[2].pdispVal;
+
+          char *name = get_object_name (mailitem);
+          if (!name || strcmp (name, "_MailItem"))
+            {
+              log_debug ("%s:%s: move is not about a mailitem.",
+                         SRCNAME, __func__);
+              xfree (name);
+              break;
+            }
+          xfree (name);
+
+          char *uid = get_unique_id (mailitem, 0, nullptr);
+          if (!uid)
+            {
+              LPMESSAGE msg = get_oom_base_message (mailitem);
+              uid = mapi_get_uid (msg);
+              gpgol_release (msg);
+              if (!uid)
+                {
+                  log_debug ("%s:%s: Failed to get uid for %p",
+                             SRCNAME, __func__, mailitem);
+                  break;
+                }
+            }
+
+          Mail *mail = Mail::getMailForUUID (uid);
+          xfree (uid);
+          if (!mail)
+            {
+              log_error ("%s:%s: Failed to find mail for uuid",
+                         SRCNAME, __func__);
+              break;
+            }
+          if (mail->isCryptoMail ())
+            {
+              log_debug ("%s:%s: Detected move of crypto mail. %p Closing",
+                          SRCNAME, __func__, mail);
+
+              mail->setIsAboutToBeMoved (true);
+              if (Mail::close (mail))
+                {
+                  log_error ("%s:%s: Failed to close.",
+                             SRCNAME, __func__);
+                  break;
+                }
+            }
+        }
+      default:
+        break;
+#if 0
+        log_oom_extra ("%s:%s: Unhandled Event: %lx \n",
+                       SRCNAME, __func__, dispid);
+#endif
+    }
+  return S_OK;
+}
+END_EVENT_SINK(FolderEvents, IID_FolderEvents)
index ead39ec..cb0c9e3 100644 (file)
@@ -61,6 +61,7 @@ using namespace GpgME;
 
 static std::map<LPDISPATCH, Mail*> s_mail_map;
 static std::map<std::string, Mail*> s_uid_map;
+static std::map<std::string, LPDISPATCH> s_folder_events_map;
 static std::set<std::string> uids_searched;
 
 GPGRT_LOCK_DEFINE (mail_map_lock);
@@ -101,7 +102,8 @@ Mail::Mail (LPDISPATCH mailitem) :
     m_disable_att_remove_warning(false),
     m_manual_crypto_opts(false),
     m_first_autosecure_check(true),
-    m_locate_count(0)
+    m_locate_count(0),
+    m_is_about_to_be_moved(false)
 {
   if (getMailForItem (mailitem))
     {
@@ -1365,6 +1367,8 @@ Mail::parsing_done()
       removeOurAttachments_o ();
     }
 
+  installFolderEventHandler_o ();
+
   log_debug ("%s:%s: Delayed invalidate to update sigstate.",
              SRCNAME, __func__);
   CloseHandle(CreateThread (NULL, 0, delayed_invalidate_ui, (LPVOID) this, 0,
@@ -1621,6 +1625,11 @@ Mail::closeAllMails_o ()
             }
         }
     }
+  for (auto fit = s_folder_events_map.begin(); fit != s_folder_events_map.end(); ++fit)
+    {
+      detach_FolderEvents_sink (fit->second);
+    }
+  s_folder_events_map.clear();
   return err;
 }
 int
@@ -3315,3 +3324,55 @@ Mail::setDoAutosecure_m (bool value)
   set_gpgol_draft_info_flags (msg, value ? 3 : 0);
   gpgoladdin_invalidate_ui();
 }
+
+void
+Mail::installFolderEventHandler_o()
+{
+  TRACEPOINT;
+  LPDISPATCH folder = get_oom_object (m_mailitem, "Parent");
+
+  if (!folder)
+    {
+      TRACEPOINT;
+      return;
+    }
+
+  char *objName = get_object_name (folder);
+  if (!objName || strcmp (objName, "MAPIFolder"))
+    {
+      log_debug ("%s:%s: Mail %p parent is not a mapi folder.",
+                 SRCNAME, __func__, m_mailitem);
+      xfree (objName);
+      gpgol_release (folder);
+      return;
+    }
+  xfree (objName);
+
+  char *path = get_oom_string (folder, "FullFolderPath");
+  if (!path)
+    {
+      TRACEPOINT;
+      path = get_oom_string (folder, "FolderPath");
+    }
+  if (!path)
+    {
+      log_error ("%s:%s: Mail %p parent has no folder path.",
+                 SRCNAME, __func__, m_mailitem);
+      gpgol_release (folder);
+      return;
+    }
+
+  std::string strPath (path);
+  xfree (path);
+
+  if (s_folder_events_map.find (strPath) == s_folder_events_map.end())
+    {
+      log_error ("%s:%s: Install folder events watcher for %s.",
+                 SRCNAME, __func__, strPath.c_str());
+      install_FolderEvents_sink (folder);
+      s_folder_events_map.insert (std::make_pair (strPath, folder));
+    }
+
+  /* Folder already registered */
+  gpgol_release (folder);
+}
index c5ea011..c6ecd2c 100644 (file)
@@ -589,6 +589,13 @@ public:
    */
   void setDoAutosecure_m (bool value);
 
+  /* Install an event handler for the folder of this mail. */
+  void installFolderEventHandler_o ();
+
+  /* Marker for a "Move" of this mail */
+  bool isAboutToBeMoved () { return m_is_about_to_be_moved; }
+  void setIsAboutToBeMoved (bool value) { m_is_about_to_be_moved = value; }
+
 private:
   void updateCategories_o ();
   void updateSigstate ();
@@ -636,5 +643,6 @@ private:
   bool m_manual_crypto_opts; /* Crypto options (sign/encrypt) have been set manually. */
   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;
 };
 #endif // MAIL_H
index 375a251..ab100c5 100644 (file)
@@ -555,6 +555,13 @@ EVENT_SINK_INVOKE(MailItemEvents)
              break;
            }
 
+          if (m_mail->isAboutToBeMoved())
+            {
+              log_debug ("%s:%s: Mail is about to be moved. Passing write for %p",
+                         SRCNAME, __func__, m_mail);
+              break;
+            }
+
           if (m_mail->isCryptoMail () && !m_mail->needsSave ())
             {
               Mail *last_mail = Mail::getLastMail ();
index ac6d2bb..8b8c7a4 100644 (file)
@@ -62,6 +62,8 @@ DEFINE_GUID(IID_IConnectionPointContainer,
 DEFINE_GUID(IID_IPictureDisp,
             0x7bf80981, 0xbf32, 0x101a,
             0x8b, 0xbb, 0x00, 0xaa, 0x00, 0x30, 0x0c, 0xab);
+DEFINE_GUID(IID_FolderEvents, 0x000630F7, 0x0000, 0x0000,
+            0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
 DEFINE_GUID(IID_ApplicationEvents, 0x0006304E, 0x0000, 0x0000,
             0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
 DEFINE_GUID(IID_ExplorerEvents, 0x0006300F, 0x0000, 0x0000,