-/*
- * Copyright notice from original mutt:
- * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org>
- * Copyright (C) 1998-2000 Thomas Roessler <roessler@does-not-exist.org>
- * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
- * Oliver Ehli <elmy@acm.org>
- * Copyright (C) 2003 Werner Koch <wk@gnupg.org>
- * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
- */
-/*
- * Copyright © 2006 Pierre Habouzit
- */
-
-#include <lib-lib/lib-lib.h>
-
-#include <lib-mime/mime.h>
-#include <lib-ui/curses.h>
-#include <lib-mx/mx.h>
-
-#include "alias.h"
-#include "handler.h"
-#include "copy.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);
-}