Compiles but I would be very surprised if it runs.
authorWerner Koch <wk@gnupg.org>
Wed, 24 Aug 2005 19:32:14 +0000 (19:32 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 24 Aug 2005 19:32:14 +0000 (19:32 +0000)
More work to come tomorrow.

Timo: You may want to look for a couple of FIXMEs and answer
my questions; if possible reply to the commit message. Thanks.

src/MapiGPGME.cpp
src/engine-gpgme.c
src/engine.h
src/gpgmsg.cpp
src/gpgmsg.hh

index 75c706e..29b499b 100644 (file)
@@ -252,24 +252,7 @@ public:
 
   const char* __stdcall getAttachmentExtension (const char *fname);
   void __stdcall freeAttachments (void);
-  int __stdcall getAttachments (void);
   
-  int __stdcall countAttachments (void) 
-  { 
-    if (attachRows == NULL)
-      return -1;
-    return (int) attachRows->cRows; 
-  }
-
-  bool __stdcall hasAttachments (void)
-  {
-//     if (attachRows == NULL)
-//       getAttachments ();
-//     bool has = attachRows->cRows > 0? true : false;
-//     freeAttachments ();
-//    return has;
-    return false;    
-  }
 
   bool __stdcall deleteAttachment (GpgMsg * msg, int pos)
   {
@@ -374,12 +357,11 @@ private:
   int   streamOnFile (const char *file, LPATTACH att);
   int   streamFromFile (const char *file, LPATTACH att);
   int   encryptAttachments (HWND hwnd);
-  int   decryptAttachments (HWND hwnd);
+  void  decryptAttachments (HWND hwnd, GpgMsg *msg);
   int   signAttachments (HWND hwnd);
   LPATTACH openAttachment (GpgMsg *msg, int pos);
   void  releaseAttachment (LPATTACH att);
   int   processAttachment (LPATTACH *att, HWND hwnd, int pos, int action);
-  bool  saveDecryptedAttachment (HWND root, const char *srcname);
   bool  signAttachment (const char *datfile);
 
 };
@@ -797,7 +779,12 @@ MapiGPGMEImpl::decrypt (HWND hwnd, GpgMsg * msg)
       return verify (hwnd, msg);
     }
 
-  /* Check whether the possible encrpted message as attachments. */
+  /* Check whether this possibly encrypted message as attachments.  We
+     check right now because we need to get into the decryptio code
+     even if the body is not encrypted but attachments are
+     available. FIXME: I am not sure whether this is the best
+     solution, we might want to skip the decryption step later and
+     also test for encrypted attachments right now.*/
   has_attach = msg->hasAttachments ();
 
   if (mtype == OPENPGP_NONE && !has_attach ) 
@@ -855,7 +842,7 @@ MapiGPGMEImpl::decrypt (HWND hwnd, GpgMsg * msg)
   if (has_attach)
     {
       log_debug ("decrypt attachments\n");
-      decryptAttachments (hwnd);
+      decryptAttachments (hwnd, msg);
     }
 
   log_debug ("%s:%s: leave (rc=%d)\n", __FILE__, __func__, err);
@@ -1414,38 +1401,6 @@ MapiGPGMEImpl::freeAttachments (void)
 }
 
 
-int
-MapiGPGMEImpl::getAttachments (void)
-{
-  // FIXME
-//     static SizedSPropTagArray (1L, PropAttNum) = {1L, {PR_ATTACH_NUM}};
-//     HRESULT hr;    
-   
-//     hr = msg->GetAttachmentTable (0, &attachTable);
-//     if (FAILED (hr))
-//     return FALSE;
-
-//     hr = HrQueryAllRows (attachTable, (LPSPropTagArray) &PropAttNum,
-//                      NULL, NULL, 0L, &attachRows);
-//     if (FAILED (hr)) {
-//     freeAttachments ();
-//     return FALSE;
-//     }
-    return TRUE;
-}
-
-
-LPATTACH
-MapiGPGMEImpl::openAttachment (GpgMsg * msg, int pos)
-{
-    HRESULT hr;
-    LPATTACH att = NULL;
-    
-    //    hr = msg->OpenAttach (pos, NULL, MAPI_BEST_ACCESS, &att);    
-    if (SUCCEEDED (hr))
-       return att;
-    return NULL;
-}
 
 
 void
@@ -1603,7 +1558,7 @@ MapiGPGMEImpl::processAttachment (LPATTACH *attm, HWND hwnd,
            }
        }
        else if (success && action == GPG_ATTACH_DECRYPT) {
-           success = saveDecryptedAttachment (NULL, outname);
+          //       success = saveDecryptedAttachment (NULL, outname);
            log_debug ("saveDecryptedAttachment ec=%d\n", success);
        }
        DeleteFile (outname);
@@ -1623,38 +1578,41 @@ MapiGPGMEImpl::processAttachment (LPATTACH *attm, HWND hwnd,
 }
 
 
-int 
-MapiGPGMEImpl::decryptAttachments (HWND hwnd)
+/* Decrypt all attachemnts of message MSG.  HWND is the usual window
+   handle. */
+void 
+MapiGPGMEImpl::decryptAttachments (HWND hwnd, GpgMsg *msg)
 {
-    int n;
+  unsigned int n;
+  LPATTACH amsg;
+  
 
-    if (!getAttachments ())
-       return FALSE;
-    n = countAttachments ();
-    log_debug ( "dec: mail has %d attachments\n", n);
-    if (!n) {
-       freeAttachments ();
-       return TRUE;
-    }
-    for (int i=0; i < n; i++) {
-      LPATTACH amsg = openAttachment (NULL/*FIXME*/,i);
-       if (amsg)
-          processAttachment (&amsg, hwnd, i, GPG_ATTACH_DECRYPT);
+  n = msg->getAttachments ();
+  log_debug ("%s:%s: message has %u attachments\n",
+             __FILE__, __func__, n);
+  if (!n)
+    return;
+  
+  for (int i=0; i < n; i++) 
+    {
+      //amsg = openAttachment (NULL/*FIXME*/,i);
+      if (amsg)
+        processAttachment (&amsg, hwnd, i, GPG_ATTACH_DECRYPT);
     }
-    freeAttachments ();
-    return 0;
+  return;
 }
 
 
+
 int
 MapiGPGMEImpl::signAttachments (HWND hwnd)
 {
-    if (!getAttachments ()) {
-        log_debug ("MapiGPGME.signAttachments: getAttachments failed\n");
-       return FALSE;
-    }
+//FIXME     if (!getAttachments ()) {
+//         log_debug ("MapiGPGME.signAttachments: getAttachments failed\n");
+//     return FALSE;
+//     }
     
-    int n = countAttachments ();
+    int n = 0/*FIXME countAttachments ()*/;
     log_debug ("MapiGPGME.signAttachments: mail has %d attachments\n", n);
     if (!n) {
        freeAttachments ();
@@ -1675,11 +1633,11 @@ MapiGPGMEImpl::signAttachments (HWND hwnd)
 int
 MapiGPGMEImpl::encryptAttachments (HWND hwnd)
 {    
-    int n;
+    unsigned int n;
 
-    if (!getAttachments ())
-       return FALSE;
-    n = countAttachments ();
+//     n = if (!getAttachments ())
+//     return FALSE;
+    n = 0 /*FIXMEcountAttachments ()*/;
     log_debug ("enc: mail has %d attachments\n", n);
     if (!n) {
        freeAttachments ();
@@ -1697,47 +1655,6 @@ MapiGPGMEImpl::encryptAttachments (HWND hwnd)
 }
 
 
-bool 
-MapiGPGMEImpl::saveDecryptedAttachment (HWND root, const char *srcname)
-                                    
-{
-    char filter[] = "All Files (*.*)|*.*||";
-    char fname[MAX_PATH+1];
-    char *p;
-    OPENFILENAME ofn;
-
-    for (size_t i=0; i< strlen (filter); i++)  {
-       if (filter[i] == '|')
-           filter[i] = '\0';
-    }
-
-    memset (fname, 0, sizeof (fname));
-    p = strstr (srcname, ATT_PREFIX);
-    if (!p)
-       strncpy (fname, srcname, MAX_PATH);
-    else {
-       strncpy (fname, srcname, (p-srcname));
-       strcat (fname, srcname+(p-srcname)+strlen (ATT_PREFIX));        
-    }
-
-    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 attachments";
-    ofn.lpstrFilter = filter;
-
-    if (GetSaveFileName (&ofn)) {
-       log_debug ("copy %s -> %s\n", srcname, fname);
-       return CopyFile (srcname, fname, FALSE) == 0? false : true;
-    }
-    return true;
-}
-
 
 void  
 MapiGPGMEImpl::showVersion (void)
index d4cee4a..eb45fa7 100644 (file)
 
 #include <config.h>
 
-#include <windows.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <errno.h>
+
+#define COBJMACROS
+#include <windows.h>
+#include <objidl.h> /* For IStream. */
 
 #include "gpgme.h"
 #include "keycache.h"
@@ -389,6 +393,99 @@ op_decrypt_file (const char *infile, const char *outfile)
 }
 
 
+/* The read callback used by GPGME to read data from an IStream object. */
+static ssize_t
+stream_read_cb (void *handle, void *buffer, size_t size)
+{
+  LPSTREAM stream = handle;
+  HRESULT hr;
+  ULONG nread;
+
+  /* For EOF detection we assume that Read returns no error and thus
+     nread will be 0.  The specs say that "Depending on the
+     implementation, either S_FALSE or an error code could be returned
+     when reading past the end of the stream"; thus we are not really
+     sure whether our assumption is correct.  OTOH, at another place
+     the docuemntation says that the implementation used by
+     ISequentialStream exhibits the same EOF behaviour has found on
+     the MSDOS FAT file system.  So we seem to have good karma. */
+  hr = IStream_Read (stream, buffer, size, &nread);
+  if (hr != S_OK)
+    {
+      log_debug ("%s:%s: Read failed: hr=%#lx", __FILE__, __func__, hr);
+      errno = EIO;
+      return -1;
+    }
+  return nread;
+}
+
+/* The write callback used by GPGME to write data to an IStream object. */
+static ssize_t
+stream_write_cb (void *handle, const void *buffer, size_t size)
+{
+  LPSTREAM stream = handle;
+  HRESULT hr;
+  ULONG nwritten;
+
+  hr = IStream_Write (stream, buffer, size, &nwritten);
+  if (hr != S_OK)
+    {
+      log_debug ("%s:%s: Write failed: hr=%#lx", __FILE__, __func__, hr);
+      errno = EIO;
+      return -1;
+    }
+  return nwritten;
+}
+
+
+/* Decrypt the stream INSTREAM directly to the stream OUTSTREAM.
+   Returns 0 on success or an gpgme error code on failure. */
+int
+op_decrypt_stream (LPSTREAM instream, LPSTREAM outstream)
+{    
+  gpgme_data_t in = NULL;
+  gpgme_data_t out = NULL;    
+  gpgme_ctx_t ctx = NULL;
+  gpgme_error_t err;
+  struct decrypt_key_s *dk;
+  struct gpgme_data_cbs cbs;
+  
+  memset (&cbs, 0, sizeof cbs);
+  cbs.read = stream_read_cb;
+  cbs.write = stream_write_cb;
+
+  dk = xcalloc (1, sizeof *dk);
+
+  err = gpgme_data_new_from_cbs (&in, &cbs, instream);
+  if (err)
+    goto fail;
+
+  err = gpgme_new (&ctx);
+  if (err)
+    goto fail;
+
+  err = gpgme_data_new_from_cbs (&out, &cbs, outstream);
+  if (err)
+    goto fail;
+
+  gpgme_set_passphrase_cb (ctx, passphrase_callback_box, dk);
+  dk->ctx = ctx;
+  err = gpgme_op_decrypt (ctx, in, out);
+  dk->ctx = NULL;
+  update_passphrase_cache (err, dk);
+
+ fail:
+  if (in)
+    gpgme_data_release (in);
+  if (out)
+    gpgme_data_release (out);
+  if (ctx)
+    gpgme_release (ctx);
+  xfree (dk);
+  return err;
+}
+
+
 /* Try to figure out why the encryption failed and provide a suitable
    error code. */
 static gpgme_error_t
index 4f53fbb..cf61d0f 100644 (file)
@@ -28,6 +28,8 @@ extern "C" {
 #endif
 #endif
 
+#include <gpgme.h>
+
 typedef enum {
     OP_SIG_NORMAL = 0,
     OP_SIG_DETACH = 1,
@@ -57,6 +59,7 @@ int op_sign_start (const char *inbuf, char **outbuf);
 int op_sign_file (int mode, const char *infile, const char *outfile, int ttl);
 
 int op_decrypt_file (const char *infile, const char *outfile);
+int op_decrypt_stream (LPSTREAM instream, LPSTREAM outstream);
 int op_decrypt_start (const char *inbuf, char **outbuf, int ttl);
 
 int op_lookup_keys (char **id, gpgme_key_t **keys, char ***unknown, size_t *n);
index 4454c69..302b1a0 100644 (file)
 #include "mymapi.h"
 #include "mymapitags.h"
 
+
 #include "gpgmsg.hh"
 #include "util.h"
 #include "msgcache.h"
+#include "engine.h"
+
+/* The string used as the standard XXXXX of decrypted attachments. */
+#define ATT_FILE_PREFIX ".pgpenc"
+
+
 
 /*
    The implementation class of MapiGPGME.  
@@ -42,12 +49,15 @@ class GpgMsgImpl : public GpgMsg
 public:    
   GpgMsgImpl () 
   {
-    this->message = NULL;
-    this->body = NULL;
-    this->body_plain = NULL;
-    this->body_cipher = NULL;
-    this->body_signed = NULL;
-    this->body_cipher_is_html = false;
+    message = NULL;
+    body = NULL;
+    body_plain = NULL;
+    body_cipher = NULL;
+    body_signed = NULL;
+    body_cipher_is_html = false;
+
+    attach.table = NULL;
+    attach.rows = NULL;
   }
 
   ~GpgMsgImpl ()
@@ -58,6 +68,17 @@ public:
     xfree (body_plain);
     xfree (body_cipher);
     xfree (body_signed);
+
+    if (attach.table)
+      {
+        attach.table->Release ();
+        attach.table = NULL;
+      }
+    if (attach.rows)
+      {
+        FreeProws (attach.rows);
+        attach.rows = NULL;
+      }
   }
 
   void destroy ()
@@ -97,6 +118,8 @@ public:
   void saveChanges (bool permanent);
   bool matchesString (const char *string);
   char **getRecipients (void);
+  unsigned int getAttachments (void);
+  void decryptAttachment (HWND hwnd, int pos, bool save_plaintext);
 
 
 private:
@@ -106,10 +129,15 @@ private:
   char *body_cipher;  /* Enciphered version of BODY or NULL. */
   char *body_signed;  /* Signed version of BODY or NULL. */
   bool body_cipher_is_html; /* Indicating that BODY_CIPHER holds HTML. */
+
+  /* This structure collects the information about attachments. */
+  struct 
+  {
+    LPMAPITABLE table;/* The loaded attachment table or NULL. */
+    LPSRowSet   rows; /* The retrieved set of rows from the table. */
+  } attach;
   
   void loadBody (void);
-  
-  
 };
 
 
@@ -490,16 +518,314 @@ GpgMsgImpl::getRecipients ()
 
 /* Returns whether the message has any attachments. */
 bool
-GpgMsgImpl::hasAttachments ()
+GpgMsgImpl::hasAttachments (void)
 {
-//   if (!attachRows)
-//     getAttachments ();
+  return !!getAttachments ();
+}
 
-//   bool has = attachRows->cRows > 0? true : false;
-//     freeAttachments ();
-//     return has;
-  return false;
+
+/* Reads the attachment information and returns the number of
+   attachments. */
+unsigned int
+GpgMsgImpl::getAttachments (void)
+{
+  SizedSPropTagArray (1L, propAttNum) = {
+    1L, {PR_ATTACH_NUM}
+  };
+  HRESULT hr;    
+  LPMAPITABLE table;
+  LPSRowSet   rows;
+
+  if (!message)
+    return 0;
+
+  if (!attach.table)
+    {
+      hr = message->GetAttachmentTable (0, &table);
+      if (FAILED (hr))
+        {
+          log_debug ("%s:%s: GetAttachmentTable failed: hr=%#lx",
+                     __FILE__, __func__, hr);
+          return 0;
+        }
+      
+      hr = HrQueryAllRows (table, (LPSPropTagArray)&propAttNum,
+                           NULL, NULL, 0, &rows);
+      if (FAILED (hr))
+        {
+          table->Release ();
+          return 0;
+        }
+      attach.table = table;
+      attach.rows = rows;
+    }
+
+  return rows->cRows > 0? rows->cRows : 0;
+}
+
+/* Return the attachemnt method for attachmet OBJ. In case of error we
+   return 0 which happens to be not defined. */
+static int
+get_attach_method (LPATTACH obj)
+{
+  HRESULT hr;
+  LPSPropValue propval = NULL;
+  int method ;
+
+  hr = HrGetOneProp ((LPMAPIPROP)obj, PR_ATTACH_METHOD, &propval);
+  if (FAILED (hr))
+    {
+      log_error ("%s:%s: error getting attachment method: hr=%#lx",
+                 __FILE__, __func__, hr);
+      return 0; 
+    }
+  /* We don't bother checking whether we really get a PT_LONG ulong
+     back; if not the system is seriously damaged and we can't do
+     further harm by returning a possible random value. */
+  method = propval->Value.l;
+  MAPIFreeBuffer (propval);
+  return method;
+}
+
+
+/* Return the filename from the attachment as a malloced string.  The
+   encoding we return will be utf8, however the MAPI docs declare that
+   MAPI does only handle plain ANSI and thus we don't really care
+   later on.  In fact we would need to convert the filename back to
+   wchar and use the Unicode versions of the file API.  Returns NULL
+   on error or if no filename is available. */
+static char *
+get_attach_filename (LPATTACH obj)
+{
+  HRESULT hr;
+  LPSPropValue propval;
+  char *name = NULL;
+
+  hr = HrGetOneProp ((LPMAPIPROP)obj, PR_ATTACH_LONG_FILENAME, &propval);
+  if (FAILED(hr)) 
+    hr = HrGetOneProp ((LPMAPIPROP)obj, PR_ATTACH_FILENAME, &propval);
+  if (FAILED(hr))
+    {
+      log_debug ("%s:%s: no filename property found", __FILE__, __func__);
+      return NULL;
+    }
+
+  switch ( PROP_TYPE (propval->ulPropTag) )
+    {
+    case PT_UNICODE:
+      name = wchar_to_utf8 (propval->Value.lpszW);
+      if (!name)
+        log_debug ("%s:%s: error converting to utf8\n", __FILE__, __func__);
+      break;
+      
+    case PT_STRING8:
+      name = xstrdup (propval->Value.lpszA);
+      break;
+      
+    default:
+      log_debug ("%s:%s: proptag=%xlx not supported\n",
+                 __FILE__, __func__, propval->ulPropTag);
+      break;
+    }
+  MAPIFreeBuffer (propval);
+  return name;
+}
+
+
+
+
+/* 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];
+  const char *s;
+  OPENFILENAME ofn;
+
+  memset (fname, 0, sizeof (fname));
+
+#if 0
+  /* FIXME: What the heck does this code? Looking for a prefix in a
+     string an removing it.  Why?.  Also: possible buffer overflow
+     with possible user supplied data.  --- My guess is that we don't
+     need it anymore, now that we are wrinting directly to the
+     outfile. */
+  s = strstr (srcname, ATT_FILE_PREFIX);
+  if (!s)
+    strncpy (fname, srcname, MAX_PATH);
+  else 
+    {
+      strncpy (fname, srcname, (p-srcname));
+      strcat (fname, srcname+(p-srcname)+strlen (ATT_FILE_PREFIX));    
+    }
+#endif
+
+  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 attachments";
+  ofn.lpstrFilter = filter;
+
+  if (GetSaveFileName (&ofn))
+    return xstrdup (fname);
+  return NULL;
 }
 
 
 
+/* Decrypt the attachment with the internal number POS.
+   SAVE_PLAINTEXT must be true to save the attachemnt; displaying a
+   attachment is not yet supported. */
+void
+GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext)
+{    
+  HRESULT hr;
+  LPATTACH att;
+  int method, err;
+  BOOL success = TRUE;
+
+  /* Make sure that we can access the attachment table. */
+  if (!message || !getAttachments ())
+    {
+      log_debug ("%s:%s: no attachemnts at all", __FILE__, __func__);
+      return;
+    }
+
+  if (!save_plaintext)
+    {
+      log_error ("%s:%s: save_plaintext not requested", __FILE__, __func__);
+      return;
+    }
+
+  hr = message->OpenAttach (pos, NULL, MAPI_BEST_ACCESS, &att);        
+  if (FAILED (hr))
+    {
+      log_debug ("%s:%s: can't open attachment %d: hr=%#lx",
+                 __FILE__, __func__, pos, hr);
+      return;
+    }
+
+  method = get_attach_method (att);
+  if ( method == ATTACH_EMBEDDED_MSG)
+    {
+      /* This is an embedded message.  The orginal G-DATA plugin
+         decrypted the message and then updated the attachemnt;
+         i.e. stored the plaintext.  This seemed to ensure that the
+         attachemnt message was properly displayed.  I am not sure
+         what we should do - it might be necessary to have a callback
+         to allow displaying the attachment.  Needs further
+         experiments. */
+      LPMESSAGE emb;
+      
+      hr = att->OpenProperty (PR_ATTACH_DATA_OBJ, &IID_IMessage, 0, 
+                              MAPI_MODIFY, (LPUNKNOWN*)&emb);
+      if (FAILED (hr))
+        {
+          log_error ("%s:%s: can't open data obj of attachment %d: hr=%#lx",
+                     __FILE__, __func__, pos, hr);
+          goto leave;
+        }
+
+      //FIXME  Not sure what to do here.  Did it ever work?
+      //       setWindow (hwnd);
+      //       setMessage (emb);
+      //if (doCmdAttach (action))
+      //  success = FALSE;
+      //XXX;
+      //emb->SaveChanges (FORCE_SAVE);
+      //att->SaveChanges (FORCE_SAVE);
+      emb->Release ();
+    }
+  else if (method == ATTACH_BY_VALUE)
+    {
+      char *outname;
+      char *suggested_name;
+      LPSTREAM from, to;
+
+      suggested_name = get_attach_filename (att);
+      /* FIXME: WHY do we need this check?
+        if (checkAttachmentExtension (strrchr (tmp, '.')) == false)
+          {
+             log_debug ( "%s: no pgp extension found.\n", tmp);
+             xfree (tmp);
+             xfree (inname);
+             r eturn TRUE;
+             } */
+      outname = get_save_filename (hwnd, suggested_name);
+      xfree (suggested_name);
+
+      hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 
+                              0, 0, (LPUNKNOWN*) &from);
+      if (FAILED (hr))
+        {
+          log_error ("%s:%s: can't open data of attachment %d: hr=%#lx",
+                     __FILE__, __func__, pos, hr);
+          xfree (outname);
+          goto leave;
+        }
+
+      /* If we would want to write to a temporary file, we would use:
+         hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
+                                (SOF_UNIQUEFILENAME | STGM_DELETEONRELEASE
+                                 |STGM_CREATE | STGM_READWRITE),
+                                 NULL, "gpg", &to);    */
+      hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
+                             (STGM_CREATE | STGM_READWRITE),
+                             outname, NULL, &to); 
+      if (FAILED (hr)) 
+        {
+          log_error ("%s:%s: can't create stream for `%s': hr=%#lx\n",
+                     __FILE__, __func__, outname, hr); 
+          from->Release ();
+          xfree (outname);
+          goto leave;
+        }
+      
+      err = op_decrypt_stream (from, to);
+      if (err)
+        {
+          log_debug ("%s:%s: decrypt stream failed: %s",
+                     __FILE__, __func__, op_strerror (err)); 
+          to->Revert ();
+          to->Release ();
+          from->Release ();
+          MessageBox (NULL, op_strerror (err),
+                      "GPG Attachment Decryption", MB_ICONERROR|MB_OK);
+          /* FIXME: We might need to delete outname now.  However a
+             sensible implementation of the stream object should have
+             done it trhough the Revert call. */
+          xfree (outname);
+          goto leave;
+        }
+        
+      to->Commit (0);
+      to->Release ();
+      from->Release ();
+
+      /*  Hmmm: Why are we deleting the attachment now????? 
+          Disabled until clarified.   FIXME */
+      //if (message->DeleteAttach (pos, 0, NULL, 0) == S_OK)
+      //   show error;
+
+      xfree (outname);
+    }
+  else
+    {
+      log_error ("%s:%s: attachment %d: method %d not supported",
+                 __FILE__, __func__, pos, method);
+    }
+
+ leave:
+  /* Close this attachment. */
+  att->Release ();
+}
index b83737b..d602ce8 100644 (file)
@@ -99,6 +99,14 @@ public:
      the strings.  On failure NULL is returned.  */
   virtual char **getRecipients (void);
 
+  /* Return the number of attachments. */
+  virtual unsigned int getAttachments (void);
+
+  /* Decrypt the attachment with the internal number POS.
+     SAVE_PLAINTEXT must be true to save the attachemnt; displaying a
+     attachemnt is not yet supported. */
+  virtual void decryptAttachment (HWND hwnd, int pos, bool save_plaintext);
+
 };