[git] GpgOL - branch, master, updated. gpgol-1.1.3-51-gd1a9b54

by Andre Heinecke cvs at cvs.gnupg.org
Tue Aug 6 18:41:54 CEST 2013


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  d1a9b54ba57016d0194ada1778f09126af1e9afd (commit)
      from  a81d6897e302fa0fceb73647d41ee27370bf1a57 (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 d1a9b54ba57016d0194ada1778f09126af1e9afd
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 6 16:04:17 2013 +0000

    Implement add encrypted attachment
    
        Add a binary encrypted attachment to a Message object using
        OOM. The binary option requires very recent Versions of
        GPA or Kleopatra.
    
        * src/common.c, src/common.h (get_pretty_attachment_name),
        (get_tmp_outfile): New. Helper functions for attachments.
        * src/engine-assuan.c (op_assuan_encrypt): Handle binary option.
        * src/engine.h (ENGINE_FLAG_BINARY_OUTPUT): New.
        * src/mimemaker.c, src/mimemaker.h (sink_file_write): New. Sink
        to work on a file handle.
        * src/oomhelp.cpp, src/oomhelp.h (add_oom_attachment): New.
        Add an attachment to an Object with an Attachments collection.
        * src/ribbon-callbacks.cpp (addEncSignedAttachment): Implment
        adding an encrypted attachment.
    
    --
      Although it is still possible to add an attachment over MAPI
      I found no way to update the Inspector of the Message Object
      aside from closing it / opening a new inspector.

diff --git a/src/common.c b/src/common.c
index 9818ae5..dd8b2d7 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1054,3 +1054,116 @@ fix_linebreaks (char *str, int *len)
   *dst = '\0';
   *len = dst - str;
 }
+
+/* Get a pretty name for the file at path path. File extension
+   will be set to work for the protocol as provided in protocol.
+   Returns NULL on success.
+   Caller must free result. */
+wchar_t *
+get_pretty_attachment_name (wchar_t *path, protocol_t protocol)
+{
+  wchar_t* pretty;
+  wchar_t* buf;
+
+  if (!path || !wcslen (path))
+    {
+      log_error("%s:%s: No path given", SRCNAME, __func__);
+      return NULL;
+    }
+
+  pretty = (wchar_t*) xmalloc ((MAX_PATH + 1) * sizeof (wchar_t));
+  memset (pretty, 0, (MAX_PATH + 1) * sizeof (wchar_t));
+
+  buf = wcsrchr (path, '\\') + 1;
+
+  if (!buf || !*buf)
+    {
+      log_error("%s:%s: No filename found in path", SRCNAME, __func__);
+      xfree (pretty);
+      return NULL;
+    }
+
+  wcscpy (pretty, buf);
+
+  buf = pretty + wcslen(pretty);
+  if (protocol == PROTOCOL_SMIME)
+    {
+      *(buf++) = '.';
+      *(buf++) = 'p';
+      *(buf++) = '7';
+      *(buf++) = 'm';
+
+    }
+  else
+    {
+      *(buf++) = '.';
+      *(buf++) = 'g';
+      *(buf++) = 'p';
+      *(buf++) = 'g';
+    }
+
+  return pretty;
+}
+
+/* Open a file in a temporary directory, take name as a
+   suggestion and put the open Handle in outHandle.
+   Returns the actually used file name in case there
+   were other files with that name. */
+wchar_t*
+get_tmp_outfile (wchar_t *name, HANDLE *outHandle)
+{
+  wchar_t tmpPath[MAX_PATH];
+  wchar_t *outName;
+  wchar_t *fileExt = NULL;
+  int tries = 1;
+
+  if (!name || !wcslen(name))
+    {
+      log_error ("%s:%s: Needs a name.",
+                 SRCNAME, __func__);
+      return NULL;
+    }
+
+  /* We should probably use the unicode variants here
+     but this would mean adding OpenStreamOnFileW to
+     out mapi */
+
+  if (!GetTempPathW (MAX_PATH, tmpPath))
+    {
+      log_error ("%s:%s: Could not get tmp path.",
+                 SRCNAME, __func__);
+      return NULL;
+    }
+
+  outName = (wchar_t*) xmalloc ((MAX_PATH + 1) * sizeof(wchar_t));
+  memset (outName, 0, (MAX_PATH + 1) * sizeof (wchar_t));
+
+  snwprintf (outName, MAX_PATH, L"%s%s", tmpPath, name);
+  fileExt = wcschr (wcschr(outName, '\\'), '.');
+
+  while ((*outHandle = CreateFileW (outName,
+                                    GENERIC_WRITE | GENERIC_READ,
+                                    0, /* We do not share this */
+                                    NULL,
+                                    CREATE_NEW,
+                                    FILE_ATTRIBUTE_TEMPORARY,
+                                    NULL)) == INVALID_HANDLE_VALUE)
+    {
+      wchar_t fnameBuf[MAX_PATH];
+      wchar_t origName[MAX_PATH];
+      snwprintf (origName, MAX_PATH, L"%s%s", tmpPath, name);
+      fileExt = wcschr (wcsrchr(origName, '\\'), '.');
+      wcsncpy (fnameBuf, origName, fileExt - origName);
+      snwprintf (outName, MAX_PATH, L"%s%i%s", fnameBuf, tries++, fileExt);
+      if (tries > 100)
+        {
+          /* You have to know when to give up,.. */
+          log_error ("%s:%s: Could not get a name out of 100 tries",
+                     SRCNAME, __func__);
+          xfree (outName);
+          return NULL;
+        }
+    }
+
+  return outName;
+}
diff --git a/src/common.h b/src/common.h
index 265a470..a3efad6 100644
--- a/src/common.h
+++ b/src/common.h
@@ -190,6 +190,11 @@ size_t qp_decode (char *buffer, size_t length, int *r_slbrk);
 void b64_init (b64_state_t *state);
 size_t b64_decode (b64_state_t *state, char *buffer, size_t length);
 
+/* Get a temporary filename with and its name */
+wchar_t *get_tmp_outfile (wchar_t *name, HANDLE *outHandle);
+
+wchar_t *get_pretty_attachment_name (wchar_t *path, protocol_t protocol);
+
 /* The length of the boundary - the buffer needs to be allocated one
    byte larger. */
 #define BOUNDARYSIZE 20
diff --git a/src/engine-assuan.c b/src/engine-assuan.c
index 6523e1b..9af3782 100644
--- a/src/engine-assuan.c
+++ b/src/engine-assuan.c
@@ -1704,7 +1704,11 @@ op_assuan_encrypt (protocol_t protocol,
   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (err)
     goto leave;
-  snprintf (line, sizeof line, "OUTPUT FD=%d", (unsigned int)outpipe[1]);
+  if (flags & ENGINE_FLAG_BINARY_OUTPUT)
+    snprintf (line, sizeof line, "OUTPUT FD=%d --binary",
+              (unsigned int)outpipe[1]);
+  else
+    snprintf (line, sizeof line, "OUTPUT FD=%d", (unsigned int)outpipe[1]);
   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (err)
     goto leave;
diff --git a/src/engine.h b/src/engine.h
index f92dc4f..0dd07fc 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -44,8 +44,9 @@ typedef struct engine_keyinfo_s *engine_keyinfo_t;
 struct engine_filter_s;
 typedef struct engine_filter_s *engine_filter_t;
 
-/* Flag values used by the engine functions.  */ 
-#define ENGINE_FLAG_SIGN_FOLLOWS 1  /* Expect a sign+encrypt operation.  */
+/* Flag values used by the engine functions.  */
+#define ENGINE_FLAG_SIGN_FOLLOWS  1  /* Expect a sign+encrypt operation.  */
+#define ENGINE_FLAG_BINARY_OUTPUT 2  /* Create binary output */
 
 
 
diff --git a/src/mimemaker.c b/src/mimemaker.c
index 6a358a4..93450db 100644
--- a/src/mimemaker.c
+++ b/src/mimemaker.c
@@ -95,6 +95,29 @@ sink_std_write (sink_t sink, const void *data, size_t datalen)
   return 0;
 }
 
+/* Write method used with a sink_t that contains a file object.  */
+int
+sink_file_write (sink_t sink, const void *data, size_t datalen)
+{
+  HANDLE hFile = sink->cb_data;
+  DWORD written = NULL;
+
+  if (!hFile || hFile == INVALID_HANDLE_VALUE)
+    {
+      log_error ("%s:%s: sink not setup for writing", SRCNAME, __func__);
+      return -1;
+    }
+  if (!data)
+    return 0;  /* Flush - nothing to do here.  */
+
+  if (!WriteFile (hFile, data, datalen, &written, NULL))
+    {
+      log_error ("%s:%s: Write failed: ", SRCNAME, __func__);
+      return -1;
+    }
+  return 0;
+}
+
 
 /* Make sure that PROTOCOL is usable or return a suitable protocol.
    On error PROTOCOL_UNKNOWN is returned.  */
diff --git a/src/mimemaker.h b/src/mimemaker.h
index 0c804b3..fa7eca7 100644
--- a/src/mimemaker.h
+++ b/src/mimemaker.h
@@ -50,6 +50,7 @@ int mime_encrypt (LPMESSAGE message, HWND hwnd,
 int mime_sign_encrypt (LPMESSAGE message, HWND hwnd,
                        protocol_t protocol, char **recipients);
 int sink_std_write (sink_t sink, const void *data, size_t datalen);
+int sink_file_write (sink_t sink, const void *data, size_t datalen);
 int sink_encryption_write (sink_t encsink, const void *data, size_t datalen);
 int write_buffer_for_cb (void *opaque, const void *data, size_t datalen);
 int write_buffer (sink_t sink, const void *data, size_t datalen);
diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp
index 21be27f..a0e25ff 100644
--- a/src/oomhelp.cpp
+++ b/src/oomhelp.cpp
@@ -824,3 +824,75 @@ get_oom_recipients (LPDISPATCH recipients)
     }
   return recipientAddrs;
 }
+
+/* Add an attachment to the outlook dispatcher disp
+   that has an Attachment property.
+   inFile is the path to the attachment. Name is the
+   name that should be used in outlook. */
+int
+add_oom_attachment (LPDISPATCH disp, wchar_t* inFileW)
+{
+  LPDISPATCH attachments = get_oom_object (disp, "Attachments");
+
+  DISPID dispid;
+  DISPPARAMS dispparams;
+  VARIANT vtResult;
+  VARIANT aVariant[4];
+  HRESULT hr;
+  BSTR inFileB = NULL;
+  unsigned int argErr = 0;
+  EXCEPINFO execpinfo;
+
+  if (!inFileW || !wcslen (inFileW))
+    {
+      log_error ("%s:%s: no filename provided", SRCNAME, __func__);
+      return -1;
+    }
+
+  dispid = lookup_oom_dispid (attachments, "Add");
+
+  if (dispid == DISPID_UNKNOWN)
+  {
+    log_error ("%s:%s: could not find attachment dispatcher",
+               SRCNAME, __func__);
+    return -1;
+  }
+
+  inFileB = SysAllocString (inFileW);
+
+  dispparams.rgvarg = aVariant;
+
+  /* Contrary to the documentation the Source is the last
+     parameter and not the first. Additionally DisplayName
+     is documented but gets ignored by Outlook since Outlook
+     2003 */
+
+  dispparams.rgvarg[0].vt = VT_BSTR; /* DisplayName */
+  dispparams.rgvarg[0].bstrVal = NULL;
+  dispparams.rgvarg[1].vt = VT_INT;  /* Position */
+  dispparams.rgvarg[1].intVal = 1;
+  dispparams.rgvarg[2].vt = VT_INT;  /* Type */
+  dispparams.rgvarg[2].intVal = 1;
+  dispparams.rgvarg[3].vt = VT_BSTR; /* Source */
+  dispparams.rgvarg[3].bstrVal = inFileB;
+  dispparams.cArgs = 4;
+  dispparams.cNamedArgs = 0;
+  VariantInit (&vtResult);
+  hr = attachments->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                            DISPATCH_METHOD, &dispparams,
+                            &vtResult, &execpinfo, &argErr);
+  if (hr != S_OK)
+    {
+      log_debug ("%s:%s: error: invoking Add p=%p vt=%d hr=0x%x argErr=0x%x",
+                 SRCNAME, __func__,
+                 vtResult.pdispVal, vtResult.vt, (unsigned int)hr,
+                 (unsigned int)argErr);
+      dump_excepinfo (execpinfo);
+    }
+
+  SysFreeString (inFileB);
+  VariantClear (&vtResult);
+  RELDISP (attachments);
+
+  return hr == S_OK ? 0 : -1;
+}
diff --git a/src/oomhelp.h b/src/oomhelp.h
index 231c27d..7858b42 100644
--- a/src/oomhelp.h
+++ b/src/oomhelp.h
@@ -122,8 +122,11 @@ void del_oom_button (LPDISPATCH button);
 HWND get_oom_context_window (LPDISPATCH context);
 
 /* Get the address of the recipients as string list */
-char **
-get_oom_recipients (LPDISPATCH recipients);
+char ** get_oom_recipients (LPDISPATCH recipients);
+
+/* Add an attachment to a dispatcher */
+int
+add_oom_attachment (LPDISPATCH disp, wchar_t* inFile);
 
 #ifdef __cplusplus
 }
diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp
index 0afead1..966d74f 100644
--- a/src/ribbon-callbacks.cpp
+++ b/src/ribbon-callbacks.cpp
@@ -825,6 +825,216 @@ encryptSelection (LPDISPATCH ctrl)
 HRESULT
 addEncSignedAttachment (LPDISPATCH ctrl)
 {
-  /* TODO */
+  LPDISPATCH context = NULL;
+  LPDISPATCH mailItem = NULL;
+  LPDISPATCH sender = NULL;
+  LPDISPATCH recipients = NULL;
+  HRESULT hr;
+  char* senderAddr = NULL;
+  char** recipientAddrs = NULL;
+
+  HWND curWindow;
+  char *fileToEncrypt = NULL;
+  wchar_t *fileToEncryptW = NULL;
+  wchar_t *encryptedFile = NULL;
+  wchar_t *attachName = NULL;
+  HANDLE hFile = NULL;
+  HANDLE hEncFile = NULL;
+
+  unsigned int session_number;
+  struct sink_s encsinkmem;
+  sink_t encsink = &encsinkmem;
+  struct sink_s sinkmem;
+  sink_t sink = &sinkmem;
+  engine_filter_t filter = NULL;
+  protocol_t protocol;
+  STATSTG tmpStat;
+  int rc = 0;
+  int i = 0;
+  LPSTREAM tmpstream = NULL;
+
+  memset (encsink, 0, sizeof *encsink);
+  memset (sink, 0, sizeof *sink);
+
+  hr = getContext (ctrl, &context);
+  if (FAILED(hr))
+      return hr;
+
+  /* First do the check for recipients as this is likely
+     to fail */
+  mailItem = get_oom_object (context, "CurrentItem");
+  sender = get_oom_object (mailItem, "Session.CurrentUser");
+  recipients = get_oom_object (mailItem, "Recipients");
+  recipientAddrs = get_oom_recipients (recipients);
+
+  if (!recipientAddrs || !(*recipientAddrs))
+    {
+      MessageBox (NULL,
+                  _("Please add at least one recipent."),
+                  _("GpgOL"),
+                  MB_ICONINFORMATION|MB_OK);
+      goto failure;
+    }
+
+  /* Get a file handle to read from */
+  fileToEncrypt = get_open_filename (NULL, _("Select file to encrypt"));
+
+  if (!fileToEncrypt)
+    {
+      log_debug ("No file selected");
+      goto failure;
+    }
+
+  fileToEncryptW = utf8_to_wchar2 (fileToEncrypt, strlen(fileToEncrypt));
+  xfree (fileToEncrypt);
+
+  hFile = CreateFileW (fileToEncryptW,
+                       GENERIC_READ,
+                       FILE_SHARE_READ,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL,
+                       NULL);
+  if (hFile == INVALID_HANDLE_VALUE)
+    {
+      /* Should not happen as the Open File dialog
+         should have prevented this.
+         Maybe this also happens when a file is
+         not readable. In that case we might want
+         to switch to a localized error naming the file. */
+      MessageBox (NULL,
+                  "Internal error in GpgOL.\n"
+                  "Could not open File.",
+                  _("GpgOL"),
+                  MB_ICONERROR|MB_OK);
+      return S_OK;
+    }
+
+  /* Now do the encryption preperations */
+
+  if (!mailItem || !sender || !recipients)
+    {
+      MessageBox (NULL,
+                  "Internal error in GpgOL.\n"
+                  "Could not find all objects.",
+                  _("GpgOL"),
+                  MB_ICONERROR|MB_OK);
+      log_error ("%s:%s: Could not find all objects.",
+                 SRCNAME, __func__);
+      goto failure;
+    }
+
+  senderAddr = get_oom_string (sender, "Address");
+
+  session_number = engine_new_session_number ();
+
+  /* Prepare the encryption sink */
+  if ((rc = engine_create_filter (&filter, write_buffer_for_cb, sink)))
+    {
+      goto failure;
+    }
+
+  encsink->cb_data = filter;
+  encsink->writefnc = sink_encryption_write;
+
+  engine_set_session_number (filter, session_number);
+  engine_set_session_title (filter, _("GpgOL"));
+  if ((rc=engine_encrypt_prepare (filter, curWindow,
+                                  PROTOCOL_UNKNOWN,
+                                  ENGINE_FLAG_BINARY_OUTPUT,
+                                  senderAddr, recipientAddrs, &protocol)))
+    {
+      log_error ("%s:%s: engine encrypt prepare failed : %s",
+                 SRCNAME, __func__, gpg_strerror (rc));
+      goto failure;
+    }
+
+  attachName = get_pretty_attachment_name (fileToEncryptW, protocol);
+
+  if (!attachName)
+    {
+      log_error ("%s:%s: Could not get a decent attachment name",
+                 SRCNAME, __func__);
+      goto failure;
+    }
+
+  encryptedFile = get_tmp_outfile (attachName, &hEncFile);
+  sink->cb_data = hEncFile;
+  sink->writefnc = sink_file_write;
+
+  if ((rc=engine_encrypt_start (filter, 0)))
+    {
+      log_error ("%s:%s: engine encrypt start failed: %s",
+                 SRCNAME, __func__, gpg_strerror (rc));
+      goto failure;
+    }
+
+  /* Read the file in chunks and write them to the encryption
+     buffer */
+  {
+    char buf[4096];
+    DWORD bytesRead = 0;
+    do
+      {
+        if (!ReadFile (hFile, buf, sizeof buf, &bytesRead, NULL))
+          {
+            rc = -1;
+            log_error ("%s:%s: Could not read source file: %s",
+                       SRCNAME, __func__);
+            goto failure;
+          }
+        if ((rc = write_buffer (encsink, bytesRead ? buf : NULL, bytesRead)))
+          {
+            rc = -1;
+            log_error ("%s:%s: Could not wirte out buffer",
+                       SRCNAME, __func__);
+            goto failure;
+          }
+      }
+    while (bytesRead);
+  }
+  /* Lets hope the user did not select a huge file. We are hanging
+     here until encryption is completed.. */
+  if ((rc = engine_wait (filter)))
+    goto failure;
+
+  filter = NULL; /* Not valid anymore.  */
+  encsink->cb_data = NULL; /* Not needed anymore.  */
+
+  if (!sink->enc_counter)
+    {
+      log_error ("%s:%s: nothing received from engine", SRCNAME, __func__);
+      goto failure;
+    }
+
+  /* Now we have an encrypted file behind encryptedFile. Let's add it */
+  add_oom_attachment (mailItem, encryptedFile);
+
+failure:
+  if (filter)
+    engine_cancel (filter);
+
+  if (hEncFile)
+    {
+      CloseHandle (hEncFile);
+      DeleteFileW (encryptedFile);
+    }
+  xfree (senderAddr);
+  xfree (encryptedFile);
+  xfree (fileToEncryptW);
+  xfree (attachName);
+  RELDISP (mailItem);
+  RELDISP (sender);
+  RELDISP (recipients);
+
+  if (hFile)
+    CloseHandle (hFile);
+  if (recipientAddrs)
+    {
+      for (i=0; recipientAddrs && recipientAddrs[i]; i++)
+        xfree (recipientAddrs[i]);
+      xfree (recipientAddrs);
+    }
+
   return S_OK;
 }

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

Summary of changes:
 src/common.c             |  113 ++++++++++++++++++++++++
 src/common.h             |    5 +
 src/engine-assuan.c      |    6 +-
 src/engine.h             |    5 +-
 src/mimemaker.c          |   23 +++++
 src/mimemaker.h          |    1 +
 src/oomhelp.cpp          |   72 ++++++++++++++++
 src/oomhelp.h            |    7 +-
 src/ribbon-callbacks.cpp |  212 +++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 438 insertions(+), 6 deletions(-)


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




More information about the Gnupg-commits mailing list