changeset: 6443:b4c57d3fd7e8
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Apr 19 13:15:48 2015 -0700
link:      http://dev.mutt.org/hg/mutt/rev/b4c57d3fd7e8

Allow multiple crypt-hooks with the same regexp. (closes #3727).

Changes the crypt-hook to accumulate a LIST of hooks with
the same regexp, as opposed to replacing the hook data.
This is useful for the case of encrypted mailing lists.

Update pgp classic and gpgme to process a LIST of crypt-hook
values instead of just one.

This version of the patch creates a new _mutt_list_hook() function that
(in theory) other hooks could use if they were changed to return a list.
It also changes the behavior when a crypt-hook is declined: previously
it would immediately use the original recipient for key selection.  Now
it will only do that if all crypt-hooks for a recipient are declined.
This allows all, a subset, or none of the hooks to be used.

Thanks to Rejo Zenger, Remco Rijnders, and Dale Woolridge for their work
on various versions of this patch.

changeset: 6444:067a3ac42c3b
user:      Kevin McCarthy <ke...@8t8.us>
date:      Sun Apr 19 13:15:50 2015 -0700
link:      http://dev.mutt.org/hg/mutt/rev/067a3ac42c3b

Add $crypt_confirmhook option. (see #3727)

Allow the confirmation prompt for crypt-hooks to be disabled.  This is
useful for multiple crypt-hook users (e.g. encrypted mailing lists), or
just for people who are certain of their crypt-hooks and don't want to
be prompted every time.

Thanks to Dale Woolridge for the original patch.

diffs (536 lines):

diff -r 1e26a962ab7a -r 067a3ac42c3b crypt-gpgme.c
--- a/crypt-gpgme.c     Wed Apr 15 19:25:46 2015 -0700
+++ b/crypt-gpgme.c     Sun Apr 19 13:15:50 2015 -0700
@@ -4354,6 +4354,7 @@
    prompting will be used.  */
 static char *find_keys (ADDRESS *adrlist, unsigned int app, int oppenc_mode)
 {
+  LIST *crypt_hook_list, *crypt_hook = NULL;
   char *crypt_hook_val = NULL;
   const char *keyID = NULL;
   char *keylist = NULL, *t;
@@ -4363,6 +4364,10 @@
   ADDRESS *p, *q;
   crypt_key_t *k_info;
   const char *fqdn = mutt_fqdn (1);
+  char buf[LONG_STRING];
+  int forced_valid;
+  int r;
+  int key_selected;
 
 #if 0
   *r_application = APPLICATION_PGP|APPLICATION_SMIME;
@@ -4370,105 +4375,127 @@
 
   for (p = adrlist; p ; p = p->next)
     {
-      char buf[LONG_STRING];
-      int forced_valid = 0;
-      
-      q = p;
-      k_info = NULL;
-      
-      if ((crypt_hook_val = mutt_crypt_hook (p)) != NULL)
-        {
-          int r = M_NO;
-          if (! oppenc_mode)
-            {
-              snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
-                        crypt_hook_val, p->mailbox);
-              r = mutt_yesorno (buf, M_YES);
-            }
-          if (oppenc_mode || (r == M_YES))
-            {
-              if (crypt_is_numerical_keyid (crypt_hook_val))
-                {
-                  keyID = crypt_hook_val;
-                  if (strncmp (keyID, "0x", 2) == 0)
-                    keyID += 2;
-                  goto bypass_selection;                /* you don't see this. 
*/
-                }
-
-              /* check for e-mail address */
-              if ((t = strchr (crypt_hook_val, '@')) && 
-                  (addr = rfc822_parse_adrlist (NULL, crypt_hook_val)))
-                {
-                  if (fqdn)
-                    rfc822_qualify (addr, fqdn);
-                  q = addr;
-                }
-              else if (! oppenc_mode)
-               {
+      key_selected = 0;
+      crypt_hook_list = crypt_hook = mutt_crypt_hook (p);
+      do
+      {
+        q = p;
+        forced_valid = 0;
+        k_info = NULL;
+
+        if (crypt_hook != NULL)
+          {
+            crypt_hook_val = crypt_hook->data;
+            r = M_YES;
+            if (! oppenc_mode && option(OPTCRYPTCONFIRMHOOK))
+              {
+                snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
+                          crypt_hook_val, p->mailbox);
+                r = mutt_yesorno (buf, M_YES);
+              }
+            if (r == M_YES)
+              {
+                if (crypt_is_numerical_keyid (crypt_hook_val))
+                  {
+                    keyID = crypt_hook_val;
+                    if (strncmp (keyID, "0x", 2) == 0)
+                      keyID += 2;
+                    goto bypass_selection;                /* you don't see 
this. */
+                  }
+
+                /* check for e-mail address */
+                if ((t = strchr (crypt_hook_val, '@')) && 
+                    (addr = rfc822_parse_adrlist (NULL, crypt_hook_val)))
+                  {
+                    if (fqdn)
+                      rfc822_qualify (addr, fqdn);
+                    q = addr;
+                  }
+                else if (! oppenc_mode)
+                  {
 #if 0            
-                 k_info = crypt_getkeybystr (crypt_hook_val, 
KEYFLAG_CANENCRYPT, 
-                                             *r_application, &forced_valid);
+                    k_info = crypt_getkeybystr (crypt_hook_val, 
KEYFLAG_CANENCRYPT, 
+                                                *r_application, &forced_valid);
 #else
-                 k_info = crypt_getkeybystr (crypt_hook_val, 
KEYFLAG_CANENCRYPT, 
-                                             app, &forced_valid);
+                    k_info = crypt_getkeybystr (crypt_hook_val, 
KEYFLAG_CANENCRYPT, 
+                                                app, &forced_valid);
 #endif
-               }
-            }
-          else if (r == -1)
-            {
-              FREE (&keylist);
-              rfc822_free_address (&addr);
-              return NULL;
-            }
-        }
-
-      if (k_info == NULL)
-        {
-          k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
-                                       app, &forced_valid, oppenc_mode);
-        }
-
-      if ((k_info == NULL) && (! oppenc_mode))
-        {
-          snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
-          
-          k_info = crypt_ask_for_key (buf, q->mailbox,
-                                      KEYFLAG_CANENCRYPT,
+                  }
+              }
+            else if (r == M_NO)
+              {
+                if (key_selected || (crypt_hook->next != NULL))
+                  {
+                    crypt_hook = crypt_hook->next;
+                    continue;
+                  }
+              }
+            else if (r == -1)
+              {
+                FREE (&keylist);
+                rfc822_free_address (&addr);
+                mutt_free_list (&crypt_hook_list);
+                return NULL;
+              }
+          }
+
+        if (k_info == NULL)
+          {
+            k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
+                                        app, &forced_valid, oppenc_mode);
+          }
+
+        if ((k_info == NULL) && (! oppenc_mode))
+          {
+            snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), 
q->mailbox);
+            
+            k_info = crypt_ask_for_key (buf, q->mailbox,
+                                        KEYFLAG_CANENCRYPT,
 #if 0
-                                      *r_application,
+                                        *r_application,
 #else
-                                      app,
+                                        app,
 #endif
-                                      &forced_valid);
-        }
-
-      if (k_info == NULL)
-        {
-          FREE (&keylist);
-          rfc822_free_address (&addr);
-          return NULL;
-        }
-
-
-      keyID = crypt_fpr_or_lkeyid (k_info);
+                                        &forced_valid);
+          }
+
+        if (k_info == NULL)
+          {
+            FREE (&keylist);
+            rfc822_free_address (&addr);
+            mutt_free_list (&crypt_hook_list);
+            return NULL;
+          }
+
+
+        keyID = crypt_fpr_or_lkeyid (k_info);
 
 #if 0
-      if (k_info->flags & KEYFLAG_ISX509)
-        *r_application &= ~APPLICATION_PGP;
-      if (!(k_info->flags & KEYFLAG_ISX509))
-        *r_application &= ~APPLICATION_SMIME;
+        if (k_info->flags & KEYFLAG_ISX509)
+          *r_application &= ~APPLICATION_PGP;
+        if (!(k_info->flags & KEYFLAG_ISX509))
+          *r_application &= ~APPLICATION_SMIME;
 #endif
-      
-  bypass_selection:
-      keylist_size += mutt_strlen (keyID) + 4 + 1;
-      safe_realloc (&keylist, keylist_size);
-      sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
-               keylist_used ? " " : "",  keyID,
-               forced_valid? "!":"");
-      keylist_used = mutt_strlen (keylist);
         
-      crypt_free_key (&k_info);
-      rfc822_free_address (&addr);
+    bypass_selection:
+        keylist_size += mutt_strlen (keyID) + 4 + 1;
+        safe_realloc (&keylist, keylist_size);
+        sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
+                keylist_used ? " " : "",  keyID,
+                forced_valid? "!":"");
+        keylist_used = mutt_strlen (keylist);
+
+        key_selected = 1;
+
+        crypt_free_key (&k_info);
+        rfc822_free_address (&addr);
+
+        if (crypt_hook != NULL)
+          crypt_hook = crypt_hook->next;
+
+      } while (crypt_hook != NULL);
+
+      mutt_free_list (&crypt_hook_list);
     }
   return (keylist);
 }
diff -r 1e26a962ab7a -r 067a3ac42c3b doc/manual.xml.head
--- a/doc/manual.xml.head       Wed Apr 15 19:25:46 2015 -0700
+++ b/doc/manual.xml.head       Sun Apr 19 13:15:50 2015 -0700
@@ -3633,6 +3633,13 @@
 the key Mutt would normally use.  The <command>crypt-hook</command>
 command provides a method by which you can specify the ID of the public
 key to be used when encrypting messages to a certain recipient.
+You may use multiple crypt-hooks with the same regexp; multiple
+matching crypt-hooks result in the use of multiple keyids for
+a recipient.  During key selection, Mutt will confirm whether each
+crypt-hook is to be used (unless the <link
+linkend="crypt-confirmhook">$crypt_confirmhook</link> option is unset).
+If all crypt-hooks for a recipient are declined, Mutt will use the
+original recipient address for key selection instead.
 </para>
 
 <para>
diff -r 1e26a962ab7a -r 067a3ac42c3b doc/muttrc.man.head
--- a/doc/muttrc.man.head       Wed Apr 15 19:25:46 2015 -0700
+++ b/doc/muttrc.man.head       Sun Apr 19 13:15:50 2015 -0700
@@ -354,6 +354,11 @@
 to a certain recipient.  The meaning of "key ID" is to be taken
 broadly: This can be a different e-mail address, a numerical key ID,
 or even just an arbitrary search string.
+You may use multiple
+\fBcrypt-hook\fPs with the same \fIregexp\fP; multiple matching
+\fBcrypt-hook\fPs result in the use of multiple \fIkey-id\fPs for
+a recipient.
+
 .TP
 \fBpush\fP \fIstring\fP
 This command adds the named \fIstring\fP to the keyboard buffer.
diff -r 1e26a962ab7a -r 067a3ac42c3b hook.c
--- a/hook.c    Wed Apr 15 19:25:46 2015 -0700
+++ b/hook.c    Sun Apr 19 13:15:50 2015 -0700
@@ -125,7 +125,7 @@
        ptr->rx.not == not &&
        !mutt_strcmp (pattern.data, ptr->rx.pattern))
     {
-      if (data & (M_FOLDERHOOK | M_SENDHOOK | M_SEND2HOOK | M_MESSAGEHOOK | 
M_ACCOUNTHOOK | M_REPLYHOOK))
+      if (data & (M_FOLDERHOOK | M_SENDHOOK | M_SEND2HOOK | M_MESSAGEHOOK | 
M_ACCOUNTHOOK | M_REPLYHOOK | M_CRYPTHOOK))
       {
        /* these hooks allow multiple commands with the same
         * pattern, so if we've already seen this pattern/command pair, just
@@ -448,6 +448,20 @@
   return (NULL);
 }
 
+static LIST *_mutt_list_hook (const char *match, int hook)
+{
+  HOOK *tmp = Hooks;
+  LIST *matches = NULL;
+
+  for (; tmp; tmp = tmp->next)
+  {
+    if ((tmp->type & hook) &&
+        ((match && regexec (tmp->rx.rx, match, 0, NULL, 0) == 0) ^ 
tmp->rx.not))
+      matches = mutt_add_list (matches, tmp->command);
+  }
+  return (matches);
+}
+
 char *mutt_charset_hook (const char *chs)
 {
   return _mutt_string_hook (chs, M_CHARSETHOOK);
@@ -458,9 +472,9 @@
   return _mutt_string_hook (chs, M_ICONVHOOK);
 }
 
-char *mutt_crypt_hook (ADDRESS *adr)
+LIST *mutt_crypt_hook (ADDRESS *adr)
 {
-  return _mutt_string_hook (adr->mailbox, M_CRYPTHOOK);
+  return _mutt_list_hook (adr->mailbox, M_CRYPTHOOK);
 }
 
 #ifdef USE_SOCKET
diff -r 1e26a962ab7a -r 067a3ac42c3b init.h
--- a/init.h    Wed Apr 15 19:25:46 2015 -0700
+++ b/init.h    Sun Apr 19 13:15:50 2015 -0700
@@ -491,6 +491,14 @@
   ** $$crypt_replyencrypt,
   ** $$crypt_autosign, $$crypt_replysign and $$smime_is_default.
   */
+  { "crypt_confirmhook",       DT_BOOL, R_NONE, OPTCRYPTCONFIRMHOOK, 1 },
+  /*
+  ** .pp
+  ** If set, then you will be prompted for confirmation of keys when using
+  ** the \fIcrypt-hook\fP command.  If unset, no such confirmation prompt will
+  ** be presented.  This is generally considered unsafe, especially where
+  ** typos are concerned.
+  */
   { "crypt_opportunistic_encrypt", DT_BOOL, R_NONE, 
OPTCRYPTOPPORTUNISTICENCRYPT, 0 },
   /*
   ** .pp
diff -r 1e26a962ab7a -r 067a3ac42c3b mutt.h
--- a/mutt.h    Wed Apr 15 19:25:46 2015 -0700
+++ b/mutt.h    Sun Apr 19 13:15:50 2015 -0700
@@ -461,6 +461,7 @@
   OPTCRYPTAUTOENCRYPT,
   OPTCRYPTAUTOPGP,
   OPTCRYPTAUTOSMIME,
+  OPTCRYPTCONFIRMHOOK,
   OPTCRYPTOPPORTUNISTICENCRYPT,
   OPTCRYPTREPLYENCRYPT,
   OPTCRYPTREPLYSIGN,
diff -r 1e26a962ab7a -r 067a3ac42c3b pgp.c
--- a/pgp.c     Wed Apr 15 19:25:46 2015 -0700
+++ b/pgp.c     Sun Apr 19 13:15:50 2015 -0700
@@ -1195,91 +1195,116 @@
  */
 char *pgp_findKeys (ADDRESS *adrlist, int oppenc_mode)
 {
+  LIST *crypt_hook_list, *crypt_hook = NULL;
   char *keyID, *keylist = NULL;
   size_t keylist_size = 0;
   size_t keylist_used = 0;
   ADDRESS *addr = NULL;
   ADDRESS *p, *q;
   pgp_key_t k_info = NULL;
+  char buf[LONG_STRING];
+  int r;
+  int key_selected;
 
   const char *fqdn = mutt_fqdn (1);
 
   for (p = adrlist; p ; p = p->next)
   {
-    char buf[LONG_STRING];
+    key_selected = 0;
+    crypt_hook_list = crypt_hook = mutt_crypt_hook (p);
+    do
+    {
+      q = p;
+      k_info = NULL;
 
-    q = p;
-    k_info = NULL;
+      if (crypt_hook != NULL)
+      {
+        keyID = crypt_hook->data;
+        r = M_YES;
+        if (! oppenc_mode && option(OPTCRYPTCONFIRMHOOK))
+        {
+          snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID, 
p->mailbox);
+          r = mutt_yesorno (buf, M_YES);
+        }
+        if (r == M_YES)
+        {
+          if (crypt_is_numerical_keyid (keyID))
+          {
+            if (strncmp (keyID, "0x", 2) == 0)
+              keyID += 2;
+            goto bypass_selection;             /* you don't see this. */
+          }
 
-    if ((keyID = mutt_crypt_hook (p)) != NULL)
-    {
-      int r = M_NO;
-      if (! oppenc_mode)
+          /* check for e-mail address */
+          if (strchr (keyID, '@') &&
+              (addr = rfc822_parse_adrlist (NULL, keyID)))
+          {
+            if (fqdn) rfc822_qualify (addr, fqdn);
+            q = addr;
+          }
+          else if (! oppenc_mode)
+          {
+            k_info = pgp_getkeybystr (keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING);
+          }
+        }
+        else if (r == M_NO)
+        {
+          if (key_selected || (crypt_hook->next != NULL))
+          {
+            crypt_hook = crypt_hook->next;
+            continue;
+          }
+        }
+        else if (r == -1)
+        {
+          FREE (&keylist);
+          rfc822_free_address (&addr);
+          mutt_free_list (&crypt_hook_list);
+          return NULL;
+        }
+      }
+
+      if (k_info == NULL)
       {
-        snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID, 
p->mailbox);
-        r = mutt_yesorno (buf, M_YES);
+        pgp_invoke_getkeys (q);
+        k_info = pgp_getkeybyaddr (q, KEYFLAG_CANENCRYPT, PGP_PUBRING, 
oppenc_mode);
       }
-      if (oppenc_mode || (r == M_YES))
+
+      if ((k_info == NULL) && (! oppenc_mode))
       {
-       if (crypt_is_numerical_keyid (keyID))
-       {
-         if (strncmp (keyID, "0x", 2) == 0)
-           keyID += 2;
-         goto bypass_selection;                /* you don't see this. */
-       }
-       
-       /* check for e-mail address */
-       if (strchr (keyID, '@') && 
-           (addr = rfc822_parse_adrlist (NULL, keyID)))
-       {
-         if (fqdn) rfc822_qualify (addr, fqdn);
-         q = addr;
-       }
-       else if (! oppenc_mode)
-       {
-         k_info = pgp_getkeybystr (keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING);
-       }
+        snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
+        k_info = pgp_ask_for_key (buf, q->mailbox,
+                              KEYFLAG_CANENCRYPT, PGP_PUBRING);
       }
-      else if (r == -1)
+
+      if (k_info == NULL)
       {
-       FREE (&keylist);
-       rfc822_free_address (&addr);
-       return NULL;
+        FREE (&keylist);
+        rfc822_free_address (&addr);
+        mutt_free_list (&crypt_hook_list);
+        return NULL;
       }
-    }
 
-    if (k_info == NULL)
-    {
-      pgp_invoke_getkeys (q);
-      k_info = pgp_getkeybyaddr (q, KEYFLAG_CANENCRYPT, PGP_PUBRING, 
oppenc_mode);
-    }
+      keyID = pgp_fpr_or_lkeyid (k_info);
 
-    if ((k_info == NULL) && (! oppenc_mode))
-    {
-      snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
-      k_info = pgp_ask_for_key (buf, q->mailbox,
-                             KEYFLAG_CANENCRYPT, PGP_PUBRING);
-    }
+    bypass_selection:
+      keylist_size += mutt_strlen (keyID) + 4;
+      safe_realloc (&keylist, keylist_size);
+      sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "",      
/* __SPRINTF_CHECKED__ */
+              keyID);
+      keylist_used = mutt_strlen (keylist);
 
-    if (k_info == NULL)
-    {
-      FREE (&keylist);
+      key_selected = 1;
+
+      pgp_free_key (&k_info);
       rfc822_free_address (&addr);
-      return NULL;
-    }
 
-    keyID = pgp_fpr_or_lkeyid (k_info);
-    
-  bypass_selection:
-    keylist_size += mutt_strlen (keyID) + 4;
-    safe_realloc (&keylist, keylist_size);
-    sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "",        
/* __SPRINTF_CHECKED__ */
-            keyID);
-    keylist_used = mutt_strlen (keylist);
+      if (crypt_hook != NULL)
+        crypt_hook = crypt_hook->next;
 
-    pgp_free_key (&k_info);
-    rfc822_free_address (&addr);
+    } while (crypt_hook != NULL);
 
+    mutt_free_list (&crypt_hook_list);
   }
   return (keylist);
 }
diff -r 1e26a962ab7a -r 067a3ac42c3b protos.h
--- a/protos.h  Wed Apr 15 19:25:46 2015 -0700
+++ b/protos.h  Sun Apr 19 13:15:50 2015 -0700
@@ -146,7 +146,7 @@
 char *mutt_get_body_charset (char *, size_t, BODY *);
 const char *mutt_get_name (ADDRESS *);
 char *mutt_get_parameter (const char *, PARAMETER *);
-char *mutt_crypt_hook (ADDRESS *);
+LIST *mutt_crypt_hook (ADDRESS *);
 char *mutt_make_date (char *, size_t);
 
 const char *mutt_make_version (void);

Reply via email to