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

Reply via email to