[svn] GPGol - r104 - in trunk: . src

svn author wk cvs at cvs.gnupg.org
Thu Sep 22 18:29:20 CEST 2005


Author: wk
Date: 2005-09-22 18:29:19 +0200 (Thu, 22 Sep 2005)
New Revision: 104

Modified:
   trunk/ChangeLog
   trunk/NEWS
   trunk/README
   trunk/TODO
   trunk/configure.ac
   trunk/src/ChangeLog
   trunk/src/common.c
   trunk/src/engine-gpgme.c
   trunk/src/gpgmsg.cpp
   trunk/src/intern.h
   trunk/src/pgpmime.c
   trunk/src/pgpmime.h
   trunk/src/rfc822parse.c
Log:
Allow saving of PGP/MIME encrypted attachments.

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/ChangeLog	2005-09-22 16:29:19 UTC (rev 104)
@@ -1,3 +1,7 @@
+2005-09-22  Werner Koch  <wk at g10code.com>
+
+	Released 0.9.2.
+
 2005-09-19  Werner Koch  <wk at g10code.com>
 
 	Released 0.9.1.

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/NEWS	2005-09-22 16:29:19 UTC (rev 104)
@@ -1,3 +1,9 @@
+Noteworthy changes for version 0.9.2 (2005-09-22)
+=================================================
+
+* Saving attachments from PGP/MIME encrypted messages works.
+
+
 Noteworthy changes for version 0.9.1 (2005-09-19)
 =================================================
 

Modified: trunk/README
===================================================================
--- trunk/README	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/README	2005-09-22 16:29:19 UTC (rev 104)
@@ -9,12 +9,12 @@
            DLL will be named "gpgol.dll".  It is to be build using
            the Mingw toolchain.
 
-To install this plugin, copy it to some directory (e.g. where gpg lives),
-make sure that the libgpg-error.dll and gpgme.dll are available in a
-directory where Windows searches for DLLs (e.g. c:\winnt\system32),
-stop Outlook, run the command "regsvr32 gpgol.dll" and start
-Outlook. You should then find a new tab named "GnuPG" in Outlook's
-option menu.
+To install this plugin, copy "gpgol.dll" to some directory (e.g. where
+gpg lives), make sure that the libgpg-error.dll and gpgme.dll are
+available in a directory where Windows searches for DLLs
+(e.g. c:\winnt\system32), stop Outlook, run the command "regsvr32
+gpgol.dll" and start Outlook. You should then find a new tab named
+"GnuPG" in Outlook's option menu.
 
 Note: For building in src/ you need to throw an original mapi32.dll
 into this directory.  This is due to a bug in the binutils: ld is not

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/TODO	2005-09-22 16:29:19 UTC (rev 104)
@@ -16,4 +16,6 @@
   detect whether this is an encrypted message and change the
   MessageClass accordingly.
 
+* Allow for symmetric encryption.
 
+

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/configure.ac	2005-09-22 16:29:19 UTC (rev 104)
@@ -15,7 +15,7 @@
 
 # Version number: Remember to change it immediately *after* a release.
 #                 Add a "-cvs" prefix for non-released code.
-AC_INIT(gpgol, 0.9.1, bug-gpgol at g10code.com)
+AC_INIT(gpgol, 0.9.2, bug-gpgol at g10code.com)
 
 NEED_GPGME_API=1
 NEED_GPGME_VERSION=1.1.0

Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/src/ChangeLog	2005-09-22 16:29:19 UTC (rev 104)
@@ -1,3 +1,18 @@
+2005-09-22  Werner Koch  <wk at g10code.com>
+
+	* engine-gpgme.c (decrypt_stream): Use gpgme_op_decrypt_verify.
+
+	* gpgmsg.cpp (gatherAttachmentInfo): Ignore attestations when
+	checking for pgp/mime.
+
+	* pgpmime.c (pgpmime_decrypt): Added arg HWND.
+	(message_cb, plaintext_handler): Write attachments.
+	* pgpmime.c (base64_decode): New.
+	* rfc822parse.c (parse_field): Treat Content-Disposition special.
+
+	* gpgmsg.cpp (get_save_filename): Moved to ..
+	* common.c (get_save_filename): .. here.
+
 2005-09-20  Timo Schulz  <ts at g10code.com>
 
 	* attach.c: New.

Modified: trunk/src/common.c
===================================================================
--- trunk/src/common.c	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/src/common.c	2005-09-22 16:29:19 UTC (rev 104)
@@ -72,6 +72,41 @@
 }
 
 
+
+/* Return a filename to be used for saving an attachment. Returns a
+   malloced string on success. HWND is the current Window and SRCNAME
+   the filename to be used as suggestion.  On error (i.e. cancel) NULL
+   is returned. */
+char *
+get_save_filename (HWND root, const char *srcname)
+				     
+{
+  char filter[] = "All Files (*.*)\0*.*\0\0";
+  char fname[MAX_PATH+1];
+  OPENFILENAME ofn;
+
+  memset (fname, 0, sizeof (fname));
+  strncpy (fname, srcname, MAX_PATH-1);
+  fname[MAX_PATH] = 0;  
+  
+
+  memset (&ofn, 0, sizeof (ofn));
+  ofn.lStructSize = sizeof (ofn);
+  ofn.hwndOwner = root;
+  ofn.lpstrFile = fname;
+  ofn.nMaxFile = MAX_PATH;
+  ofn.lpstrFileTitle = NULL;
+  ofn.nMaxFileTitle = 0;
+  ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
+  ofn.lpstrTitle = "GPG - Save decrypted attachment";
+  ofn.lpstrFilter = filter;
+
+  if (GetSaveFileName (&ofn))
+    return xstrdup (fname);
+  return NULL;
+}
+
+
 void
 out_of_core (void)
 {

Modified: trunk/src/engine-gpgme.c
===================================================================
--- trunk/src/engine-gpgme.c	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/src/engine-gpgme.c	2005-09-22 16:29:19 UTC (rev 104)
@@ -592,7 +592,7 @@
 
   gpgme_set_passphrase_cb (ctx, passphrase_callback_box, &dk);
   dk.ctx = ctx;
-  err = gpgme_op_decrypt (ctx, in, out);
+  err = gpgme_op_decrypt_verify (ctx, in, out);
   dk.ctx = NULL;
   update_passphrase_cache (err, &dk);
   /* Act upon the result of the decryption operation. */

Modified: trunk/src/gpgmsg.cpp
===================================================================
--- trunk/src/gpgmsg.cpp	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/src/gpgmsg.cpp	2005-09-22 16:29:19 UTC (rev 104)
@@ -970,7 +970,8 @@
           return gpg_error (GPG_ERR_GENERAL);
         }
 
-      err = pgpmime_decrypt (from, opt.passwd_ttl, &plaintext, attestation);
+      err = pgpmime_decrypt (from, opt.passwd_ttl, &plaintext, attestation,
+                             hwnd);
       
       from->Release ();
       att->Release ();
@@ -1690,40 +1691,6 @@
 
 
 
-
-/* Return a filename to be used for saving an attachment. Returns an
-   malloced string on success. HWND is the current Window and SRCNAME
-   the filename to be used as suggestion.  On error; i.e. cancel NULL
-   is returned. */
-static char *
-get_save_filename (HWND root, const char *srcname)
-				     
-{
-  char filter[] = "All Files (*.*)\0*.*\0\0";
-  char fname[MAX_PATH+1];
-  OPENFILENAME ofn;
-
-  memset (fname, 0, sizeof (fname));
-  strncpy (fname, srcname, MAX_PATH-1);
-  fname[MAX_PATH] = 0;  
-  
-
-  memset (&ofn, 0, sizeof (ofn));
-  ofn.lStructSize = sizeof (ofn);
-  ofn.hwndOwner = root;
-  ofn.lpstrFile = fname;
-  ofn.nMaxFile = MAX_PATH;
-  ofn.lpstrFileTitle = NULL;
-  ofn.nMaxFileTitle = 0;
-  ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
-  ofn.lpstrTitle = "GPG - Save decrypted attachment";
-  ofn.lpstrFilter = filter;
-
-  if (GetSaveFileName (&ofn))
-    return xstrdup (fname);
-  return NULL;
-}
-
 
 /* Read the attachment ATT and try to detect whether this is a PGP
    Armored message.  METHOD is the attach method of ATT.  Returns 0 if
@@ -1793,6 +1760,7 @@
   attach_info_t table;
   unsigned int pos, n_attach;
   const char *s;
+  unsigned int attestation_count = 0;
 
   is_pgpmime = false;
   has_attestation = false;
@@ -1840,7 +1808,10 @@
           && !stricmp (table[pos].filename, "GPGol-Attestation.txt")
           && table[pos].content_type
           && !stricmp (table[pos].content_type, "text/plain"))
-        has_attestation = true;
+        {
+          has_attestation = true;
+          attestation_count++;
+        }
 
       att->Release ();
     }
@@ -1913,9 +1884,12 @@
   /* Simple check whether this is PGP/MIME encrypted.  At least with
      OL2003 the content-type of the body is also correctly set but we
      don't make use of this as it is not clear whether this is true
-     for othyer storage providers. */
+     for other storage providers.  We use a hack to ignore extra
+     attesttation attachments: Those are assume to come after the both
+     PGP/MIME parts. */
   if (!opt.compat.no_pgpmime
-      && pos == 2 && table[0].content_type && table[1].content_type
+      && pos == 2 + attestation_count
+      && table[0].content_type && table[1].content_type
       && !stricmp (table[0].content_type, "application/pgp-encrypted")
       && !stricmp (table[1].content_type, "application/octet-stream")
       && isPgpmimeVersionPart (0))
@@ -1932,9 +1906,9 @@
 
 
 
-/* Verify the ATTachment at attachments and table position POS_DATA
-   agains the signature at position POS_SIG.  Display the status for
-   each signature. */
+/* Verify the attachment as recorded in TABLE and at table position
+   POS_DATA against the signature at position POS_SIG.  Display the
+   status for each signature. */
 void
 GpgMsgImpl::verifyAttachment (HWND hwnd, attach_info_t table,
                               unsigned int pos_data,

Modified: trunk/src/intern.h
===================================================================
--- trunk/src/intern.h	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/src/intern.h	2005-09-22 16:29:19 UTC (rev 104)
@@ -120,6 +120,7 @@
 /*-- common.c --*/
 void set_global_hinstance (HINSTANCE hinst);
 void center_window (HWND childwnd, HWND style);
+char *get_save_filename (HWND root, const char *srcname);
 
 HRESULT w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e);
 

Modified: trunk/src/pgpmime.c
===================================================================
--- trunk/src/pgpmime.c	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/src/pgpmime.c	2005-09-22 16:29:19 UTC (rev 104)
@@ -33,7 +33,9 @@
 #include <assert.h>
 #include <string.h>
 
+#define COBJMACROS
 #include <windows.h>
+#include <objidl.h> /* For IStream. */
 
 #include <gpgme.h>
 
@@ -41,6 +43,7 @@
 #include "mymapitags.h"
 
 #include "rfc822parse.h"
+#include "intern.h"
 #include "util.h"
 #include "pgpmime.h"
 #include "engine.h"
@@ -50,20 +53,66 @@
    only for 1000 bytes; thus 2000 seems to be a reasonable value. */
 #define LINEBUFSIZE 2000
 
+/* The reverse base-64 list used for base-64 decoding. */
+static unsigned char const asctobin[256] = {
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 
+  0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
+  0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 
+  0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 
+  0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 
+  0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+  0xff, 0xff, 0xff, 0xff
+};
+
+
+
+
 /* The context object we use to track information. */
 struct pgpmime_context
 {
+  HWND hwnd;          /* A window handle to be used for message boxes etc. */
   rfc822parse_t msg;  /* The handle of the RFC822 parser. */
 
   int nesting_level;  /* Current MIME nesting level. */
   int in_data;        /* We are currently in data (body or attachment). */
 
   
-  gpgme_data_t body;  /* NULL or a data object used to collect the
-                         body part we are going to display later. */
-  int collect_body;   /* True if we are collecting the body lines. */
-  int is_qp_encoded;  /* Current part is QP encoded. */
+  gpgme_data_t body;      /* NULL or a data object used to collect the
+                             body part we are going to display later. */
+  int collect_body;       /* True if we are collecting the body lines. */
+  int collect_attachment; /* True if we are collecting an attachment. */
+  int is_qp_encoded;      /* Current part is QP encoded. */
+  int is_base64_encoded;  /* Current part is base 64 encoded. */
 
+  int part_counter;       /* Counts the number of processed parts. */
+  char *filename;         /* Current filename (malloced) or NULL. */
+
+  LPSTREAM outstream;     /* NULL or a stream to write a part to. */
+
+  /* Helper to keep the state of the base64 decoder. */
+  struct 
+  {
+    int idx;
+    unsigned char val;
+    int stop_seen;
+    int invalid_encoding;
+  } base64;
+
   int line_too_long;  /* Indicates that a received line was too long. */
   int parser_error;   /* Indicates that we encountered a error from
                          the parser. */
@@ -98,7 +147,73 @@
 }
 
 
+/* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Returns
+   the new length of the buffer. CTX is required to return errors and
+   to maintain state of the decoder.  */
+static size_t
+base64_decode (pgpmime_context_t ctx, char *buffer, size_t length)
+{
+  int idx = ctx->base64.idx;
+  unsigned char val = ctx->base64.val;
+  int c;
+  char *d, *s;
 
+  if (ctx->base64.stop_seen)
+    return 0;
+
+  for (s=d=buffer; length; length--, s++)
+    {
+      if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
+        continue;
+      if (*s == '=')
+        { 
+          /* Pad character: stop */
+          if (idx == 1)
+            *d++ = val; 
+          ctx->base64.stop_seen = 1;
+          break;
+        }
+
+      if ((c = asctobin[*(unsigned char *)s]) == 255) 
+        {
+          if (!ctx->base64.invalid_encoding)
+            log_debug ("%s: invalid base64 character %02X at pos %d skipped\n",
+                       __func__, *(unsigned char*)s, (int)(s-buffer));
+          ctx->base64.invalid_encoding = 1;
+          continue;
+        }
+
+      switch (idx) 
+        {
+        case 0: 
+          val = c << 2;
+          break;
+        case 1: 
+          val |= (c>>4)&3;
+          *d++ = val;
+          val = (c<<4)&0xf0;
+          break;
+        case 2: 
+          val |= (c>>2)&15;
+          *d++ = val;
+          val = (c<<6)&0xc0;
+          break;
+        case 3: 
+          val |= c&0x3f;
+          *d++ = val;
+          break;
+        }
+      idx = (idx+1) % 4;
+    }
+
+  
+  ctx->base64.idx = idx;
+  ctx->base64.val = val;
+  return d - buffer;
+}
+
+
+
 /* Print the message event EVENT. */
 static void
 debug_message_event (pgpmime_context_t ctx, rfc822parse_event_t event)
@@ -136,6 +251,7 @@
 message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
 {
   pgpmime_context_t ctx = opaque;
+  HRESULT hr;
 
   debug_message_event (ctx, event);
   if (event == RFC822PARSE_T2BODY)
@@ -144,6 +260,7 @@
       const char *s1, *s2;
       size_t off;
       char *p;
+      int is_text = 0;
 
       field = rfc822parse_parse_field (msg, "Content-Type", -1);
       if (field)
@@ -156,33 +273,117 @@
 
               if (!strcmp (s1, "multipart"))
                 {
-                  if (!strcmp (s2, "signed"))
-                    ;
-                  else if (!strcmp (s2, "encrypted"))
-                    ;
+                  /* We don't care about the top level multipart layer
+                     but wait until it comes to the actual parts which
+                     then will get stored as attachments.
+
+                     For now encapsulated signed or encrypted
+                     containers are not processed in a special way as
+                     they should. */
                 }
               else if (!strcmp (s1, "text"))
                 {
-                  if (!ctx->body)
-                    {
-                      if (!gpgme_data_new (&ctx->body))
-                        ctx->collect_body = 1;
-                    }
+                  is_text = 1;
                 }
+              else /* Other type. */
+                {
+                  ctx->collect_attachment = 1;
+                }
+
             }
           
           rfc822parse_release_field (field);
         }
+      else
+        {
+          /* No content-type at all indicates text/plain. */
+          is_text = 1;
+        }
       ctx->in_data = 1;
 
+      /* Need to figure out the encoding. */
       ctx->is_qp_encoded = 0;
+      ctx->is_base64_encoded = 0;
       p = rfc822parse_get_field (msg, "Content-Transfer-Encoding", -1, &off);
       if (p)
         {
           if (!stricmp (p+off, "quoted-printable"))
             ctx->is_qp_encoded = 1;
+          else if (!stricmp (p+off, "base64"))
+            {
+              ctx->is_base64_encoded = 1;
+              ctx->base64.idx = 0;
+              ctx->base64.val = 0;
+              ctx->base64.stop_seen = 0;
+              ctx->base64.invalid_encoding = 0;
+            }
           free (p);
         }
+
+      /* If this is a text part, decide whether we treat it as our body. */
+      if (is_text)
+        {
+          /* If this is the first text part at all we will
+             start to collect it and use it later as the
+             regular body.  An initialized ctx->BODY is an
+             indication that this is not the first text part -
+             we treat such a part like any other
+             attachment. */
+          if (!ctx->body)
+            {
+              if (!gpgme_data_new (&ctx->body))
+                ctx->collect_body = 1;
+            }
+          else
+            ctx->collect_attachment = 1;
+        }
+
+      /* Now that if we have an attachment prepare for writing it out. */
+      if (ctx->collect_attachment)
+        {
+          p = NULL;
+          field = rfc822parse_parse_field (msg, "Content-Disposition", -1);
+          if (field)
+            {
+              s1 = rfc822parse_query_parameter (field, "filename", 0);
+              if (s1)
+                p = xstrdup (s1);
+              rfc822parse_release_field (field);
+            }
+          if (!p)
+            {
+              p = xmalloc (50);
+              snprintf (p, 49, "unnamed-%d.dat", ctx->part_counter);
+            }
+          if (ctx->outstream)
+            {
+              IStream_Release (ctx->outstream);
+              ctx->outstream = NULL;
+            }
+        tryagain:
+          xfree (ctx->filename);
+          ctx->filename = get_save_filename (ctx->hwnd, p);
+          if (!ctx->filename)
+            ctx->collect_attachment = 0; /* User das not want to save it. */
+          else
+            {
+              hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
+                                     (STGM_CREATE | STGM_READWRITE),
+                                     ctx->filename, NULL, &ctx->outstream); 
+              if (FAILED (hr)) 
+                {
+                  log_error ("%s:%s: can't create file `%s': hr=%#lx\n",
+                             __FILE__, __func__, ctx->filename, hr); 
+                  MessageBox (ctx->hwnd, "Error creating file\n"
+                              "Please select anther one",
+                              "I/O-Error", MB_ICONERROR|MB_OK);
+                  goto tryagain;
+                }
+              log_debug ("%s:%s: writing attachment to `%s'\n",
+                         __FILE__, __func__, ctx->filename); 
+            }
+          xfree (p);
+        }
     }
   else if (event == RFC822PARSE_LEVEL_DOWN)
     {
@@ -203,10 +404,19 @@
     {
       ctx->in_data = 0;
       ctx->collect_body = 0;
+      ctx->collect_attachment = 0;
+      xfree (ctx->filename);
+      ctx->filename = NULL;
+      if (ctx->outstream)
+        {
+          IStream_Commit (ctx->outstream, 0);
+          IStream_Release (ctx->outstream);
+          ctx->outstream = NULL;
+        }
     }
   else if (event == RFC822PARSE_BEGIN_HEADER)
     {
-      
+      ctx->part_counter++;
     }
 
   return 0;
@@ -219,12 +429,12 @@
 {
   pgpmime_context_t ctx = handle;
   const char *s;
-  size_t n, pos;
+  size_t nleft, pos, len;
 
   s = buffer;
   pos = ctx->linebufpos;
-  n = size;
-  for (; n ; n--, s++)
+  nleft = size;
+  for (; nleft ; nleft--, s++)
     {
       if (pos >= ctx->linebufsize)
         {
@@ -250,17 +460,57 @@
 
           if (ctx->in_data && ctx->collect_body && ctx->body)
             {
-              if (ctx->collect_body == 1)
+              /* We are inside the body of the message.  Save it away
+                 to a gpgme data object.  Note that this gets only
+                 used for the first text part. */
+              if (ctx->collect_body == 1)  /* Need to skip the first line. */
                 ctx->collect_body = 2;
               else
                 {
                   if (ctx->is_qp_encoded)
-                    pos = qp_decode (ctx->linebuf, pos);
-                  gpgme_data_write (ctx->body, ctx->linebuf, pos);
-                  gpgme_data_write (ctx->body, "\r\n", 2);
+                    len = qp_decode (ctx->linebuf, pos);
+                  else if (ctx->is_base64_encoded)
+                    len = base64_decode (ctx, ctx->linebuf, pos);
+                  else
+                    len = pos;
+                  if (len)
+                    gpgme_data_write (ctx->body, ctx->linebuf, len);
+                  if (!ctx->is_base64_encoded)
+                    gpgme_data_write (ctx->body, "\r\n", 2);
                 }
             }
+          else if (ctx->in_data && ctx->collect_attachment)
+            {
+              /* We are inside of an attachment part.  Write it out. */
+              if (ctx->collect_attachment == 1)  /* Skip the first line. */
+                ctx->collect_attachment = 2;
+              else if (ctx->outstream)
+                {
+                  HRESULT hr = 0;
 
+                  if (ctx->is_qp_encoded)
+                    len = qp_decode (ctx->linebuf, pos);
+                  else if (ctx->is_base64_encoded)
+                    len = base64_decode (ctx, ctx->linebuf, pos);
+                  else
+                    len = pos;
+                  if (len)
+                    hr = IStream_Write (ctx->outstream, ctx->linebuf,
+                                        len, NULL);
+                  if (!hr && !ctx->is_base64_encoded)
+                    hr = IStream_Write (ctx->outstream, "\r\n", 2, NULL);
+                  if (hr)
+                    {
+                      log_debug ("%s:%s: Write failed: hr=%#lx",
+                                 __FILE__, __func__, hr);
+                      MessageBox (ctx->hwnd, "Error writing file",
+                                  "I/O-Error", MB_ICONERROR|MB_OK);
+                      ctx->parser_error = 1;
+                      return 0; /* Error. */
+                    }
+                }
+            }
+          
           /* Continue with next line. */
           pos = 0;
         }
@@ -275,10 +525,11 @@
    multipart/mixed) and allow saving of all attachments. On success a
    newly allocated body will be stored at BODY.  If ATTESTATION is not
    NULL a text with the result of the signature verification will get
-   printed to it.  */
+   printed to it.  HWND is the window to be used for message box and
+   such. */
 int
 pgpmime_decrypt (LPSTREAM instream, int ttl, char **body,
-                 gpgme_data_t attestation)
+                 gpgme_data_t attestation, HWND hwnd)
 {
   gpg_error_t err;
   struct gpgme_data_cbs cbs;
@@ -292,6 +543,7 @@
 
   ctx = xcalloc (1, sizeof *ctx + LINEBUFSIZE);
   ctx->linebufsize = LINEBUFSIZE;
+  ctx->hwnd = hwnd;
 
   ctx->msg = rfc822parse_open (message_cb, ctx);
   if (!ctx->msg)
@@ -306,7 +558,7 @@
     goto leave;
 
   err = op_decrypt_stream_to_gpgme (instream, plaintext, ttl,
-                                    NULL, NULL);
+                                    NULL, attestation);
   if (!err && (ctx->parser_error || ctx->line_too_long))
     err = gpg_error (GPG_ERR_GENERAL);
 
@@ -326,11 +578,20 @@
     }
 
  leave:
-  rfc822parse_close (ctx->msg);
   if (plaintext)
     gpgme_data_release (plaintext);
-  if (ctx && ctx->body)
-    gpgme_data_release (ctx->body);
-  xfree (ctx);
+  if (ctx)
+    {
+      if (ctx->outstream)
+        {
+          IStream_Revert (ctx->outstream);
+          IStream_Release (ctx->outstream);
+        }
+      rfc822parse_close (ctx->msg);
+      if (ctx->body)
+        gpgme_data_release (ctx->body);
+      xfree (ctx->filename);
+      xfree (ctx);
+    }
   return err;
 }

Modified: trunk/src/pgpmime.h
===================================================================
--- trunk/src/pgpmime.h	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/src/pgpmime.h	2005-09-22 16:29:19 UTC (rev 104)
@@ -29,7 +29,7 @@
 #endif
 
 int pgpmime_decrypt (LPSTREAM instream, int ttl, char **body,
-                     gpgme_data_t attestation);
+                     gpgme_data_t attestation, HWND hwnd);
 
 
 

Modified: trunk/src/rfc822parse.c
===================================================================
--- trunk/src/rfc822parse.c	2005-09-21 06:40:51 UTC (rev 103)
+++ trunk/src/rfc822parse.c	2005-09-22 16:29:19 UTC (rev 104)
@@ -757,7 +757,8 @@
   static const char specials[] = "<>@.,;:\\[]\"()";
   static const char specials2[] = "<>@.,;:";
   static const char tspecials[] = "/?=<>@,;:\\[]\"()";
-  static const char tspecials2[] = "/?=<>@.,;:";
+  static const char tspecials2[] = "/?=<>@.,;:";  /* FIXME: really
+                                                     include '.'?*/
   static struct 
   {
     const unsigned char *name;
@@ -765,6 +766,7 @@
   } tspecial_header[] = {
     { "Content-Type", 12},
     { "Content-Transfer-Encoding", 25},
+    { "Content-Disposition", 19},
     { NULL, 0}
   };
   const char *delimiters;




More information about the Gnupg-commits mailing list