<<< Date Index >>>     <<< Thread Index >>>

Opportunistic Encryption [PATCH]



Attached is a patch to an an option for opportunistic PGP encryption
(mutt will automatically encrypt email to anyone in your keyring for
which it has the required encryption keys).  This functionality is
similar to that of mozilla's enigmail package.

Quick start: add "set pgp_opportunistic_encrypt=yes" to ~/.muttrc and
send a message to anyone for whom you have a key.

I also tried to think of a nice interface to allow the following
behavior (but couldn't come up with one):

* Globally default to opportunistic encryption unless either the user
  overrides the default manually through the pgp menu (this much is
  done) or the recipient is on a list of "do not opportunistically
  encrypt" people.  The problem I run into is that the way mutt's
  interface operates, the global option is used to set the initial
  value of the menu option controlling opportunistic encryption (this
  is the same way that pgp_autoencrypt works).  When it comes time to
  run the send-hook and change the pgp_opportunistic_encrypt setting,
  the user's menu choice (which should really override both the
  per-message send-hook setting and the global setting) cannot be
  distinguished from the global default.  E.g. I may want to
  opportunistically encrypt messages by default, except not by default
  to Alice (who keeps her PGP key only at work), and I'd like to be
  able to *sometimes* manually override even that setting via the pgp
  menu and encrypt, if I know that she's recieving this message at
  work.  Once I accept the global default as the user's default menu
  choice, I lose the ability to distinguish between the states "global
  default is opportunistic encryption, user wants to override any
  local address settings and opportunistically encrypt" and "global
  default is opportunistic encryption, user wants to retain default
  global setting *unless* local address setting overrides global
  settings".  The only way I see to pull this off is to introduce a
  tri-state option (force don't opportunistically encrypt, force
  opportunistically encrypt, use default), which seems excessively
  complicated.

The reason pgp_autoencrypt doesn't suffer from the above problem is
that people just don't *use* pgp_autoencrypt globally, and the reason
that pgp_autosign doesn't suffer from the above problem is that nobody
really cares if a message is unnecessarily signed.

It's a bit simpler than it sounds.  :-)

In any event, feedback is welcome.

And thank you, mutt coders, for a very nice piece of software.

-- 
Best of luck,
Mark Schreiber
diff -u mutt-1.4.2.1/compose.c mutt-1.4.2.1-oppencrypt/compose.c
--- mutt-1.4.2.1/compose.c      2002-07-24 04:41:29.000000000 -0400
+++ mutt-1.4.2.1-oppencrypt/compose.c   2004-06-13 20:12:36.216828531 -0400
@@ -113,8 +113,12 @@
     addstr (_("Sign, Encrypt"));
   else if (pgp & PGPENCRYPT)
     addstr (_("Encrypt"));
+  else if ((pgp & PGPSIGN) && (pgp & PGPOPPORTUNISTICENCRYPT))
+    addstr (_("Sign, Opportunistic Encrypt"));
   else if (pgp & PGPSIGN)
     addstr (_("Sign"));
+  else if (pgp & PGPOPPORTUNISTICENCRYPT)
+    addstr (_("Opportunistic Encrypt"));
   else
     addstr (_("Clear"));
   clrtoeol ();
@@ -130,8 +134,8 @@
   pgp_key_t *p;
   char input_signas[SHORT_STRING];
 
-  switch (mutt_multi_choice (_("(e)ncrypt, (s)ign, sign (a)s, (b)oth, or 
(f)orget it? "),
-                            _("esabf")))
+  switch (mutt_multi_choice (_("(e)ncrypt, (s)ign, sign (a)s, (b)oth, 
(o)pportunistic encrypt, or (f)orget it? "),
+                            _("esabof")))
   {
   case 1: /* (e)ncrypt */
     bits |= PGPENCRYPT;
@@ -164,10 +168,14 @@
     break;
 
   case 4: /* (b)oth */
-    bits = PGPENCRYPT | PGPSIGN;
+    bits |= PGPENCRYPT | PGPSIGN;
     break;
 
-  case 5: /* (f)orget it */
+  case 5: /* (o)pportunstic encrypt */
+    bits |= PGPOPPORTUNISTICENCRYPT;
+    break;
+
+  case 6: /* (f)orget it */
     bits = 0;
     break;
   }
Common subdirectories: mutt-1.4.2.1/contrib and mutt-1.4.2.1-oppencrypt/contrib
Only in mutt-1.4.2.1-oppencrypt: cscope.out
Common subdirectories: mutt-1.4.2.1/doc and mutt-1.4.2.1-oppencrypt/doc
Common subdirectories: mutt-1.4.2.1/imap and mutt-1.4.2.1-oppencrypt/imap
diff -u mutt-1.4.2.1/init.h mutt-1.4.2.1-oppencrypt/init.h
--- mutt-1.4.2.1/init.h 2002-07-24 04:41:29.000000000 -0400
+++ mutt-1.4.2.1-oppencrypt/init.h      2004-06-13 19:34:05.709496391 -0400
@@ -1186,6 +1186,13 @@
   ** \fIpgp-menu\fP, when encryption is not required or signing is
   ** requested as well.
   */
+  { "pgp_opportunistic_encrypt",       DT_BOOL, R_NONE, 
OPTPGPOPPORTUNISTICENCRYPT, 0 },
+  /*
+  ** .pp Setting this variable will cause Mutt to attempt to PGP/MIME
+  ** encrypt outgoing messages if it can find all necessary encryption
+  ** keys in the keychain being used.
+  */
+
   { "pgp_ignore_subkeys", DT_BOOL, R_NONE, OPTPGPIGNORESUB, 1},
   /*
   ** .pp
Common subdirectories: mutt-1.4.2.1/intl and mutt-1.4.2.1-oppencrypt/intl
Common subdirectories: mutt-1.4.2.1/m4 and mutt-1.4.2.1-oppencrypt/m4
diff -u mutt-1.4.2.1/mutt.h mutt-1.4.2.1-oppencrypt/mutt.h
--- mutt-1.4.2.1/mutt.h 2002-07-24 05:46:58.000000000 -0400
+++ mutt-1.4.2.1-oppencrypt/mutt.h      2004-06-13 20:07:57.602019486 -0400
@@ -424,6 +424,7 @@
 #ifdef HAVE_PGP
   OPTPGPAUTOSIGN,
   OPTPGPAUTOENCRYPT,
+  OPTPGPOPPORTUNISTICENCRYPT,
   OPTPGPIGNORESUB,
   OPTPGPLONGIDS,
   OPTPGPREPLYENCRYPT,
@@ -466,6 +467,7 @@
 #ifdef HAVE_PGP
   OPTPGPCHECKTRUST,    /* (pseudo) used by pgp_select_key () */
   OPTDONTHANDLEPGPKEYS,        /* (pseudo) used to extract PGP keys */
+  OPTPGPSILENT, /* (pseudo) do not interact with the user */
 #endif
 
 
@@ -621,7 +623,7 @@
 typedef struct header
 {
 #ifdef HAVE_PGP
-  unsigned int pgp : 4;
+  unsigned int pgp : 5;
 #endif
 
   unsigned int mime : 1;               /* has a Mime-Version header? */
diff -u mutt-1.4.2.1/pgp.c mutt-1.4.2.1-oppencrypt/pgp.c
--- mutt-1.4.2.1/pgp.c  2002-01-09 10:39:28.000000000 -0500
+++ mutt-1.4.2.1-oppencrypt/pgp.c       2004-06-13 17:37:06.009347518 -0400
@@ -1366,7 +1366,8 @@
     {
       int r;
       snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID, 
p->mailbox);
-      if ((r = mutt_yesorno (buf, M_YES)) == M_YES)
+      if (option(OPTPGPSILENT) ||
+                 ((r = mutt_yesorno (buf, M_YES)) == M_YES))
       {
        /* check for e-mail address */
        if ((t = strchr (keyID, '@')) && 
@@ -1394,8 +1395,8 @@
     {
       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
 
-      if ((key = pgp_ask_for_key (buf, q->mailbox,
-                                 KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL)
+      if (option(OPTPGPSILENT) || ((key = pgp_ask_for_key (buf, q->mailbox,
+                                         KEYFLAG_CANENCRYPT, PGP_PUBRING)) == 
NULL))
       {
        safe_free ((void **)&keylist);
        rfc822_free_address (&tmp);
@@ -1669,7 +1670,24 @@
   return b;
 }
 
+/* returns 0 if we have the appropriate keys for encrypting the message */
+int pgp_test_keys(HEADER *msg)
+{
+       char * pgpkeylist = NULL;
+       int return_code = -1;
+       
+       set_option (OPTPGPCHECKTRUST);
+       set_option (OPTPGPSILENT);
 
+       pgpkeylist = pgp_findKeys(msg->env->to, msg->env->cc, msg->env->bcc);
+       if (pgpkeylist)
+       {
+               FREE(&pgpkeylist);
+               return_code = 0;
+       }
+       unset_option (OPTPGPSILENT);
+       return return_code;
+}
 
 int pgp_get_keys (HEADER *msg, char **pgpkeylist)
 {
diff -u mutt-1.4.2.1/pgp.h mutt-1.4.2.1-oppencrypt/pgp.h
--- mutt-1.4.2.1/pgp.h  2001-03-28 09:59:52.000000000 -0500
+++ mutt-1.4.2.1-oppencrypt/pgp.h       2004-06-13 16:08:49.000000000 -0400
@@ -62,6 +62,7 @@
 int mutt_parse_pgp_hdr (char *, int);
 int pgp_decrypt_mime (FILE *, FILE **, BODY *, BODY **);
 int pgp_get_keys (HEADER *, char **);
+int pgp_test_keys (HEADER *);
 int pgp_protect (HEADER *, char *);
 int pgp_query (BODY *);
 /* int pgp_string_matches_hint (const char *s, LIST * hints); */
diff -u mutt-1.4.2.1/pgpkey.c mutt-1.4.2.1-oppencrypt/pgpkey.c
--- mutt-1.4.2.1/pgpkey.c       2002-01-15 04:04:28.000000000 -0500
+++ mutt-1.4.2.1-oppencrypt/pgpkey.c    2004-06-13 15:53:14.747908917 -0400
@@ -622,7 +622,7 @@
        snprintf (buff, sizeof (buff), _("%s Do you really want to use the 
key?"),
                  _(s));
 
-       if (mutt_yesorno (buff, 0) != 1)
+       if (option(OPTPGPSILENT) || (mutt_yesorno (buff, 0) != 1))
        {
          mutt_clear_error ();
          break;
diff -u mutt-1.4.2.1/pgplib.h mutt-1.4.2.1-oppencrypt/pgplib.h
--- mutt-1.4.2.1/pgplib.h       2001-06-26 06:25:39.000000000 -0400
+++ mutt-1.4.2.1-oppencrypt/pgplib.h    2004-06-13 18:38:29.879832106 -0400
@@ -23,6 +23,7 @@
 #define PGPSIGN     (1 << 1)
 #define PGPKEY      (1 << 2)
 #define PGPGOODSIGN (1 << 3)
+#define PGPOPPORTUNISTICENCRYPT (1 << 4)
 
 #define KEYFLAG_CANSIGN                (1 <<  0)
 #define KEYFLAG_CANENCRYPT             (1 <<  1)
Common subdirectories: mutt-1.4.2.1/po and mutt-1.4.2.1-oppencrypt/po
diff -u mutt-1.4.2.1/send.c mutt-1.4.2.1-oppencrypt/send.c
--- mutt-1.4.2.1/send.c 2002-01-30 17:50:59.000000000 -0500
+++ mutt-1.4.2.1-oppencrypt/send.c      2004-06-13 20:05:55.175740951 -0400
@@ -1251,6 +1251,11 @@
        msg->pgp |= PGPSIGN;
       if (option (OPTPGPAUTOENCRYPT))
        msg->pgp |= PGPENCRYPT;
+      if (option (OPTPGPOPPORTUNISTICENCRYPT))
+      {
+        int i =  PGPOPPORTUNISTICENCRYPT;
+       msg->pgp |= i;
+      };        
       
       msg->pgp |= set_pgp_flags (cur, ctx);
     }
@@ -1415,6 +1420,13 @@
   encode_descriptions (msg->content, 1);
   
 #ifdef HAVE_PGP
+  if ((msg->pgp & PGPOPPORTUNISTICENCRYPT) && !(msg->pgp & PGPENCRYPT))
+  {
+    if (pgp_test_keys (msg) != -1)
+         msg->pgp |= PGPENCRYPT;
+  }
+
+  
   if (msg->pgp)
   {
     /* save the decrypted attachments */

Attachment: pgpxGBSCPOiDr.pgp
Description: PGP signature