Skip to content

Commit

Permalink
Allow multiple crypt-hooks with the same regexp. (closes #3727).
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kevin8t8 authored and karelzak committed Jul 17, 2015
1 parent 2a5ee63 commit 0598a02
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 146 deletions.
193 changes: 110 additions & 83 deletions crypt-gpgme.c
Original file line number Diff line number Diff line change
Expand Up @@ -4361,6 +4361,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;
Expand All @@ -4370,112 +4371,138 @@ 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;
#endif

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);
}
Expand Down
6 changes: 6 additions & 0 deletions doc/manual.xml.head
Original file line number Diff line number Diff line change
Expand Up @@ -3652,6 +3652,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>
Expand Down
5 changes: 5 additions & 0 deletions doc/muttrc.man.head
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
20 changes: 17 additions & 3 deletions hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down
Loading

0 comments on commit 0598a02

Please sign in to comment.