]> granicus.if.org Git - neomutt/commitdiff
Allow multiple crypt-hooks with the same regexp. (closes #3727).
authorKevin McCarthy <kevin@8t8.us>
Sun, 19 Apr 2015 20:15:48 +0000 (13:15 -0700)
committerKevin McCarthy <kevin@8t8.us>
Sun, 19 Apr 2015 20:15:48 +0000 (13:15 -0700)
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.

crypt-gpgme.c
doc/manual.xml.head
doc/muttrc.man.head
hook.c
pgp.c
protos.h

index 9d00d4d17ab4989f94cb91fc57ea5a2c5f5e5282..7bb1997f4b341190f92387b5c9519b5d54fe4296 100644 (file)
@@ -4354,6 +4354,7 @@ static crypt_key_t *crypt_ask_for_key (char *tag,
    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 @@ static char *find_keys (ADDRESS *adrlist, unsigned int app, int oppenc_mode)
   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 @@ static char *find_keys (ADDRESS *adrlist, unsigned int app, int oppenc_mode)
 
   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. */
-                }
+      key_selected = 0;
+      crypt_hook_list = crypt_hook = mutt_crypt_hook (p);
+      do
+      {
+        q = p;
+        forced_valid = 0;
+        k_info = NULL;
 
-              /* 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 (crypt_hook != NULL)
+          {
+            crypt_hook_val = crypt_hook->data;
+            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)
+                  {
 #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;
-            }
-        }
+                  }
+              }
+            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)
+          {
+            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 ((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);
-        }
+                                        &forced_valid);
+          }
 
-      if (k_info == NULL)
-        {
-          FREE (&keylist);
-          rfc822_free_address (&addr);
-          return NULL;
-        }
+        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);
+        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);
 }
index 0de25e33645d669a4df7ed6cfe3b05dfe92a1952..cb1ed626daf741495829305de94583ffbe0e2916 100644 (file)
@@ -3633,6 +3633,12 @@ destination address, or because, for some reasons, you need to override
 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.  If all crypt-hooks for a recipient are
+declined, Mutt will use the original recipient address for key selection
+instead.
 </para>
 
 <para>
index f213734f3b13a8a54632cc896093bbbb93927a73..0b5658cba267847fdef0fc6b8ba44206d79f825e 100644 (file)
@@ -354,6 +354,11 @@ specify the ID of the public key to be used when encrypting messages
 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 --git a/hook.c b/hook.c
index 34f310653b17004cb1b14255e775d901cff14ab2..664b1e4599f448039d7cde5fc452ddca39883021 100644 (file)
--- a/hook.c
+++ b/hook.c
@@ -125,7 +125,7 @@ int mutt_parse_hook (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
        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 @@ static char *_mutt_string_hook (const char *match, int hook)
   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 @@ char *mutt_iconv_hook (const char *chs)
   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 --git a/pgp.c b/pgp.c
index dafd0ff9afbf003faf80279bcf778660912da0e7..11e42543135f4ef2a2f20445a44f4a845cf44707 100644 (file)
--- a/pgp.c
+++ b/pgp.c
@@ -1195,91 +1195,116 @@ BODY *pgp_sign_message (BODY *a)
  */
 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_NO;
+        if (! oppenc_mode)
+        {
+          snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID, p->mailbox);
+          r = mutt_yesorno (buf, M_YES);
+        }
+        if (oppenc_mode || (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. */
+          }
+
+          /* 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 ((keyID = mutt_crypt_hook (p)) != NULL)
-    {
-      int r = M_NO;
-      if (! oppenc_mode)
+      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);
 }
index f17852dc5b4321c2c2e2875e044af6239ec4e91a..d232a4f6e1b7fe8d2ea2991c8521f14654bde363 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -146,7 +146,7 @@ char *mutt_gen_msgid (void);
 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);