merge crypt back into $top_builddir :)
[apps/madmutt.git] / crypt.c
similarity index 91%
rename from lib-crypt/crypt-gpgme.c
rename to crypt.c
index 5bd3173..b22d616 100644 (file)
+++ b/crypt.c
@@ -19,6 +19,7 @@
 #include <lib-ui/curses.h>
 #include <lib-ui/enter.h>
 #include <lib-ui/menu.h>
+#include <lib-mx/mx.h>
 
 #include "crypt.h"
 
@@ -3907,3 +3908,387 @@ void crypt_smime_getkeys (ENVELOPE * env)
 {
 }
 
+/***************************************************************************/
+
+void crypt_invoke_message (int type)
+{
+    if (type & APPLICATION_PGP) {
+        mutt_message _("Invoking PGP...");
+    }
+    else if (type & APPLICATION_SMIME) {
+        mutt_message _("Invoking S/MIME...");
+    }
+}
+
+int mutt_protect (HEADER * msg, char *keylist)
+{
+  BODY *pbody = NULL, *tmp_pbody = NULL;
+  BODY *tmp_smime_pbody = NULL;
+  BODY *tmp_pgp_pbody = NULL;
+  int flags = msg->security;
+
+  if (!isendwin ())
+    mutt_endwin (NULL);
+
+  tmp_smime_pbody = msg->content;
+  tmp_pgp_pbody = msg->content;
+
+  if (msg->security & SIGN) {
+    if (msg->security & APPLICATION_SMIME) {
+      if (!(tmp_pbody = crypt_smime_sign_message (msg->content)))
+        return -1;
+      pbody = tmp_smime_pbody = tmp_pbody;
+    }
+
+    if ((msg->security & APPLICATION_PGP)
+        && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) {
+      if (!(tmp_pbody = crypt_pgp_sign_message (msg->content)))
+        return -1;
+
+      flags &= ~SIGN;
+      pbody = tmp_pgp_pbody = tmp_pbody;
+    }
+
+    if ((msg->security & APPLICATION_SMIME)
+        && (msg->security & APPLICATION_PGP)) {
+      /* here comes the draft ;-) */
+    }
+  }
+
+
+  if (msg->security & ENCRYPT) {
+    if ((msg->security & APPLICATION_SMIME)) {
+      if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
+                                                        keylist))) {
+        /* signed ? free it! */
+        return (-1);
+      }
+      /* free tmp_body if messages was signed AND encrypted ... */
+      if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) {
+        /* detatch and dont't delete msg->content,
+           which tmp_smime_pbody->parts after signing. */
+        tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
+        msg->content->next = NULL;
+        body_list_wipe(&tmp_smime_pbody);
+      }
+      pbody = tmp_pbody;
+    }
+
+    if ((msg->security & APPLICATION_PGP)) {
+      if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
+                                               flags & SIGN))) {
+
+        /* did we perform a retainable signature? */
+        if (flags != msg->security) {
+          /* remove the outer multipart layer */
+          tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
+          /* get rid of the signature */
+          body_list_wipe(&tmp_pgp_pbody->next);
+        }
+
+        return (-1);
+      }
+
+      /* destroy temporary signature envelope when doing retainable 
+       * signatures.
+
+       */
+      if (flags != msg->security) {
+        tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
+        body_list_wipe(&tmp_pgp_pbody->next);
+      }
+    }
+  }
+
+  if (pbody)
+    msg->content = pbody;
+
+  return 0;
+}
+
+
+int crypt_query (BODY * m)
+{
+  int t = 0;
+
+  if (!m)
+    return 0;
+
+  if (m->type == TYPEAPPLICATION) {
+    t |= mutt_is_application_pgp (m);
+
+    t |= mutt_is_application_smime (m);
+    if (t && m->goodsig)
+      t |= GOODSIGN;
+    if (t && m->badsig)
+      t |= BADSIGN;
+  }
+  else if (m->type == TYPETEXT) {
+    t |= mutt_is_application_pgp (m);
+    if (t && m->goodsig)
+      t |= GOODSIGN;
+  }
+
+  if (m->type == TYPEMULTIPART) {
+    t |= mutt_is_multipart_encrypted (m);
+    t |= mutt_is_multipart_signed (m);
+
+    if (t && m->goodsig)
+      t |= GOODSIGN;
+  }
+
+  if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) {
+    BODY *p;
+    int u, v, w;
+
+    u = m->parts ? ~0 : 0;      /* Bits set in all parts */
+    w = 0;                      /* Bits set in any part  */
+
+    for (p = m->parts; p; p = p->next) {
+      v = crypt_query (p);
+      u &= v;
+      w |= v;
+    }
+    t |= u | (w & ~GOODSIGN);
+
+    if ((w & GOODSIGN) && !(u & GOODSIGN))
+      t |= PARTSIGN;
+  }
+
+  return t;
+}
+
+
+static void crypt_write_signed(BODY * a, STATE * s, FILE *fp)
+{
+    int c;
+    short hadcr;
+    size_t bytes;
+
+    fseeko (s->fpin, a->hdr_offset, 0);
+    bytes = a->length + a->offset - a->hdr_offset;
+    hadcr = 0;
+    while (bytes > 0) {
+        if ((c = fgetc (s->fpin)) == EOF)
+            break;
+
+        bytes--;
+
+        if (c == '\r')
+            hadcr = 1;
+        else {
+            if (c == '\n' && !hadcr)
+                fputc ('\r', fp);
+
+            hadcr = 0;
+        }
+        fputc (c, fp);
+    }
+}
+
+
+
+void convert_to_7bit (BODY * a)
+{
+  while (a) {
+    if (a->type == TYPEMULTIPART) {
+      if (a->encoding != ENC7BIT) {
+        a->encoding = ENC7BIT;
+        convert_to_7bit (a->parts);
+      } else {
+        convert_to_7bit (a->parts);
+      }
+    }
+    else if (a->type == TYPEMESSAGE &&
+             m_strcasecmp(a->subtype, "delivery-status")) {
+      if (a->encoding != ENC7BIT)
+        mutt_message_to_7bit (a, NULL);
+    }
+    else if (a->encoding == ENC8BIT)
+      a->encoding = ENCQUOTEDPRINTABLE;
+    else if (a->encoding == ENCBINARY)
+      a->encoding = ENCBASE64;
+    else if (a->content && a->encoding != ENCBASE64 &&
+             (a->content->from || a->content->space))
+      a->encoding = ENCQUOTEDPRINTABLE;
+    a = a->next;
+  }
+}
+
+
+static void extract_keys_aux(FILE *fpout, HEADER *h)
+{
+    mutt_parse_mime_message (Context, h);
+
+    rewind(fpout);
+    if (h->security & APPLICATION_PGP) {
+        mutt_copy_message(fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
+        fflush (fpout);
+
+        mutt_endwin (_("Trying to extract PGP keys...\n"));
+    }
+
+    if (h->security & APPLICATION_SMIME) {
+        if (h->security & ENCRYPT)
+            mutt_copy_message (fpout, Context, h, M_CM_NOHEADER
+                               | M_CM_DECODE_CRYPT | M_CM_DECODE_SMIME, 0);
+        else
+            mutt_copy_message(fpout, Context, h, 0, 0);
+        fflush (fpout);
+
+        mutt_message (_("Trying to extract S/MIME certificates...\n"));
+    }
+
+    rewind(fpout);
+    crypt_invoke_import(fpout, h->security & APPLICATION_SMIME);
+}
+
+void crypt_extract_keys_from_messages(HEADER * h)
+{
+    FILE *tmpfp = tmpfile();
+    if (!tmpfp) {
+        mutt_error(_("Could not create temporary file"));
+        return;
+    }
+
+    set_option(OPTDONTHANDLEPGPKEYS);
+    if (!h) {
+        int i;
+        for (i = 0; i < Context->vcount; i++) {
+            if (!Context->hdrs[Context->v2r[i]]->tagged)
+                continue;
+            extract_keys_aux(tmpfp, Context->hdrs[Context->v2r[i]]);
+        }
+    } else {
+        extract_keys_aux(tmpfp, h);
+    }
+    unset_option(OPTDONTHANDLEPGPKEYS);
+    m_fclose(&tmpfp);
+
+    if (isendwin())
+        mutt_any_key_to_continue(NULL);
+}
+
+
+
+static void crypt_fetch_signatures (BODY ***signatures, BODY * a, int *n)
+{
+  for (; a; a = a->next) {
+    if (a->type == TYPEMULTIPART)
+      crypt_fetch_signatures (signatures, a->parts, n);
+    else {
+      if ((*n % 5) == 0)
+        p_realloc(signatures, *n + 6);
+
+      (*signatures)[(*n)++] = a;
+    }
+  }
+}
+
+
+/*
+ * This routine verifies a  "multipart/signed"  body.
+ */
+
+int mutt_signed_handler (BODY * a, STATE * s)
+{
+  unsigned major, minor;
+  char *protocol;
+  int rc, i, goodsig = 1, sigcnt = 0;
+  BODY *b = a;
+
+  protocol = parameter_getval(a->parameter, "protocol");
+  a = a->parts;
+
+  switch (mime_which_token(protocol, -1)) {
+    case MIME_APPLICATION_PGP_SIGNATURE:
+      major = TYPEAPPLICATION;
+      minor = MIME_PGP_SIGNATURE;
+      break;
+    case MIME_APPLICATION_X_PKCS7_SIGNATURE:
+      major = TYPEAPPLICATION;
+      minor = MIME_X_PKCS7_SIGNATURE;
+      break;
+    case MIME_APPLICATION_PKCS7_SIGNATURE:
+      major = TYPEAPPLICATION;
+      minor = MIME_PKCS7_SIGNATURE;
+      break;
+    case MIME_MULTIPART_MIXED:
+      major = TYPEMULTIPART;
+      minor = MIME_MIXED;
+      break;
+
+    default:
+      state_printf(s, _("[-- Error: "
+                        "Unknown multipart/signed protocol %s! --]\n\n"),
+                    protocol);
+      return mutt_body_handler (a, s);
+  }
+
+  /* consistency check */
+  if (!(a && a->next && a->next->type == major &&
+        mime_which_token(a->next->subtype, -1) == minor))
+  {
+    state_attach_puts(_("[-- Error: "
+                        "Inconsistent multipart/signed structure! --]\n\n"),
+                      s);
+    return mutt_body_handler (a, s);
+  }
+
+  if (s->flags & M_DISPLAY) {
+    BODY **sigs = NULL;
+
+    crypt_fetch_signatures (&sigs, a->next, &sigcnt);
+    if (sigcnt) {
+      FILE *tmpfp = tmpfile();
+
+      if (!tmpfp) {
+          mutt_error(_("Could not create temporary file"));
+      } else {
+        crypt_write_signed(a, s, tmpfp);
+        rewind(tmpfp);
+        for (i = 0; i < sigcnt; i++) {
+          if (sigs[i]->type == TYPEAPPLICATION) {
+            int subtype;
+
+            switch ((subtype = mime_which_token(sigs[i]->subtype, -1))) {
+              case MIME_PGP_SIGNATURE:
+              case MIME_X_PKCS7_SIGNATURE:
+              case MIME_PKCS7_SIGNATURE:
+                if (crypt_verify_one(sigs[i], s, tmpfp, subtype != MIME_PGP_SIGNATURE) != 0)
+                  goodsig = 0;
+
+                m_fclose(&tmpfp);
+                continue;
+
+              default:
+                break;
+            }
+          }
+
+          state_printf(s, _("[-- Warning: "
+                            "We can't verify %s/%s signatures. --]\n\n"),
+                       TYPE (sigs[i]), sigs[i]->subtype);
+        }
+      }
+
+      b->goodsig = goodsig;
+      b->badsig  = !goodsig;
+
+      /* Now display the signed body */
+      state_attach_puts(_("[-- The following data is signed --]\n\n"), s);
+
+      p_delete(&sigs);
+    } else {
+      state_attach_puts(_("[-- Warning: Can't find any signatures. --]\n\n"),
+                        s);
+    }
+  }
+
+  rc = mutt_body_handler (a, s);
+
+  if (s->flags & M_DISPLAY && sigcnt)
+    state_attach_puts (_("\n[-- End of signed data --]\n"), s);
+
+  return (rc);
+}