]> granicus.if.org Git - mutt/commitdiff
Autocrypt outgoing emails.
authorKevin McCarthy <kevin@8t8.us>
Sun, 21 Jul 2019 22:15:06 +0000 (15:15 -0700)
committerKevin McCarthy <kevin@8t8.us>
Sat, 3 Aug 2019 21:08:09 +0000 (14:08 -0700)
Change crypt_get_keys() to query autocrypt.

When oppenc_mode is set, we still query the original keyring
regardless, because the compose menu can still run oppenc even if
autocrypt is on.

Since mutt_autocrypt_ui_recommendation() checks each key as part of
making the recommendation, add a keylist parameter and use that
function.

Add gpgme changes to use the autocrypt context for encryption.

Postpone work:
* Change mutt_protect() to have a postpone parameter.  Remove the
  manual toggling of the SIGN bit outside the call when postponing.

* Since autocrypt doesn't set the SIGN bit, this allows us to turn off
  signing inside mutt_protect() for both normal and autocrypt mode.

* Set the autocrypt postpone key in AutocryptDefaultKey.

Write autocrypt and gossip headers in outgoing emails.

12 files changed:
autocrypt/autocrypt.c
autocrypt/autocrypt.h
compose.c
crypt-gpgme.c
crypt.c
cryptglue.c
globals.h
mutt.h
mutt_crypt.h
postpone.c
send.c
sendlib.c

index dd3ccb82eff6550eeea55db5799d208df265af4b..7ac2bd5f706d7083f602b80d0ac7923fcbfc5dba 100644 (file)
@@ -439,13 +439,19 @@ cleanup:
   return rv;
 }
 
-autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr)
+/* Returns the recommendation.  If the recommendataion is > NO and
+ * keylist is not NULL, keylist will be populated with the autocrypt
+ * keyids
+ */
+autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr, char **keylist)
 {
   autocrypt_rec_t rv = AUTOCRYPT_REC_OFF;
   AUTOCRYPT_ACCOUNT *account = NULL;
   AUTOCRYPT_PEER *peer = NULL;
   ADDRESS *recip, *recips = NULL, *last = NULL;
   int all_encrypt = 1, has_discourage = 0;
+  BUFFER *keylist_buf = NULL;
+  const char *matching_key;
 
   if (!option (OPTAUTOCRYPT) ||
       mutt_autocrypt_init (0) ||
@@ -460,6 +466,9 @@ autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr)
   if (mutt_autocrypt_db_account_get (hdr->env->from, &account) <= 0)
     goto cleanup;
 
+  keylist_buf = mutt_buffer_pool_get ();
+  mutt_buffer_addstr (keylist_buf, account->keyid);
+
   last = rfc822_append (&recips, hdr->env->to, 0);
   last = rfc822_append (last ? &last : &recips, hdr->env->cc, 0);
   rfc822_append (last ? &last : &recips, hdr->env->bcc, 0);
@@ -475,6 +484,8 @@ autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr)
 
     if (mutt_autocrypt_gpgme_is_valid_key (peer->keyid))
     {
+      matching_key = peer->keyid;
+
       if (!(peer->last_seen && peer->autocrypt_timestamp) ||
           (peer->last_seen - peer->autocrypt_timestamp > 35 * 24 * 60 * 60))
       {
@@ -487,12 +498,18 @@ autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr)
     }
     else if (mutt_autocrypt_gpgme_is_valid_key (peer->gossip_keyid))
     {
+      matching_key = peer->gossip_keyid;
+
       has_discourage = 1;
       all_encrypt = 0;
     }
     else
       goto cleanup;
 
+    if (mutt_buffer_len (keylist_buf))
+      mutt_buffer_addch (keylist_buf, ' ');
+    mutt_buffer_addstr (keylist_buf, matching_key);
+
     mutt_autocrypt_db_peer_free (&peer);
   }
 
@@ -503,9 +520,195 @@ autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr)
   else
     rv = AUTOCRYPT_REC_AVAILABLE;
 
+  if (keylist)
+    mutt_str_replace (keylist, mutt_b2s (keylist_buf));
+
 cleanup:
   mutt_autocrypt_db_account_free (&account);
   rfc822_free_address (&recips);
   mutt_autocrypt_db_peer_free (&peer);
+  mutt_buffer_pool_release (&keylist_buf);
+  return rv;
+}
+
+int mutt_autocrypt_set_sign_as_default_key (HEADER *hdr)
+{
+  int rv = -1;
+  AUTOCRYPT_ACCOUNT *account = NULL;
+
+  if (!option (OPTAUTOCRYPT) ||
+      mutt_autocrypt_init (0) ||
+      !hdr ||
+      !hdr->env->from ||
+      hdr->env->from->next)
+    return -1;
+
+  if (mutt_autocrypt_db_account_get (hdr->env->from, &account) <= 0)
+    goto cleanup;
+  if (!account->keyid)
+    goto cleanup;
+
+  mutt_str_replace (&AutocryptSignAs, account->keyid);
+  mutt_str_replace (&AutocryptDefaultKey, account->keyid);
+
+  rv = 0;
+
+cleanup:
+  mutt_autocrypt_db_account_free (&account);
+  return rv;
+}
+
+
+static void write_autocrypt_header_line (FILE *fp, const char *addr,
+                                         int prefer_encrypt,
+                                         const char *keydata)
+{
+  int count = 0;
+
+  fprintf (fp, "addr=%s; ", addr);
+  if (prefer_encrypt)
+    fputs ("prefer-encrypt=mutual; ", fp);
+  fputs ("keydata=\n", fp);
+
+  while (*keydata)
+  {
+    count = 0;
+    fputs ("\t", fp);
+    while (*keydata && count < 75)
+    {
+      fputc (*keydata, fp);
+      count++;
+      keydata++;
+    }
+    fputs ("\n", fp);
+  }
+}
+
+int mutt_autocrypt_write_autocrypt_header (ENVELOPE *env, FILE *fp)
+{
+  int rv = -1;
+  AUTOCRYPT_ACCOUNT *account = NULL;
+
+  if (!option (OPTAUTOCRYPT) ||
+      mutt_autocrypt_init (0) ||
+      !env ||
+      !env->from ||
+      env->from->next)
+    return -1;
+
+  if (mutt_autocrypt_db_account_get (env->from, &account) <= 0)
+    goto cleanup;
+  if (!account->keydata)
+    goto cleanup;
+
+  fputs ("Autocrypt: ", fp);
+  write_autocrypt_header_line (fp, account->email_addr, account->prefer_encrypt,
+                               account->keydata);
+
+  rv = 0;
+
+cleanup:
+  mutt_autocrypt_db_account_free (&account);
+  return rv;
+}
+
+int mutt_autocrypt_write_gossip_headers (ENVELOPE *env, FILE *fp)
+{
+  AUTOCRYPTHDR *gossip;
+
+  if (!option (OPTAUTOCRYPT) ||
+      mutt_autocrypt_init (0) ||
+      !env)
+    return -1;
+
+  for (gossip = env->autocrypt_gossip; gossip; gossip = gossip->next)
+  {
+    fputs ("Autocrypt-Gossip: ", fp);
+    write_autocrypt_header_line (fp, gossip->addr, 0, gossip->keydata);
+  }
+
+  return 0;
+}
+
+int mutt_autocrypt_generate_gossip_list (HEADER *hdr)
+{
+  int rv = -1;
+  AUTOCRYPT_PEER *peer = NULL;
+  AUTOCRYPT_ACCOUNT *account = NULL;
+  ADDRESS *recip, *recips = NULL, *last = NULL;
+  AUTOCRYPTHDR *gossip;
+  const char *keydata, *addr;
+  ENVELOPE *mime_headers;
+
+  if (!option (OPTAUTOCRYPT) ||
+      mutt_autocrypt_init (0) ||
+      !hdr)
+    return -1;
+
+  mime_headers = hdr->content->mime_headers;
+  if (!mime_headers)
+    mime_headers = hdr->content->mime_headers = mutt_new_envelope ();
+  mutt_free_autocrypthdr (&mime_headers->autocrypt_gossip);
+
+  last = rfc822_append (&recips, hdr->env->to, 0);
+  last = rfc822_append (last ? &last : &recips, hdr->env->cc, 0);
+
+  for (recip = recips; recip; recip = recip->next)
+  {
+    /* At this point, we just accept missing keys and include what
+     * we can. */
+    if (mutt_autocrypt_db_peer_get (recip, &peer) <= 0)
+      continue;
+
+    keydata = NULL;
+    if (mutt_autocrypt_gpgme_is_valid_key (peer->keyid))
+      keydata = peer->keydata;
+    else if (mutt_autocrypt_gpgme_is_valid_key (peer->gossip_keyid))
+      keydata = peer->gossip_keydata;
+
+    if (keydata)
+    {
+      gossip = mutt_new_autocrypthdr ();
+      gossip->addr = safe_strdup (peer->email_addr);
+      gossip->keydata = safe_strdup (keydata);
+      gossip->next = mime_headers->autocrypt_gossip;
+      mime_headers->autocrypt_gossip = gossip;
+    }
+
+    mutt_autocrypt_db_peer_free (&peer);
+  }
+
+  for (recip = hdr->env->reply_to; recip; recip = recip->next)
+  {
+    addr = keydata = NULL;
+    if (mutt_autocrypt_db_account_get (recip, &account) > 0)
+    {
+      addr = account->email_addr;
+      keydata = account->keydata;
+    }
+    else if (mutt_autocrypt_db_peer_get (recip, &peer) > 0)
+    {
+      addr = peer->email_addr;
+      if (mutt_autocrypt_gpgme_is_valid_key (peer->keyid))
+        keydata = peer->keydata;
+      else if (mutt_autocrypt_gpgme_is_valid_key (peer->gossip_keyid))
+        keydata = peer->gossip_keydata;
+    }
+
+    if (keydata)
+    {
+      gossip = mutt_new_autocrypthdr ();
+      gossip->addr = safe_strdup (addr);
+      gossip->keydata = safe_strdup (keydata);
+      gossip->next = mime_headers->autocrypt_gossip;
+      mime_headers->autocrypt_gossip = gossip;
+    }
+    mutt_autocrypt_db_account_free (&account);
+    mutt_autocrypt_db_peer_free (&peer);
+  }
+
+  rfc822_free_address (&recips);
+  mutt_autocrypt_db_account_free (&account);
+  mutt_autocrypt_db_peer_free (&peer);
   return rv;
 }
index 2608277da3799b96d7140d9034b11c40b8c727aa..83c5f7c8ff40899d8ed944327bd54cb57700afef 100644 (file)
@@ -75,6 +75,10 @@ int mutt_autocrypt_init (int);
 void mutt_autocrypt_cleanup (void);
 int mutt_autocrypt_process_autocrypt_header (HEADER *hdr, ENVELOPE *env);
 int mutt_autocrypt_process_gossip_header (HEADER *hdr, ENVELOPE *env);
-autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr);
+autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr, char **keylist);
+int mutt_autocrypt_set_sign_as_default_key (HEADER *hdr);
+int mutt_autocrypt_write_autocrypt_header (ENVELOPE *env, FILE *fp);
+int mutt_autocrypt_write_gossip_headers (ENVELOPE *env, FILE *fp);
+int mutt_autocrypt_generate_gossip_list (HEADER *hdr);
 
 #endif
index 4ae322f64a746074607325d507dab348fc2d641b..6c3a3b3996438b47e94f5680433aef57f9522d43 100644 (file)
--- a/compose.c
+++ b/compose.c
@@ -258,7 +258,7 @@ static void autocrypt_compose_menu (HEADER *msg)
   {
     case 1:
       msg->security |= (AUTOCRYPT | AUTOCRYPT_OVERRIDE);
-      msg->security &= ~(ENCRYPT | SIGN | OPPENCRYPT);
+      msg->security &= ~(ENCRYPT | SIGN | OPPENCRYPT | INLINE);
       break;
     case 2:
       msg->security &= ~AUTOCRYPT;
@@ -363,25 +363,28 @@ static void redraw_crypt_lines (compose_redraw_data_t *rd)
 #ifdef USE_AUTOCRYPT
   mutt_window_move (MuttIndexWindow, HDR_AUTOCRYPT, 0);
   mutt_window_clrtoeol (MuttIndexWindow);
-  SETCOLOR (MT_COLOR_COMPOSE_HEADER);
-  printw ("%*s", HeaderPadding[HDR_AUTOCRYPT], _(Prompts[HDR_AUTOCRYPT]));
-  NORMAL_COLOR;
-  if (option (OPTAUTOCRYPT) && (msg->security & AUTOCRYPT))
-  {
-    SETCOLOR (MT_COLOR_COMPOSE_SECURITY_ENCRYPT);
-    addstr (_("Encrypt"));
-  }
-  else
+  if (option (OPTAUTOCRYPT))
   {
-    SETCOLOR (MT_COLOR_COMPOSE_SECURITY_NONE);
-    addstr (_("Off"));
-  }
+    SETCOLOR (MT_COLOR_COMPOSE_HEADER);
+    printw ("%*s", HeaderPadding[HDR_AUTOCRYPT], _(Prompts[HDR_AUTOCRYPT]));
+    NORMAL_COLOR;
+    if (msg->security & AUTOCRYPT)
+    {
+      SETCOLOR (MT_COLOR_COMPOSE_SECURITY_ENCRYPT);
+      addstr (_("Encrypt"));
+    }
+    else
+    {
+      SETCOLOR (MT_COLOR_COMPOSE_SECURITY_NONE);
+      addstr (_("Off"));
+    }
 
-  SETCOLOR (MT_COLOR_COMPOSE_HEADER);
-  mutt_window_mvprintw (MuttIndexWindow, HDR_AUTOCRYPT, 40, "%s",
-                        _("Recommendation: "));
-  NORMAL_COLOR;
-  printw ("%s", _(AutocryptRecUiFlags[rd->autocrypt_rec]));
+    SETCOLOR (MT_COLOR_COMPOSE_HEADER);
+    mutt_window_mvprintw (MuttIndexWindow, HDR_AUTOCRYPT, 40, "%s",
+                          _("Recommendation: "));
+    NORMAL_COLOR;
+    printw ("%s", _(AutocryptRecUiFlags[rd->autocrypt_rec]));
+  }
 #endif
 }
 
@@ -393,28 +396,29 @@ static void update_crypt_info (compose_redraw_data_t *rd)
     crypt_opportunistic_encrypt (msg);
 
 #ifdef USE_AUTOCRYPT
-  rd->autocrypt_rec = mutt_autocrypt_ui_recommendation (msg);
-
-  /* Anything that enables ENCRYPT or SIGN, or turns on SMIME
-   * overrides autocrypt, be it oppenc or the user having turned on
-   * those flags manually. */
-  if (msg->security & (ENCRYPT | SIGN | APPLICATION_SMIME))
-    msg->security &= ~(AUTOCRYPT | AUTOCRYPT_OVERRIDE);
-  else
+  if (option (OPTAUTOCRYPT))
   {
-    if (!(msg->security & AUTOCRYPT_OVERRIDE))
+    rd->autocrypt_rec = mutt_autocrypt_ui_recommendation (msg, NULL);
+
+    /* Anything that enables ENCRYPT or SIGN, or turns on SMIME
+     * overrides autocrypt, be it oppenc or the user having turned on
+     * those flags manually. */
+    if (msg->security & (ENCRYPT | SIGN | APPLICATION_SMIME))
+      msg->security &= ~(AUTOCRYPT | AUTOCRYPT_OVERRIDE);
+    else
     {
-      if (rd->autocrypt_rec == AUTOCRYPT_REC_YES)
-        msg->security |= AUTOCRYPT;
-      else
-        msg->security &= ~AUTOCRYPT;
+      if (!(msg->security & AUTOCRYPT_OVERRIDE))
+      {
+        if (rd->autocrypt_rec == AUTOCRYPT_REC_YES)
+        {
+          msg->security |= AUTOCRYPT;
+          msg->security &= ~INLINE;
+        }
+        else
+          msg->security &= ~AUTOCRYPT;
+      }
     }
   }
-  /* TODO:
-   * - autocrypt menu for manually enabling/disabling (turns on override)
-   * - deal with pgp and smime menu and their effects on security->AUTOCRYPT
-   *   when encryption or signing is enabled or if switch to smime mode
-   */
 #endif
 
   redraw_crypt_lines (rd);
@@ -1630,6 +1634,9 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
 
 #ifdef USE_AUTOCRYPT
       case OP_COMPOSE_AUTOCRYPT_MENU:
+        if (!option (OPTAUTOCRYPT))
+          break;
+
        if ((WithCrypto & APPLICATION_SMIME)
             && (msg->security & APPLICATION_SMIME))
        {
@@ -1655,6 +1662,15 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
     }
   }
 
+#ifdef USE_AUTOCRYPT
+  /* This is a fail-safe to make sure the bit isn't somehow turned
+   * on.  The user could have disabled the option after setting AUTOCRYPT,
+   * or perhaps resuming or replying to an autocrypt message.
+   */
+  if (!option (OPTAUTOCRYPT))
+    msg->security &= ~AUTOCRYPT;
+#endif
+
   mutt_pop_current_menu (menu);
   mutt_menuDestroy (&menu);
 
index bbdede5f806695db5d33af2917e0da2832bde893..83f6ae6ac1fb778931b601afb5af1dd758af51d9 100644 (file)
@@ -564,6 +564,13 @@ static gpgme_ctx_t create_gpgme_context (int for_smime)
   gpgme_ctx_t ctx;
 
   err = gpgme_new (&ctx);
+
+#ifdef USE_AUTOCRYPT
+  if (!err && option (OPTAUTOCRYPTGPGME))
+    err = gpgme_ctx_set_engine_info (ctx, GPGME_PROTOCOL_OpenPGP, NULL,
+                                     AutocryptDir);
+#endif
+
   if (err)
     {
       mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
@@ -944,6 +951,10 @@ static int set_signer (gpgme_ctx_t ctx, int for_smime)
 
   if (for_smime)
     signid = SmimeSignAs ? SmimeSignAs : SmimeDefaultKey;
+#ifdef USE_AUTOCRYPT
+  else if (option (OPTAUTOCRYPTGPGME))
+    signid = AutocryptSignAs;
+#endif
   else
     signid = PgpSignAs ? PgpSignAs : PgpDefaultKey;
 
diff --git a/crypt.c b/crypt.c
index 85ab5fdff1db7bac5d1e42f059e9d78ed96c21ca..84d8bd0e2b9d39def210c2922144ca30e51d0c0f 100644 (file)
--- a/crypt.c
+++ b/crypt.c
 #include "copy.h"
 #include "mutt_crypt.h"
 
+#ifdef USE_AUTOCRYPT
+#include "autocrypt.h"
+#endif
+
 #include <sys/wait.h>
 #include <string.h>
 #include <stdlib.h>
@@ -123,26 +127,38 @@ int crypt_valid_passphrase(int flags)
 }
 
 
-
-int mutt_protect (HEADER *msg, char *keylist)
+/* In postpone mode, signing is automatically disabled. */
+int mutt_protect (HEADER *msg, char *keylist, int postpone)
 {
   BODY *pbody = NULL, *tmp_pbody = NULL;
   BODY *tmp_smime_pbody = NULL;
   BODY *tmp_pgp_pbody = NULL;
   ENVELOPE *protected_headers = NULL;
-  int flags = (WithCrypto & APPLICATION_PGP)? msg->security: 0;
+  int security, sign, has_retainable_sig = 0;
   int i;
 
   if (!WithCrypto)
     return -1;
 
-  if (!(msg->security & (ENCRYPT | SIGN)))
+  security = msg->security;
+  sign = security & (AUTOCRYPT | SIGN);
+  if (postpone)
+  {
+    sign = 0;
+    security &= ~SIGN;
+  }
+
+  if (!(security & (ENCRYPT | AUTOCRYPT)) && !sign)
     return 0;
 
-  if ((msg->security & SIGN) && !crypt_valid_passphrase (msg->security))
+  if (sign &&
+      !(security & AUTOCRYPT) &&
+      !crypt_valid_passphrase (security))
     return (-1);
 
-  if ((WithCrypto & APPLICATION_PGP) && ((msg->security & PGPINLINE) == PGPINLINE))
+  if ((WithCrypto & APPLICATION_PGP) &&
+      !(security & AUTOCRYPT) &&
+      ((security & PGPINLINE) == PGPINLINE))
   {
     if ((msg->content->type != TYPETEXT) ||
         ascii_strcasecmp (msg->content->subtype, "plain"))
@@ -168,7 +184,7 @@ int mutt_protect (HEADER *msg, char *keylist)
     {
       /* they really want to send it inline... go for it */
       if (!isendwin ()) mutt_endwin _("Invoking PGP...");
-      pbody = crypt_pgp_traditional_encryptsign (msg->content, flags, keylist);
+      pbody = crypt_pgp_traditional_encryptsign (msg->content, security, keylist);
       if (pbody)
       {
         msg->content = pbody;
@@ -193,15 +209,15 @@ int mutt_protect (HEADER *msg, char *keylist)
   if ((WithCrypto & APPLICATION_PGP))
     tmp_pgp_pbody   = msg->content;
 
-  if (option (OPTCRYPTUSEPKA) && (msg->security & SIGN))
+  if (option (OPTCRYPTUSEPKA) && sign)
   {
     /* Set sender (necessary for e.g. PKA).  */
 
     if ((WithCrypto & APPLICATION_SMIME)
-        && (msg->security & APPLICATION_SMIME))
+        && (security & APPLICATION_SMIME))
       crypt_smime_set_sender (msg->env->from->mailbox);
     else if ((WithCrypto & APPLICATION_PGP)
-             && (msg->security & APPLICATION_PGP))
+             && (security & APPLICATION_PGP))
       crypt_pgp_set_sender (msg->env->from->mailbox);
   }
 
@@ -217,10 +233,30 @@ int mutt_protect (HEADER *msg, char *keylist)
     msg->content->mime_headers = protected_headers;
   }
 
-  if (msg->security & SIGN)
+  /* A note about msg->content->mime_headers.  If postpone or send
+   * fails, the mime_headers is cleared out before returning to the
+   * compose menu.  So despite the "robustness" code above and in the
+   * gen_gossip_list function below, mime_headers will not be set when
+   * entering mutt_protect().
+   *
+   * This is important to note because the user could toggle
+   * $crypt_protected_headers_write or $autocrypt off back in the
+   * compose menu.  We don't want mutt_write_rfc822_header() to write
+   * stale data from one option if the other is set.
+   */
+#ifdef USE_AUTOCRYPT
+  if (option (OPTAUTOCRYPT) &&
+      !postpone &&
+      (security & AUTOCRYPT))
+  {
+    mutt_autocrypt_generate_gossip_list (msg);
+  }
+#endif
+
+  if (sign)
   {
     if ((WithCrypto & APPLICATION_SMIME)
-        && (msg->security & APPLICATION_SMIME))
+        && (security & APPLICATION_SMIME))
     {
       if (!(tmp_pbody = crypt_smime_sign_message (msg->content)))
        goto bail;
@@ -228,29 +264,30 @@ int mutt_protect (HEADER *msg, char *keylist)
     }
 
     if ((WithCrypto & APPLICATION_PGP)
-        && (msg->security & APPLICATION_PGP)
-        && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG)))
+        && (security & APPLICATION_PGP)
+        && (!(security & (ENCRYPT | AUTOCRYPT)) || option (OPTPGPRETAINABLESIG)))
     {
       if (!(tmp_pbody = crypt_pgp_sign_message (msg->content)))
         goto bail;
 
-      flags &= ~SIGN;
+      has_retainable_sig = 1;
+      sign = 0;
       pbody = tmp_pgp_pbody = tmp_pbody;
     }
 
     if (WithCrypto
-        && (msg->security & APPLICATION_SMIME)
-       && (msg->security & APPLICATION_PGP))
+        && (security & APPLICATION_SMIME)
+       && (security & APPLICATION_PGP))
     {
       /* here comes the draft ;-) */
     }
   }
 
 
-  if (msg->security & ENCRYPT)
+  if (security & (ENCRYPT | AUTOCRYPT))
   {
     if ((WithCrypto & APPLICATION_SMIME)
-        && (msg->security & APPLICATION_SMIME))
+        && (security & APPLICATION_SMIME))
     {
       if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
                                                         keylist)))
@@ -271,14 +308,14 @@ int mutt_protect (HEADER *msg, char *keylist)
     }
 
     if ((WithCrypto & APPLICATION_PGP)
-        && (msg->security & APPLICATION_PGP))
+        && (security & APPLICATION_PGP))
     {
-      if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
-                                               flags & SIGN)))
+      if (!(pbody = crypt_pgp_encrypt_message (msg, tmp_pgp_pbody, keylist,
+                                               sign)))
       {
 
        /* did we perform a retainable signature? */
-       if (flags != msg->security)
+       if (has_retainable_sig)
        {
          /* remove the outer multipart layer */
          tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
@@ -293,7 +330,7 @@ int mutt_protect (HEADER *msg, char *keylist)
        * signatures.
 
        */
-      if (flags != msg->security)
+      if (has_retainable_sig)
       {
        tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
        mutt_free_body (&tmp_pgp_pbody->next);
@@ -820,6 +857,17 @@ int crypt_get_keys (HEADER *msg, char **keylist, int oppenc_mode)
   if (!WithCrypto)
     return 0;
 
+  *keylist = NULL;
+
+#ifdef USE_AUTOCRYPT
+  if (!oppenc_mode && (msg->security & AUTOCRYPT))
+  {
+    if (mutt_autocrypt_ui_recommendation (msg, keylist) <= AUTOCRYPT_REC_NO)
+      return (-1);
+    return (0);
+  }
+#endif
+
   if ((WithCrypto & APPLICATION_PGP))
     set_option (OPTPGPCHECKTRUST);
 
@@ -831,8 +879,6 @@ int crypt_get_keys (HEADER *msg, char **keylist, int oppenc_mode)
     rfc822_qualify (adrlist, fqdn);
   adrlist = mutt_remove_duplicates (adrlist);
 
-  *keylist = NULL;
-
   if (oppenc_mode || (msg->security & ENCRYPT))
   {
     if ((WithCrypto & APPLICATION_PGP)
index e2af8bba144c2f0278fa4d80b7a08c5cbfd71c7a..ce822173b88c962eb3ff10a0f65878adc85c814b 100644 (file)
 
 #include "crypt-mod.h"
 
+#ifdef USE_AUTOCRYPT
+#include "autocrypt.h"
+#endif
+
 /*
 
   Generic
@@ -52,6 +56,7 @@ extern struct crypt_module_specs crypt_mod_smime_classic;
 #endif
 
 #ifdef CRYPT_BACKEND_GPGME
+#include "crypt-gpgme.h"
 extern struct crypt_module_specs crypt_mod_pgp_gpgme;
 extern struct crypt_module_specs crypt_mod_smime_gpgme;
 #endif
@@ -237,8 +242,24 @@ BODY *crypt_pgp_sign_message (BODY *a)
 
 /* Warning: A is no longer freed in this routine, you need to free it
    later.  This is necessary for $fcc_attach. */
-BODY *crypt_pgp_encrypt_message (BODY *a, char *keylist, int sign)
+BODY *crypt_pgp_encrypt_message (HEADER *msg, BODY *a, char *keylist, int sign)
 {
+#ifdef USE_AUTOCRYPT
+  BODY *result;
+
+  if (msg->security & AUTOCRYPT)
+  {
+    if (mutt_autocrypt_set_sign_as_default_key (msg))
+      return NULL;
+
+    set_option (OPTAUTOCRYPTGPGME);
+    result = pgp_gpgme_encrypt_message (a, keylist, sign);
+    unset_option (OPTAUTOCRYPTGPGME);
+
+    return result;
+  }
+#endif
+
   if (CRYPT_MOD_CALL_CHECK (PGP, pgp_encrypt_message))
     return (CRYPT_MOD_CALL (PGP, pgp_encrypt_message)) (a, keylist, sign);
 
index 68c7e40c00bc513b5dcdbfcace20b6969fe2df9b..43de667115946f7809917f26fae96d5233159614 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -42,6 +42,8 @@ WHERE char *AttachCharset;
 WHERE char *AttachFormat;
 #ifdef USE_AUTOCRYPT
 WHERE char *AutocryptDir;
+WHERE char *AutocryptSignAs;  /* This is used in crypt-gpgme.c */
+WHERE char *AutocryptDefaultKey;  /* Used for postponing messages */
 #endif
 WHERE char *Charset;
 WHERE char *ComposeFormat;
diff --git a/mutt.h b/mutt.h
index 653eb3ae402c8707b8d7f5af9fe338049b6a232d..ba0df11e0fe79f59b19a717cc9b32071b1b4db7f 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -604,6 +604,7 @@ enum
   OPTPGPCHECKTRUST,    /* (pseudo) used by pgp_select_key () */
   OPTDONTHANDLEPGPKEYS,        /* (pseudo) used to extract PGP keys */
   OPTIGNOREMACROEVENTS, /* (pseudo) don't process macro/push/exec events while set */
+  OPTAUTOCRYPTGPGME,    /* (pseudo) use Autocrypt context inside crypt-gpgme.c */
 
   OPTMAX
 };
index 791822975ecef73740dfea6bf02aa12c7b48441c..28f70ee93e3a677e832ccd39c05a39f9d284800d 100644 (file)
@@ -111,7 +111,7 @@ typedef struct pgp_keyinfo *pgp_key_t;
 
 /* Some prototypes -- old crypt.h. */
 
-int mutt_protect (HEADER *, char *);
+int mutt_protect (HEADER *, char *, int);
 
 int mutt_is_multipart_encrypted (BODY *);
 
@@ -244,7 +244,7 @@ BODY *crypt_pgp_sign_message (BODY *a);
 
 /* Warning: A is no longer freed in this routine, you need to free it
    later.  This is necessary for $fcc_attach. */
-BODY *crypt_pgp_encrypt_message (BODY *a, char *keylist, int sign);
+BODY *crypt_pgp_encrypt_message (HEADER *msg, BODY *a, char *keylist, int sign);
 
 /* Invoke the PGP command to import a key. */
 void crypt_pgp_invoke_import (const char *fname);
index cdae2d0de1dd0755bcb6d3cde06de96358c7ea3a..0b8f658df18618c7af1e718fa5340ba2034140af 100644 (file)
@@ -442,6 +442,20 @@ int mutt_parse_crypt_hdr (const char *p, int set_empty_signas, int crypt_app)
         flags |= OPPENCRYPT;
         break;
 
+      case 'a':
+      case 'A':
+#ifdef USE_AUTOCRYPT
+        flags |= AUTOCRYPT;
+#endif
+        break;
+
+      case 'z':
+      case 'Z':
+#ifdef USE_AUTOCRYPT
+        flags |= AUTOCRYPT_OVERRIDE;
+#endif
+        break;
+
       case 's':
       case 'S':
         flags |= SIGN;
diff --git a/send.c b/send.c
index 0cb6cf1832bc88b247902eedd4a84b18c516a135..7f037df3f6ae90ec031cc1d10d24251f85e99652 100644 (file)
--- a/send.c
+++ b/send.c
 #include "rfc3676.h"
 #include "attach.h"
 
+#ifdef USE_AUTOCRYPT
+#include "autocrypt.h"
+#endif
+
 #include <ctype.h>
 #include <stdlib.h>
 #include <locale.h>
@@ -1200,10 +1204,12 @@ static int save_fcc (HEADER *msg, char *fcc, size_t fcc_len,
    * Protected Headers. */
   if (!option (OPTFCCBEFORESEND))
   {
-    if (WithCrypto && (msg->security & (ENCRYPT | SIGN)) && option (OPTFCCCLEAR))
+    if (WithCrypto &&
+        (msg->security & (ENCRYPT | SIGN | AUTOCRYPT))
+        && option (OPTFCCCLEAR))
     {
       msg->content = clear_content;
-      msg->security &= ~(ENCRYPT | SIGN);
+      msg->security &= ~(ENCRYPT | SIGN | AUTOCRYPT);
       mutt_free_envelope (&msg->content->mime_headers);
     }
 
@@ -1212,7 +1218,7 @@ static int save_fcc (HEADER *msg, char *fcc, size_t fcc_len,
         msg->content->type == TYPEMULTIPART)
     {
       if (WithCrypto
-          && (msg->security & (ENCRYPT | SIGN))
+          && (msg->security & (ENCRYPT | SIGN | AUTOCRYPT))
           && (mutt_strcmp (msg->content->subtype, "encrypted") == 0 ||
               mutt_strcmp (msg->content->subtype, "signed") == 0))
       {
@@ -1228,7 +1234,7 @@ static int save_fcc (HEADER *msg, char *fcc, size_t fcc_len,
           /* this means writing only the main part */
           msg->content = clear_content->parts;
 
-          if (mutt_protect (msg, pgpkeylist) == -1)
+          if (mutt_protect (msg, pgpkeylist, 0) == -1)
           {
             /* we can't do much about it at this point, so
              * fallback to saving the whole thing to fcc
@@ -1454,7 +1460,6 @@ static int postpone_message (HEADER *msg, HEADER *cur, char *fcc, int flags)
 {
   char *pgpkeylist = NULL;
   char *encrypt_as = NULL;
-  int is_signed;
   BODY *clear_content = NULL;
 
   if (!Postponed)
@@ -1468,7 +1473,8 @@ static int postpone_message (HEADER *msg, HEADER *cur, char *fcc, int flags)
 
   mutt_encode_descriptions (msg->content, 1);
 
-  if (WithCrypto && option (OPTPOSTPONEENCRYPT) && (msg->security & ENCRYPT))
+  if (WithCrypto && option (OPTPOSTPONEENCRYPT) &&
+      (msg->security & (ENCRYPT | AUTOCRYPT)))
   {
     if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP))
       encrypt_as = PgpDefaultKey;
@@ -1477,28 +1483,28 @@ static int postpone_message (HEADER *msg, HEADER *cur, char *fcc, int flags)
     if (!encrypt_as)
       encrypt_as = PostponeEncryptAs;
 
-    if (encrypt_as)
+#ifdef USE_AUTOCRYPT
+    if (msg->security & AUTOCRYPT)
     {
-      is_signed = msg->security & SIGN;
-      if (is_signed)
-        msg->security &= ~SIGN;
+      if (mutt_autocrypt_set_sign_as_default_key (msg))
+        return -1;
+      encrypt_as = AutocryptDefaultKey;
+    }
+#endif
 
+    if (encrypt_as)
+    {
       pgpkeylist = safe_strdup (encrypt_as);
       clear_content = msg->content;
-      if (mutt_protect (msg, pgpkeylist) == -1)
+      if (mutt_protect (msg, pgpkeylist, 1) == -1)
       {
-        if (is_signed)
-          msg->security |= SIGN;
         FREE (&pgpkeylist);
         msg->content = mutt_remove_multipart (msg->content);
         decode_descriptions (msg->content);
         return -1;
       }
 
-      if (is_signed)
-        msg->security |= SIGN;
       FREE (&pgpkeylist);
-
       mutt_encode_descriptions (msg->content, 0);
     }
   }
@@ -1898,23 +1904,36 @@ ci_send_message (int flags,             /* send mode */
    */
   if (WithCrypto && (msg->security == 0) && !(flags & (SENDBATCH | SENDMAILX | SENDPOSTPONED | SENDRESEND)))
   {
-    if (option (OPTCRYPTAUTOSIGN))
-      msg->security |= SIGN;
-    if (option (OPTCRYPTAUTOENCRYPT))
-      msg->security |= ENCRYPT;
-    if (option (OPTCRYPTREPLYENCRYPT) && cur && (cur->security & ENCRYPT))
-      msg->security |= ENCRYPT;
-    if (option (OPTCRYPTREPLYSIGN) && cur && (cur->security & SIGN))
-      msg->security |= SIGN;
-    if (option (OPTCRYPTREPLYSIGNENCRYPTED) && cur && (cur->security & ENCRYPT))
-      msg->security |= SIGN;
-    if ((WithCrypto & APPLICATION_PGP) &&
-        ((msg->security & (ENCRYPT | SIGN)) || option (OPTCRYPTOPPORTUNISTICENCRYPT)))
-    {
-      if (option (OPTPGPAUTOINLINE))
-       msg->security |= INLINE;
-      if (option (OPTPGPREPLYINLINE) && cur && (cur->security & INLINE))
-       msg->security |= INLINE;
+    if (
+#ifdef USE_AUTOCRYPT
+      option (OPTAUTOCRYPT)
+#else
+      0
+#endif
+      && cur && (cur->security & AUTOCRYPT))
+    {
+      msg->security |= (AUTOCRYPT | AUTOCRYPT_OVERRIDE);
+    }
+    else
+    {
+      if (option (OPTCRYPTAUTOSIGN))
+        msg->security |= SIGN;
+      if (option (OPTCRYPTAUTOENCRYPT))
+        msg->security |= ENCRYPT;
+      if (option (OPTCRYPTREPLYENCRYPT) && cur && (cur->security & ENCRYPT))
+        msg->security |= ENCRYPT;
+      if (option (OPTCRYPTREPLYSIGN) && cur && (cur->security & SIGN))
+        msg->security |= SIGN;
+      if (option (OPTCRYPTREPLYSIGNENCRYPTED) && cur && (cur->security & ENCRYPT))
+        msg->security |= SIGN;
+      if ((WithCrypto & APPLICATION_PGP) &&
+          ((msg->security & (ENCRYPT | SIGN)) || option (OPTCRYPTOPPORTUNISTICENCRYPT)))
+      {
+        if (option (OPTPGPAUTOINLINE))
+          msg->security |= INLINE;
+        if (option (OPTPGPREPLYINLINE) && cur && (cur->security & INLINE))
+          msg->security |= INLINE;
+      }
     }
 
     if (msg->security || option (OPTCRYPTOPPORTUNISTICENCRYPT))
@@ -1961,7 +1980,7 @@ ci_send_message (int flags,               /* send mode */
        * or OPTCRYPTREPLYENCRYPT, then don't enable opportunistic encrypt for
        * the message.
        */
-      if (! (msg->security & ENCRYPT))
+      if (! (msg->security & (ENCRYPT|AUTOCRYPT)))
       {
         msg->security |= OPPENCRYPT;
         crypt_opportunistic_encrypt(msg);
@@ -2106,13 +2125,13 @@ main_loop:
 
   if (WithCrypto)
   {
-    if (msg->security & (ENCRYPT | SIGN))
+    if (msg->security & (ENCRYPT | SIGN | AUTOCRYPT))
     {
       /* save the decrypted attachments */
       clear_content = msg->content;
 
       if ((crypt_get_keys (msg, &pgpkeylist, 0) == -1) ||
-          mutt_protect (msg, pgpkeylist) == -1)
+          mutt_protect (msg, pgpkeylist, 0) == -1)
       {
         msg->content = mutt_remove_multipart (msg->content);
 
@@ -2154,7 +2173,7 @@ main_loop:
     {
       if (!WithCrypto)
         ;
-      else if ((msg->security & ENCRYPT) ||
+      else if ((msg->security & (ENCRYPT | AUTOCRYPT)) ||
                ((msg->security & SIGN)
                 && msg->content->type == TYPEAPPLICATION))
       {
index 331cc2b26cb0ae6c803a5b966b861ac262893d61..95f0e83e0e49ce3628703fcfaf956263fc00ebdc 100644 (file)
--- a/sendlib.c
+++ b/sendlib.c
 #include "mutt_idna.h"
 #include "buffy.h"
 
+#ifdef USE_AUTOCRYPT
+#include "autocrypt.h"
+#endif
+
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -415,8 +419,15 @@ int mutt_write_mime_header (BODY *a, FILE *f)
   if (a->encoding != ENC7BIT)
     fprintf(f, "Content-Transfer-Encoding: %s\n", ENCODING (a->encoding));
 
-  if (option (OPTCRYPTPROTHDRSWRITE) && a->mime_headers)
+  if ((option (OPTCRYPTPROTHDRSWRITE)
+#ifdef USE_AUTOCRYPT
+       || option (OPTAUTOCRYPT)
+#endif
+        ) &&
+      a->mime_headers)
+  {
     mutt_write_rfc822_header (f, a->mime_headers, NULL, MUTT_WRITE_HEADER_MIME, 0, 0);
+  }
 
   /* Do NOT add the terminator here!!! */
   return (ferror (f) ? -1 : 0);
@@ -2091,6 +2102,16 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach,
     fputc ('\n', fp);
   }
 
+#ifdef USE_AUTOCRYPT
+  if (option (OPTAUTOCRYPT))
+  {
+    if (mode == MUTT_WRITE_HEADER_NORMAL)
+      mutt_autocrypt_write_autocrypt_header (env, fp);
+    if (mode == MUTT_WRITE_HEADER_MIME)
+      mutt_autocrypt_write_gossip_headers (env, fp);
+  }
+#endif
+
   /* Add any user defined headers */
   for (; tmp; tmp = tmp->next)
   {
@@ -2859,6 +2880,12 @@ int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int post,
     }
     if (hdr->security & INLINE)
       fputc ('I', msg->fp);
+#ifdef USE_AUTOCRYPT
+    if (hdr->security & AUTOCRYPT)
+      fputc ('A', msg->fp);
+    if (hdr->security & AUTOCRYPT_OVERRIDE)
+      fputc ('Z', msg->fp);
+#endif
     fputc ('\n', msg->fp);
   }