Cleanups, fixed a few bugs, use winpt as default keymananger.
authorWerner Koch <wk@gnupg.org>
Fri, 26 Aug 2005 18:43:55 +0000 (18:43 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 26 Aug 2005 18:43:55 +0000 (18:43 +0000)
You need to use the laterst gpgme from CVS due to a bug over there.

TODO
src/config-dialog.c
src/display.cpp
src/display.h
src/engine-gpgme.c
src/gpgmsg.cpp
src/gpgmsg.hh
src/intern.h
src/main.c
src/olflange.cpp
src/passphrase-dialog.c

diff --git a/TODO b/TODO
index fd8a1d4..ee2fa6b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,23 +1,18 @@
-* Show more details in case of some errors.\r
-  For example 'No Secret Key' should contain the key-ID\r
-  and if possible the primary user-ID.\r
-\r
-* much better HTML support.\r
-\r
-* factor out more common code in encrypt, signEncrypt.\r
-\r
-* grep all XXX in the code and provide fixes.\r
-\r
-* provide a general passphrase caching system to allow to store\r
-  more than one passphrase. This can be done with a hash table and\r
-  the key-ID is used as the index to access the passphrase.\r
-\r
-* handle unicode messages and find out why UTF-8 messages cannot be\r
-  manipulated.\r
-\r
-* find out why sometimes the new body cannot set to a MAPI object. In\r
-  this case the body is empty but the W32 API said it was correctly set.\r
-\r
-* implement a static shared section inside the DLL to provide the key cache\r
-  objects. right now we load all keys on demand.\r
-\r
+* Show more details in case of some errors.
+  For example 'No Secret Key' should contain the key-ID
+  and if possible the primary user-ID.
+
+* much better HTML support.
+
+* find out why sometimes the new body cannot set to a MAPI object. In
+  this case the body is empty but the W32 API said it was correctly set.
+  This might be due to the length of the object.  HrGetOneProp has
+  such limitations adn thus it owould be reasonable to assume that the
+  same holds true for HrSetOneProp.  We might want to use Openproperty
+  for longer texts.
+
+* There is no verification status for attachments. What about
+  generating a new text attachemnts with the status information?  We
+  need to make sure that it can be identified as locally generated.
+
+
index 32bb6f2..c154b1c 100644 (file)
@@ -27,6 +27,7 @@
 #include <shlobj.h>
 #include <time.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include <gpgme.h>
 
 #include "outlgpg-ids.h"
@@ -370,28 +371,65 @@ config_dialog_box (HWND parent)
 int
 start_key_manager (void)
 {
-    PROCESS_INFORMATION pi;
-    STARTUPINFO si;
-    char *keyman = NULL;
-    
-    if (load_config_value (NULL, REGPATH, "keyManager", &keyman))
-       return -1;
-
-    /* create startup info for the gpg process */
-    memset (&si, 0, sizeof (si));
-    si.cb = sizeof (STARTUPINFO);
-    si.dwFlags = STARTF_USESHOWWINDOW;
-    si.wShowWindow = SW_SHOW;
-
-    if (CreateProcess (NULL, keyman,
-                       NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
-                       NULL, NULL, &si, &pi) == TRUE) {
-       CloseHandle (pi.hProcess);
-       CloseHandle (pi.hThread);
+  PROCESS_INFORMATION pi;
+  STARTUPINFO si;
+  char *p;
+  char *keyman = NULL;
+  
+  if (load_config_value (NULL, REGPATH, "keyManager", &keyman))
+    {
+      /* In case we did not found a registry entry we try to locate
+         the keymanager in the same directory as the gpgme backend. */
+      gpgme_engine_info_t info;
+
+      if (gpgme_get_engine_info (&info))
+        return -1;
+
+      while (info && info->protocol != GPGME_PROTOCOL_OpenPGP)
+        info = info->next;
+      if (info && info->file_name && *info->file_name)
+        {
+          keyman = xmalloc (strlen (info->file_name) + 10);
+          strcpy (keyman, info->file_name);
+          for (p=keyman; *p; p++)
+            if (*p == '/')
+              *p = '\\';
+          p = strrchr (keyman, '\\');
+          if (!p)
+            {
+              xfree (keyman);
+              return -1;
+            }
+          strcpy (p+1, "winpt.exe");
+          if (access (keyman, F_OK))
+            {
+              strcpy (p+1, "gpa.exe");
+              if (access (keyman, F_OK))
+                {
+                  xfree (keyman);
+                  return -1;
+                }
+            }
+        }
     }
 
-    xfree (keyman);
-    return 0;
+
+  
+  /* Create startup info for the keymanager process. */
+  memset (&si, 0, sizeof (si));
+  si.cb = sizeof (STARTUPINFO);
+  si.dwFlags = STARTF_USESHOWWINDOW;
+  si.wShowWindow = SW_SHOW;
+  
+  if (CreateProcess (NULL, keyman,
+                     NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
+                     NULL, NULL, &si, &pi) == TRUE) {
+    CloseHandle (pi.hProcess);
+    CloseHandle (pi.hThread);
+  }
+  
+  xfree (keyman);
+  return 0;
 }
 
 
index a54d1aa..2fe6614 100644 (file)
@@ -53,7 +53,7 @@ is_html_body (const char *body)
 }
 
 
-/* Create a new body from body wth suitable line endings. Caller must
+/* Create a new body from body with suitable line endings. Caller must
    release the result. */
 char *
 add_html_line_endings (const char *body)
@@ -133,3 +133,42 @@ update_display (HWND hwnd, GpgMsg *msg)
     }
 }
 
+
+/* Set the body of MESSAGE to STRING.  Returns 0 on success or an
+   error code otherwise. */
+int
+set_message_body (LPMESSAGE message, const char *string)
+{
+  HRESULT hr;
+  SPropValue prop;
+  BOOL dummy_bool;
+  const char *s;
+  
+  /* Decide whether we ned to use the Unicode version. */
+  for (s=string; *s && !(*s & 0x80); s++)
+    ;
+  if (*s)
+    {
+      prop.ulPropTag = PR_BODY_W;
+      prop.Value.lpszW = utf8_to_wchar (string);
+      hr = HrSetOneProp (message, &prop);
+      xfree (prop.Value.lpszW);
+    }
+  else /* Only plain ASCII. */
+    {
+      prop.ulPropTag = PR_BODY_A;
+      prop.Value.lpszA = (CHAR*)string;
+      hr = HrSetOneProp (message, &prop);
+    }
+  if (hr != S_OK)
+    {
+      log_debug ("%s:%s: HrSetOneProp failed: hr=%#lx\n",
+                 __FILE__, __func__, hr); 
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+  hr = RTFSync (message, RTF_SYNC_BODY_CHANGED, &dummy_bool);
+  if (hr != S_OK)
+    log_debug ("%s:%s: RTFSync failed: hr=%#lx - error ignored",
+               __FILE__, __func__, hr); 
+  return 0;
+}
index a6d09e9..a55e993 100644 (file)
@@ -30,4 +30,7 @@ char *add_html_line_endings (const char *body);
 
 int update_display (HWND hwnd, GpgMsg *msg);
 
+int set_message_body (LPMESSAGE message, const char *string);
+
+
 #endif /*DISPLAY_H*/
index 6a59aeb..105347a 100644 (file)
@@ -64,7 +64,7 @@ op_set_debug_mode (int val, const char *file)
   if (val > 0) 
     {
       debug_file = (char *)xcalloc (1, strlen (file) + strlen (s) + 2);
-      sprintf (debug_file, "%s=%d:%s", s, val, file);
+      sprintf (debug_file, "%s=%d;%s", s, val, file);
       putenv (debug_file);
     }
   else
@@ -530,9 +530,10 @@ op_decrypt (const char *inbuf, char **outbuf, int ttl)
     }
 
 
-  /* If the callback indicated a cancel operation, clear the error. */
-  if (dk.opts & OPT_FLAG_CANCEL)
-    err = 0;
+  /* If the callback indicated a cancel operation, set the error
+     accordingly. */
+  if (err && (dk.opts & OPT_FLAG_CANCEL))
+    err = gpg_error (GPG_ERR_CANCELED);
   
 leave:    
   if (ctx)
@@ -580,6 +581,37 @@ op_decrypt_stream (LPSTREAM instream, LPSTREAM outstream, int ttl)
   err = gpgme_op_decrypt (ctx, in, out);
   dk.ctx = NULL;
   update_passphrase_cache (err, &dk);
+  /* Act upon the result of the decryption operation. */
+  if (!err) 
+    {
+      gpgme_verify_result_t res;
+
+      /* Decryption succeeded.  Now check the state of the signatures. */
+      res = gpgme_op_verify_result (ctx);
+      if (res && res->signatures)
+        verify_dialog_box (res);
+    }
+  else if (gpgme_err_code (err) == GPG_ERR_DECRYPT_FAILED)
+    {
+      /* The decryption failed.  See whether we can determine the real
+         problem. */
+      gpgme_decrypt_result_t res;
+      res = gpgme_op_decrypt_result (ctx);
+      if (res != NULL && res->recipients != NULL &&
+          gpgme_err_code (res->recipients->status) == GPG_ERR_NO_SECKEY)
+        err = GPG_ERR_NO_SECKEY;
+      /* XXX: return the keyids */
+    }
+  else
+    {
+      /* Decryption failed for other reasons. */
+    }
+
+
+  /* If the callback indicated a cancel operation, set the error
+     accordingly. */
+  if (err && (dk.opts & OPT_FLAG_CANCEL))
+    err = gpg_error (GPG_ERR_CANCELED);
 
  fail:
   if (in)
index beb61c2..16331d2 100644 (file)
@@ -120,9 +120,7 @@ public:
   const char *GpgMsgImpl::getDisplayText (void);
   const char *getPlainText (void);
   void setPlainText (char *string);
-  void setCipherText (char *string, bool html);
   void setSignedText (char *string);
-  void saveChanges (bool permanent);
   bool matchesString (const char *string);
 
   int decrypt (HWND hwnd);
@@ -238,14 +236,15 @@ GpgMsgImpl::loadBody (void)
                               0, 0, (LPUNKNOWN*)&stream);
   if ( hr != S_OK )
     {
-      log_debug_w32 (hr, "%s:%s: OpenProperty failed", __FILE__, __func__);
+      log_debug ("%s:%s: OpenProperty failed: hr=%#lx",
+                 __FILE__, __func__, hr);
       return;
     }
 
   hr = stream->Stat (&statInfo, STATFLAG_NONAME);
   if ( hr != S_OK )
     {
-      log_debug_w32 (hr, "%s:%s: Stat failed", __FILE__, __func__);
+      log_debug ("%s:%s: Stat failed: hr=%#lx", __FILE__, __func__, hr);
       stream->Release ();
       return;
     }
@@ -257,7 +256,7 @@ GpgMsgImpl::loadBody (void)
   hr = stream->Read (body, (size_t)statInfo.cbSize.QuadPart, &nread);
   if ( hr != S_OK )
     {
-      log_debug_w32 (hr, "%s:%s: Read failed", __FILE__, __func__);
+      log_debug ("%s:%s: Read failed: hr=%#lx", __FILE__, __func__, hr);
       xfree (body);
       body = NULL;
       stream->Release ();
@@ -395,16 +394,6 @@ GpgMsgImpl::setPlainText (char *string)
   msgcache_put (body_plain, 0, message);
 }
 
-/* Save STRING as the ciphertext version of the message.  WARNING:
-   ownership of STRING is transferred to this object. HTML indicates
-   whether the ciphertext was originally HTML. */
-void
-GpgMsgImpl::setCipherText (char *string, bool html)
-{
-  xfree (body_cipher);
-  body_cipher = string;
-  body_cipher_is_html = html;
-}
 
 /* Save STRING as the signed version of the message.  WARNING:
    ownership of STRING is transferred to this object. */
@@ -415,71 +404,6 @@ GpgMsgImpl::setSignedText (char *string)
   body_signed = string;
 }
 
-/* Save the changes made to the message.  With PERMANENT set to true
-   they are really stored, when not set they are only saved
-   temporary. */
-void
-GpgMsgImpl::saveChanges (bool permanent)
-{
-  SPropValue sProp; 
-  HRESULT hr;
-  int rc = TRUE;
-
-  if (!body_plain)
-    return; /* Nothing to save. */
-
-  if (!permanent)
-    return;
-  
-  /* Make sure that the Plaintext and the Richtext are in sync. */
-//   if (message)
-//     {
-//       BOOL changed;
-
-//       sProp.ulPropTag = PR_BODY_A;
-//       sProp.Value.lpszA = "";
-//       hr = HrSetOneProp(message, &sProp);
-//       changed = false;
-//       RTFSync(message, RTF_SYNC_BODY_CHANGED, &changed);
-//       sProp.Value.lpszA = body_plain;
-//       hr = HrSetOneProp(message, &sProp);
-//       RTFSync(message, RTF_SYNC_BODY_CHANGED, &changed);
-//     }
-
-  sProp.ulPropTag = PR_BODY_W;
-  sProp.Value.lpszW = utf8_to_wchar (body_plain);
-  if (!sProp.Value.lpszW)
-    {
-      log_debug_w32 (-1, "%s:%s: error converting from utf8\n",
-                     __FILE__, __func__);
-      return;
-    }
-  hr = HrSetOneProp (message, &sProp);
-  xfree (sProp.Value.lpszW);
-  if (hr < 0)
-    log_debug_w32 (-1, "%s:%s: HrSetOneProp failed", __FILE__, __func__);
-  else
-    {
-      log_debug ("%s:%s: PR_BODY set to `%s'\n",
-                 __FILE__, __func__, body_plain);
-      {
-        GpgMsg *xmsg = CreateGpgMsg (message);
-        log_debug ("%s:%s:    cross check `%s'\n",
-                   __FILE__, __func__, xmsg->getOrigText ());
-        delete xmsg;
-      }
-      if (permanent && message)
-        {
-          hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
-          if (hr < 0)
-            log_debug_w32 (-1, "%s:%s: SaveChanges failed",
-                           __FILE__, __func__);
-        }
-    }
-
-  log_debug ("%s:%s: leave\n", __FILE__, __func__);
-}
-
 
 /* Returns true if STRING matches the actual message. */ 
 bool
@@ -589,6 +513,7 @@ GpgMsgImpl::decrypt (HWND hwnd)
   char *plaintext = NULL;
   int has_attach;
   int err;
+  HRESULT hr;
 
   mtype = getMessageType ();
   if (mtype == OPENPGP_CLEARSIG)
@@ -612,7 +537,9 @@ GpgMsgImpl::decrypt (HWND hwnd)
       return 0;
     }
 
-  err = op_decrypt (getOrigText (), &plaintext, opt.passwd_ttl);
+
+  err = *getOrigText()? op_decrypt (getOrigText (), &plaintext, opt.passwd_ttl)
+                      : gpg_error (GPG_ERR_NO_DATA);
   if (err)
     {
       if (has_attach && gpg_err_code (err) == GPG_ERR_NO_DATA)
@@ -625,16 +552,22 @@ GpgMsgImpl::decrypt (HWND hwnd)
     {  
       int is_html = is_html_body (plaintext);
 
+      set_message_body (message, plaintext);
       setPlainText (plaintext);
       plaintext = NULL;
 
       /* Also set PR_BODY but do not use 'SaveChanges' to make it
          permanently.  This way the user can reply with the
-         plaintext but the ciphertext is still stored. */
+         plaintext but the ciphertext is still stored. 
+
+         NOET: That does not work for OL2003!  This is the reason we
+         implemented the (not fully working) msgcache system. */
       log_debug ("decrypt isHtml=%d\n", is_html);
 
       /* XXX: find a way to handle text/html message in a better way! */
-      if (is_html || update_display (hwnd, this))
+      /* I have disabled the kludge to see what happens to a html
+         message. */
+      if (/*is_html ||*/ update_display (hwnd, this))
         {
           const char s[] = 
             "The message text cannot be displayed.\n"
@@ -648,11 +581,12 @@ GpgMsgImpl::decrypt (HWND hwnd)
           if (what == IDYES) 
             {
               log_debug ("decrypt: saving plaintext message.\n");
-              saveChanges (1);
+              hr = message->SaveChanges (KEEP_OPEN_READWRITE|FORCE_SAVE);
+              if (FAILED (hr))
+                log_debug ("%s:%s: SaveChanges failed: hr=%#lx",
+                           __FILE__, __func__, hr);
             }
        }
-      else
-        saveChanges (0);
     }
 
   if (has_attach)
@@ -752,6 +686,19 @@ GpgMsgImpl::sign (HWND hwnd)
          failed. */
     }
 
+  /* Now that we successfully processed the attachments, we can save
+     the changes to the body.  For unknown reasons we need to set it
+     to empty first. */
+  if (*plaintext)
+    {
+      err = set_message_body (message, "");
+      if (!err)
+        set_message_body (message, signedtext);
+      if (err)
+        goto leave;
+    }
+
+
  leave:
   xfree (signedtext);
   gpgme_key_release (sign_key);
@@ -777,6 +724,7 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign)
   int err = 0;
   size_t all = 0;
   int n_keys;
+    
   
   if (!*(plaintext = getOrigText ()) && !hasAttachments ()) 
     {
@@ -847,10 +795,11 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign)
         }
 
       if (is_html) 
-        setCipherText (add_html_line_endings (ciphertext), true);
-      else
-        setCipherText (ciphertext, false);
-      ciphertext = NULL;
+        {
+          char *tmp = add_html_line_endings (ciphertext);
+          xfree (ciphertext);
+          ciphertext = tmp;
+        }
 
 //       {
 //         HRESULT hr;
@@ -886,11 +835,30 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign)
       for (int i=0; !err && i < n; i++) 
         err = encryptAttachment (hwnd, i, keys, NULL, 0);
       if (err)
-        MessageBox (NULL, op_strerror (err),
-                    "GPG Attachment Encryption", MB_ICONERROR|MB_OK);
+        {
+          MessageBox (NULL, op_strerror (err),
+                      "GPG Attachment Encryption", MB_ICONERROR|MB_OK);
+          goto leave;
+        }
     }
 
+  /* Now that we successfully processed the attachments, we can save
+     the changes to the body.  For unknown reasons we need to set it
+     to empty first. */
+  if (*plaintext)
+    {
+      err = set_message_body (message, "");
+      if (!err)
+        set_message_body (message, ciphertext);
+      if (err)
+        goto leave;
+    }
+
+
  leave:
+  /* FIXME: What to do with already encrypted attachments if some of
+     the encrypted (or other operations) failed? */
+
   for (int i=0; i < n_keys; i++)
     xfree (unknown[i]);
   if (n_keys)
@@ -1147,6 +1115,8 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
   LPATTACH att;
   int method, err;
 
+  log_debug ("%s:%s: processing attachment %d", __FILE__, __func__, pos);
+
   /* Make sure that we can access the attachment table. */
   if (!message || !getAttachments ())
     {
@@ -1207,6 +1177,9 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
       LPSTREAM from, to;
 
       suggested_name = get_attach_filename (att);
+      if (suggested_name)
+        log_debug ("%s:%s: attachment %d, filename `%s'", 
+                   __FILE__, __func__, pos, suggested_name);
       /* We only want to automatically decrypt attachmenst with
          certain extensions.  FIXME: Also look for content-types. */
       if (!suggested_name 
@@ -1215,8 +1188,8 @@ GpgMsgImpl::decryptAttachment (HWND hwnd, int pos, bool save_plaintext,
               && stricmp (s, ".gpg") 
               && stricmp (s, ".asc")))
         {
-          log_debug ( "%s:%s: attachment %d has no pgp extension\n", 
-                      __FILE__, __func__);
+          log_debug ("%s:%s: attachment %d has no pgp extension\n", 
+                     __FILE__, __func__, pos);
           goto leave;
         }
       outname = get_save_filename (hwnd, suggested_name);
index 9a367f4..0cb29e6 100644 (file)
@@ -67,19 +67,10 @@ public:
      ownership of STRING is transferred to this object. */
   virtual void setPlainText (char *string);
 
-  /* Save STRING as the ciphertext version of the message.  WARNING:
-     ownership of STRING is transferred to this object. */
-  virtual void setCipherText (char *string, bool html);
-
   /* Save STRING as the signed version of the message.  WARNING:
      ownership of STRING is transferred to this object. */
   virtual void setSignedText (char *string);
   
-  /* Save the changes made to the message.  With PERMANENT set to true
-     they are really stored, when not set they are only saved
-     temporary. */
-  virtual void saveChanges (bool permanent);
-
   /* Return true if STRING matches the actual message. */ 
   virtual bool matchesString (const char *string);
 
index 10d63e1..f404b1e 100644 (file)
@@ -120,9 +120,13 @@ struct
   int enc_format;            /* Encryption format for attachments. */
   char *default_key;         /* Malloced default key or NULL. */
   int add_default_key;       /* Always also encrypt to the default key. */
+
+  unsigned int compat_flags; /* compatibility flags. */
 } opt;
 
 
+#define COMPAT_NOMSGCACHE() (opt.compat_flags & 1)
+
 
 
 /*-- common.c --*/
index cb087ec..f9a21a8 100644 (file)
@@ -320,6 +320,12 @@ read_options (void)
   load_extension_value ("defaultKey", &val);
   set_default_key (val);
   xfree (val); val = NULL;
+
+  /* Note, that on prupose theses flags are only Registry changeable.
+     The format of the entry is a string of the format "0xnnnnnnn". */
+  load_extension_value ("compatFlags", &val);
+  opt.compat_flags = val? strtoul (val, NULL, 0) : 0;
+  xfree (val); val = NULL;
 }
 
 
index 2ca9162..9c4c455 100644 (file)
@@ -385,7 +385,7 @@ CGPGExchExt::~CGPGExchExt (void)
           op_deinit ();
           write_options ();
           g_bInitDll = FALSE;
-          log_debug ("%s:%s: DLL shutdown down\n", __FILE__, __func__);
+          log_debug ("%s:%s: DLL closed down\n", __FILE__, __func__);
        }       
     }
 }
@@ -808,7 +808,8 @@ CGPGExchExtCommands::InstallCommands (
       hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
       if (FAILED(hr))
         log_debug ("%s:%s: getObject failed: hr=%#x\n", hr);
-      else if ( (body = msgcache_get (pMessage, &refhandle)) 
+      else if ( !COMPAT_NOMSGCACHE() 
+                && (body = msgcache_get (pMessage, &refhandle)) 
                 && (pDisp = find_outlook_property (pEECB, "Body", &dispid)))
         {
           dispparams.cNamedArgs = 1;
index 410309a..843d8d9 100644 (file)
@@ -497,9 +497,9 @@ passphrase_callback_box (void *opaque, const char *uid_hint,
       if (rc <= 0) 
         log_debug_w32 (-1, "%s: dialog failed (rc=%d)", __func__, rc);
     }
-  else /* FIXME: Don't write the passphrase to the log file. */
-    log_debug ("%s:%s: hd=%p hd->pass=`%s'\n",
-               __FILE__, __func__, hd, hd && hd->pass? hd->pass: "(null)");
+  else 
+    log_debug ("%s:%s: hd=%p hd->pass=`[censored]'\n",
+               __FILE__, __func__, hd);
 
   /* If we got a passphrase, send it to the FD. */
   if (hd->pass)