Mercurial > hg > Applications > mh
diff uip/pgpshow.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | 441a2190cfae |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uip/pgpshow.c Mon Apr 18 23:46:02 2005 +0900 @@ -0,0 +1,614 @@ +/* pgpshow.c - PGP viewer */ +#ifndef lint +static char ident[] = "@(#)$Id$"; +#endif /* lint */ + +#include "../h/mh.h" +#include <stdio.h> +#include <errno.h> +#include <signal.h> +#include <sys/stat.h> +#ifdef UNISTD +#include <unistd.h> +#endif /* UNISTD */ +#ifdef LOCALE +#include <locale.h> +#endif /* LOCALE */ + +void pgp_show(); +void pgp_store(); +void pgp_mime(); +int tee(); +static TYPESIG goodbye(); + +/* */ + +static struct swit switches[] = { +#define PGPPROC 0 + {"pgpproc program", -7}, + +#define SHOWSW 1 + {"show", 0}, +#define NSHOWSW 2 + {"noshow", 0}, + +#define STORESW 3 + {"store", 0}, +#define NSTORESW 4 + {"nostore", 0}, + +#define MIMESW 5 + {"mime", 0}, +#define NMIMESW 6 + {"nomime", 0}, + +#define HELPSW 7 + {"help", 4}, + + {NULL, 0} +}; + +/* */ + +static int showsw = 0; +static int storesw = 0; +static int mimesw = 0; + +static char *pgpproc = ""; /* "pgp"; */ +static char *showprog = "show"; /* not showproc */ +extern char *moreproc; + +static char tmpfil1[BUFSIZ]; +static char tmpfil2[BUFSIZ]; +static FILE *out = NULL; + +#define PGP_SIGN 1 +#define PGP_ENCRYPT 2 + +#define PGP_VER2 (int)1 +#define PGP_VER5 (int)2 + +#define PGP2_GOOD_SIGNATURE "Good signature from user" +#define PGP5_GOOD_SIGNATURE "Good signature made" + +#define NOT_INSTALLED 127 + +/* */ + +main(argc, argv) +int argc; +char *argv[]; +{ + int i, paramp = 0; + char *cp, buf[BUFSIZ]; + char **ap, **argp, *arguments[MAXARGS], *param[MAXARGS]; + +#ifdef LOCALE + setlocale(LC_ALL, ""); +#endif /* LOCALE */ +#ifdef JAPAN + ml_init(); +#endif /* JAPAN */ + invo_name = r1bindex(argv[0], '/'); + if ((cp = m_find(invo_name)) != NULL) { + ap = brkstring(cp = getcpy(cp), " ", "\n"); + ap = copyip(ap, arguments); + } + else + ap = arguments; + (void) copyip(argv + 1, ap); + argp = arguments; + +/* */ + + while ((cp = *argp++)) { + if (*cp == '-') + switch (smatch(++cp, switches)) { + case AMBIGSW: + ambigsw(cp, switches); + done(1); + case UNKWNSW: + adios(NULLCP, "-%s unknown", cp); + case HELPSW: + (void) sprintf(buf, "%s [switches] file .. [parameters]", + invo_name); + help(buf, switches); + done(1); + + case SHOWSW: + showsw++; + continue; + case NSHOWSW: + showsw = 0; + continue; + + case STORESW: + storesw++; + continue; + case NSTORESW: + storesw = 0; + continue; + + case MIMESW: + mimesw++; + continue; + case NMIMESW: + mimesw = 0; + continue; + + case PGPPROC: + if (!(pgpproc = *argp++) || *pgpproc == '-') + adios(NULLCP, "missing argument to %s", argp[-2]); + continue; + } + else + param[paramp++] = cp; + } + param[paramp] = NULLCP; + if ((!showsw && !storesw) || paramp < (mimesw ? 2 : 1)) + adios(NULLCP, "usage: %s [switches] file .. [parameters]", invo_name); + tmpfil1[0] = tmpfil2[0] = '\0'; + +/* */ + + if (mimesw) { + int protocol = 0; + char *micalg = NULLCP; + for (i = 2; param[i]; i++) { + if (uprf(param[i], "protocol=")) { + if (uleq(param[i] + 9, "application/pgp-signature")) + protocol = PGP_SIGN; + else if (uleq(param[i] + 9, "application/pgp-encrypted")) + protocol = PGP_ENCRYPT; + else + adios(NULLCP, + "protocol \"%s\" is unsupported", param[i] + 9); + } + if (uprf(param[i], "micalg=")) { + micalg = param[i] + 7; + if (!uleq(micalg, "pgp-md5") && !uleq(micalg, "pgp-sha1")) + adios(NULLCP, "micalg \"%s\" is unsupported", micalg); + } + } + if (!protocol) + adios(NULLCP, "protocol parameter is required"); + + pgp_mime(param[0], param[1], protocol, micalg, showsw); + } else { + int fmtmime = 0; + for (i = 1; param[i]; i++) { + if (uleq(param[i], "format=mime")) { + fmtmime = 1; + break; + } + } + if (showsw) + pgp_show(param[0], fmtmime); + else + pgp_store(param[0], fmtmime); + } + + done(0); +} + +void +pgp_show(file, fmtmime) +char *file; +int fmtmime; +{ + int pid, nopgp = 0; + char *ap[5]; + + (void) signal(SIGHUP, goodbye); + (void) signal(SIGINT, goodbye); + (void) signal(SIGQUIT, goodbye); + (void) signal(SIGPIPE, goodbye); + (void) signal(SIGTERM, goodbye); + + (void) strcpy(tmpfil1, m_scratch("", m_maildir(invo_name))); + if ((out = fopen(tmpfil1, "w")) == NULL) { + (void) strcpy(tmpfil1, m_tmpfil(invo_name)); + if ((out = fopen(tmpfil1, "w")) == NULL) { + advise(tmpfil1, "unable to create"); + goodbye(); + } + } + (void) chmod(tmpfil1, 0600); + fclose(out); + out = NULL; + unlink(tmpfil1); + + if (! *pgpproc) { + /* for PGP5 */ + ap[0] = pgpproc = "pgpv"; + ap[1] = file; + ap[2] = "-o"; + ap[3] = tmpfil1; + ap[4] = NULLCP; + if (tee(ap, PGP_VER5) == NOTOK) + /* Let's try old PGP */ + pgpproc = "pgp"; + else + pgpproc = ""; + } + if (*pgpproc) { + /* for PGP2 */ + ap[0] = r1bindex(pgpproc, '/'); + if (tee(ap, PGP_VER2) == NOTOK) { + advise(pgpproc, "unable to exec"); + nopgp = 1; + } + } + + if (fmtmime) { + ap[0] = r1bindex(showprog, '/'); + ap[1] = "-file"; + ap[2] = nopgp ? file : tmpfil1; + ap[3] = NULLCP; + } else { + ap[0] = r1bindex(moreproc, '/'); + ap[1] = nopgp ? file : tmpfil1; + ap[2] = NULLCP; + } + + switch (pid = fork()) { + case NOTOK: + advise("fork", "unable to"); + goodbye(); + + case OK: + execvp(fmtmime ? showprog : moreproc, ap); + adios(fmtmime ? showprog : moreproc, "unable to exec"); + + default: + if (pidXwait(pid, fmtmime ? showprog : r1bindex(moreproc, '/'))) + goodbye(); + break; + } + unlink(tmpfil1); +} + +void +pgp_store(file, fmtmime) +char *file; +int fmtmime; +{ + int pid, state; + char *ap[5]; + + (void) signal(SIGHUP, goodbye); + (void) signal(SIGINT, goodbye); + (void) signal(SIGQUIT, goodbye); + (void) signal(SIGPIPE, goodbye); + (void) signal(SIGTERM, goodbye); + + (void) strcpy(tmpfil1, m_scratch("", m_maildir(invo_name))); + if ((out = fopen(tmpfil1, "w")) == NULL) { + (void) strcpy(tmpfil1, m_tmpfil(invo_name)); + if ((out = fopen(tmpfil1, "w")) == NULL) { + advise(tmpfil1, "unable to create"); + goodbye(); + } + } + (void) chmod(tmpfil1, 0600); + cpydata(fileno(stdin), fileno(out), "stdin", tmpfil1); + fclose(out); + out = NULL; + + if (! *pgpproc) { + /* for PGP5 */ + ap[0] = "pgpv"; + ap[1] = tmpfil1; + ap[2] = "-o"; + ap[3] = file; + ap[4] = NULLCP; + + switch (pid = fork()) { + case NOTOK: + advise("fork", "unable to"); + goodbye(); + + case OK: + execvp("pgpv", ap); + /* maybe PGP5 is not installed. */ + _exit(NOT_INSTALLED); + + default: +#if 0 + state = pidwait(pid, OK); + if (WIFEXITED(state) && WEXITSTATUS(state) == NOT_INSTALLED) +#else + if ((state = pidwait(pid, OK)) == (NOT_INSTALLED << 8)) +#endif + /* Let's try old PGP */ + pgpproc = "pgp"; + else if (pidstatus(state, stdout, "pgpv")) + goodbye(); + break; + } + } + if (*pgpproc) { + /* for PGP2 */ + ap[0] = r1bindex(pgpproc, '/'); + + switch (pid = fork()) { + case NOTOK: + advise("fork", "unable to"); + goodbye(); + + case OK: + execvp(pgpproc, ap); + adios(pgpproc, "unable to exec"); + + default: + if (pidXwait(pid, r1bindex(pgpproc, '/'))) + goodbye(); + break; + } + } + unlink(tmpfil1); + + if (fmtmime) { + if (!m_find("path")) + free(path("./", TFOLDER)); + if (!(ap[0] = m_find(inbox))) + ap[0] = defalt; + if (*ap[0] != '+' && *ap[0] != '@') + ap[0] = add(ap[0], add("+", NULLCP)); + ap[1] = NULL; + refile(ap, file); + } +} + +void +pgp_mime(file1, file2, protocol, micalg, showsw) +char *file1, *file2, *micalg; +int protocol, showsw; +{ + int pid; + char *cp, *ap[6], buf[BUFSIZ]; + FILE *in; + + (void) signal(SIGHUP, goodbye); + (void) signal(SIGINT, goodbye); + (void) signal(SIGQUIT, goodbye); + (void) signal(SIGPIPE, goodbye); + (void) signal(SIGTERM, goodbye); + + (void) strcpy(tmpfil1, m_scratch("", m_maildir(invo_name))); + if ((out = fopen(tmpfil1, "w")) == NULL) { + (void) strcpy(tmpfil1, m_tmpfil(invo_name)); + if ((out = fopen(tmpfil1, "w")) == NULL) { + advise(tmpfil1, "unable to create"); + goodbye(); + } + } + (void) chmod(tmpfil1, 0600); + + if (protocol == PGP_SIGN) { + if ((in = fopen(file1, "r")) == NULL) { + advise(file1, "unable to open"); + goodbye(); + } + + while (fgets(buf, sizeof(buf) - 2, in)) { + cp = buf + strlen(buf) - 1; + if (*cp-- == '\n' && *cp != '\r') { + *++cp = '\r'; + *++cp = '\n'; + *++cp = '\0'; + } + fputs(buf, out); + } + fclose(in); + fclose(out); + out = NULL; + + ap[1] = "+batchmode=on"; + ap[2] = file2; + ap[3] = "-o"; + ap[4] = tmpfil1; + ap[5] = NULLCP; + } else { + fclose(out); + out = NULL; + unlink(tmpfil1); + + ap[1] = file2; + ap[2] = "-o"; + ap[3] = tmpfil1; + ap[4] = NULLCP; + } + if (! *pgpproc) { + /* for PGP5 */ + ap[0] = pgpproc = "pgpv"; + if (tee(ap, PGP_VER5) == NOTOK) { + if (protocol == PGP_SIGN && !uleq(micalg, "pgp-md5")) { + /* PGP2 only support PGP-MD5 */ + advise(pgpproc, "unable to exec"); + pgpproc = ""; + } else + /* Let's try old PGP */ + pgpproc = "pgp"; + } else + pgpproc = ""; + } + if (*pgpproc) { + /* for PGP2 */ + ap[0] = r1bindex(pgpproc, '/'); + if (protocol == PGP_SIGN) { + ap[3] = tmpfil1; + ap[4] = NULLCP; + } + if (tee(ap, PGP_VER2) == NOTOK) { + advise(pgpproc, "unable to exec"); + if (protocol != PGP_SIGN) + goodbye(); + } + } + + ap[0] = r1bindex(showprog, '/'); + ap[1] = "-file"; + if (protocol == PGP_SIGN) + ap[2] = file1; + else { + if ((in = fopen(tmpfil1, "r")) == NULL) { + advise(tmpfil1, "unable to open"); + goodbye(); + } + + (void) strcpy(tmpfil2, m_scratch("", m_maildir(invo_name))); + if ((out = fopen(tmpfil2, "w")) == NULL) { + (void) strcpy(tmpfil2, m_tmpfil(invo_name)); + if ((out = fopen(tmpfil2, "w")) == NULL) { + advise(tmpfil2, "unable to create"); + goodbye(); + } + } + (void) chmod(tmpfil2, 0600); + + while (fgets(buf, sizeof(buf) - 1, in)) { + cp = buf + strlen(buf) - 1; + if (*cp-- == '\n' && *cp == '\r') { + *cp++ = '\n'; + *cp = '\0'; + } + fputs(buf, out); + } + fclose(in); + fclose(out); + out = NULL; + + ap[2] = tmpfil2; + } + ap[3] = NULLCP; + unlink(tmpfil1); + + if (!showsw) { + if (!m_find("path")) + free(path("./", TFOLDER)); + if (!(ap[0] = m_find(inbox))) + ap[0] = defalt; + if (*ap[0] != '+' && *ap[0] != '@') + ap[0] = add(ap[0], add("+", NULLCP)); + ap[1] = NULL; + refile(ap, ap[2]); + return; + } + + switch (pid = fork()) { + case NOTOK: + advise("fork", "unable to"); + goodbye(); + + case OK: + execvp(showprog, ap); + adios(showprog, "unable to exec"); + + default: + if (pidXwait(pid, r1bindex(showprog, '/'))) + goodbye(); + break; + } + if (tmpfil2[0]) + unlink(tmpfil2); +} + +int +tee(ap, pgpver) +char *ap[]; +int pgpver; +{ + int cnt, state, pid, pdes[2]; + char *cp, *ep, *np, buf[BUFSIZ]; + + if (pipe(pdes) == NOTOK) { + advise(NULLCP, "unable to open pipe"); + goodbye(); + } + + switch (pid = fork()) { + case NOTOK: + close(pdes[0]); + close(pdes[1]); + advise("fork", "unable to"); + goodbye(); + + case OK: + if (pdes[1] != fileno(stdout)) + dup2(pdes[1], fileno(stdout)); + if (pdes[1] != fileno(stderr)) { + dup2(pdes[1], fileno(stderr)); + if (pdes[1] != fileno(stdout)) + close(pdes[1]); + } + close(pdes[0]); + execvp(pgpproc, ap); + /* maybe PGP is not installed. */ + _exit(NOT_INSTALLED); + } + close(pdes[1]); + + cp = ep = buf; + while ((cnt = read(pdes[0], buf + (ep - cp), sizeof(buf) - (ep - cp) - 1)) + > 0) { + write(fileno(stdout), buf + (ep - cp), cnt); + + ep = buf + (ep - cp) + cnt; + cp = buf; + while (cp < ep) { + np = cp; + while (np < ep && *np != '\n') + np++; + if (np < ep || (cp == buf && np == buf + sizeof(buf) - 1)) { + char *xp, *yp; + *np = '\0'; + if ((pgpver == PGP_VER5 + && strncmp(cp, PGP5_GOOD_SIGNATURE, + strlen(PGP5_GOOD_SIGNATURE)) == 0) + || + (pgpver == PGP_VER2 + && strncmp(cp, PGP2_GOOD_SIGNATURE, + strlen(PGP2_GOOD_SIGNATURE)) == 0)) { + pgpver = -1; + } + if (pgpver < 0 + && (xp = index(cp, '"')) && (yp = rindex(xp + 1, '"'))) { + *yp = '\0'; + m_putenv("PGP_SIGNATURE", xp + 1); + pgpver = 0; + } + } else { + bcopy(cp, buf, ep - cp); + break; + } + cp = np + 1; + } + } + close(pdes[0]); + +#if 0 + state = pidwait(pid, OK); + if (WIFEXITED(state) && WEXITSTATUS(state) == NOT_INSTALLED) +#else + if ((state = pidwait(pid, OK)) == (NOT_INSTALLED << 8)) +#endif + return NOTOK; + + if (pidstatus(state, stdout, r1bindex(pgpproc, '/'))) + goodbye(); + + return OK; +} + +static TYPESIG goodbye() +{ + if (out) + fclose(out); + if (tmpfil1[0]) + unlink(tmpfil1); + if (tmpfil2[0]) + unlink(tmpfil2); + done(1); + /* NOT REACHED */ +}