#include <lib-ui/curses.h>
#include <lib-ui/enter.h>
#include <lib-ui/menu.h>
+#include <lib-mx/mx.h>
#include "crypt.h"
{
}
+/***************************************************************************/
+
+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);
+}