[git] GpgOL - branch, outlook14, updated. gpgol-1.1.3-12-g3f9cedf

by Andre Heinecke cvs at cvs.gnupg.org
Wed Jul 10 20:03:51 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, outlook14 has been updated
       via  3f9cedf40b5bbba3ddf4fdcaad46e3749ce91724 (commit)
       via  bd44cdf7984cc6e41c6b390577626a6c60c8ae75 (commit)
       via  76061280cb9e28971e05b473b1a0d771dc592ae8 (commit)
      from  d737d168278cfec479cb1bd49b8825d98e7260c0 (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 3f9cedf40b5bbba3ddf4fdcaad46e3749ce91724
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Wed Jul 10 17:28:47 2013 +0000

    Add icon callbacks and decrypt selection action
    
        This uses the same icons / icon ID's as the old extension
        and does not handle transparency. There is some prepared
        code to enable full alpha channel handling by using PNG included.
    
        * src/gpgoladdin.cpp (GetIDsOfNames): Return dispID's for new
        callbacks. Use new ID_MAPPER macro.
        (Invoke): Resolve getIcon and decryptSelection calls.
        (GetCustomUI): Add image callbacks and decrypt selection.
        * src/ribbon-callbacks.cpp (encryptSelection): Add missing free.
        (decryptSelection): New. Decrypt selected text and replace it
        by plaintext if decryption was successful.
        (getIcon): Create picturedispatcher on the queried ressource
        bitmap.
        * src/ribbon-callbacks.h: Add new ID's and prototypes
    
    --
        The old image mechanism for CommandBar items was to combine a
        trasparancy mask with a picture bitmap to create transparent
        images. This can no longer be used and the suggested / documented
        way instead is now to use bitmaps generated from PNGs. For now
        we just return the picture part of the bitmaps. Looks ugly but
        should be ok for now.

diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp
index 0a7323d..807e5a6 100644
--- a/src/gpgoladdin.cpp
+++ b/src/gpgoladdin.cpp
@@ -50,6 +50,9 @@
                                      SRCNAME, __func__, __LINE__); \
                         } while (0)
 
+#define ICON_SIZE_LARGE  32
+#define ICON_SIZE_NORMAL 16
+
 ULONG addinLocks = 0;
 
 /* This is the main entry point for the addin
@@ -390,6 +393,16 @@ GpgolRibbonExtender::GetTypeInfo (UINT iTypeInfo, LCID lcid,
    http://blogs.msdn.com/b/andreww/archive/2007/03/09/
 why-is-it-so-hard-to-shim-iribbonextensibility.aspx
    */
+
+#define ID_MAPPER(name,id)                      \
+  if (!wcscmp (rgszNames[i], name))             \
+    {                                           \
+      found = true;                             \
+      rgDispId[i] = id;                         \
+      break;                                    \
+    }                                           \
+
+
 STDMETHODIMP
 GpgolRibbonExtender::GetIDsOfNames (REFIID riid, LPOLESTR *rgszNames,
                                     UINT cNames, LCID lcid,
@@ -407,24 +420,19 @@ GpgolRibbonExtender::GetIDsOfNames (REFIID riid, LPOLESTR *rgszNames,
   for (unsigned int i = 0; i < cNames; i++)
     {
       log_debug ("%s:%s: GetIDsOfNames for: %S",
-                 SRCNAME, __func__, rgszNames[0]);
+                 SRCNAME, __func__, rgszNames[i]);
       /* How this is supposed to work with cNames > 1 is unknown,
          but we can just say that we won't support callbacks with
          different parameters and just match the name (the first element)
          and we give it one of our own dispIds's that are later handled in
          the invoke part */
-      if (!wcscmp (rgszNames[i], L"attachmentDecryptCallback"))
-        {
-          found = true;
-          rgDispId[i] = ID_CMD_DECRYPT;
-          break;
-        }
-      if (!wcscmp (rgszNames[i], L"encryptSelection"))
-        {
-          found = true;
-          rgDispId[i] = ID_CMD_ENCRYPT_SELECTION;
-          break;
-        }
+      ID_MAPPER (L"attachmentDecryptCallback", ID_CMD_DECRYPT)
+      ID_MAPPER (L"encryptSelection", ID_CMD_ENCRYPT_SELECTION)
+      ID_MAPPER (L"decryptSelection", ID_CMD_DECRYPT_SELECTION)
+      ID_MAPPER (L"btnCertManager", ID_BTN_CERTMANAGER)
+      ID_MAPPER (L"btnDecrypt", ID_BTN_DECRYPT)
+      ID_MAPPER (L"btnDecryptLarge", ID_BTN_DECRYPT_LARGE)
+      ID_MAPPER (L"btnEncrypt", ID_BTN_ENCRYPT)
     }
 
   if (cNames > 1)
@@ -458,6 +466,16 @@ GpgolRibbonExtender::Invoke (DISPID dispid, REFIID riid, LCID lcid,
         return decryptAttachments (parms->rgvarg[0].pdispVal);
       case ID_CMD_ENCRYPT_SELECTION:
         return encryptSelection (parms->rgvarg[0].pdispVal);
+      case ID_CMD_DECRYPT_SELECTION:
+        return decryptSelection (parms->rgvarg[0].pdispVal);
+      case ID_BTN_CERTMANAGER:
+        return getIcon (ID_BTN_CERTMANAGER, ICON_SIZE_LARGE, result);
+      case ID_BTN_ENCRYPT:
+        return getIcon (ID_BTN_ENCRYPT, ICON_SIZE_NORMAL, result);
+      case ID_BTN_DECRYPT:
+        return getIcon (ID_BTN_DECRYPT, ICON_SIZE_NORMAL, result);
+      case ID_BTN_DECRYPT_LARGE:
+        return getIcon (ID_BTN_DECRYPT_LARGE, ICON_SIZE_LARGE, result);
     }
 
   log_debug ("%s:%s: leave", SRCNAME, __func__);
@@ -524,20 +542,15 @@ GpgolRibbonExtender::GetCustomUI (BSTR RibbonID, BSTR * RibbonXml)
         L"<contextMenu idMso=\"ContextMenuText\">"
         L" <button id=\"encryptButton\""
         L"         label=\"Encrypt Text\""
+        L"         getImage=\"btnEncrypt\""
         L"         onAction=\"encryptSelection\"/>"
+        L" <button id=\"decryptButton\""
+        L"         label=\"Decrypt Selection\""
+        L"         getImage=\"btnDecrypt\""
+        L"         onAction=\"decryptSelection\"/>"
         L" </contextMenu>"
         L"</contextMenus>"
         L"</customUI>"
-/*
-        L"<customUI xmlns=\"http://schemas.microsoft.com/office/2009/07/customui\">"
-L"<contextMenus>"
-L"    <contextMenu idMso=\"ContextMenuMailItem\">"
-L"        <button id=\"MyContextMenuMailItem\""
-L"            label=\"Encrypt selection\""
-L"            onAction=\"encryptSelection\"/>"
-L"    </contextMenu>"
-L"</contextMenus>"
-        L"</customUI>"*/
       );
     }
   else if (!wcscmp (RibbonID, L"Microsoft.Outlook.Mail.Read"))
@@ -568,7 +581,7 @@ L"</contextMenus>"
         L"     <group id=\"general\""
         L"            label=\"Allgemein\">"
         L"       <button id=\"CustomButton\""
-        L"               imageMso=\"HappyFace\""
+        L"               getImage=\"btnCertManager\""
         L"               size=\"large\""
         L"               label=\"Zertifikatsverwaltung\""
         L"               onAction=\"startCertManager\"/>"
@@ -582,7 +595,7 @@ L"</contextMenus>"
         L"                <button id=\"gpgol_contextual_decrypt\""
         L"                    size=\"large\""
         L"                    label=\"Save and decrypt\""
-        L"                    imageMso=\"HappyFace\""
+        L"                    getImage=\"btnDecryptLarge\""
         L"                    onAction=\"attachmentDecryptCallback\" />"
         L"            </group>"
         L"        </tab>"
@@ -592,8 +605,9 @@ L"</contextMenus>"
         L" <contextMenus>"
         L" <contextMenu idMso=\"ContextMenuAttachments\">"
         L"   <button id=\"gpgol_decrypt\""
-        L"    label=\"Save and decrypt\""
-        L"    onAction=\"attachmentDecryptCallback\"/>"
+        L"           label=\"Save and decrypt\""
+        L"           getImage=\"btnDecrypt\""
+        L"           onAction=\"attachmentDecryptCallback\"/>"
         L" </contextMenu>"
         L" </contextMenus>"
         L"</customUI>"
diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp
index cf390ec..7499eeb 100644
--- a/src/ribbon-callbacks.cpp
+++ b/src/ribbon-callbacks.cpp
@@ -22,6 +22,7 @@
 #endif
 
 #include <windows.h>
+#include <olectl.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -42,6 +43,7 @@
 #include "engine-assuan.h"
 #include "mapihelp.h"
 #include "mimemaker.h"
+#include "filetype.h"
 
 /* Gets the context of a ribbon control. And prints some
    useful debug output */
@@ -311,6 +313,7 @@ encryptSelection (LPDISPATCH ctrl)
   engine_cancel (filter);
   if (tmpstream)
     tmpstream->Release();
+  xfree (text);
   xfree (senderAddr);
 
   return S_OK;
@@ -415,3 +418,257 @@ decryptAttachments (LPDISPATCH ctrl)
   return S_OK; /* If we return an error outlook will show that our
                   callback function failed in an ugly window. */
 }
+
+HRESULT
+decryptSelection (LPDISPATCH ctrl)
+{
+  LPDISPATCH context;
+  LPDISPATCH selection;
+  LPDISPATCH wordEditor;
+  LPDISPATCH wordApplication;
+
+  struct sink_s decsinkmem;
+  sink_t decsink = &decsinkmem;
+  struct sink_s sinkmem;
+  sink_t sink = &sinkmem;
+
+  LPSTREAM tmpstream = NULL;
+  engine_filter_t filter = NULL;
+  LPOLEWINDOW actExplorer;
+  HWND curWindow;
+  char* text = NULL;
+  int rc = 0;
+  unsigned int session_number;
+  HRESULT hr;
+  STATSTG tmpStat;
+
+  protocol_t protocol;
+
+  hr = getContext (ctrl, &context);
+  if (FAILED(hr))
+      return hr;
+
+  memset (decsink, 0, sizeof *decsink);
+  memset (sink, 0, sizeof *sink);
+
+  actExplorer = (LPOLEWINDOW) get_oom_object(context,
+                                             "Application.ActiveExplorer");
+  if (actExplorer)
+    actExplorer->GetWindow (&curWindow);
+  else
+    {
+      log_debug ("%s:%s: Could not find active window",
+                 SRCNAME, __func__);
+      curWindow = NULL;
+    }
+
+  wordEditor = get_oom_object (context, "WordEditor");
+  wordApplication = get_oom_object (wordEditor, "get_Application");
+  selection = get_oom_object (wordApplication, "get_Selection");
+
+  if (!wordEditor || !wordApplication || !selection)
+    {
+      MessageBox (NULL,
+                  _("Internal error in GpgOL.\n"
+                    "Could not find all objects."),
+                  _("GpgOL"),
+                  MB_ICONINFORMATION|MB_OK);
+      log_error ("%s:%s: Could not find all objects.",
+                 SRCNAME, __func__);
+      return S_OK;
+    }
+
+  text = get_oom_string (selection, "Text");
+
+  if (!text || strlen (text) <= 1)
+    {
+      /* TODO more usable if we just use all text in this case? */
+      MessageBox (NULL,
+                  _("Please select the data you wish to decrypt."),
+                  _("GpgOL"),
+                  MB_ICONINFORMATION|MB_OK);
+      return S_OK;
+    }
+
+  /* Determine the protocol based on the content */
+  protocol = is_cms_data (text, strlen (text)) ? PROTOCOL_SMIME :
+    PROTOCOL_OPENPGP;
+
+  hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
+                         (SOF_UNIQUEFILENAME | STGM_DELETEONRELEASE
+                          | STGM_CREATE | STGM_READWRITE),
+                         NULL, "GPG", &tmpstream);
+
+  if (FAILED (hr))
+    {
+      log_error ("%s:%s: can't create temp file: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      rc = -1;
+      goto failure;
+    }
+
+  sink->cb_data = tmpstream;
+  sink->writefnc = sink_std_write;
+
+  session_number = engine_new_session_number ();
+  if (engine_create_filter (&filter, write_buffer_for_cb, sink))
+    goto failure;
+
+  decsink->cb_data = filter;
+  decsink->writefnc = sink_encryption_write;
+
+  engine_set_session_number (filter, session_number);
+  engine_set_session_title (filter, _("Decrypt Selection"));
+
+  if ((rc=engine_decrypt_start (filter, curWindow,
+                                protocol,
+                                1, NULL)))
+    {
+      log_error ("%s:%s: engine decrypt start failed: %s",
+                 SRCNAME, __func__, gpg_strerror (rc));
+      goto failure;
+    }
+
+  /* Write the text in the decryption sink. */
+  rc = write_buffer (decsink, text, strlen (text));
+
+  /* Flush the decryption sink and wait for the encryption to get
+     ready.  */
+  if ((rc = write_buffer (decsink, NULL, 0)))
+    goto failure;
+  if ((rc = engine_wait (filter)))
+    goto failure;
+  filter = NULL; /* Not valid anymore.  */
+  decsink->cb_data = NULL; /* Not needed anymore.  */
+
+  if (!sink->enc_counter)
+    {
+      log_debug ("%s:%s: nothing received from engine", SRCNAME, __func__);
+      goto failure;
+    }
+
+  /* Check the size of the decrypted data */
+  tmpstream->Stat (&tmpStat, 0);
+
+  if (tmpStat.cbSize.QuadPart > UINT_MAX)
+    {
+      MessageBox (curWindow, _("GpgOL"),
+                  _("Selected text too long."),
+                  MB_ICONINFORMATION|MB_OK);
+      log_error ("%s:%s: No one should write so large mails.",
+                 SRCNAME, __func__);
+      goto failure;
+    }
+
+  /* Copy the encrypted stream to the message editor.  */
+  {
+    LARGE_INTEGER off;
+    ULONG nread;
+    char buffer[(unsigned int)tmpStat.cbSize.QuadPart];
+
+    off.QuadPart = 0;
+    hr = tmpstream->Seek (off, STREAM_SEEK_SET, NULL);
+    if (hr)
+      {
+        log_error ("%s:%s: seeking back to the begin failed: hr=%#lx",
+                   SRCNAME, __func__, hr);
+        rc = gpg_error (GPG_ERR_EIO);
+        goto failure;
+      }
+    hr = tmpstream->Read (buffer, sizeof buffer, &nread);
+    if (hr)
+      {
+        log_error ("%s:%s: IStream::Read failed: hr=%#lx",
+                   SRCNAME, __func__, hr);
+        rc = gpg_error (GPG_ERR_EIO);
+        goto failure;
+      }
+    if (strlen (buffer) > 1)
+      {
+        /* Now replace the selection with the encrypted text */
+        put_oom_string (selection, "Text", buffer);
+      }
+    else
+      {
+        /* Just to be save not to overwrite the selection with
+           an empty buffer */
+        log_error ("%s:%s: unexpected problem ", SRCNAME, __func__);
+        goto failure;
+      }
+  }
+
+ failure:
+  if (rc)
+    log_debug ("%s:%s: failed rc=%d (%s) <%s>", SRCNAME, __func__, rc,
+               gpg_strerror (rc), gpg_strsource (rc));
+  engine_cancel (filter);
+  xfree (text);
+  if (tmpstream)
+    tmpstream->Release();
+
+  return S_OK;
+}
+
+HRESULT
+getIcon (int id, int size, VARIANT* result)
+{
+  PICTDESC pdesc;
+  LPDISPATCH pPict;
+  HRESULT hr;
+  UINT fuload;
+
+  memset (&pdesc, 0, sizeof pdesc);
+  pdesc.cbSizeofstruct = sizeof pdesc;
+  pdesc.picType = PICTYPE_BITMAP;
+
+/*
+   In the future we might want to use PNGs here to have
+   full Alpha Channel support for the icons
+
+   Here is an example how this could look like with gdiplus:
+
+   GdiplusStartupInput gdiplusStartupInput;
+   ULONG_PTR gdiplusToken;
+   Bitmap* pbitmap;
+
+   GetModuleFileName(glob_hinst, szModuleFileName, MAX_PATH);
+
+   gdiplusStartupInput.DebugEventCallback = NULL;
+   gdiplusStartupInput.SuppressBackgroundThread = FALSE;
+   gdiplusStartupInput.SuppressExternalCodecs = FALSE;
+   gdiplusStartupInput.GdiplusVersion = 1;
+   GdiplusStartup (&gdiplusToken, &gdiplusStartupInput, NULL);
+
+   pbitmap = Bitmap::FromFile (L"c:\\foo.png", FALSE);
+   if (!pbitmap || pbitmap->GetHBITMAP (0, &pdesc.bmp.hbitmap))
+     {
+       log_error ("%s:%s: failed to load file.",
+                  SRCNAME, __func__);
+     }
+*/
+
+  fuload = LR_CREATEDIBSECTION | LR_SHARED;
+
+  pdesc.bmp.hbitmap = (HBITMAP) LoadImage (glob_hinst,
+                                           MAKEINTRESOURCE (id),
+                                           IMAGE_BITMAP, size, size, fuload);
+
+  /* Wrap the image into an OLE object.  */
+  hr = OleCreatePictureIndirect (&pdesc, IID_IPictureDisp,
+                                 TRUE, (void **) &pPict);
+  if (hr != S_OK || !pPict)
+    {
+      log_error ("%s:%s: OleCreatePictureIndirect failed: hr=%#lx\n",
+                 SRCNAME, __func__, hr);
+      return -1;
+    }
+
+  result->pdispVal = pPict;
+  result->vt = VT_DISPATCH;
+
+  /*
+  GdiplusShutdown (gdiplusToken);
+  */
+
+  return S_OK;
+}
diff --git a/src/ribbon-callbacks.h b/src/ribbon-callbacks.h
index 547e17d..3eed831 100644
--- a/src/ribbon-callbacks.h
+++ b/src/ribbon-callbacks.h
@@ -22,10 +22,20 @@
 
 #include "gpgoladdin.h"
 
+/* For the Icon IDS */
+#include "dialogs.h"
+
 /* Id's of our callbacks */
 #define ID_CMD_DECRYPT           2
 #define ID_CMD_ENCRYPT_SELECTION 3
+#define ID_CMD_DECRYPT_SELECTION 4
+#define ID_BTN_CERTMANAGER       IDB_KEY_MANAGER_32
+#define ID_BTN_DECRYPT           IDB_DECRYPT_16
+#define ID_BTN_DECRYPT_LARGE     IDB_DECRYPT_32
+#define ID_BTN_ENCRYPT           IDB_ENCRYPT_16
 
 HRESULT decryptAttachments (LPDISPATCH ctrl);
 HRESULT encryptSelection (LPDISPATCH ctrl);
+HRESULT decryptSelection (LPDISPATCH ctrl);
+HRESULT getIcon (int id, int size, VARIANT* result);
 #endif

commit bd44cdf7984cc6e41c6b390577626a6c60c8ae75
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Wed Jul 10 17:24:50 2013 +0000

    Fix debug output in dump_excepinfo
    
        One line was accidentally removed.
    
        * src/oomhelp.cpp (dump_excepinfo): Add source line.
    
    --
      Source is actually pretty important as it tells you where
      your exception occured like "Microsoft Word" even if you originally
      started in the OOM.

diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp
index c660629..59e5cdb 100644
--- a/src/oomhelp.cpp
+++ b/src/oomhelp.cpp
@@ -111,6 +111,7 @@ dump_excepinfo (EXCEPINFO err)
   log_debug ("%s:%s: Dumping exception: \n"
              "              wCode: 0x%x\n"
              "              wReserved: 0x%x\n"
+             "              source: %S\n"
              "              desc: %S\n"
              "              help: %S\n"
              "              helpCtx: 0x%x\n"

commit 76061280cb9e28971e05b473b1a0d771dc592ae8
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Wed Jul 10 17:23:43 2013 +0000

    Use CMS object detection from GPA
    
        * src/common.c, src/common.h: Remove old tlv parser code which
        was the base for the gpa implementation.
        * src/mapihelp.cpp, src/mimeparser.c: Use new macro names
        * src/parsetlv.c, src/parsetlv.h, src/filetype.c, src/filetype.h:
        New. Taken from GPA revision 7a5b070
        * src/Makefile.am: Add new files
    
    --
        The filetype code can be used to detect the protocol of decryped
        content and will be used in decrypt selection.

diff --git a/src/Makefile.am b/src/Makefile.am
index 4c59507..18c1355 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -81,7 +81,9 @@ gpgol_SOURCES = \
 	cmdbarcontrols.cpp cmdbarcontrols.h \
 	w32-gettext.c w32-gettext.h \
 	gpgoladdin.cpp gpgoladdin.h \
-	ribbon-callbacks.cpp ribbon-callbacks.h
+	ribbon-callbacks.cpp ribbon-callbacks.h \
+	parsetlv.c parsetlv.h \
+	filetype.c filetype.h
 
 
 #treeview_SOURCES = treeview.c
diff --git a/src/common.c b/src/common.c
index b422154..fa75d52 100644
--- a/src/common.c
+++ b/src/common.c
@@ -921,84 +921,6 @@ gpgol_spawn_detached (const char *cmdline)
 
 
 
-
-/* Simple but pretty complete ASN.1 BER parser.  Parse the data at the
-   address of BUFFER with a length given at the address of SIZE.  On
-   success return 0 and update BUFFER and SIZE to point to the value.
-   Do not update them on error.  The information about the object are
-   stored in the caller allocated TI structure.  */
-int
-parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti)
-{
-  int c;
-  unsigned long tag;
-  const unsigned char *buf = (const unsigned char *)(*buffer);
-  size_t length = *size;
-
-  ti->cls = 0;
-  ti->tag = 0;
-  ti->is_cons = 0;
-  ti->is_ndef = 0;
-  ti->length = 0;
-  ti->nhdr = 0;
-
-  if (!length)
-    return -1;
-  c = *buf++; length--; ++ti->nhdr;
-
-  ti->cls = (c & 0xc0) >> 6;
-  ti->is_cons = !!(c & 0x20);
-  tag = c & 0x1f;
-
-  if (tag == 0x1f)
-    {
-      tag = 0;
-      do
-        {
-          tag <<= 7;
-          if (!length)
-            return -1;
-          c = *buf++; length--; ++ti->nhdr;
-          tag |= c & 0x7f;
-        }
-      while (c & 0x80);
-    }
-  ti->tag = tag;
-
-  if (!length)
-    return -1;
-  c = *buf++; length--; ++ti->nhdr;
-
-  if ( !(c & 0x80) )
-    ti->length = c;
-  else if (c == 0x80)
-    ti->is_ndef = 1;
-  else if (c == 0xff)
-    return -1;
-  else
-    {
-      unsigned long len = 0;
-      int count = (c & 0x7f);
-
-      if (count > sizeof (len) || count > sizeof (size_t))
-        return -1;
-
-      for (; count; count--)
-        {
-          len <<= 8;
-          if (!length)
-            return -1;
-          c = *buf++; length--; ++ti->nhdr;
-          len |= c & 0xff;
-        }
-      ti->length = len;
-    }
-  
-  *buffer = buf;
-  *size = length;
-  return 0;
-}
-
 /* Percent-escape the string STR by replacing colons with '%3a'.  If
    EXTRA is not NULL all characters in it are also escaped. */
 char *
diff --git a/src/common.h b/src/common.h
index 6097568..ede4d2b 100644
--- a/src/common.h
+++ b/src/common.h
@@ -175,27 +175,6 @@ typedef struct b64_state_s b64_state_t;
 /* Macros to used in conditionals to enable debug output.  */
 #define debug_commands    (opt.enable_debug & DBG_COMMANDS)
 
-
-/* Type and constants used with parse_tlv.  */
-struct tlvinfo_s
-{
-  int cls;            /* The class of the tag.  */
-  int tag;            /* The tag.  */
-  int is_cons;        /* True if it is a constructed object.  */
-  int is_ndef;        /* True if the object has an indefinite length.  */
-  size_t length;      /* The length of the value.  */
-  size_t nhdr;        /* The number of octets in the header (tag,length). */
-};
-typedef struct tlvinfo_s tlvinfo_t;
-#define MY_ASN_CLASS_UNIVERSAL   0
-#define MY_ASN_CLASS_APPLICATION 1
-#define MY_ASN_CLASS_CONTEXT     2
-#define MY_ASN_CLASS_PRIVATE     3
-#define MY_ASN_TAG_OBJECT_ID     6
-#define MY_ASN_TAG_SEQUENCE     16
-
-
-
 /*-- common.c --*/
 void set_global_hinstance (HINSTANCE hinst);
 void center_window (HWND childwnd, HWND style);
@@ -217,9 +196,6 @@ char *generate_boundary (char *buffer);
 
 int gpgol_spawn_detached (const char *cmdline);
 
-int parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti);
-
-
 /*-- recipient-dialog.c --*/
 unsigned int recipient_dialog_box (gpgme_key_t **ret_rset);
 unsigned int recipient_dialog_box2 (gpgme_key_t *fnd, char **unknown,
diff --git a/src/filetype.c b/src/filetype.c
new file mode 100644
index 0000000..c59dde7
--- /dev/null
+++ b/src/filetype.c
@@ -0,0 +1,150 @@
+/* filetype.c -  Identify file types
+ * Copyright (C) 2012 g10 Code GmbH
+ *
+ * This file 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.
+ *
+ * This file 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parsetlv.h"
+#include "filetype.h"
+
+
+/* The size of the buffer we use to identify CMS objects.  */
+#define CMS_BUFFER_SIZE 2048
+
+
+/* Warning: DATA may be binary but there must be a Nul before DATALEN.  */
+static int
+detect_cms (const char *data, size_t datalen)
+{
+  tlvinfo_t ti;
+  const char *s;
+  size_t n;
+
+  if (datalen < 24) /* Object is probably too short for CMS.  */
+    return 0;
+
+  s = data;
+  n = datalen;
+  if (parse_tlv (&s, &n, &ti))
+    goto try_pgp; /* Not properly BER encoded.  */
+  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
+        && ti.is_cons))
+    goto try_pgp; /* A CMS object always starts witn a sequence.  */
+  if (parse_tlv (&s, &n, &ti))
+    goto try_pgp; /* Not properly BER encoded.  */
+  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_OBJECT_ID
+        && !ti.is_cons && ti.length) || ti.length > n)
+    goto try_pgp; /* This is not an OID as expected.  */
+  if (ti.length == 9)
+    {
+      if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x03", 9))
+        return 1; /* Encrypted (aka Enveloped Data).  */
+      if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02", 9))
+        return 1; /* Signed.  */
+    }
+
+ try_pgp:
+  /* Check whether this might be a non-armored PGP message.  We need
+     to do this before checking for armor lines, so that we don't get
+     fooled by armored messages inside a signed binary PGP message.  */
+  if ((data[0] & 0x80))
+    {
+      /* That might be a binary PGP message.  At least it is not plain
+         ASCII.  Of course this might be certain lead-in text of
+         armored CMS messages.  However, I am not sure whether this is
+         at all defined and in any case it is uncommon.  Thus we don't
+         do any further plausibility checks but stupidly assume no CMS
+         armored data will follow.  */
+      return 0;
+    }
+
+  /* Now check whether there are armor lines.  */
+  for (s = data; s && *s; s = (*s=='\n')?(s+1):((s=strchr (s,'\n'))?(s+1):s))
+    {
+      if (!strncmp (s, "-----BEGIN ", 11))
+        {
+          if (!strncmp (s+11, "PGP ", 4))
+            return 0; /* This is PGP */
+          return 1; /* Not PGP, thus we assume CMS.  */
+        }
+    }
+
+  return 0;
+}
+
+
+/* Return true if the file FNAME looks like an CMS file.  There is no
+   error return, just a best effort try to identify CMS in a file with
+   a CMS object.  */
+int
+is_cms_file (const char *fname)
+{
+  int result;
+  FILE *fp;
+  char *data;
+  size_t datalen;
+
+  fp = fopen (fname, "rb");
+  if (!fp)
+    return 0; /* Not found - can't be a CMS file.  */
+
+  data = malloc (CMS_BUFFER_SIZE);
+  if (!data)
+    {
+      fclose (fp);
+      return 0; /* Oops */
+    }
+
+  datalen = fread (data, 1, CMS_BUFFER_SIZE - 1, fp);
+  data[datalen] = 0;
+  fclose (fp);
+
+  result = detect_cms (data, datalen);
+  free (data);
+  return result;
+}
+
+
+/* Return true if the data (DATA,DATALEN) looks like an CMS object.
+   There is no error return, just a best effort try to identify CMS.  */
+int
+is_cms_data (const char *data, size_t datalen)
+{
+  int result;
+  char *buffer;
+
+  if (datalen < 24)
+    return 0; /* Too short - don't bother to copy the buffer.  */
+
+  if (datalen > CMS_BUFFER_SIZE - 1)
+    datalen = CMS_BUFFER_SIZE - 1;
+
+  buffer = malloc (datalen + 1);
+  if (!buffer)
+    return 0; /* Oops */
+  memcpy (buffer, data, datalen);
+  buffer[datalen] = 0;
+
+  result = detect_cms (buffer, datalen);
+  free (buffer);
+  return result;
+}
diff --git a/src/filetype.h b/src/filetype.h
new file mode 100644
index 0000000..ae24726
--- /dev/null
+++ b/src/filetype.h
@@ -0,0 +1,35 @@
+/* filetype.h -  Identify file types
+ * Copyright (C) 2012 g10 Code GmbH
+ *
+ * This file 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.
+ *
+ * This file 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 FILETYPE_H
+#define FILETYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+}
+#endif
+#endif
+
+int is_cms_file (const char *fname);
+int is_cms_data (const char *data, size_t datalen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*FILETYPE_H*/
diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp
index 0385bed..1d6d7c5 100644
--- a/src/mapihelp.cpp
+++ b/src/mapihelp.cpp
@@ -30,6 +30,7 @@
 #include "rfc822parse.h"
 #include "serpent.h"
 #include "mapihelp.h"
+#include "parsetlv.h"
 
 #ifndef CRYPT_E_STREAM_INSUFFICIENT_DATA
 #define CRYPT_E_STREAM_INSUFFICIENT_DATA 0x80091011
@@ -761,12 +762,12 @@ is_really_cms_encrypted (LPMESSAGE message)
   n = nread;
   if (parse_tlv (&p, &n, &ti))
     goto leave;
-  if (!(ti.cls == MY_ASN_CLASS_UNIVERSAL && ti.tag == MY_ASN_TAG_SEQUENCE
+  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
         && ti.is_cons) )
     goto leave;
   if (parse_tlv (&p, &n, &ti))
     goto leave;
-  if (!(ti.cls == MY_ASN_CLASS_UNIVERSAL && ti.tag == MY_ASN_TAG_OBJECT_ID
+  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_OBJECT_ID
         && !ti.is_cons && ti.length) || ti.length > n)
     goto leave;
   /* Now is this enveloped data (1.2.840.113549.1.7.3)
diff --git a/src/mimeparser.c b/src/mimeparser.c
index b43bead..e885729 100644
--- a/src/mimeparser.c
+++ b/src/mimeparser.c
@@ -42,6 +42,7 @@
 #include "mapihelp.h"
 #include "serpent.h"
 #include "mimeparser.h"
+#include "parsetlv.h"
 
 
 #define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
@@ -234,12 +235,12 @@ is_cms_signed_data (const char *buffer, size_t length)
           
   if (parse_tlv (&p, &n, &ti))
     return 0;
-  if (!(ti.cls == MY_ASN_CLASS_UNIVERSAL && ti.tag == MY_ASN_TAG_SEQUENCE
+  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
         && ti.is_cons) )
     return 0;
   if (parse_tlv (&p, &n, &ti))
     return 0;
-  if (!(ti.cls == MY_ASN_CLASS_UNIVERSAL && ti.tag == MY_ASN_TAG_OBJECT_ID
+  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_OBJECT_ID
         && !ti.is_cons && ti.length) || ti.length > n)
     return 0;
   if (ti.length == 9 && !memcmp (p, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02", 9))
diff --git a/src/parsetlv.c b/src/parsetlv.c
new file mode 100644
index 0000000..afdc522
--- /dev/null
+++ b/src/parsetlv.c
@@ -0,0 +1,103 @@
+/* parsetlv.c -  ASN.1 TLV functions
+ * Copyright (C) 2005, 2007, 2008, 2012 g10 Code GmbH
+ *
+ * This file 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.
+ *
+ * This file 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parsetlv.h"
+
+
+/* Simple but pretty complete ASN.1 BER parser.  Parse the data at the
+   address of BUFFER with a length given at the address of SIZE.  On
+   success return 0 and update BUFFER and SIZE to point to the value.
+   Do not update them on error.  The information about the object are
+   stored in the caller allocated TI structure.  */
+int
+parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti)
+{
+  int c;
+  unsigned long tag;
+  const unsigned char *buf = (const unsigned char *)(*buffer);
+  size_t length = *size;
+
+  ti->cls = 0;
+  ti->tag = 0;
+  ti->is_cons = 0;
+  ti->is_ndef = 0;
+  ti->length = 0;
+  ti->nhdr = 0;
+
+  if (!length)
+    return -1;
+  c = *buf++; length--; ++ti->nhdr;
+
+  ti->cls = (c & 0xc0) >> 6;
+  ti->is_cons = !!(c & 0x20);
+  tag = c & 0x1f;
+
+  if (tag == 0x1f)
+    {
+      tag = 0;
+      do
+        {
+          tag <<= 7;
+          if (!length)
+            return -1;
+          c = *buf++; length--; ++ti->nhdr;
+          tag |= c & 0x7f;
+        }
+      while (c & 0x80);
+    }
+  ti->tag = tag;
+
+  if (!length)
+    return -1;
+  c = *buf++; length--; ++ti->nhdr;
+
+  if ( !(c & 0x80) )
+    ti->length = c;
+  else if (c == 0x80)
+    ti->is_ndef = 1;
+  else if (c == 0xff)
+    return -1;
+  else
+    {
+      unsigned long len = 0;
+      int count = (c & 0x7f);
+
+      if (count > sizeof (len) || count > sizeof (size_t))
+        return -1;
+
+      for (; count; count--)
+        {
+          len <<= 8;
+          if (!length)
+            return -1;
+          c = *buf++; length--; ++ti->nhdr;
+          len |= c & 0xff;
+        }
+      ti->length = len;
+    }
+
+  *buffer = buf;
+  *size = length;
+  return 0;
+}
diff --git a/src/parsetlv.h b/src/parsetlv.h
new file mode 100644
index 0000000..8ae548b
--- /dev/null
+++ b/src/parsetlv.h
@@ -0,0 +1,55 @@
+/* parsetlv.h -  TLV functions defintions
+ * Copyright (C) 2012 g10 Code GmbH
+ *
+ * This file 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.
+ *
+ * This file 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 PARSETLV_H
+#define PARSETLV_H
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+}
+#endif
+#endif
+
+/* ASN.1 constants.  */
+#define ASN1_CLASS_UNIVERSAL   0
+#define ASN1_CLASS_APPLICATION 1
+#define ASN1_CLASS_CONTEXT     2
+#define ASN1_CLASS_PRIVATE     3
+#define ASN1_TAG_OBJECT_ID     6
+#define ASN1_TAG_SEQUENCE     16
+
+
+/* Object used with parse_tlv.  */
+struct tlvinfo_s
+{
+  int cls;            /* The class of the tag.  */
+  int tag;            /* The tag.  */
+  int is_cons;        /* True if it is a constructed object.  */
+  int is_ndef;        /* True if the object has an indefinite length.  */
+  size_t length;      /* The length of the value.  */
+  size_t nhdr;        /* The number of octets in the header (tag,length). */
+};
+typedef struct tlvinfo_s tlvinfo_t;
+
+/*-- parsetlv.c --*/
+int parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*PARSETLV_H*/

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

Summary of changes:
 src/Makefile.am          |    4 +-
 src/common.c             |   78 --------------
 src/common.h             |   24 -----
 src/filetype.c           |  150 +++++++++++++++++++++++++++
 src/filetype.h           |   35 ++++++
 src/gpgoladdin.cpp       |   68 ++++++++-----
 src/mapihelp.cpp         |    5 +-
 src/mimeparser.c         |    5 +-
 src/oomhelp.cpp          |    1 +
 src/parsetlv.c           |  103 ++++++++++++++++++
 src/parsetlv.h           |   55 ++++++++++
 src/ribbon-callbacks.cpp |  257 ++++++++++++++++++++++++++++++++++++++++++++++
 src/ribbon-callbacks.h   |   10 ++
 13 files changed, 661 insertions(+), 134 deletions(-)
 create mode 100644 src/filetype.c
 create mode 100644 src/filetype.h
 create mode 100644 src/parsetlv.c
 create mode 100644 src/parsetlv.h


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




More information about the Gnupg-commits mailing list