/* * Copyright notice from original mutt: * Copyright (C) 1997-2000 Thomas Roessler * * This file is part of mutt-ng, see http://www.muttng.org/. * It's licensed under the GNU General Public License, * please see the file GPL in the top level source directory. */ /* This file contains the new pgp invocation code. Note that this * is almost entirely format based. */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include "mutt.h" #include "mutt_curses.h" #include "mutt_idna.h" #include "pgp.h" #include "rfc822.h" #include "lib/mem.h" #include "lib/intl.h" #include "lib/str.h" #include "lib/debug.h" /* * The actual command line formatter. */ struct pgp_command_context { short need_passphrase; /* %p */ const char *fname; /* %f */ const char *sig_fname; /* %s */ const char *signas; /* %a */ const char *ids; /* %r */ }; const char *_mutt_fmt_pgp_command (char *dest, size_t destlen, char op, const char *src, const char *prefix, const char *ifstring, const char *elsestring, unsigned long data, format_flag flags) { char fmt[16]; struct pgp_command_context *cctx = (struct pgp_command_context *) data; int optional = (flags & M_FORMAT_OPTIONAL); switch (op) { case 'r': { if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL (cctx->ids)); } else if (!cctx->ids) optional = 0; break; } case 'a': { if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL (cctx->signas)); } else if (!cctx->signas) optional = 0; break; } case 's': { if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname)); } else if (!cctx->sig_fname) optional = 0; break; } case 'f': { if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, NONULL (cctx->fname)); } else if (!cctx->fname) optional = 0; break; } case 'p': { if (!optional) { snprintf (fmt, sizeof (fmt), "%%%ss", prefix); snprintf (dest, destlen, fmt, cctx->need_passphrase ? "PGPPASSFD=0" : ""); } else if (!cctx->need_passphrase || pgp_use_gpg_agent ()) optional = 0; break; } default: { *dest = '\0'; break; } } if (optional) mutt_FormatString (dest, destlen, ifstring, _mutt_fmt_pgp_command, data, 0); else if (flags & M_FORMAT_OPTIONAL) mutt_FormatString (dest, destlen, elsestring, _mutt_fmt_pgp_command, data, 0); return (src); } void mutt_pgp_command (char *d, size_t dlen, struct pgp_command_context *cctx, const char *fmt) { mutt_FormatString (d, dlen, NONULL (fmt), _mutt_fmt_pgp_command, (unsigned long) cctx, 0); debug_print (2, ("%s\n", d)); } /* * Glue. */ static pid_t pgp_invoke (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, short need_passphrase, const char *fname, const char *sig_fname, const char *signas, const char *ids, const char *format) { struct pgp_command_context cctx; char cmd[HUGE_STRING]; memset (&cctx, 0, sizeof (cctx)); if (!format || !*format) return (pid_t) - 1; cctx.need_passphrase = need_passphrase; cctx.fname = fname; cctx.sig_fname = sig_fname; cctx.signas = signas; cctx.ids = ids; mutt_pgp_command (cmd, sizeof (cmd), &cctx, format); return mutt_create_filter_fd (cmd, pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd); } /* * The exported interface. * * This is historic and may be removed at some point. * */ pid_t pgp_invoke_decode (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, const char *fname, short need_passphrase) { return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, need_passphrase, fname, NULL, NULL, NULL, PgpDecodeCommand); } pid_t pgp_invoke_verify (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, const char *fname, const char *sig_fname) { return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 0, fname, sig_fname, NULL, NULL, PgpVerifyCommand); } pid_t pgp_invoke_decrypt (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, const char *fname) { return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 1, fname, NULL, NULL, NULL, PgpDecryptCommand); } pid_t pgp_invoke_sign (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, const char *fname) { return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 1, fname, NULL, PgpSignAs, NULL, PgpSignCommand); } pid_t pgp_invoke_encrypt (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, const char *fname, const char *uids, int sign) { if (sign) return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 1, fname, NULL, PgpSignAs, uids, PgpEncryptSignCommand); else return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 0, fname, NULL, NULL, uids, PgpEncryptOnlyCommand); } pid_t pgp_invoke_traditional (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, const char *fname, const char *uids, int flags) { if (flags & ENCRYPT) return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, flags & SIGN ? 1 : 0, fname, NULL, PgpSignAs, uids, flags & SIGN ? PgpEncryptSignCommand : PgpEncryptOnlyCommand); else return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 1, fname, NULL, PgpSignAs, NULL, PgpClearSignCommand); } void pgp_invoke_import (const char *fname) { char _fname[_POSIX_PATH_MAX + SHORT_STRING]; char cmd[HUGE_STRING]; struct pgp_command_context cctx; memset (&cctx, 0, sizeof (cctx)); mutt_quote_filename (_fname, sizeof (_fname), fname); cctx.fname = _fname; mutt_pgp_command (cmd, sizeof (cmd), &cctx, PgpImportCommand); mutt_system (cmd); } void pgp_invoke_getkeys (ADDRESS * addr) { char buff[LONG_STRING]; char tmp[LONG_STRING]; char cmd[HUGE_STRING]; int devnull; char *personal; struct pgp_command_context cctx; if (!PgpGetkeysCommand) return; memset (&cctx, 0, sizeof (cctx)); personal = addr->personal; addr->personal = NULL; *tmp = '\0'; mutt_addrlist_to_local (addr); rfc822_write_address_single (tmp, sizeof (tmp), addr, 0); mutt_quote_filename (buff, sizeof (buff), tmp); addr->personal = personal; cctx.ids = buff; mutt_pgp_command (cmd, sizeof (cmd), &cctx, PgpGetkeysCommand); devnull = open ("/dev/null", O_RDWR); if (!isendwin ()) mutt_message _("Fetching PGP key..."); mutt_system (cmd); if (!isendwin ()) mutt_clear_error (); close (devnull); } pid_t pgp_invoke_export (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, const char *uids) { return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 0, NULL, NULL, NULL, uids, PgpExportCommand); } pid_t pgp_invoke_verify_key (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, const char *uids) { return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 0, NULL, NULL, NULL, uids, PgpVerifyKeyCommand); } pid_t pgp_invoke_list_keys (FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, int pgpinfd, int pgpoutfd, int pgperrfd, pgp_ring_t keyring, LIST * hints) { char uids[HUGE_STRING]; char tmpuids[HUGE_STRING]; char quoted[HUGE_STRING]; *uids = '\0'; for (; hints; hints = hints->next) { mutt_quote_filename (quoted, sizeof (quoted), (char *) hints->data); snprintf (tmpuids, sizeof (tmpuids), "%s %s", uids, quoted); strcpy (uids, tmpuids); /* __STRCPY_CHECKED__ */ } return pgp_invoke (pgpin, pgpout, pgperr, pgpinfd, pgpoutfd, pgperrfd, 0, NULL, NULL, NULL, uids, keyring == PGP_SECRING ? PgpListSecringCommand : PgpListPubringCommand); }