changeset: 6429:5b443e7da81b user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:47 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/5b443e7da81b
Refactor the address list generation out of the find_keys routines. All four find_keys routines have a similar set up code for generating a single address list out of the to, cc, bcc lists. This patch pulls all the code into crypt_get_keys. This is done to simplify the functions before later patches make them more complicated (with the oppenc_mode parameter). changeset: 6430:04eb395d80a7 user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:49 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/04eb395d80a7 Introduce an oppenc_mode parameter It's added to the parameter lists through the call stack down to the find_keys calls. No functionality is implemented yet. This patch is separated just to keep other patches more readable. changeset: 6431:80b963ff82d3 user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:51 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/80b963ff82d3 Pull is_numerical_keyid() into crypt.c. A subsequent patch (re?)-introduces a call to is_numerical_keyid inside find_keys(). Rather than duplicate the function, this patch pulls it into crypt.c, where find_keys() and pgp_findKeys() can both call it. changeset: 6432:db2abe57adb5 user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:52 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/db2abe57adb5 Implement oppenc_mode in the find_keys methods. oppenc_mode is used by crypt_opportunistic_encrypt to determine whether there are valid keys for all recipients of a message, without prompting the user. The patch wraps around prompts, and makes getkeybyaddr methods return a valid address-matching key without prompting. The patch also fixes a small problem with gpgme's getkeybyaddr. When determining if there were multiple strong matches, it was comparing the crypt_key_t instead of its kobj member (gpgme_key_t). The patch also enables a call to crypt_is_numerical_keyid() in find_keys(), so that crypt-hooks can actually be checked without prompting when gpgme is enabled. (The addition was patterned off of the pgp_findKeys() function). changeset: 6433:b10d0a945623 user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:53 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/b10d0a945623 Implement crypt_opportunistic_encrypt(). This function will be called to flip encryption on and off based on message recipients. changeset: 6434:b38c4838976f user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:54 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/b38c4838976f Add the crypt_opportunistic_encrypt option and calls. This patch creates the OPTCRYPTOPPORTUNISTICENCRYPT option and documentation. It also adds calls to crypt_opportunistic_encrypt() during initial message composition, after updating to, cc, or bcc, and after editing the message (if edit_headers is enabled). changeset: 6435:2ec6a8d91de4 user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:55 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/2ec6a8d91de4 Add a security bit to the message for oppenc mode. This allows oppenc to be enabled/disabled on a message level. If something initially enables encryption, such as crypt_autoencrypt or crypt_replyencrypt, oppenc is turned off for the message. Change the postpone/resume code to persist the oppenc bit. Also change resend message to enable and invoke oppenc if the option is set. changeset: 6436:b8ead28d8e84 user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:56 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/b8ead28d8e84 Add ui elements for oppenc mode. Add a status message to the Security line when oppenc is enabled. For each send menu, add the ability to toggle it on or off. When enabled, the menus won't show the (e)ncrypt or (b)oth options, and the (c)lear function only clears the SIGN bit when it is active. Change the gpgme_send_menu() to directly use the ENCRYPT and SIGN flags instead of the PGPENCRYPT/SIGN and SMIMEENCRYPT/SMIME flags. Using the latter sometimes resulted in the APPLICATION bit unset, which made oppenc unhappy. The send_menus previously used a switch statement using choice numbers. Since the menus now vary based on the oppenc option and message bit being set, these were all changed to convert the numbers back to a choice letter. changeset: 6437:1bd26d871d76 user: Kevin McCarthy <ke...@8t8.us> date: Mon Mar 30 15:45:58 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/1bd26d871d76 Fix const errors caused by find_keys() changes. Part 4 of the oppenc series changed the keyID type to const as part of some cleanup changes. At the time, that only propagated to crypt_getkeybystr(), but with the fingerprint changes, this is starting to propagate too far. Create a separate non-const variable to deal with the crypt hook value and revert crypt_getkeybystr()'s parameter to non-const. diffs (truncated from 2029 to 950 lines): diff -r 59bd9030e898 -r 1bd26d871d76 compose.c --- a/compose.c Tue Mar 17 16:28:56 2015 -0700 +++ b/compose.c Mon Mar 30 15:45:58 2015 -0700 @@ -141,6 +141,9 @@ addstr (_(" (S/MIME)")); } + if (option (OPTCRYPTOPPORTUNISTICENCRYPT) && (msg->security & OPPENCRYPT)) + addstr (_(" (OppEnc mode)")); + clrtoeol (); move (HDR_CRYPTINFO, 0); clrtoeol (); @@ -526,14 +529,29 @@ break; case OP_COMPOSE_EDIT_TO: menu->redraw = edit_address_list (HDR_TO, &msg->env->to); + if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) + { + crypt_opportunistic_encrypt (msg); + redraw_crypt_lines (msg); + } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_BCC: menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc); + if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) + { + crypt_opportunistic_encrypt (msg); + redraw_crypt_lines (msg); + } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_CC: menu->redraw = edit_address_list (HDR_CC, &msg->env->cc); + if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) + { + crypt_opportunistic_encrypt (msg); + redraw_crypt_lines (msg); + } mutt_message_hook (NULL, msg, M_SEND2HOOK); break; case OP_COMPOSE_EDIT_SUBJECT: @@ -593,6 +611,8 @@ mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); FREE (&err); } + if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) + crypt_opportunistic_encrypt (msg); } else { @@ -1220,7 +1240,8 @@ mutt_clear_error (); break; } - msg->security = 0; + msg->security &= ~APPLICATION_SMIME; + msg->security |= APPLICATION_PGP; } msg->security = crypt_pgp_send_menu (msg, &menu->redraw); redraw_crypt_lines (msg); @@ -1246,7 +1267,8 @@ mutt_clear_error (); break; } - msg->security = 0; + msg->security &= ~APPLICATION_PGP; + msg->security |= APPLICATION_SMIME; } msg->security = crypt_smime_send_menu(msg, &menu->redraw); redraw_crypt_lines (msg); diff -r 59bd9030e898 -r 1bd26d871d76 crypt-gpgme.c --- a/crypt-gpgme.c Tue Mar 17 16:28:56 2015 -0700 +++ b/crypt-gpgme.c Mon Mar 30 15:45:58 2015 -0700 @@ -4052,21 +4052,25 @@ } static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities, - unsigned int app, int *forced_valid) + unsigned int app, int *forced_valid, + int oppenc_mode) { ADDRESS *r, *p; LIST *hints = NULL; int weak = 0; int invalid = 0; + int addr_match = 0; int multi = 0; int this_key_has_strong; + int this_key_has_addr_match; int this_key_has_weak; int this_key_has_invalid; int match; crypt_key_t *keys, *k; - crypt_key_t *the_valid_key = NULL; + crypt_key_t *the_strong_valid_key = NULL; + crypt_key_t *a_valid_addrmatch_key = NULL; crypt_key_t *matches = NULL; crypt_key_t **matches_endp = &matches; @@ -4077,7 +4081,8 @@ if (a && a->personal) hints = crypt_add_string_to_hints (hints, a->personal); - mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); + if (! oppenc_mode ) + mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN) ); mutt_free_list (&hints); @@ -4103,6 +4108,7 @@ this_key_has_weak = 0; /* weak but valid match */ this_key_has_invalid = 0; /* invalid match */ this_key_has_strong = 0; /* strong and valid match */ + this_key_has_addr_match = 0; match = 0; /* any match */ r = rfc822_parse_adrlist (NULL, k->uid); @@ -4111,25 +4117,29 @@ int validity = crypt_id_matches_addr (a, p, k); if (validity & CRYPT_KV_MATCH) /* something matches */ + { match = 1; - /* is this key a strong candidate? */ - if ((validity & CRYPT_KV_VALID) - && (validity & CRYPT_KV_STRONGID) - && (validity & CRYPT_KV_ADDR)) + if (validity & CRYPT_KV_VALID) { - if (the_valid_key && the_valid_key != k) - multi = 1; - the_valid_key = k; - this_key_has_strong = 1; + if (validity & CRYPT_KV_ADDR) + { + if (validity & CRYPT_KV_STRONGID) + { + if (the_strong_valid_key + && the_strong_valid_key->kobj != k->kobj) + multi = 1; + this_key_has_strong = 1; + } + else + this_key_has_addr_match = 1; + } + else + this_key_has_weak = 1; } - else if ((validity & CRYPT_KV_MATCH) - && !(validity & CRYPT_KV_VALID)) - this_key_has_invalid = 1; - else if ((validity & CRYPT_KV_MATCH) - && (!(validity & CRYPT_KV_STRONGID) - || !(validity & CRYPT_KV_ADDR))) - this_key_has_weak = 1; + else + this_key_has_invalid = 1; + } } rfc822_free_address (&r); @@ -4137,14 +4147,20 @@ { crypt_key_t *tmp; - if (!this_key_has_strong && this_key_has_invalid) - invalid = 1; - if (!this_key_has_strong && this_key_has_weak) - weak = 1; - *matches_endp = tmp = crypt_copy_key (k); matches_endp = &tmp->next; - the_valid_key = tmp; + + if (this_key_has_strong) + the_strong_valid_key = tmp; + else if (this_key_has_addr_match) + { + addr_match = 1; + a_valid_addrmatch_key = tmp; + } + else if (this_key_has_invalid) + invalid = 1; + else if (this_key_has_weak) + weak = 1; } } @@ -4152,7 +4168,16 @@ if (matches) { - if (the_valid_key && !multi && !weak + if (oppenc_mode) + { + if (the_strong_valid_key) + k = crypt_copy_key (the_strong_valid_key); + else if (a_valid_addrmatch_key) + k = crypt_copy_key (a_valid_addrmatch_key); + else + k = NULL; + } + else if (the_strong_valid_key && !multi && !weak && !addr_match && !(invalid && option (OPTPGPSHOWUNUSABLE))) { /* @@ -4162,7 +4187,7 @@ * * Proceed without asking the user. */ - k = crypt_copy_key (the_valid_key); + k = crypt_copy_key (the_strong_valid_key); } else { @@ -4171,6 +4196,7 @@ */ k = crypt_select_key (matches, a, NULL, app, forced_valid); } + crypt_free_key (&matches); } else @@ -4305,45 +4331,26 @@ } /* This routine attempts to find the keyids of the recipients of a - message. It returns NULL if any of the keys can not be found. */ -static char *find_keys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc, - unsigned int app) + message. It returns NULL if any of the keys can not be found. + If oppenc_mode is true, only keys that can be determined without + prompting will be used. */ +static char *find_keys (ADDRESS *adrlist, unsigned int app, int oppenc_mode) { - char *keyID, *keylist = NULL, *t; + char *crypt_hook_val = NULL; + const char *keyID = NULL; + char *keylist = NULL, *t; size_t keylist_size = 0; size_t keylist_used = 0; - ADDRESS *tmp = NULL, *addr = NULL; - ADDRESS **last = &tmp; + ADDRESS *addr = NULL; ADDRESS *p, *q; - int i; - crypt_key_t *k_info, *key; + crypt_key_t *k_info; const char *fqdn = mutt_fqdn (1); #if 0 *r_application = APPLICATION_PGP|APPLICATION_SMIME; #endif - - for (i = 0; i < 3; i++) - { - switch (i) - { - case 0: p = to; break; - case 1: p = cc; break; - case 2: p = bcc; break; - default: abort (); - } - - *last = rfc822_cpy_adr (p, 0); - while (*last) - last = &((*last)->next); - } - - if (fqdn) - rfc822_qualify (tmp, fqdn); - - tmp = mutt_remove_duplicates (tmp); - - for (p = tmp; p ; p = p->next) + + for (p = adrlist; p ; p = p->next) { char buf[LONG_STRING]; int forced_valid = 0; @@ -4351,28 +4358,40 @@ q = p; k_info = NULL; - if ((keyID = mutt_crypt_hook (p)) != NULL) + if ((crypt_hook_val = mutt_crypt_hook (p)) != NULL) { - int r; - snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), - keyID, p->mailbox); - if ((r = mutt_yesorno (buf, M_YES)) == M_YES) + 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 (keyID, '@')) && - (addr = rfc822_parse_adrlist (NULL, keyID))) + if ((t = strchr (crypt_hook_val, '@')) && + (addr = rfc822_parse_adrlist (NULL, crypt_hook_val))) { if (fqdn) rfc822_qualify (addr, fqdn); q = addr; } - else + else if (! oppenc_mode) { #if 0 - k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT, + k_info = crypt_getkeybystr (crypt_hook_val, KEYFLAG_CANENCRYPT, *r_application, &forced_valid); #else - k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT, + k_info = crypt_getkeybystr (crypt_hook_val, KEYFLAG_CANENCRYPT, app, &forced_valid); #endif } @@ -4380,69 +4399,70 @@ else if (r == -1) { FREE (&keylist); - rfc822_free_address (&tmp); rfc822_free_address (&addr); return NULL; } } - if (k_info == NULL - && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT, - app, &forced_valid)) == 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); - if ((key = crypt_ask_for_key (buf, q->mailbox, - KEYFLAG_CANENCRYPT, + k_info = crypt_ask_for_key (buf, q->mailbox, + KEYFLAG_CANENCRYPT, #if 0 - *r_application, + *r_application, #else - app, + app, #endif - &forced_valid)) == NULL) - { - FREE (&keylist); - rfc822_free_address (&tmp); - rfc822_free_address (&addr); - return NULL; - } + &forced_valid); } - else - key = k_info; - - { - const char *s = crypt_fpr (key); + + if (k_info == NULL) + { + FREE (&keylist); + rfc822_free_address (&addr); + return NULL; + } + + + keyID = crypt_fpr (k_info); #if 0 - if (key->flags & KEYFLAG_ISX509) - *r_application &= ~APPLICATION_PGP; - if (!(key->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 - keylist_size += mutt_strlen (s) + 4 + 1; - safe_realloc (&keylist, keylist_size); - sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */ - keylist_used ? " " : "", s, - forced_valid? "!":""); - } + 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 (&key); + crypt_free_key (&k_info); rfc822_free_address (&addr); } - rfc822_free_address (&tmp); return (keylist); } -char *pgp_gpgme_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) +char *pgp_gpgme_findkeys (ADDRESS *adrlist, int oppenc_mode) { - return find_keys (to, cc, bcc, APPLICATION_PGP); + return find_keys (adrlist, APPLICATION_PGP, oppenc_mode); } -char *smime_gpgme_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) +char *smime_gpgme_findkeys (ADDRESS *adrlist, int oppenc_mode) { - return find_keys (to, cc, bcc, APPLICATION_SMIME); + return find_keys (adrlist, APPLICATION_SMIME, oppenc_mode); } #ifdef HAVE_GPGME_OP_EXPORT_KEYS @@ -4562,82 +4582,146 @@ { crypt_key_t *p; char input_signas[SHORT_STRING]; + char *prompt, *letters, *choices; int choice; - if (msg->security & APPLICATION_PGP) - is_smime = 0; - else if (msg->security & APPLICATION_SMIME) - is_smime = 1; - if (is_smime) - choice = mutt_multi_choice ( - _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"), - _("esabpfc")); - else - choice = mutt_multi_choice ( - _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"), - _("esabmfc")); - - switch (choice) + msg->security |= APPLICATION_SMIME; + else + msg->security |= APPLICATION_PGP; + + /* + * Opportunistic encrypt is controlling encryption. + * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different + * letter choices for those. + */ + if (option (OPTCRYPTOPPORTUNISTICENCRYPT) && (msg->security & OPPENCRYPT)) { - case 1: /* (e)ncrypt */ - msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT); - msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN); - break; - - case 2: /* (s)ign */ - msg->security |= (is_smime? SMIMESIGN :PGPSIGN); - msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT); - break; - - case 3: /* sign (a)s */ -/* unset_option(OPTCRYPTCHECKTRUST); */ - if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN, - is_smime? APPLICATION_SMIME:APPLICATION_PGP, - NULL))) + if (is_smime) { - snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p)); - mutt_str_replace (is_smime? &SmimeDefaultKey : &PgpSignAs, input_signas); - crypt_free_key (&p); - - msg->security |= (is_smime? SMIMESIGN:PGPSIGN); + prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off? "); + letters = _("sapfco"); + choices = "SapFCo"; } -#if 0 else { - msg->security &= (is_smime? ~SMIMESIGN : ~PGPSIGN); + prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off? "); + letters = _("samfco"); + choices = "SamFCo"; } -#endif - *redraw = REDRAW_FULL; - break; - - case 4: /* (b)oth */ - msg->security = (is_smime? (SMIMEENCRYPT|SMIMESIGN):(PGPENCRYPT|PGPSIGN)); - break; - - case 5: /* (p)gp or s/(m)ime */ - is_smime = !is_smime; - break; - - case 6: /* (f)orget it */ - case 7: /* (c)lear */ - msg->security = 0; - break; } - - if (choice == 6 || choice == 7) - ; - else if (is_smime) + /* + * Opportunistic encryption option is set, but is toggled off + * for this message. + */ + else if (option (OPTCRYPTOPPORTUNISTICENCRYPT)) + { + if (is_smime) { - msg->security &= ~APPLICATION_PGP; - msg->security |= APPLICATION_SMIME; + prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode? "); + letters = _("esabpfco"); + choices = "esabpfcO"; } + else + { + prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode? "); + letters = _("esabmfco"); + choices = "esabmfcO"; + } + } + /* + * Opportunistic encryption is unset + */ else + { + if (is_smime) { - msg->security &= ~APPLICATION_SMIME; - msg->security |= APPLICATION_PGP; + prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear? "); + letters = _("esabpfc"); + choices = "esabpfc"; } - + else + { + prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear? "); + letters = _("esabmfc"); + choices = "esabmfc"; + } + } + + choice = mutt_multi_choice (prompt, letters); + if (choice > 0) + { + switch (choices[choice - 1]) + { + case 'e': /* (e)ncrypt */ + msg->security |= ENCRYPT; + msg->security &= ~SIGN; + break; + + case 's': /* (s)ign */ + msg->security &= ~ENCRYPT; + msg->security |= SIGN; + break; + + case 'S': /* (s)ign in oppenc mode */ + msg->security |= SIGN; + break; + + case 'a': /* sign (a)s */ + if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN, + is_smime? APPLICATION_SMIME:APPLICATION_PGP, + NULL))) + { + snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p)); + mutt_str_replace (is_smime? &SmimeDefaultKey : &PgpSignAs, input_signas); + crypt_free_key (&p); + + msg->security |= SIGN; + } + *redraw = REDRAW_FULL; + break; + + case 'b': /* (b)oth */ + msg->security |= (ENCRYPT | SIGN); + break; + + case 'p': /* (p)gp or s/(m)ime */ + case 'm': + is_smime = !is_smime; + if (is_smime) + { + msg->security &= ~APPLICATION_PGP; + msg->security |= APPLICATION_SMIME; + } + else + { + msg->security &= ~APPLICATION_SMIME; + msg->security |= APPLICATION_PGP; + } + crypt_opportunistic_encrypt (msg); + break; + + case 'f': /* (f)orget it */ + case 'c': /* (c)lear */ + msg->security &= ~(ENCRYPT | SIGN); + break; + + case 'F': /* (f)orget it or (c)lear in oppenc mode */ + case 'C': + msg->security &= ~SIGN; + break; + + case 'O': /* oppenc mode on */ + msg->security |= OPPENCRYPT; + crypt_opportunistic_encrypt (msg); + break; + + case 'o': /* oppenc mode off */ + msg->security &= ~OPPENCRYPT; + break; + } + } + return (msg->security); } diff -r 59bd9030e898 -r 1bd26d871d76 crypt-gpgme.h --- a/crypt-gpgme.h Tue Mar 17 16:28:56 2015 -0700 +++ b/crypt-gpgme.h Mon Mar 30 15:45:58 2015 -0700 @@ -24,8 +24,8 @@ void pgp_gpgme_init (void); void smime_gpgme_init (void); -char *pgp_gpgme_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc); -char *smime_gpgme_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc); +char *pgp_gpgme_findkeys (ADDRESS *adrlist, int oppenc_mode); +char *smime_gpgme_findkeys (ADDRESS *adrlist, int oppenc_mode); BODY *pgp_gpgme_encrypt_message (BODY *a, char *keylist, int sign); BODY *smime_gpgme_build_smime_entity (BODY *a, char *keylist); diff -r 59bd9030e898 -r 1bd26d871d76 crypt-mod-pgp-classic.c --- a/crypt-mod-pgp-classic.c Tue Mar 17 16:28:56 2015 -0700 +++ b/crypt-mod-pgp-classic.c Mon Mar 30 15:45:58 2015 -0700 @@ -46,9 +46,9 @@ return pgp_application_pgp_handler (m, s); } -static char *crypt_mod_pgp_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) +static char *crypt_mod_pgp_findkeys (ADDRESS *adrlist, int oppenc_mode) { - return pgp_findKeys (to, cc, bcc); + return pgp_findKeys (adrlist, oppenc_mode); } static BODY *crypt_mod_pgp_sign_message (BODY *a) diff -r 59bd9030e898 -r 1bd26d871d76 crypt-mod-pgp-gpgme.c --- a/crypt-mod-pgp-gpgme.c Tue Mar 17 16:28:56 2015 -0700 +++ b/crypt-mod-pgp-gpgme.c Mon Mar 30 15:45:58 2015 -0700 @@ -70,9 +70,9 @@ pgp_gpgme_invoke_import (fname); } -static char *crypt_mod_pgp_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) +static char *crypt_mod_pgp_findkeys (ADDRESS *adrlist, int oppenc_mode) { - return pgp_gpgme_findkeys (to, cc, bcc); + return pgp_gpgme_findkeys (adrlist, oppenc_mode); } static BODY *crypt_mod_pgp_sign_message (BODY *a) diff -r 59bd9030e898 -r 1bd26d871d76 crypt-mod-smime-classic.c --- a/crypt-mod-smime-classic.c Tue Mar 17 16:28:56 2015 -0700 +++ b/crypt-mod-smime-classic.c Mon Mar 30 15:45:58 2015 -0700 @@ -46,9 +46,9 @@ return smime_application_smime_handler (m, s); } -static char *crypt_mod_smime_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) +static char *crypt_mod_smime_findkeys (ADDRESS *adrlist, int oppenc_mode) { - return smime_findKeys (to, cc, bcc); + return smime_findKeys (adrlist, oppenc_mode); } static BODY *crypt_mod_smime_sign_message (BODY *a) diff -r 59bd9030e898 -r 1bd26d871d76 crypt-mod-smime-gpgme.c --- a/crypt-mod-smime-gpgme.c Tue Mar 17 16:28:56 2015 -0700 +++ b/crypt-mod-smime-gpgme.c Mon Mar 30 15:45:58 2015 -0700 @@ -55,9 +55,9 @@ return smime_gpgme_application_handler (m, s); } -static char *crypt_mod_smime_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) +static char *crypt_mod_smime_findkeys (ADDRESS *adrlist, int oppenc_mode) { - return smime_gpgme_findkeys (to, cc, bcc); + return smime_gpgme_findkeys (adrlist, oppenc_mode); } static BODY *crypt_mod_smime_sign_message (BODY *a) diff -r 59bd9030e898 -r 1bd26d871d76 crypt-mod.h --- a/crypt-mod.h Tue Mar 17 16:28:56 2015 -0700 +++ b/crypt-mod.h Mon Mar 30 15:45:58 2015 -0700 @@ -43,8 +43,7 @@ typedef BODY *(*crypt_func_pgp_traditional_encryptsign_t) (BODY *a, int flags, char *keylist); typedef BODY *(*crypt_func_pgp_make_key_attachment_t) (char *tempf); -typedef char *(*crypt_func_findkeys_t) (ADDRESS *to, - ADDRESS *cc, ADDRESS *bcc); +typedef char *(*crypt_func_findkeys_t) (ADDRESS *adrlist, int oppenc_mode); typedef BODY *(*crypt_func_sign_message_t) (BODY *a); typedef BODY *(*crypt_func_pgp_encrypt_message_t) (BODY *a, char *keylist, int sign); diff -r 59bd9030e898 -r 1bd26d871d76 crypt.c --- a/crypt.c Tue Mar 17 16:28:56 2015 -0700 +++ b/crypt.c Mon Mar 30 15:45:58 2015 -0700 @@ -707,8 +707,11 @@ -int crypt_get_keys (HEADER *msg, char **keylist) +int crypt_get_keys (HEADER *msg, char **keylist, int oppenc_mode) { + ADDRESS *adrlist = NULL, *last = NULL; + const char *fqdn = mutt_fqdn (1); + /* Do a quick check to make sure that we can find all of the encryption * keys if the user has requested this service. */ @@ -719,31 +722,73 @@ if ((WithCrypto & APPLICATION_PGP)) set_option (OPTPGPCHECKTRUST); + last = rfc822_append (&adrlist, msg->env->to, 0); + last = rfc822_append (last ? &last : &adrlist, msg->env->cc, 0); + rfc822_append (last ? &last : &adrlist, msg->env->bcc, 0); + + if (fqdn) + rfc822_qualify (adrlist, fqdn); + adrlist = mutt_remove_duplicates (adrlist); + *keylist = NULL; - if (msg->security & ENCRYPT) + if (oppenc_mode || (msg->security & ENCRYPT)) { if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP)) { - if ((*keylist = crypt_pgp_findkeys (msg->env->to, msg->env->cc, - msg->env->bcc)) == NULL) + if ((*keylist = crypt_pgp_findkeys (adrlist, oppenc_mode)) == NULL) + { + rfc822_free_address (&adrlist); return (-1); + } unset_option (OPTPGPCHECKTRUST); } if ((WithCrypto & APPLICATION_SMIME) && (msg->security & APPLICATION_SMIME)) { - if ((*keylist = crypt_smime_findkeys (msg->env->to, msg->env->cc, - msg->env->bcc)) == NULL) + if ((*keylist = crypt_smime_findkeys (adrlist, oppenc_mode)) == NULL) + { + rfc822_free_address (&adrlist); return (-1); + } } } + + rfc822_free_address (&adrlist); return (0); } +/* + * Check if all recipients keys can be automatically determined. + * Enable encryption if they can, otherwise disable encryption. + */ + +void crypt_opportunistic_encrypt(HEADER *msg) +{ + char *pgpkeylist = NULL; + + if (!WithCrypto) + return; + + if (! (option (OPTCRYPTOPPORTUNISTICENCRYPT) && (msg->security & OPPENCRYPT)) ) + return; + + crypt_get_keys (msg, &pgpkeylist, 1); + if (pgpkeylist != NULL ) + { + msg->security |= ENCRYPT; + FREE (&pgpkeylist); + } + else + { + msg->security &= ~ENCRYPT; + } +} + + static void crypt_fetch_signatures (BODY ***signatures, BODY *a, int *n) { @@ -980,3 +1025,25 @@ *pps = ps; return pfcopy; } + + +/* + * Used by pgp_findKeys and find_keys to check if a crypt-hook + * value is a key id. + */ + +short crypt_is_numerical_keyid (const char *s) +{ + /* or should we require the "0x"? */ + if (strncmp (s, "0x", 2) == 0) + s += 2; + if (strlen (s) % 8) + return 0; + while (*s) + if (strchr ("0123456789ABCDEFabcdef", *s++) == NULL) + return 0; + + return 1; +} + + diff -r 59bd9030e898 -r 1bd26d871d76 cryptglue.c --- a/cryptglue.c Tue Mar 17 16:28:56 2015 -0700 +++ b/cryptglue.c Mon Mar 30 15:45:58 2015 -0700 @@ -199,11 +199,13 @@ } /* This routine attempts to find the keyids of the recipients of a - message. It returns NULL if any of the keys can not be found. */ -char *crypt_pgp_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) + message. It returns NULL if any of the keys can not be found. + If oppenc_mode is true, only keys that can be determined without + prompting will be used. */ +char *crypt_pgp_findkeys (ADDRESS *adrlist, int oppenc_mode) { if (CRYPT_MOD_CALL_CHECK (PGP, findkeys)) - return (CRYPT_MOD_CALL (PGP, findkeys)) (to, cc, bcc); + return (CRYPT_MOD_CALL (PGP, findkeys)) (adrlist, oppenc_mode); return NULL; } @@ -333,11 +335,13 @@ } /* This routine attempts to find the keyids of the recipients of a - message. It returns NULL if any of the keys can not be found. */ -char *crypt_smime_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) + message. It returns NULL if any of the keys can not be found. + If oppenc_mode is true, only keys that can be determined without + prompting will be used. */ +char *crypt_smime_findkeys (ADDRESS *adrlist, int oppenc_mode) { if (CRYPT_MOD_CALL_CHECK (SMIME, findkeys)) - return (CRYPT_MOD_CALL (SMIME, findkeys)) (to, cc, bcc); + return (CRYPT_MOD_CALL (SMIME, findkeys)) (adrlist, oppenc_mode); return NULL; } diff -r 59bd9030e898 -r 1bd26d871d76 init.h --- a/init.h Tue Mar 17 16:28:56 2015 -0700 +++ b/init.h Mon Mar 30 15:45:58 2015 -0700 @@ -491,6 +491,27 @@ ** $$crypt_replyencrypt, ** $$crypt_autosign, $$crypt_replysign and $$smime_is_default. */ + { "crypt_opportunistic_encrypt", DT_BOOL, R_NONE, OPTCRYPTOPPORTUNISTICENCRYPT, 0 }, + /* + ** .pp + ** Setting this variable will cause Mutt to automatically enable and + ** disable encryption, based on whether all message recipient keys + ** can be located by mutt. + ** .pp + ** When this option is enabled, mutt will determine the encryption + ** setting each time the TO, CC, and BCC lists are edited. If + ** $$edit_headers is set, mutt will also do so each time the message + ** is edited. + ** .pp + ** While this is set, encryption settings can't be manually changed. + ** The pgp or smime menus provide an option to disable the option for + ** a particular message. + ** .pp + ** If $$crypt_autoencrypt or $$crypt_replyencrypt enable encryption for + ** a message, this option will be disabled for the message. It can + ** be manually re-enabled in the pgp or smime menus. + ** (Crypto only) + */ { "pgp_replyencrypt", DT_SYN, R_NONE, UL "crypt_replyencrypt", 1 }, { "crypt_replyencrypt", DT_BOOL, R_NONE, OPTCRYPTREPLYENCRYPT, 1 }, /* diff -r 59bd9030e898 -r 1bd26d871d76 mutt.h --- a/mutt.h Tue Mar 17 16:28:56 2015 -0700 +++ b/mutt.h Mon Mar 30 15:45:58 2015 -0700 @@ -461,6 +461,7 @@ OPTCRYPTAUTOENCRYPT, OPTCRYPTAUTOPGP, OPTCRYPTAUTOSMIME, + OPTCRYPTOPPORTUNISTICENCRYPT, OPTCRYPTREPLYENCRYPT, OPTCRYPTREPLYSIGN, OPTCRYPTREPLYSIGNENCRYPTED, @@ -704,8 +705,8 @@ typedef struct header { - unsigned int security : 11; /* bit 0-6: flags, bit 7,8: application. - see: crypt.h pgplib.h, smime.h */ + unsigned int security : 12; /* bit 0-8: flags, bit 9,10: application. + see: mutt_crypt.h pgplib.h, smime.h */ unsigned int mime : 1; /* has a MIME-Version header? */ unsigned int flagged : 1; /* marked important? */ diff -r 59bd9030e898 -r 1bd26d871d76 mutt_crypt.h