Removed keycache and reworked dialog internals.
authorWerner Koch <wk@gnupg.org>
Tue, 27 Sep 2005 16:45:50 +0000 (16:45 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 27 Sep 2005 16:45:50 +0000 (16:45 +0000)
Not fully tested.

14 files changed:
src/ChangeLog
src/Makefile.am
src/engine-gpgme.c
src/engine.h
src/gpgmsg.cpp
src/gpgmsg.hh
src/intern.h
src/keycache.c [deleted file]
src/keycache.h [deleted file]
src/main.c
src/passphrase-dialog.c
src/pgpmime.c
src/recipient-dialog.c
src/verify-dialog.c

index 1326106..e8c6d49 100644 (file)
@@ -1,3 +1,43 @@
+2005-09-27  Werner Koch  <wk@g10code.com>
+
+       * pgpmime.c (pgpmime_decrypt): Pass a pseduo filename to the
+       decryption function.
+
+       * verify-dialog.c (load_sigbox): Get key direct from gpgme.
+       * passphrase-dialog.c (load_secbox, load_recipbox): Reworked.
+       (decrypt_key_dlg_proc, decrypt_key_ext_dlg_proc): Reworked.
+       (count_keys, release_keyarray): New.
+       (signer_dialog_box, passphrase_callback_box): Adjusted to above
+       changes.
+       * engine-gpgme.c (op_deinit): Remove keycache cleanup.
+       * Makefile.am (gpgol_SOURCES): Removed keycache.c, keycache.h.
+       * keycache.c, keycache.h: Removed.
+
+       * recipient-dialog.c (recipient_dialog_box) 
+       (recipient_dialog_box2): Rewritten and changed interface.
+       (load_rsetbox): Removed keycache stuff and rewrote to make use of
+       the keyarray.
+       (copy_item, initialize_keybox, recipient_dlg_proc): Ditto.
+       (keycache_to_key_array): Removed.
+       * engine-gpgme.c (op_lookup_keys): Rewritten, changed interface.
+       * gpgmsg.cpp (count_recipients): Renamed to ..
+       (count_strings): .. this.
+       (count_keys): New.
+       (free_recipient_array): Renamed to ..
+       (free_string_array): .. this.
+       (encrypt_and_sign): Adjusted for changes in op_lookup_keys and
+       recipient_dialog_box2.
+
+2005-09-26  Werner Koch  <wk@g10code.com>
+
+       * passphrase-dialog.c (get_pubkey_algo_str): Add DSA and old Elgamal.
+
+       * gpgmsg.cpp (gatherAttachmentInfo): Ignore attachments we can't
+       open.
+
+       * main.c (write_options): Print message on error.  Rearranged to
+       make use of a table for all options.
+
 2005-09-23  Werner Koch  <wk@g10code.com>
 
        * recipient-dialog.c (recipient_dlg_proc): Removed
index 99d1f6b..b85ec3a 100644 (file)
@@ -36,7 +36,6 @@ gpgol_SOURCES = \
        rfc822parse.c rfc822parse.h \
         common.c intern.h          \
        passcache.c passcache.h     \
-        keycache.c keycache.h      \
         config-dialog.c                    \
         passphrase-dialog.c         \
         recipient-dialog.c          \
index 20be2cc..f1900ba 100644 (file)
@@ -35,7 +35,6 @@
 #include <objidl.h> /* For IStream. */
 
 #include "gpgme.h"
-#include "keycache.h"
 #include "intern.h"
 #include "passcache.h"
 #include "engine.h"
@@ -90,7 +89,6 @@ void
 op_deinit (void)
 {
   cleanup ();
-  cleanup_keycache_objects ();
 }
 
 
@@ -1183,39 +1181,63 @@ add_verify_attestation (gpgme_data_t a, gpgme_ctx_t ctx,
 
 
 \f
-/* Try to find a key for each item in array NAMES. If one ore more
-   items were not found, they are stored as malloced strings to the
-   newly allocated array UNKNOWN at the corresponding position.  Found
-   keys are stored in the newly allocated array KEYS. If N is not NULL
-   the total number of items will be stored at that address.  Note,
-   that both UNKNOWN may have NULL entries inbetween. The fucntion
-   returns the nuber of keys not found. Caller needs to releade KEYS
-   and UNKNOWN. 
-
-   FIXME: The calling convetion is far to complicated.  Needs to be revised.
-
+/* Try to find a key for each item in array NAMES. Item not found are
+   stored as malloced strings in tghe newly allocated array UNKNOWN.
+   Found keys are stored in the newly allocated array KEYS.  Both
+   arrays are terminated by a NULL entry.  Caller needs to releade
+   KEYS and UNKNOWN.
+
+   Returns: 0 on success. However success may also be that one or all
+   keys are unknown.
 */
 int 
-op_lookup_keys (char **names, gpgme_key_t **keys, char ***unknown, size_t *n)
+op_lookup_keys (char **names, gpgme_key_t **keys, char ***unknown)
 {
-    int i, pos=0;
-    gpgme_key_t k;
-
-    for (i=0; names[i]; i++)
-       ;
-    if (n)
-       *n = i;
-    *unknown = (char **)xcalloc (i+1, sizeof (char*));
-    *keys = (gpgme_key_t *)xcalloc (i+1, sizeof (gpgme_key_t));
-    for (i=0; names[i]; i++) {
-       /*k = find_gpg_email(id[i]);*/
-       k = get_gpg_key (names[i]);
-       if (!k)
-           (*unknown)[pos++] = xstrdup (names[i]);
-       else
-           (*keys)[i] = k;
+  gpgme_error_t err;
+  gpgme_ctx_t ctx;
+  size_t n;
+  int i, kpos, upos;
+  gpgme_key_t k, k2;
+
+  *keys = NULL;
+  *unknown = NULL;
+
+  err = gpgme_new (&ctx);
+  if (err)
+    return -1; /* Error. */
+
+  for (n=0; names[n]; n++)
+    ;
+
+  *keys =  xcalloc (n+1, sizeof *keys);
+  *unknown = xcalloc (n+1, sizeof *unknown);
+
+  for (i=kpos=upos=0; names[i]; i++)
+    {
+      k = NULL;
+      err = gpgme_op_keylist_start (ctx, names[i], 0);
+      if (!err)
+        {
+          err = gpgme_op_keylist_next (ctx, &k);
+          if (!err && gpgme_op_keylist_next (ctx, &k2))
+            {
+              /* More than one matching key available.  Take this one
+                 as unknown. */
+              gpgme_key_release (k);
+              gpgme_key_release (k2);
+              k = k2 = NULL;
+            }
+        }
+      gpgme_op_keylist_end (ctx);
+
+      if (k)
+        (*keys)[kpos++] = k;
+      else
+        (*unknown)[upos++] = xstrdup (names[i]);
     }
-    return (i-pos);
+
+  gpgme_release (ctx);
+  return 0;
 }
 
 
index 1368ee8..746321e 100644 (file)
@@ -75,7 +75,7 @@ int op_verify_detached_sig (LPSTREAM data, const char *sig,
 
 int op_export_keys (const char *pattern[], const char *outfile);
 
-int op_lookup_keys (char **id, gpgme_key_t **keys, char ***unknown, size_t *n);
+int op_lookup_keys (char **names, gpgme_key_t **keys, char ***unknown);
 
 const char *userid_from_key (gpgme_key_t k);
 const char *keyid_from_key (gpgme_key_t k);
index 554ca50..e892586 100644 (file)
@@ -64,6 +64,8 @@ struct attach_info
 {
   int end_of_table;  /* True if this is the last plus one entry of the
                         table. */
+  int invalid;       /* Invalid table entry - usally ignored. */
+   
   int is_encrypted;  /* This is an encrypted attchment. */
   int is_signed;     /* This is a signed attachment. */
   unsigned int sig_pos; /* For signed attachments the index of the
@@ -249,17 +251,15 @@ free_key_array (gpgme_key_t *keys)
     }
 }
 
-/* Release an array of strings with recipient names. */
+/* Release an array of strings. */
 static void
-free_recipient_array (char **recipients)
+free_string_array (char **strings)
 {
-  int i;
-
-  if (recipients)
+  if (strings)
     {
-      for (i=0; recipients[i]; i++) 
-       xfree (recipients[i]);  
-      xfree (recipients);
+      for (int i=0; strings[i]; i++) 
+       xfree (strings[i]);     
+      xfree (strings);
     }
 }
 
@@ -280,13 +280,23 @@ release_attach_info (attach_info_t table)
 }
 
 
-/* Return the number of recipients in the array RECIPIENTS. */
-static int 
-count_recipients (char **recipients)
+/* Return the number of strings in the array STRINGS. */
+static size_t
+count_strings (char **strings)
 {
-  int i;
+  size_t i;
+  
+  for (i=0; strings[i]; i++)
+    ;
+  return i;
+}
+
+static size_t
+count_keys (gpgme_key_t *keys)
+{
+  size_t i;
   
-  for (i=0; recipients[i] != NULL; i++)
+  for (i=0; keys[i]; i++)
     ;
   return i;
 }
@@ -1203,8 +1213,7 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
   char **recipients = NULL;
   char **unknown = NULL;
   int err = 0;
-  size_t all = 0;
-  int n_keys;
+  size_t n_keys, n_unknown, n_recp;
     
   
   if (!*(plaintext = getOrigText ()) && !hasAttachments ()) 
@@ -1224,24 +1233,31 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
     }
 
   /* Gather the keys for the recipients. */
+      TRACEPOINT();
   recipients = getRecipients ();
-  n_keys = op_lookup_keys (recipients, &keys, &unknown, &all);
-
-  log_debug ("%s:%s: found %d recipients, need %d, unknown=%p\n",
-             __FILE__, __func__, n_keys, all, unknown);
+      TRACEPOINT();
+  if ( op_lookup_keys (recipients, &keys, &unknown) )
+    {
+      log_debug ("%s.%s: leave (lookup keys failed)\n", __FILE__, __func__);
+      return gpg_error (GPG_ERR_GENERAL);  
+    }
+      TRACEPOINT();
+  n_recp = count_strings (recipients);
+  n_keys = count_keys (keys);
+  n_unknown = count_strings (unknown);
+      TRACEPOINT();
   
-  if (n_keys != count_recipients (recipients))
+  log_debug ("%s:%s: found %d recipients, need %d, unknown=%d\n",
+             __FILE__, __func__, (int)n_keys, (int)n_recp, (int)n_unknown);
+  
+  if (n_keys != n_recp)
     {
-      int opts = 0;
-      gpgme_key_t *keys2 = NULL;
+      unsigned int opts;
+      gpgme_key_t *keys2;
 
-      /* FIXME: The implementation is not correct: op_lookup_keys
-         returns the number of missing keys but we compare against the
-         total number of keys; thus the box would pop up even when all
-         have been found. */
       log_debug ("%s:%s: calling recipient_dialog_box2", __FILE__, __func__);
-      recipient_dialog_box2 (keys, unknown, all, &keys2, &opts);
-      xfree (keys);
+      opts = recipient_dialog_box2 (keys, unknown, &keys2);
+      free_key_array (keys);
       keys = keys2;
       if (opts & OPT_FLAG_CANCEL) 
         {
@@ -1347,13 +1363,9 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
   /* 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)
-    xfree (unknown);
-
   free_key_array (keys);
-  free_recipient_array (recipients);
+  free_string_array (recipients);
+  free_string_array (unknown);
   xfree (ciphertext);
   log_debug ("%s:%s: leave (err=%s)\n", __FILE__, __func__, op_strerror (err));
   return err;
@@ -1474,7 +1486,7 @@ get_attach_method (LPATTACH obj)
 }
 
 
-/* Return the content-type of the attachment OBJ or NULL if it dow not
+/* Return the content-type of the attachment OBJ or NULL if it does not
    exists.  Caller must free. */
 static char *
 get_attach_mime_tag (LPATTACH obj)
@@ -1761,6 +1773,7 @@ GpgMsgImpl::gatherAttachmentInfo (void)
   unsigned int pos, n_attach;
   const char *s;
   unsigned int attestation_count = 0;
+  unsigned int invalid_count = 0;
 
   is_pgpmime = false;
   has_attestation = false;
@@ -1780,6 +1793,8 @@ GpgMsgImpl::gatherAttachmentInfo (void)
         {
           log_error ("%s:%s: can't open attachment %d: hr=%#lx",
                      __FILE__, __func__, pos, hr);
+          table[pos].invalid = 1;
+          invalid_count++;
           continue;
         }
 
@@ -1820,6 +1835,8 @@ GpgMsgImpl::gatherAttachmentInfo (void)
   /* Figure out whether there are encrypted attachments. */
   for (pos=0; !table[pos].end_of_table; pos++)
     {
+      if (table[pos].invalid)
+        continue;
       if (table[pos].armor_type == ARMOR_MESSAGE)
         table[pos].is_encrypted = 1;
       else if (table[pos].filename && (s = strrchr (table[pos].filename, '.'))
@@ -1844,6 +1861,8 @@ GpgMsgImpl::gatherAttachmentInfo (void)
   /* Figure out what attachments are signed. */
   for (pos=0; !table[pos].end_of_table; pos++)
     {
+      if (table[pos].invalid)
+        continue;
       if (table[pos].filename && (s = strrchr (table[pos].filename, '.'))
           &&  !stricmp (s, ".asc")
           && table[pos].content_type  
@@ -1855,13 +1874,18 @@ GpgMsgImpl::gatherAttachmentInfo (void)
              detached signature.  To correlate the data file and the
              signature we keep track of the POS. */
           for (unsigned int i=0; !table[i].end_of_table; i++)
-            if (i != pos && table[i].filename 
-                && strlen (table[i].filename) == len
-                && !strncmp (table[i].filename, table[pos].filename, len))
-              {
-                table[i].is_signed = 1;
-                table[i].sig_pos = pos;
-              }
+            {
+              if (table[i].invalid)
+                continue;
+              if (i != pos && table[i].filename 
+                  && strlen (table[i].filename) == len
+                  && !strncmp (table[i].filename, table[pos].filename, len))
+                {
+                  table[i].is_signed = 1;
+                  table[i].sig_pos = pos;
+                }
+            }
+          
         }
       else if (table[pos].content_type  
                && (!stricmp (table[pos].content_type, "application/pgp")
@@ -1873,6 +1897,8 @@ GpgMsgImpl::gatherAttachmentInfo (void)
   log_debug ("%s:%s: attachment info:\n", __FILE__, __func__);
   for (pos=0; !table[pos].end_of_table; pos++)
     {
+      if (table[pos].invalid)
+        continue;
       log_debug ("\t%d %d %d %u %d `%s' `%s' `%s'\n",
                  pos, table[pos].is_encrypted,
                  table[pos].is_signed, table[pos].sig_pos,
@@ -1885,14 +1911,15 @@ GpgMsgImpl::gatherAttachmentInfo (void)
      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 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 + 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))
+     attesttation attachments: Those are assumed to come after the
+     both PGP/MIME parts. */
+  if (opt.compat.no_pgpmime)
+    ;
+  else if (pos == 2 + attestation_count + invalid_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))
     {
       log_debug ("\tThis is a PGP/MIME encrypted message - table adjusted");
       table[0].is_encrypted = 0;
index 99e7f12..b928782 100644 (file)
@@ -45,66 +45,66 @@ public:
     }
 
   /* Set a new MAPI message into the object. */
-  virtual void setMapiMessage (LPMESSAGE msg);
+  virtual void setMapiMessage (LPMESSAGE msg) = 0;
 
   /* Set the callback for Exchange. */
-  virtual void setExchangeCallback (void *cb);
+  virtual void setExchangeCallback (void *cb) = 0;
 
   /* Don't pop up any message boxes. */
-  virtual void setSilent (bool value);
+  virtual void setSilent (bool value) = 0;
 
   /* Return the type of the message. */
-  virtual openpgp_t getMessageType (void);
+  virtual openpgp_t getMessageType (void) = 0;
 
   /* Returns whether the message has any attachments. */
-  virtual bool hasAttachments (void);
+  virtual bool hasAttachments (void) = 0;
 
   /* Return the body text as received or composed.  This is guaranteed
      to never return NULL.  Usually getMessageType is used to check
      whether there is a suitable message. */
-  virtual const char *getOrigText (void);
+  virtual const char *getOrigText (void) = 0;
 
   /* Return the text of the message to be used for the display.  The
      message objects has intrinsic knowledge about the correct
      text.  */
-  virtual const char *getDisplayText (void);
+  virtual const char *getDisplayText (void) = 0;
 
   /* Return a malloced array of malloced strings with the recipients
      of the message. Caller is responsible for freeing this array and
      the strings.  On failure NULL is returned.  */
-  virtual char **getRecipients (void);
+  virtual char **getRecipients (void) = 0;
 
   /* Decrypt and verify the message and all attachments.  */
-  virtual int decrypt (HWND hwnd);
+  virtual int decrypt (HWND hwnd) = 0;
 
   /* Sign the message and optionally the attachments. */
-  virtual int sign (HWND hwnd);
+  virtual int sign (HWND hwnd) = 0;
 
   /* Encrypt the entire message including any attachments. Returns 0
      on success. */
-  virtual int encrypt (HWND hwnd);
+  virtual int encrypt (HWND hwnd) = 0;
 
   /* Encrypt and sign the entire message including any
      attachments. Return 0 on success. */
-  virtual int signEncrypt (HWND hwnd);
+  virtual int signEncrypt (HWND hwnd) = 0;
 
   /* Attach the key identified by KEYID to the message. */
-  virtual int attachPublicKey (const char *keyid);
+  virtual int attachPublicKey (const char *keyid) = 0;
 
   /* Return the number of attachments. */
-  virtual unsigned int getAttachments (void);
+  virtual unsigned int getAttachments (void) = 0;
 
   /* 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,
-                                  int ttl, const char *filename);
+                                  int ttl, const char *filename) = 0;
 
   virtual void signAttachment (HWND hwnd, int pos,
-                               gpgme_key_t sign_key, int ttl);
+                               gpgme_key_t sign_key, int ttl) = 0;
 
   virtual int encryptAttachment (HWND hwnd, int pos, gpgme_key_t *keys,
-                                 gpgme_key_t sign_key, int ttl);
+                                 gpgme_key_t sign_key, int ttl) = 0;
 
 };
 
index 29a5cbf..5a20225 100644 (file)
@@ -82,7 +82,6 @@ struct decrypt_key_s
   int ttl;  /* TTL of the passphrase. */
   unsigned int flags;
   unsigned int hide_pwd:1;
-  unsigned int use_as_cb:1;
   unsigned int last_was_bad:1;
 };
 
@@ -129,9 +128,9 @@ int watcher_free_hook (void);
 void watcher_set_callback_ctx (void *cb);
 
 /*-- recipient-dialog.c --*/
-int recipient_dialog_box(gpgme_key_t **ret_rset, int *ret_opts);
-int recipient_dialog_box2 (gpgme_key_t *fnd, char **unknown, size_t n,
-                          gpgme_key_t **ret_rset, int *ret_opts);
+unsigned int recipient_dialog_box(gpgme_key_t **ret_rset);
+unsigned int recipient_dialog_box2 (gpgme_key_t *fnd, char **unknown,
+                                    gpgme_key_t **ret_rset);
 
 /*-- passphrase-dialog.c --*/
 int signer_dialog_box (gpgme_key_t *r_key, char **r_passwd);
diff --git a/src/keycache.c b/src/keycache.c
deleted file mode 100644 (file)
index e64bba5..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/* keycache.c
- *     Copyright (C) 2004 Timo Schulz
- *     Copyright (C) 2005 g10 Code GmbH
- *
- * This file is part of GPGol.
- *
- * GPGol 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.
- *  
- * GPGol 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with GPGol; if not, write to the Free Software Foundation, 
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
- */
-#include <windows.h>
-#include <time.h>
-
-#include "gpgme.h"
-#include "keycache.h"
-#include "intern.h"
-
-static keycache_t pubring = NULL;
-static keycache_t secring = NULL;
-static time_t last_timest = 0;
-
-
-/* Initialize global keycache objects */
-void
-init_keycache_objects (void)
-{
-    if (pubring || secring)
-       cleanup_keycache_objects ();
-    keycache_init (NULL, 0, &pubring);
-    keycache_init (NULL, 1, &secring);
-}
-
-
-/* Cleanup global keycache objects */
-void 
-cleanup_keycache_objects (void)
-{
-    keycache_release (pubring);
-    pubring = NULL;
-    keycache_release (secring);
-    secring = NULL;
-}
-
-
-/* Initialize global keycache from external objects */
-void
-load_keycache_objects (keycache_t ring[2])
-{
-    pubring = ring[0];
-    secring = ring[1];
-}
-
-/* Create a new keycache object and return it in r_ctx. */
-int 
-keycache_new (keycache_t *r_ctx)
-{
-    keycache_t c;
-
-    c = xcalloc (1, sizeof *c);
-    *r_ctx = c;
-    return 0;
-}
-
-
-/* Release keycache object */
-void 
-keycache_release (keycache_t ctx)
-{
-    keycache_t n;
-
-    while (ctx) {
-       n = ctx->next;
-       gpgme_key_release (ctx->key);
-       free (ctx);
-       ctx = n;
-    }
-}
-
-/* Free the keycache object but not the keys which are stored in it. */
-void 
-keycache_free(keycache_t ctx)
-{
-    keycache_t n;
-
-    while (ctx) {
-       n = ctx->next;
-       free (ctx);
-       ctx = n;
-    }
-}
-
-
-/* Add a key to the keycache object. */
-int 
-keycache_add (keycache_t *ctx, gpgme_key_t key)
-{
-    keycache_t c;
-    int rc;
-
-    rc = keycache_new (&c);
-    if (rc)
-       return rc;
-    c->key = key;
-    c->next = *ctx;
-    *ctx = c;
-
-    return 0;
-}
-
-
-/* Initialize the keycache object with GPG keys which match the
-   given pattern. */
-int 
-keycache_init (const char *pattern, int seconly, keycache_t *r_ctx)
-{
-    gpgme_ctx_t ctx;
-    gpgme_key_t key;
-    gpgme_error_t rc;
-
-    rc = gpgme_new (&ctx);
-    if (rc)
-       return rc;
-
-    rc = gpgme_op_keylist_start (ctx, pattern, seconly);
-    if (rc)
-       goto leave;
-    while (!gpgme_op_keylist_next (ctx, &key))
-       keycache_add (r_ctx, key);
-    gpgme_op_keylist_end (ctx);
-
-leave:
-    gpgme_release (ctx);
-    return rc;
-}
-
-
-/* Return the size of the keycache object */
-int 
-keycache_size (keycache_t ctx)
-{
-    int i;
-    keycache_t n;
-    for (i=0, n=ctx; n; n = n->next, i++)
-       ;
-    return i;
-}
-
-
-/* Find a key specified by an email address */
-gpgme_key_t
-find_gpg_email (const char *str)
-{
-    keycache_t n;
-    gpgme_user_id_t u;
-
-    for (n=pubring; n; n = n->next) {
-       for (u = n->key->uids; u; u = u->next) {
-           if (strstr (u->uid, str))
-               return n->key;
-       }
-    }
-    return NULL;
-}
-
-/* Find a key in the public keyring cache */
-gpgme_key_t 
-find_gpg_key (const char *str, int type)
-{
-    keycache_t n;
-    gpgme_subkey_t s;
-
-    if (type == 1)
-       return find_gpg_email (str);
-
-    for (n=pubring; n; n = n->next) {
-       for (s=n->key->subkeys; s; s = s->next) {
-           if (!strncmp(str, s->keyid+8, 8))
-               return n->key;
-       }
-    }
-    return NULL;
-}
-
-
-/* this function works directly with GPG. caller has to free the key. */
-gpgme_key_t
-get_gpg_key (const char *str)
-{
-    gpgme_error_t rc;
-    gpgme_ctx_t ctx;
-    gpgme_key_t key;
-
-    rc = gpgme_new (&ctx);
-    if (rc)
-       return NULL;
-    rc = gpgme_op_keylist_start (ctx, str, 0);
-    if (!rc)
-       rc = gpgme_op_keylist_next (ctx, &key);
-    gpgme_release (ctx);
-    return key;
-}
-
-
-/* Enumerate all public keys. If the keycache is not initialized, load it. */
-int 
-enum_gpg_keys (gpgme_key_t * ret_key, void **ctx)
-{
-    if (!pubring) {
-       keycache_release (pubring); pubring=NULL;
-       keycache_init (NULL, 0, &pubring);
-       *ctx = pubring;
-    }
-    if (!ret_key) {
-       if (time (NULL) > last_timest+1750) { /* refresh after 30 minutes */
-           last_timest = time (NULL);
-           cleanup_keycache_objects ();
-           keycache_init(NULL, 0, &pubring);       
-       }
-       *ctx = pubring;
-       return 0;
-    }
-    *ret_key = ((keycache_t)(*ctx))->key;
-    *ctx = ((keycache_t)(*ctx))->next;
-    return *ctx != NULL? 0 : -1;
-}
-
-
-/* Enumerate all secret keys. */
-int 
-enum_gpg_seckeys (gpgme_key_t * ret_key, void **ctx)
-{
-    if (!secring ||*ctx == NULL) {
-       keycache_release (secring); secring=NULL;
-       keycache_init (NULL, 1, &secring);
-       *ctx = secring;
-    }
-    if (!ret_key)
-       return 0;
-    *ret_key = ((keycache_t)(*ctx))->key;
-    *ctx = ((keycache_t)(*ctx))->next;
-    return *ctx != NULL? 0 : -1;
-}
-
-
-/* Reset the secret key enumeration. */
-void 
-reset_gpg_seckeys (void **ctx)
-{
-    *ctx = secring;
-}
diff --git a/src/keycache.h b/src/keycache.h
deleted file mode 100644 (file)
index dc3071a..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* keycache.h
- *     Copyright (C) 2004 Timo Schulz
- *     Copyright (C) 2005 g10 Code GmbH
- *
- * This file is part of GPGol.
- *
- * GPGol 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.
- *  
- * GPGol 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with GPGol; if not, write to the Free Software Foundation, 
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
- */
-#ifndef GPGOL_KEYCACHE_H
-#define GPGOL_KEYCACHE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct keycache_s {
-    struct keycache_s *next;
-    gpgme_key_t key;
-};
-typedef struct keycache_s *keycache_t;
-
-void load_keycache_objects (keycache_t ring[2]);
-void init_keycache_objects (void);
-void cleanup_keycache_objects (void);
-void reset_gpg_seckeys (void **ctx);
-
-int keycache_new (keycache_t *r_ctx);
-void keycache_release (keycache_t ctx);
-int keycache_add (keycache_t *ctx, gpgme_key_t key);
-int keycache_init (const char *pattern, int seconly, keycache_t *r_ctx);
-int keycache_size (keycache_t ctx);
-void keycache_free (keycache_t ctx);
-
-keycache_t get_gpg_keycache (int sec);
-int enum_gpg_seckeys (gpgme_key_t * ret_key, void **ctx);
-int enum_gpg_keys (gpgme_key_t * ret_key, void **ctx);
-gpgme_key_t find_gpg_key (const char *str, int type);
-gpgme_key_t find_gpg_email (const char *str);
-gpgme_key_t get_gpg_key (const char *str);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*GPGOL_KEYCACHE_H*/
index 229a83c..be9cc3e 100644 (file)
@@ -361,30 +361,47 @@ write_options (void)
   struct 
   {
     const char *name;
+    int  mode;
     int  value;
+    char *s_val;
   } table[] = {
-    {"encryptDefault",           opt.encrypt_default},
-    {"signDefault",              opt.sign_default},
-    {"addDefaultKey",            opt.add_default_key},
-    {"saveDecryptedAttachments", opt.save_decrypted_attach},
-    {"autoSignAttachments",      opt.auto_sign_attach},
+    {"encryptDefault",           0, opt.encrypt_default},
+    {"signDefault",              0, opt.sign_default},
+    {"addDefaultKey",            0, opt.add_default_key},
+    {"saveDecryptedAttachments", 0, opt.save_decrypted_attach},
+    {"autoSignAttachments",      0, opt.auto_sign_attach},
+    {"storePasswdTime",          1, opt.passwd_ttl},
+    {"encodingFormat",           1, opt.enc_format},
+    {"logFile",                  2, 0, logfile},
+    {"defaultKey",               2, 0, opt.default_key},
     {NULL, 0}
   };
   char buf[32];
-  int i;
+  int rc, i;
 
   for (i=0; table[i].name; i++) 
-    store_extension_value (table[i].name, table[i].value? "1": "0");
-
-  store_extension_value ("logFile", logfile? logfile: "");
-  store_extension_value ("defaultKey", opt.default_key? opt.default_key:"");
-  
-  sprintf (buf, "%d", opt.passwd_ttl);
-  store_extension_value ("storePasswdTime", buf);
+    {
+      log_debug ("storing option `%s'\n", table[i].name);
+      switch (table[i].mode)
+        {
+        case 0:
+          rc = store_extension_value (table[i].name, table[i].value? "1": "0");
+          break;
+        case 1:
+          sprintf (buf, "%d", table[i].value);
+          rc = store_extension_value (table[i].name, buf);
+          break;
+        case 2:
+          rc = store_extension_value (table[i].name,
+                                      table[i].s_val? table[i].s_val : "");
+          break;
+        default:
+          rc = -1;
+          break;
+        }
+      if (rc)
+        log_error ("error storing option `%s': rc = %d\n", table[i].name, rc);
+    }
   
-  sprintf (buf, "%d", opt.enc_format);
-  store_extension_value ("encodingFormat", buf);
-
   return 0;
 }
-
index 4c648fc..ddedbfc 100644 (file)
 #include <gpgme.h>
 
 #include "gpgol-ids.h"
-#include "keycache.h"
 #include "passcache.h"
 #include "intern.h"
 
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     __FILE__, __func__, __LINE__); \
+                        } while (0)
 
+/* Object to maintai8n state in the dialogs. */
+struct dialog_context_s
+{
+  struct decrypt_key_s *dec; /* The decryption info. */
 
-static char const allhexdigits[] = "1234567890ABCDEFabcdef";
+  gpgme_key_t *keyarray;     /* NULL or an array of keys. */
 
+  int hide_state;            /* Flag indicating that some stuff is hidden. */
 
-#if 0 /* XXX: left over from old code?? */
-static void
-add_string_list (HWND hbox, const char **list, int start_idx)
-{
-    const char * s;
-    int i;
+  unsigned int use_as_cb;    /* This is used by the passphrase callback. */
+};
 
-    for (i=0; (s=list[i]); i++)
-       SendMessage (hbox, CB_ADDSTRING, 0, (LPARAM)(const char *)s);
-    SendMessage (hbox, CB_SETCURSEL, (WPARAM) start_idx, 0);
-}
-#endif
+
+static char const allhexdigits[] = "1234567890ABCDEFabcdef";
 
 
 static void
@@ -78,61 +78,88 @@ set_key_hint (struct decrypt_key_s * dec, HWND dlg, int ctrlid)
     xfree (key_hint);
 }
 
+/* Release the key array ARRAY as well as all COUNT keys. */
+static void
+release_keyarray (gpgme_key_t *array)
+{
+  size_t n;
+
+  if (array)
+    {
+      for (n=0; array[n]; n++)
+        gpgme_key_release (array[n]);
+      xfree (array);
+    }
+}
+
+/* Return the number of keys in the key array KEYS. */
+static size_t
+count_keys (gpgme_key_t *keys)
+{
+  size_t n = 0;
+
+  if (keys)
+    for (; *keys; keys++)
+      n++;
+  return n;
+}
+
 
 static void
 load_recipbox (HWND dlg, int ctlid, gpgme_ctx_t ctx)
 {
   gpgme_decrypt_result_t res;
   gpgme_recipient_t rset, r;
-  gpgme_ctx_t keyctx=NULL;
+  gpgme_ctx_t keyctx = NULL;
   gpgme_key_t key;
   gpgme_error_t err;
-  char *p;
-  int c=0;
+  char *buffer, *p;
+  size_t n;
   
-  if (ctx == NULL)
+  if (!ctx)
     return;
+
+  /* Lump together all recipients of the message. */
   res = gpgme_op_decrypt_result (ctx);
-  if (res == NULL || res->recipients == NULL)
+  if (!res || !res->recipients)
     return;
   rset = res->recipients;
-  for (r = rset; r; r = r->next)
-    c++;    
-  p = xcalloc (1, c*(17+2));
-  for (r = rset; r; r = r->next) {
-    strcat (p, r->keyid);
-    strcat (p, " ");
-  }
-
+  for (n=0, r = rset; r; r = r->next)
+    if (r->keyid)
+      n += strlen (r->keyid) + 1;    
+  buffer = xmalloc (n + 1);
+  for (p=buffer, r = rset; r; r = r->next)
+    if (r->keyid)
+      p = stpcpy (stpcpy (p, r->keyid), " ");
+
+  /* Run a key list on all of them to fill up the list box. */
   err = gpgme_new (&keyctx);
   if (err)
     goto fail;
-  err = gpgme_op_keylist_start (keyctx, p, 0);
+  err = gpgme_op_keylist_start (keyctx, buffer, 0);
   if (err)
     goto fail;
 
-  r = rset;
-  for (;;) 
+  while ( !gpgme_op_keylist_next (keyctx, &key) )
     {
-      err = gpgme_op_keylist_next (keyctx, &key);
-      if (err)
-       break;
-
-      if (key && key->uids != NULL)
+      if (key && key->uids && key->uids->uid)
        SendDlgItemMessage (dlg, ctlid, LB_ADDSTRING, 0,
                            (LPARAM)(const char *)key->uids->uid);
+      if (key)
        gpgme_key_release (key);
-       key = NULL;
-       r = r->next;
     }
 
-fail:
-    if (keyctx != NULL)
-       gpgme_release (keyctx);
-    xfree (p);
+ fail:
+  if (keyctx)
+    gpgme_release (keyctx);
+  xfree (buffer);
 }
 
 
+
+/* Return a string with the short description of the algorithm.  This
+   function is guaranteed to not return NULL or a string longer that 3
+   bytes. */
 const char*
 get_pubkey_algo_str (gpgme_pubkey_algo_t alg)
 {
@@ -146,7 +173,13 @@ get_pubkey_algo_str (gpgme_pubkey_algo_t alg)
       
     case GPGME_PK_ELG_E:
       return "ELG";
-      
+
+    case GPGME_PK_DSA:
+      return "DSA";
+
+    case GPGME_PK_ELG:
+      return "elg";
+
     default:
       break;
     }
@@ -155,262 +188,387 @@ get_pubkey_algo_str (gpgme_pubkey_algo_t alg)
 }
 
 
-static void
+/* Fill a combo box with all keys and return an error with those
+   keys. */
+static gpgme_key_t *
 load_secbox (HWND dlg, int ctlid)
 {
-  gpgme_key_t sk;
-  size_t n=0, doloop=1;
-  void *ctx=NULL;
-  
-  enum_gpg_seckeys (NULL, &ctx);
-  while (doloop) 
+  gpg_error_t err;
+  gpgme_ctx_t ctx;
+  gpgme_key_t key;
+  int pos;
+  gpgme_key_t *keyarray;
+  size_t keyarray_size;
+
+  TRACEPOINT();
+  err = gpgme_new (&ctx);
+  if (err)
+    return NULL;
+
+  TRACEPOINT();
+  err = gpgme_op_keylist_start (ctx, NULL, 1);
+  if (err)
+    {
+      log_error ("failed to initiate key listing: %s\n", gpg_strerror (err));
+      gpgme_release (ctx);
+      return NULL;
+    }
+
+  TRACEPOINT();
+  keyarray_size = 20; 
+  keyarray = xcalloc (keyarray_size+1, sizeof *keyarray);
+  pos = 0;
+
+  while (!gpgme_op_keylist_next (ctx, &key)) 
     {
       const char *name, *email, *keyid, *algo;
       char *p;
       
-      if (enum_gpg_seckeys (&sk, &ctx))
-       doloop = 0;
-      
-      if (sk->revoked || sk->expired || sk->disabled || sk->invalid)
-       continue;
-      if (!sk->uids)
-       continue;
-
-      name = sk->uids->name;
-      email = sk->uids->email;
-      keyid = sk->subkeys->keyid;
-      algo = get_pubkey_algo_str (sk->subkeys->pubkey_algo);
+  TRACEPOINT();
+      if (key->revoked || key->expired || key->disabled || key->invalid)
+        {
+          gpgme_key_release (key);
+          continue;
+        }
+      if (!key->uids || !key->subkeys)
+        {
+          gpgme_key_release (key);
+          continue;
+        }
+        
+      name = key->uids->name;
+      if (!name)
+        name = "";
+      email = key->uids->email;
       if (!email)
        email = "";
-      p = (char *)xcalloc (1, strlen (name) + strlen (email) + 17 + 32);
-      if (email && strlen (email))
+      keyid = key->subkeys->keyid;
+      if (!keyid || strlen (keyid) < 8)
+        {
+          gpgme_key_release (key);
+          continue;
+        }
+
+      algo = get_pubkey_algo_str (key->subkeys->pubkey_algo);
+      p = xmalloc (strlen (name) + strlen (email) + strlen (keyid+8) + 3 + 20);
+      if (email && *email)
        sprintf (p, "%s <%s> (0x%s, %s)", name, email, keyid+8, algo);
       else
        sprintf (p, "%s (0x%s, %s)", name, keyid+8, algo);
       SendDlgItemMessage (dlg, ctlid, CB_ADDSTRING, 0, 
                          (LPARAM)(const char *) p);
       xfree (p);
+
+  TRACEPOINT();
+      SendDlgItemMessage (dlg, ctlid, CB_SETITEMDATA, pos, (LPARAM)pos);
+  TRACEPOINT();
+
+      if (pos >= keyarray_size)
+        {
+          gpgme_key_t *tmparr;
+          size_t i;
+
+  TRACEPOINT();
+          keyarray_size += 10;
+          tmparr = xcalloc (keyarray_size, sizeof *tmparr);
+          for (i=0; i < pos; i++)
+            tmparr[i] = keyarray[i];
+          xfree (keyarray);
+          keyarray = tmparr;
+        }
+      keyarray[pos++] = key;
+  TRACEPOINT();
     }
-  
-  ctx = NULL;
-  reset_gpg_seckeys (&ctx);
-  doloop = 1;
-  n = 0;
-  while (doloop) 
-    {
-      if (enum_gpg_seckeys (&sk, &ctx))
-       doloop = 0;
-      if (sk->revoked || sk->expired || sk->invalid || sk->disabled)
-       continue;
-      SendDlgItemMessage (dlg, ctlid, CB_SETITEMDATA, n, (LPARAM)(DWORD)sk);
-      n++;
-    }
-  SendDlgItemMessage (dlg, ctlid, CB_SETCURSEL, 0, 0);
-  reset_gpg_seckeys (&ctx);
+
+  TRACEPOINT();
+  gpgme_op_keylist_end (ctx);
+  gpgme_release (ctx);
+  TRACEPOINT();
+  return keyarray;
 }
 
 
 static BOOL CALLBACK
 decrypt_key_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
 {
-    static struct decrypt_key_s * dec;
-    static int hide_state = 1;
-    size_t n;
-
-    switch (msg) {
-    case WM_INITDIALOG:
-        log_debug ("decrypt_key_dlg_proc: WM_INITDIALOG\n");
-       dec = (struct decrypt_key_s *)lparam;
-       if (dec && dec->use_as_cb) {
-           dec->opts = 0;
-           dec->pass = NULL;
-           set_key_hint (dec, dlg, IDC_DEC_KEYLIST);
-           EnableWindow (GetDlgItem (dlg, IDC_DEC_KEYLIST), FALSE);
+  /* Fixme: We should not use a static here but keep it in an array
+     index by DLG. */
+  static struct dialog_context_s *context; 
+  struct decrypt_key_s *dec;
+  size_t n;
+
+  if (msg == WM_INITDIALOG)
+    {
+      context = (struct dialog_context_s *)lparam;
+      context->hide_state = 1;
+      dec = context->dec;
+      TRACEPOINT();
+      if (dec && context->use_as_cb) 
+        {
+          dec->opts = 0;
+          dec->pass = NULL;
+          set_key_hint (dec, dlg, IDC_DEC_KEYLIST);
+          EnableWindow (GetDlgItem (dlg, IDC_DEC_KEYLIST), FALSE);
        }
-       if (dec && dec->last_was_bad)
-           SetDlgItemText (dlg, IDC_DEC_HINT, "Invalid passphrase; please try again...");
-       else
-           SetDlgItemText (dlg, IDC_DEC_HINT, "");
-       if (dec && !dec->use_as_cb)
-           load_secbox (dlg, IDC_DEC_KEYLIST);
-       CheckDlgButton (dlg, IDC_DEC_HIDE, BST_CHECKED);
-       center_window (dlg, NULL);
-       if (dec->hide_pwd) {
-           ShowWindow (GetDlgItem (dlg, IDC_DEC_HIDE), SW_HIDE);
-           ShowWindow (GetDlgItem (dlg, IDC_DEC_PASS), SW_HIDE);
-           ShowWindow (GetDlgItem (dlg, IDC_DEC_PASSINF), SW_HIDE);
-           /* XXX: make the dialog window smaller */
+      if (dec && dec->last_was_bad)
+        SetDlgItemText (dlg, IDC_DEC_HINT, 
+                        (dec && dec->last_was_bad)?
+                        _("Invalid passphrase; please try again..."):"");
+
+      TRACEPOINT();
+      if (dec && !context->use_as_cb)
+        context->keyarray = load_secbox (dlg, IDC_DEC_KEYLIST);
+      TRACEPOINT();
+
+      CheckDlgButton (dlg, IDC_DEC_HIDE, BST_CHECKED);
+      center_window (dlg, NULL);
+      if (dec && dec->hide_pwd) 
+        {
+          ShowWindow (GetDlgItem (dlg, IDC_DEC_HIDE), SW_HIDE);
+          ShowWindow (GetDlgItem (dlg, IDC_DEC_PASS), SW_HIDE);
+          ShowWindow (GetDlgItem (dlg, IDC_DEC_PASSINF), SW_HIDE);
        }
-       else
-           SetFocus (GetDlgItem (dlg, IDC_DEC_PASS));
-       SetForegroundWindow (dlg);
-       return FALSE;
+      else
+        SetFocus (GetDlgItem (dlg, IDC_DEC_PASS));
+
+      SetForegroundWindow (dlg);
+      return FALSE;
+    }
 
+  if (!context)
+    return FALSE;
+
+  dec = context->dec;
+
+  switch (msg) 
+    {
     case WM_DESTROY:
-        log_debug ("decrypt_key_dlg_proc: WM_DESTROY\n");
-       hide_state = 1;
-       break;
+      context->hide_state = 1;
+      break;
 
     case WM_SYSCOMMAND:
-        log_debug ("decrypt_key_dlg_proc: WM_SYSCOMMAND\n");
-       if (wparam == SC_CLOSE)
-           EndDialog (dlg, TRUE);
-       break;
+      if (wparam == SC_CLOSE)
+        EndDialog (dlg, TRUE);
+      break;
 
     case WM_COMMAND:
-        log_debug ("decrypt_key_dlg_proc: WM_COMMAND\n");
-       switch (HIWORD (wparam)) {
+      switch (HIWORD (wparam)) 
+        {
        case BN_CLICKED:
-           if ((int)LOWORD (wparam) == IDC_DEC_HIDE) {
-               HWND hwnd;
+          if ((int)LOWORD (wparam) == IDC_DEC_HIDE)
+            {
+              HWND hwnd;
 
-               hide_state ^= 1;
-               hwnd = GetDlgItem (dlg, IDC_DEC_PASS);
-               SendMessage (hwnd, EM_SETPASSWORDCHAR, hide_state? '*' : 0, 0);
-               SetFocus (hwnd);
+              context->hide_state ^= 1;
+              hwnd = GetDlgItem (dlg, IDC_DEC_PASS);
+              SendMessage (hwnd, EM_SETPASSWORDCHAR,
+                           context->hide_state? '*' : 0, 0);
+              SetFocus (hwnd);
            }
-           break;
+          break;
        }
-       switch (LOWORD (wparam)) {
+
+      switch (LOWORD (wparam)) 
+        {
        case IDOK:
-           n = SendDlgItemMessage (dlg, IDC_DEC_PASS, WM_GETTEXTLENGTH, 0, 0);
-           if (n) {
-               dec->pass = (char *)xcalloc (1, n+2);
-               GetDlgItemText (dlg, IDC_DEC_PASS, dec->pass, n+1);
+          n = SendDlgItemMessage (dlg, IDC_DEC_PASS, WM_GETTEXTLENGTH, 0, 0);
+          if (n && dec) 
+            {
+              dec->pass = xmalloc (n + 2);
+              GetDlgItemText (dlg, IDC_DEC_PASS, dec->pass, n+1);
            }
-           if (!dec->use_as_cb) {
-               int idx = SendDlgItemMessage (dlg, IDC_DEC_KEYLIST, 
-                                             CB_GETCURSEL, 0, 0);
-               dec->signer = (gpgme_key_t)SendDlgItemMessage (dlg, IDC_DEC_KEYLIST,
-                                                              CB_GETITEMDATA, idx, 0);
-               gpgme_key_ref (dec->signer);
+          if (dec && !context->use_as_cb) 
+            {
+              int idx, pos;
+
+              idx = SendDlgItemMessage (dlg, IDC_DEC_KEYLIST,
+                                        CB_GETCURSEL, 0, 0);
+              pos = SendDlgItemMessage (dlg, IDC_DEC_KEYLIST,
+                                        CB_GETITEMDATA, idx, 0);
+              if (pos >= 0 && pos < count_keys (context->keyarray))
+                {
+                  dec->signer = context->keyarray[pos];
+                  gpgme_key_ref (dec->signer);
+                }
            }
-           EndDialog (dlg, TRUE);
-           break;
-
+          EndDialog (dlg, TRUE);
+          break;
+          
        case IDCANCEL:
-           if (dec && dec->use_as_cb && (dec->flags & 0x01)) {
-               const char *warn = "If you cancel this dialog, the message will be sent without signing.\n\n"
-                                  "Do you really want to cancel?";
-               n = MessageBox (dlg, warn, "Secret Key Dialog", MB_ICONWARNING|MB_YESNO);
-               if (n == IDNO)
-                   return FALSE;
+          if (dec && context->use_as_cb && (dec->flags & 0x01)) 
+            {
+              const char *warn = _("If you cancel this dialog, the message"
+                                   " will be sent without signing.\n\n"
+                                   "Do you really want to cancel?");
+              n = MessageBox (dlg, warn, "Secret Key Dialog",
+                              MB_ICONWARNING|MB_YESNO);
+              if (n == IDNO)
+                return FALSE;
            }
-           dec->opts = OPT_FLAG_CANCEL;
-           dec->pass = NULL;
-           EndDialog (dlg, FALSE);
-           break;
+          if (dec)
+            {
+              dec->opts = OPT_FLAG_CANCEL;
+              dec->pass = NULL;
+            }
+          EndDialog (dlg, FALSE);
+          break;
        }
-       break;
+      break; /*WM_COMMAND*/
     }
-    return FALSE;
+
+  return FALSE;
 }
 
 
 static BOOL CALLBACK
 decrypt_key_ext_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
 {
-    static struct decrypt_key_s * dec;
-    static int hide_state = 1;
-    size_t n;
-
-    switch (msg) {
-    case WM_INITDIALOG:
-       dec = (struct decrypt_key_s *)lparam;
-       if (dec != NULL) {
-           dec->opts = 0;
-           dec->pass = NULL;
-           set_key_hint (dec, dlg, IDC_DECEXT_KEYLIST);
-           EnableWindow (GetDlgItem (dlg, IDC_DECEXT_KEYLIST), FALSE);
+  /* Fixme: We should not use a static here but keep it in an array
+     index by DLG. */
+  static struct dialog_context_s *context; 
+  struct decrypt_key_s * dec;
+  size_t n;
+
+  if (msg == WM_INITDIALOG)
+    {
+      context = (struct dialog_context_s *)lparam;
+      context->hide_state = 1;
+      dec = context->dec;
+      if (dec) 
+        {
+          dec->opts = 0;
+          dec->pass = NULL;
+          set_key_hint (dec, dlg, IDC_DECEXT_KEYLIST);
+          EnableWindow (GetDlgItem (dlg, IDC_DECEXT_KEYLIST), FALSE);
        }
-       if (dec && dec->last_was_bad)
-           SetDlgItemText (dlg, IDC_DECEXT_HINT, "Invalid passphrase; please try again...");
-       else
-           SetDlgItemText (dlg, IDC_DECEXT_HINT, "");
-       if (dec != NULL)
-           load_recipbox (dlg, IDC_DECEXT_RSET, (gpgme_ctx_t)dec->ctx);
-       CheckDlgButton (dlg, IDC_DECEXT_HIDE, BST_CHECKED);
-       center_window (dlg, NULL);
-       SetFocus (GetDlgItem (dlg, IDC_DECEXT_PASS));
-       SetForegroundWindow (dlg);
-       return FALSE;
 
+      SetDlgItemText (dlg, IDC_DECEXT_HINT, 
+                      (dec && dec->last_was_bad)?
+                      _("Invalid passphrase; please try again..."):"");
+      if (dec)
+        load_recipbox (dlg, IDC_DECEXT_RSET, (gpgme_ctx_t)dec->ctx);
+
+      CheckDlgButton (dlg, IDC_DECEXT_HIDE, BST_CHECKED);
+      center_window (dlg, NULL);
+      SetFocus (GetDlgItem (dlg, IDC_DECEXT_PASS));
+      SetForegroundWindow (dlg);
+      return FALSE;
+    }
+
+  if (!context)
+    return FALSE;
+
+  dec = context->dec;
+
+  switch (msg) 
+    {
     case WM_DESTROY:
-       hide_state = 1;
-       break;
+      context->hide_state = 1;
+      break;
 
     case WM_SYSCOMMAND:
-       if (wparam == SC_CLOSE)
-           EndDialog (dlg, TRUE);
-       break;
+      if (wparam == SC_CLOSE)
+        EndDialog (dlg, TRUE);
+      break;
 
     case WM_COMMAND:
-       switch (HIWORD (wparam)) {
+      switch (HIWORD (wparam)) 
+        {
        case BN_CLICKED:
-           if ((int)LOWORD (wparam) == IDC_DECEXT_HIDE) {
-               HWND hwnd;
-
-               hide_state ^= 1;
-               hwnd = GetDlgItem (dlg, IDC_DECEXT_PASS);
-               SendMessage (hwnd, EM_SETPASSWORDCHAR, hide_state? '*' : 0, 0);
-               SetFocus (hwnd);
+          if ((int)LOWORD (wparam) == IDC_DECEXT_HIDE) 
+            {
+              HWND hwnd;
+              
+              context->hide_state ^= 1;
+              hwnd = GetDlgItem (dlg, IDC_DECEXT_PASS);
+              SendMessage (hwnd, EM_SETPASSWORDCHAR,
+                           context->hide_state? '*' : 0, 0);
+              SetFocus (hwnd);
            }
-           break;
+          break;
        }
-       switch (LOWORD (wparam)) {
+
+      switch (LOWORD (wparam)) 
+        {
        case IDOK:
-           n = SendDlgItemMessage (dlg, IDC_DECEXT_PASS, WM_GETTEXTLENGTH, 0, 0);
-           if (n) {
-               dec->pass = (char *)xcalloc( 1, n+2 );
-               GetDlgItemText( dlg, IDC_DECEXT_PASS, dec->pass, n+1 );
+          n = SendDlgItemMessage (dlg, IDC_DECEXT_PASS, WM_GETTEXTLENGTH,0,0);
+          if (n && dec) 
+            {
+              dec->pass = xmalloc ( n + 2 );
+              GetDlgItemText (dlg, IDC_DECEXT_PASS, dec->pass, n+1 );
            }
-           EndDialog (dlg, TRUE);
-           break;
+          EndDialog (dlg, TRUE);
+          break;
 
        case IDCANCEL:
-           if (dec && dec->use_as_cb && (dec->flags & 0x01)) {
-               const char *warn = "If you cancel this dialog, the message will be sent without signing.\n"
-                                  "Do you really want to cancel?";
-               n = MessageBox (dlg, warn, "Secret Key Dialog", MB_ICONWARNING|MB_YESNO);
-               if (n == IDNO)
-                   return FALSE;
+          if (dec && context->use_as_cb && (dec->flags & 0x01)) 
+            {
+              const char *warn = _("If you cancel this dialog, the message"
+                                   " will be sent without signing.\n"
+                                  "Do you really want to cancel?");
+              n = MessageBox (dlg, warn, "Secret Key Dialog",
+                              MB_ICONWARNING|MB_YESNO);
+              if (n == IDNO)
+                return FALSE;
            }
-           dec->opts = OPT_FLAG_CANCEL;
-           dec->pass = NULL;
-           EndDialog (dlg, FALSE);
-           break;
+          if (dec)
+            {
+              dec->opts = OPT_FLAG_CANCEL;
+              dec->pass = NULL;
+            }
+          EndDialog (dlg, FALSE);
+          break;
        }
-       break;
+      break; /*WM_COMMAND*/
     }
-    return FALSE;
+
+  return FALSE;
 }
 
-/* Display a signer dialog which contains all secret keys, useable
-   for signing data. The key is returned in r_key. The password in
+/* Display a signer dialog which contains all secret keys, useable for
+   signing data.  The key is returned in R_KEY.  The passprase in
    r_passwd. */
 int 
 signer_dialog_box (gpgme_key_t *r_key, char **r_passwd)
 {
-    struct decrypt_key_s hd;
-    int rc = 0;
-
-    memset(&hd, 0, sizeof (hd));
-    hd.hide_pwd = 1;
-    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_DEC, GetDesktopWindow (),
-                   decrypt_key_dlg_proc, (LPARAM)&hd);
-    if (hd.signer) {
-       if (r_passwd)
-           *r_passwd = xstrdup (hd.pass);
-       else {      
-           xfree (hd.pass);
-           hd.pass = NULL;
-       }
-       *r_key = hd.signer;
+  struct dialog_context_s context; 
+  struct decrypt_key_s dec;
+  
+  TRACEPOINT();
+  memset (&context, 0, sizeof context);
+  memset (&dec, 0, sizeof dec);
+  dec.hide_pwd = 1;
+  context.dec = &dec;
+  
+  TRACEPOINT();
+  DialogBoxParam (glob_hinst, (LPCTSTR)IDD_DEC, GetDesktopWindow (),
+                  decrypt_key_dlg_proc, (LPARAM)&context);
+  TRACEPOINT();
+  if (dec.signer) 
+    {
+      if (r_passwd)
+        *r_passwd = dec.pass;
+      else 
+        {          
+          if (dec.pass)
+            wipestring (dec.pass);
+          xfree (dec.pass);
+        }
+      dec.pass = NULL;
+      *r_key = dec.signer;
+      dec.signer = NULL;
     }
-    if (hd.opts & OPT_FLAG_CANCEL)
-       rc = -1;
-    memset (&hd, 0, sizeof (hd));    
-    return rc;
+  TRACEPOINT();
+  if (dec.pass)
+    wipestring (dec.pass);
+  TRACEPOINT();
+  xfree (dec.pass);
+  if (dec.signer)
+    gpgme_key_release (dec.signer);
+  TRACEPOINT();
+  release_keyarray (context.keyarray);
+  TRACEPOINT();
+  return (dec.opts & OPT_FLAG_CANCEL)? -1 : 0;
 }
 
 
@@ -422,7 +580,7 @@ passphrase_callback_box (void *opaque, const char *uid_hint,
                         const char *pass_info,
                         int prev_was_bad, int fd)
 {
-  struct decrypt_key_s *hd = opaque;
+  struct decrypt_key_s *dec = opaque;
   DWORD nwritten = 0;
   char keyidstr[16+1];
 
@@ -432,18 +590,17 @@ passphrase_callback_box (void *opaque, const char *uid_hint,
   *keyidstr = 0; 
 
   /* First remove a possible passphrase from the return structure. */
-  if (hd->pass)
-    wipestring (hd->pass);
-  xfree (hd->pass);
-  hd->pass = NULL;
+  if (dec->pass)
+    wipestring (dec->pass);
+  xfree (dec->pass);
+  dec->pass = NULL;
 
   /* For some reasons the cancel flag has been set - write an empty
      passphrase and close the handle to indicate the cancel state to
      the backend. */
-  if (hd->opts & OPT_FLAG_CANCEL)
+  if (dec->opts & OPT_FLAG_CANCEL)
     {
-      /* FIXME: Casting an FD to a handles is very questionable.  We
-         need to check this. */
+      /* Casting the FD to a handle is okay as gpgme uses OS handles. */
       WriteFile ((HANDLE)fd, "\n", 1, &nwritten, NULL);
       CloseHandle ((HANDLE)fd);
       log_debug ("passphrase_callback_box: leave (due to cancel flag)\n");
@@ -510,20 +667,25 @@ passphrase_callback_box (void *opaque, const char *uid_hint,
     }
   else if (*keyidstr)
     {
-      hd->pass = passcache_get (keyidstr);
+      dec->pass = passcache_get (keyidstr);
       log_debug ("%s: getting passphrase for 0x%s from cache: %s\n",
-                 __func__, keyidstr, hd->pass? "hit":"miss");
+                 __func__, keyidstr, dec->pass? "hit":"miss");
     }
 
   /* Copy the keyID into the context. */
-  assert (strlen (keyidstr) < sizeof hd->keyid);
-  strcpy (hd->keyid, keyidstr);
+  assert (strlen (keyidstr) < sizeof dec->keyid);
+  strcpy (dec->keyid, keyidstr);
 
   /* If we have no cached pssphrase, popup the passphrase dialog. */
-  if (!hd->pass)
+  if (!dec->pass)
     {
       int rc;
       const char *s;
+      struct dialog_context_s context;
+
+      memset (&context, 0, sizeof context);
+      context.dec = dec;
+      context.use_as_cb = 1;
 
       /* Construct the user ID. */
       if (uid_hint)
@@ -536,31 +698,30 @@ passphrase_callback_box (void *opaque, const char *uid_hint,
         }
       else
         s = "[no user Id]";
-      xfree (hd->user_id);
-      hd->user_id = xstrdup (s);
-          
-      hd->last_was_bad = prev_was_bad;
-      hd->use_as_cb = 1; /* FIXME: For what is this used? */
-      if (hd->flags & 0x01)
+      xfree (dec->user_id);
+      dec->user_id = xstrdup (s);
+      dec->last_was_bad = prev_was_bad;
+      if (dec->flags & 0x01)
         rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_DEC,
                              GetDesktopWindow (),
-                             decrypt_key_dlg_proc, (LPARAM)hd);
+                             decrypt_key_dlg_proc, (LPARAM)&context);
       else
         rc = DialogBoxParam (glob_hinst, (LPCTSTR)IDD_DEC_EXT,
                              GetDesktopWindow (),
-                             decrypt_key_ext_dlg_proc, (LPARAM)hd);
+                             decrypt_key_ext_dlg_proc, (LPARAM)&context);
       if (rc <= 0) 
         log_debug_w32 (-1, "%s: dialog failed (rc=%d)", __func__, rc);
+      release_keyarray (context.keyarray);
     }
   else 
-    log_debug ("%s:%s: hd=%p hd->pass=`[censored]'\n",
-               __FILE__, __func__, hd);
+    log_debug ("%s:%s: dec=%p dec->pass=`[censored]'\n",
+               __FILE__, __func__, dec);
 
   /* If we got a passphrase, send it to the FD. */
-  if (hd->pass) 
+  if (dec->pass) 
     {
       log_debug ("passphrase_callback_box: sending passphrase ...\n");
-      WriteFile ((HANDLE)fd, hd->pass, strlen (hd->pass), &nwritten, NULL);
+      WriteFile ((HANDLE)fd, dec->pass, strlen (dec->pass), &nwritten, NULL);
     }
 
   WriteFile((HANDLE)fd, "\n", 1, &nwritten, NULL);
index 1b3fcdb..f139067 100644 (file)
@@ -558,7 +558,7 @@ pgpmime_decrypt (LPSTREAM instream, int ttl, char **body,
     goto leave;
 
   err = op_decrypt_stream_to_gpgme (instream, plaintext, ttl,
-                                    NULL, attestation);
+                                    "[PGP/MIME message]", attestation);
   if (!err && (ctx->parser_error || ctx->line_too_long))
     err = gpg_error (GPG_ERR_GENERAL);
 
index 1f66bfb..bd514d5 100644 (file)
 #include <gpgme.h>
 
 #include "gpgol-ids.h"
-#include "keycache.h"
 #include "intern.h"
 #include "util.h"
 
-struct recipient_cb_s {
-    char **unknown_keys;    
-    char **fnd_keys;
-    keycache_t rset;
-    size_t n;
-    int opts;
+#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
+                                     __FILE__, __func__, __LINE__); \
+                        } while (0)
+
+
+struct recipient_cb_s 
+{
+  char **unknown_keys;  /* A string array with the names of the
+                           unknown recipients. */
+
+  char **fnd_keys;      /* A string array with the user IDs of already
+                           found keys. */
+
+  /* A bit vector used to return selected options. */
+  unsigned int opts;
+
+  /* A key array to hold all keys. */
+  gpgme_key_t *keyarray;
+  size_t keyarray_count;
+
+  /* The result key Array, i.e. the selected keys.  This array is NULL
+     terminated. */
+  gpgme_key_t *selected_keys;
+  size_t      selected_keys_count;
 };
 
-struct key_item_s {
-    char name [150];
-    char e_mail[100];
-    char key_info[64];
-    char keyid[32];
-    char validity[32];
+struct key_item_s 
+{
+  char name [150];
+  char e_mail[100];
+  char key_info[64];
+  char keyid[32];
+  char validity[32];
+  char idx[20];
 };
 
 
@@ -52,7 +71,7 @@ initialize_rsetbox (HWND hwnd)
     LVCOLUMN col;
 
     memset (&col, 0, sizeof (col));
-    col.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;;
+    col.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
     col.pszText = "Name";
     col.cx = 100;
     col.iSubItem = 0;
@@ -78,45 +97,79 @@ initialize_rsetbox (HWND hwnd)
     col.iSubItem = 4;
     ListView_InsertColumn( hwnd, 4, &col );
 
+    col.pszText = "Index";
+    col.cx = 0;  /* Hide it. */
+    col.iSubItem = 5;
+    ListView_InsertColumn( hwnd, 5, &col );
+
 /*     ListView_SetExtendedListViewStyleEx( hwnd, 0, LVS_EX_FULLROWSELECT ); */
 }
 
 
-static void 
-load_rsetbox (HWND hwnd)
+static gpgme_key_t *
+load_rsetbox (HWND hwnd, size_t *r_arraysize)
 {
   LVITEM lvi;
+  gpg_error_t err;
+  gpgme_ctx_t ctx;
   gpgme_key_t key = NULL;
-  void *ctx = NULL;
+  gpgme_key_t *keyarray;
+  size_t keyarray_size;
+  size_t pos;
   char keybuf[128], *s;
-  const char * trust_items[] = 
+  const char *trust_items[] = 
     {
       "UNKNOWN",
-       "UNDEFINED",
-       "NEVER",
-       "MARGINAL",
-       "FULL",
+      "UNDEFINED",
+      "NEVER",
+      "MARGINAL",
+      "FULL",
       "ULTIMATE"
     };
-  enum {COL_NAME, COL_EMAIL, COL_KEYINF, COL_KEYID, COL_TRUST};
+  enum {COL_NAME, COL_EMAIL, COL_KEYINF, COL_KEYID, COL_TRUST, COL_IDX};
   DWORD val;
-  size_t doloop=1;
 
   memset (&lvi, 0, sizeof (lvi));
-  cleanup_keycache_objects (); /*XXX: rewrite the entire key cache! */
-  enum_gpg_keys (NULL, &ctx);
-  while (doloop) 
+
+  err = gpgme_new (&ctx);
+  if (err)
+    return NULL;
+
+  err = gpgme_op_keylist_start (ctx, NULL, 0);
+  if (err)
     {
-      if (enum_gpg_keys(&key, &ctx))
-       doloop = 0;
+      log_error ("failed to initiate key listing: %s\n", gpg_strerror (err));
+      gpgme_release (ctx);
+      return NULL;
+    }
+
+  keyarray_size = 500; 
+  keyarray = xcalloc (keyarray_size, sizeof *keyarray);
+  pos = 0;
+                 
+  while (!gpgme_op_keylist_next (ctx, &key)) 
+    {
+      /* We only want keys capable of encrypting. */
       if (!key->can_encrypt)
-       continue;
+        {
+          gpgme_key_release (key);
+          continue;
+        }
       
-      /* check that the primary key is *not* revoked, expired or invalid */
+      /* Check that the primary key is *not* revoked, expired or invalid */
       if (key->revoked || key->expired || key->invalid || key->disabled)
-       continue;
-      if (!key->uids)
-       continue;
+        {
+          gpgme_key_release (key);
+          continue;
+        }
+
+      /* Ignore keys without a user ID or woithout a subkey */
+      if (!key->uids || !key->subkeys )
+        {
+          gpgme_key_release (key);
+          continue;
+        }
+
       ListView_InsertItem (hwnd, &lvi);
       
       s = key->uids->name;
@@ -124,70 +177,126 @@ load_rsetbox (HWND hwnd)
       
       s = key->uids->email;
       ListView_SetItemText (hwnd, 0, COL_EMAIL, s);
-      
-      s = (char*)get_pubkey_algo_str (key->subkeys->pubkey_algo);
-      sprintf (keybuf, "%s", s);
+
+      s = keybuf;
+      *s = 0;
+      s = stpcpy (s, get_pubkey_algo_str (key->subkeys->pubkey_algo));
       if (key->subkeys->next)
-       {
-         s = (char*)get_pubkey_algo_str (key->subkeys->next->pubkey_algo);
-         sprintf (keybuf+strlen (keybuf), "/%s", s);
-       }      
-      strcat (keybuf, " ");
+        {
+          /* Fixme: This is not really correct because we don't know
+             which encryption subkey gpg is going to select. Same
+             holds true for the key length below. */
+          *s++ = '/';
+          s = stpcpy (s, get_pubkey_algo_str
+                      (key->subkeys->next->pubkey_algo));
+        }      
+      
+      *s++ = ' ';
       if (key->subkeys->next)
-       sprintf (keybuf+strlen (keybuf), "%d", key->subkeys->next->length);
+        sprintf (s, "%d", key->subkeys->next->length);
       else
-       sprintf (keybuf+strlen (keybuf), "%d", key->subkeys->length);
+        sprintf (s, "%d", key->subkeys->length);
 
       s = keybuf;
       ListView_SetItemText (hwnd, 0, COL_KEYINF, s);
       
-      ListView_SetItemText( hwnd, 0, COL_KEYID, key->subkeys->keyid+8);
+      if (key->subkeys->keyid  && strlen (key->subkeys->keyid) > 8)
+        ListView_SetItemText (hwnd, 0, COL_KEYID, key->subkeys->keyid+8);
       
       val = key->uids->validity;
       if (val < 0 || val > 5) 
        val = 0;
-      s = (char *)trust_items[val];
+      strcpy (keybuf, trust_items[val]);
+      s = keybuf;
       ListView_SetItemText (hwnd, 0, COL_TRUST, s);
+
+      /* I'd like to use SetItemData but that one is only available as
+         a member function of CListCtrl; I haved not figured out how
+         the vtable is made up.  Thus we use a string with the index. */
+      sprintf (keybuf, "%u", (unsigned int)pos);
+      s = keybuf;
+      ListView_SetItemText (hwnd, 0, COL_IDX, s);
+
+      if (pos >= keyarray_size)
+        {
+          gpgme_key_t *tmparr;
+          size_t i;
+
+          keyarray_size += 500;
+          tmparr = xcalloc (keyarray_size, sizeof *tmparr);
+          for (i=0; i < pos; i++)
+            tmparr[i] = keyarray[i];
+          xfree (keyarray);
+          keyarray = tmparr;
+        }
+      keyarray[pos++] = key;
+
     }
+
+  gpgme_op_keylist_end (ctx);
+  gpgme_release (ctx);
+
+  *r_arraysize = pos;
+  return keyarray;
 }
 
 
+/* Release the key array ARRAY as well as all COUNT keys. */
 static void
-copy_item (HWND dlg, int id_from, int pos)
+release_keyarray (gpgme_key_t *array, size_t count)
 {
-    HWND src, dst;
-    LVITEM lvi;
-    struct key_item_s from;
-    int idx = pos;
-
-    src = GetDlgItem (dlg, id_from);
-    dst = GetDlgItem (dlg, id_from==IDC_ENC_RSET1 ?
-                     IDC_ENC_RSET2 : IDC_ENC_RSET1);
-
-    if (idx == -1) {
-       idx = ListView_GetNextItem (src, -1, LVNI_SELECTED);
-       if (idx == -1)
-           return;
+  size_t n;
+
+  if (array)
+    {
+      for (n=0; n < count; n++)
+        gpgme_key_release (array[n]);
+      xfree (array);
     }
+}
+
+
 
-    memset (&from, 0, sizeof (from));
-    ListView_GetItemText (src, idx, 0, from.name, sizeof (from.name)-1);
-    ListView_GetItemText (src, idx, 1, from.e_mail, sizeof (from.e_mail)-1);
-    ListView_GetItemText (src, idx, 2, from.key_info, sizeof (from.key_info)-1);
-    ListView_GetItemText (src, idx, 3, from.keyid, sizeof (from.keyid)-1);
-    ListView_GetItemText (src, idx, 4, from.validity, sizeof (from.validity)-1);
-
-    ListView_DeleteItem (src, idx);
-
-    memset (&lvi, 0, sizeof (lvi));
-    ListView_InsertItem (dst, &lvi);
-    ListView_SetItemText (dst, 0, 0, from.name);
-    ListView_SetItemText (dst, 0, 1, from.e_mail);
-    ListView_SetItemText (dst, 0, 2, from.key_info);
-    ListView_SetItemText (dst, 0, 3, from.keyid);
-    ListView_SetItemText (dst, 0, 4, from.validity);
+static void
+copy_item (HWND dlg, int id_from, int pos)
+{
+  HWND src, dst;
+  LVITEM lvi;
+  struct key_item_s from;
+  int idx = pos;
+  
+  src = GetDlgItem (dlg, id_from);
+  dst = GetDlgItem (dlg, id_from==IDC_ENC_RSET1 ?
+                    IDC_ENC_RSET2 : IDC_ENC_RSET1);
+  
+  if (idx == -1)
+    {
+      idx = ListView_GetNextItem (src, -1, LVNI_SELECTED);
+      if (idx == -1)
+        return;
+    }
+  
+  memset (&from, 0, sizeof (from));
+  ListView_GetItemText (src, idx, 0, from.name, sizeof (from.name)-1);
+  ListView_GetItemText (src, idx, 1, from.e_mail, sizeof (from.e_mail)-1);
+  ListView_GetItemText (src, idx, 2, from.key_info, sizeof (from.key_info)-1);
+  ListView_GetItemText (src, idx, 3, from.keyid, sizeof (from.keyid)-1);
+  ListView_GetItemText (src, idx, 4, from.validity, sizeof (from.validity)-1);
+  ListView_GetItemText (src, idx, 5, from.idx, sizeof (from.idx)-1);
+
+  ListView_DeleteItem (src, idx);
+  
+  memset (&lvi, 0, sizeof (lvi));
+  ListView_InsertItem (dst, &lvi);
+  ListView_SetItemText (dst, 0, 0, from.name);
+  ListView_SetItemText (dst, 0, 1, from.e_mail);
+  ListView_SetItemText (dst, 0, 2, from.key_info);
+  ListView_SetItemText (dst, 0, 3, from.keyid);
+  ListView_SetItemText (dst, 0, 4, from.validity);
+  ListView_SetItemText (dst, 0, 5, from.idx);
 }
 
+
 static int
 find_item (HWND hwnd, const char *str)
 {
@@ -207,200 +316,231 @@ find_item (HWND hwnd, const char *str)
 static void
 initialize_keybox (HWND dlg, struct recipient_cb_s *cb)
 {
-    size_t i;
-    HWND box = GetDlgItem (dlg, IDC_ENC_NOTFOUND);
-    HWND rset = GetDlgItem (dlg, IDC_ENC_RSET1);
-
-    for (i=0; cb->unknown_keys[i] != NULL; i++)
-       SendMessage (box, LB_ADDSTRING, 0, (LPARAM)(const char *)cb->unknown_keys[i]);
-
-    for (i=0; i < cb->n; i++) {
-       int n;
-       if (cb->fnd_keys[i] == NULL)
-           continue;
-
-       n = find_item (rset, cb->fnd_keys[i]);
-       if (n != -1)
-           copy_item (dlg, IDC_ENC_RSET1, n);
+  size_t i;
+  HWND box = GetDlgItem (dlg, IDC_ENC_NOTFOUND);
+  HWND rset = GetDlgItem (dlg, IDC_ENC_RSET1);
+  int n;
+  
+  if (cb->unknown_keys)
+    {
+      for (i=0; cb->unknown_keys[i]; i++)
+        SendMessage (box, LB_ADDSTRING, 0,
+                     (LPARAM)(const char *)cb->unknown_keys[i]);
     }
 
+  if (cb->fnd_keys)
+    {
+      for (i=0; cb->fnd_keys[i]; i++) 
+        {
+          n = find_item (rset, cb->fnd_keys[i]);
+          if (n != -1)
+            copy_item (dlg, IDC_ENC_RSET1, n);
+        }
+    }
 }
 
 
 BOOL CALLBACK
 recipient_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
 {
-    static struct recipient_cb_s * rset_cb;
-    static int rset_state = 1;
-    NMHDR * notify;
-    HWND hrset;
-    const char *warn;
-    int i;
-
-    switch (msg) {
+  static struct recipient_cb_s * rset_cb;
+  static int rset_state = 1;
+  NMHDR * notify;
+  HWND hrset;
+  const char *warn;
+  size_t pos;
+  int i;
+
+  switch (msg) 
+    {
     case WM_INITDIALOG:
-       rset_cb = (struct recipient_cb_s *)lparam;
-       initialize_rsetbox (GetDlgItem (dlg, IDC_ENC_RSET1));
-       load_rsetbox (GetDlgItem (dlg, IDC_ENC_RSET1));
-       initialize_rsetbox (GetDlgItem (dlg, IDC_ENC_RSET2));
-       if (!rset_cb->unknown_keys) {
-           ShowWindow (GetDlgItem (dlg, IDC_ENC_INFO), SW_HIDE);
-           ShowWindow (GetDlgItem (dlg, IDC_ENC_NOTFOUND), SW_HIDE);
+      rset_cb = (struct recipient_cb_s *)lparam;
+
+      initialize_rsetbox (GetDlgItem (dlg, IDC_ENC_RSET1));
+      rset_cb->keyarray = load_rsetbox (GetDlgItem (dlg, IDC_ENC_RSET1),
+                                        &rset_cb->keyarray_count );
+
+      initialize_rsetbox (GetDlgItem (dlg, IDC_ENC_RSET2));
+
+      if (rset_cb->unknown_keys)
+        initialize_keybox (dlg, rset_cb);
+      else
+        {
+          /* No unknown keys - hide the not required windows. */
+          ShowWindow (GetDlgItem (dlg, IDC_ENC_INFO), SW_HIDE);
+          ShowWindow (GetDlgItem (dlg, IDC_ENC_NOTFOUND), SW_HIDE);
        }
-       else
-           initialize_keybox (dlg, rset_cb);
-       center_window (dlg, NULL);
-       SetForegroundWindow (dlg);
-       return TRUE;
+
+      center_window (dlg, NULL);
+      SetForegroundWindow (dlg);
+      return TRUE;
 
     case WM_SYSCOMMAND:
-       if (wparam == SC_CLOSE)
-           EndDialog (dlg, TRUE);
-       break;
+      if (wparam == SC_CLOSE)
+        EndDialog (dlg, TRUE);
+      break;
 
     case WM_NOTIFY:
-       notify = (LPNMHDR)lparam;
-       if (notify
-           && (notify->idFrom == IDC_ENC_RSET1
-           ||  notify->idFrom == IDC_ENC_RSET2)
-           && notify->code ==  NM_DBLCLK)
-           copy_item (dlg, notify->idFrom, -1);
-       break;
+      notify = (LPNMHDR)lparam;
+      if (notify && notify->code == NM_DBLCLK
+          && (notify->idFrom == IDC_ENC_RSET1
+              || notify->idFrom == IDC_ENC_RSET2))
+        copy_item (dlg, notify->idFrom, -1);
+      break;
 
     case WM_COMMAND:
-       switch (HIWORD (wparam)) {
+      switch (HIWORD (wparam))
+        {
        case BN_CLICKED:
-           if ((int)LOWORD (wparam) == IDC_ENC_OPTSYM) {
-               rset_state ^= 1;
-               EnableWindow (GetDlgItem (dlg, IDC_ENC_RSET1), rset_state);
-               EnableWindow (GetDlgItem (dlg, IDC_ENC_RSET2), rset_state);
-               ListView_DeleteAllItems (GetDlgItem (dlg, IDC_ENC_RSET2));
+          if ((int)LOWORD (wparam) == IDC_ENC_OPTSYM)
+            {
+              rset_state ^= 1;
+              EnableWindow (GetDlgItem (dlg, IDC_ENC_RSET1), rset_state);
+              EnableWindow (GetDlgItem (dlg, IDC_ENC_RSET2), rset_state);
+              ListView_DeleteAllItems (GetDlgItem (dlg, IDC_ENC_RSET2));
            }
-           break;
+          break;
        }
-       switch( LOWORD( wparam ) ) {
+
+      switch ( LOWORD (wparam) ) 
+        {
        case IDOK:
-           hrset = GetDlgItem (dlg, IDC_ENC_RSET2);
-           if (ListView_GetItemCount (hrset) == 0) {
-               MessageBox (dlg, "Please select at least one recipient key.",
-                           "Recipient Dialog", MB_ICONINFORMATION|MB_OK);
-               return FALSE;
-           }
-           keycache_new (&rset_cb->rset);
-
-           for (i=0; i < ListView_GetItemCount (hrset); i++) {
-               gpgme_key_t key;
-               char keyid[32], valid[32];
-
-               ListView_GetItemText (hrset, i, 3, keyid, sizeof (keyid)-1);
-               ListView_GetItemText (hrset, i, 4, valid, sizeof (valid)-1);
-               key = find_gpg_key(keyid, 0);
-               keycache_add(&rset_cb->rset, key);
-               if (strcmp (valid, "FULL") && strcmp (valid, "ULTIMATE"))
-                   rset_cb->opts |= OPT_FLAG_FORCE;
+          hrset = GetDlgItem (dlg, IDC_ENC_RSET2);
+          if (ListView_GetItemCount (hrset) == 0) 
+            {
+              MessageBox (dlg, "Please select at least one recipient key.",
+                          "Recipient Dialog", MB_ICONINFORMATION|MB_OK);
+              return FALSE;
            }
-           EndDialog (dlg, TRUE);
-           break;
+
+          rset_cb->selected_keys_count = ListView_GetItemCount (hrset);
+          rset_cb->selected_keys = xcalloc (rset_cb->selected_keys_count + 1,
+                                            sizeof *rset_cb->selected_keys);
+          for (i=0, pos=0; i < rset_cb->selected_keys_count; i++) 
+            {
+              gpgme_key_t key;
+              int idata;
+              char tmpbuf[30];
+
+              *tmpbuf = 0;
+              ListView_GetItemText (hrset, i, 5, tmpbuf, sizeof tmpbuf - 1);
+              idata = *tmpbuf? strtol (tmpbuf, NULL, 10) : -1;
+              if (idata >= 0 && idata < rset_cb->keyarray_count)
+                {
+                  key = rset_cb->keyarray[idata];
+                  gpgme_key_ref (key);
+                  rset_cb->selected_keys[pos++] = key;
+
+                  switch (key->uids->validity)
+                    {
+                    case GPGME_VALIDITY_FULL:
+                    case GPGME_VALIDITY_ULTIMATE:
+                      break;
+                    default:
+                      /* Force encryption if one key is not fully
+                         trusted.  Actually this is a bit silly but
+                         supposedly here to allow adding an option to
+                         disable this "feature".  */
+                      rset_cb->opts |= OPT_FLAG_FORCE;
+                      break;
+                    }
+                }
+              else
+                log_debug ("List item not correctly initialized - ignored\n");
+            }
+          rset_cb->selected_keys_count = pos;
+          EndDialog (dlg, TRUE);
+          break;
 
        case IDCANCEL:
-           warn = "If you cancel this dialog, the message will be sent in cleartext.\n\n"
-                  "Do you really want to cancel?";
-           i = MessageBox (dlg, warn, "Recipient Dialog", MB_ICONWARNING|MB_YESNO);
-           if (i == IDNO)
-               return FALSE;
-           rset_cb->opts = OPT_FLAG_CANCEL;
-           rset_cb->rset = NULL;
-           EndDialog (dlg, FALSE);
-           break;
+          warn = _("If you cancel this dialog, the message will be sent"
+                   " in cleartext.\n\n"
+                   "Do you really want to cancel?");
+          i = MessageBox (dlg, warn, "Recipient Dialog",
+                          MB_ICONWARNING|MB_YESNO);
+          if (i != IDNO)
+            {
+              rset_cb->opts = OPT_FLAG_CANCEL;
+              EndDialog (dlg, FALSE);
+            }
+          break;
        }
-       break;
+      break;
     }
-    return FALSE;
+  return FALSE;
 }
 
 
-static gpgme_key_t* 
-keycache_to_key_array (keycache_t ctx)
-{
-    keycache_t t;
-    int n = keycache_size(ctx), i=0;
-    gpgme_key_t *keys = xcalloc(n+1, sizeof (gpgme_key_t));
-    
-    for (t=ctx; t; t = t->next)
-       keys[i++] = t->key;
-    keys[i] = NULL; /*eof*/
-    return keys;
-}
-
 
-/* Display a recipient dialog to select keys and return all
-   selected keys in ret_rset. All enabled options are returned
-   in ret_opts. */
-int 
-recipient_dialog_box (gpgme_key_t **ret_rset, int *ret_opts)
+/* Display a recipient dialog to select keys and return all selected
+   keys in RET_RSET.  Returns the selected options which may include
+   OPT_FLAG_CANCEL.  */
+unsigned int 
+recipient_dialog_box (gpgme_key_t **ret_rset)
 {
-    struct recipient_cb_s cb;
-
-    memset (&cb, 0, sizeof (cb));
-    DialogBoxParam (glob_hinst, (LPCTSTR)IDD_ENC, GetDesktopWindow(),
-                   recipient_dlg_proc, (LPARAM)&cb);
-    if (cb.opts & OPT_FLAG_CANCEL) {
-       *ret_rset = NULL;
-       *ret_opts = OPT_FLAG_CANCEL;
-    }
-    else {
-       *ret_rset = keycache_to_key_array (cb.rset);
-       *ret_opts = cb.opts;
-       keycache_free (cb.rset);
-    }
-    return 0;
+  struct recipient_cb_s cb;
+  
+  *ret_rset = NULL;
+
+  memset (&cb, 0, sizeof (cb));
+  DialogBoxParam (glob_hinst, (LPCTSTR)IDD_ENC, GetDesktopWindow(),
+                  recipient_dlg_proc, (LPARAM)&cb);
+  if (cb.opts & OPT_FLAG_CANCEL)
+    release_keyarray (cb.selected_keys, cb.selected_keys_count);
+  else
+    *ret_rset = cb.selected_keys;
+  release_keyarray (cb.keyarray, cb.keyarray_count);
+  return cb.opts;
 }
 
+
 /* Exactly like recipient_dialog_box with the difference, that this
    dialog is used when some recipients were not found due to automatic
    selection. In such a case, the dialog displays the found recipients
-   and the listbox contains the items which were _not_ found. */
-int
-recipient_dialog_box2 (gpgme_key_t *fnd, char **unknown, size_t n,
-                      gpgme_key_t **ret_rset, int *ret_opts)
+   and the listbox contains the items which were _not_ found.  FND is
+   a NULL terminated array with the keys we already found, UNKNOWn is
+   a string array with names of recipients for whom we don't have a
+   key yet.  RET_RSET returs a NULL termintated array with all
+   selected keys.  The function returns the selected options which may
+   include OPT_FLAG_CANCEL.
+*/
+unsigned int
+recipient_dialog_box2 (gpgme_key_t *fnd, char **unknown,
+                      gpgme_key_t **ret_rset)
 {
-  struct recipient_cb_s *cb;
+  struct recipient_cb_s cb;
   int i;
-  
-  cb = xcalloc (1, sizeof (struct recipient_cb_s));
-  cb->n = n;
-  cb->fnd_keys = xcalloc (n+1, sizeof (char*));
-  for (i = 0; i < (int)n; i++) 
+  size_t n;
+
+  *ret_rset = NULL;
+
+  memset (&cb, 0, sizeof (cb));
+
+  for (n=0; fnd[n]; n++)
+    ;
+  cb.fnd_keys = xcalloc (n+1, sizeof *cb.fnd_keys);
+
+  for (i = 0; i < n; i++) 
     {
-      const char *name;
-      if (fnd[i] == NULL) {
-       cb->fnd_keys[i] = xstrdup (_("User-ID not found"));
-       continue;
-      }
-      name = fnd[i]->uids->uid;
-      if (!name)
-       name = _("User-ID not found");
-      cb->fnd_keys[i] = xstrdup (name);
+      if (fnd[i] && fnd[i]->uids && fnd[i]->uids->uid)
+        cb.fnd_keys[i] = xstrdup (fnd[i]->uids->uid);
+      else
+       cb.fnd_keys[i] = xstrdup (_("User-ID not found"));
     }
-  cb->unknown_keys = unknown;
+
+  cb.unknown_keys = unknown;
+
   DialogBoxParam (glob_hinst, (LPCTSTR)IDD_ENC, GetDesktopWindow (),
-                 recipient_dlg_proc, (LPARAM)cb);
-  if (cb->opts & OPT_FLAG_CANCEL) 
-    {
-      *ret_opts = cb->opts;
-      *ret_rset = NULL;
-    }
-  else 
-    {
-      *ret_rset = keycache_to_key_array (cb->rset);
-      keycache_free (cb->rset);
-    }
-  for (i = 0; i < (int)n; i++) 
-    {
-      xfree (cb->fnd_keys[i]);
-      cb->fnd_keys[i] = NULL;
-    }
-  xfree (cb->fnd_keys);
-  xfree (cb);
-  return 0;
+                 recipient_dlg_proc, (LPARAM)&cb);
+
+  if (cb.opts & OPT_FLAG_CANCEL)
+    release_keyarray (cb.selected_keys, cb.selected_keys_count);
+  else
+    *ret_rset = cb.selected_keys;
+
+  release_keyarray (cb.keyarray, cb.keyarray_count);
+  for (i = 0; i < n; i++) 
+    xfree (cb.fnd_keys[i]);
+  xfree (cb.fnd_keys);
+  return cb.opts;
 }
index 73fcc39..553ca59 100644 (file)
@@ -26,7 +26,6 @@
 #include <gpgme.h>
 
 #include "gpgol-ids.h"
-#include "keycache.h"
 #include "intern.h"
 #include "util.h"
 
@@ -77,6 +76,7 @@ load_akalist (HWND dlg, gpgme_key_t key)
 static void 
 load_sigbox (HWND dlg, gpgme_verify_result_t ctx)
 {
+  gpgme_error_t err;
   gpgme_key_t key;
   char *s, buf[2+16+1];
   char *p;
@@ -97,8 +97,24 @@ load_sigbox (HWND dlg, gpgme_verify_result_t ctx)
   buf[0] = '0'; 
   buf[1] = 'x';
   SetDlgItemText (dlg, IDC_VRY_KEYID, buf);
-  key = get_gpg_key (buf+2);
-  
+
+  {
+    gpgme_ctx_t gctx;
+
+    key = NULL;
+    if (!gpgme_new (&gctx))
+      {
+        err = gpgme_get_key (gctx, buf+2, &key, 0);
+        if (err)
+          {
+            log_debug ("getting key `%s' failed: %s",
+                       buf+2, gpg_strerror (err));
+            key = NULL;
+          }
+        gpgme_release (gctx);
+      }
+  }
+
   stat = ctx->signatures->summary;
   if (stat & GPGME_SIGSUM_GREEN)
     s = _("Good signature");