From: Kevin McCarthy Date: Sun, 19 Apr 2015 20:15:48 +0000 (-0700) Subject: Allow multiple crypt-hooks with the same regexp. (closes #3727). X-Git-Tag: neomutt-20160307~61 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cb2dfc246082638fcbf4c888be571d51e811b62d;p=neomutt 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. --- diff --git a/crypt-gpgme.c b/crypt-gpgme.c index 9d00d4d17..7bb1997f4 100644 --- a/crypt-gpgme.c +++ b/crypt-gpgme.c @@ -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); } diff --git a/doc/manual.xml.head b/doc/manual.xml.head index 0de25e336..cb1ed626d 100644 --- a/doc/manual.xml.head +++ b/doc/manual.xml.head @@ -3633,6 +3633,12 @@ destination address, or because, for some reasons, you need to override the key Mutt would normally use. The crypt-hook 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. diff --git a/doc/muttrc.man.head b/doc/muttrc.man.head index f213734f3..0b5658cba 100644 --- a/doc/muttrc.man.head +++ b/doc/muttrc.man.head @@ -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 34f310653..664b1e459 100644 --- 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 dafd0ff9a..11e425431 100644 --- 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); } diff --git a/protos.h b/protos.h index f17852dc5..d232a4f6e 100644 --- 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);