view uip/pgped.c @ 17:76d91e545ea8 default tip

addrsbr and dtimep fix
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 24 Nov 2014 14:49:25 +0900
parents 441a2190cfae
children
line wrap: on
line source

/* pgped.c - PGP editor */
#ifndef lint
static char ident[] = "@(#)$Id: pgped.c,v 1.1.1.1 2005/04/18 14:46:07 kono Exp $";
#endif /* lint */

#include "../h/mh.h"
#include "../h/mhn.h"
#include "../h/addrsbr.h"
#include "../h/aliasbr.h"
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <sys/stat.h>
#ifdef UNISTD
#include <unistd.h>
#endif /* UNISTD */
#ifdef LOCALE
#include <locale.h>
#endif /* LOCALE */

struct addrlist {
    char *address;
    struct addrlist *next;
};

struct addrlist *add_addrlist();
int exec_pgp5_for_keyid();
char *get_micalg();
static TYPESIG goodbye();

/*  */

static struct swit switches[] = {
#define ALIASW 0
    {"alias aliasfile", 0},

#define MHNPROC 1
    {"mhnproc program", 0},

#define PGPPROC 2
    {"pgpproc program", -7},

#define SIGNSW 3
    {"sign", 0},
#define NSIGNSW 4
    {"nosign", 0},

#define CRYPTSW 5
    {"encrypt", 0},
#define NCRPTSW 6
    {"noencrypt", 0},

#define MIMESW 7
    {"mime", 0},
#define NMIMESW 8
    {"nomime", 0},

#define HELPSW 9
    {"help", 4},

    {NULL, 0}
};

/*  */

static int signsw = 1;
static int encryptsw = 1;
static int mimesw = 1;

static char *mhnproc = "mhn";
static char *pgpproc = ""; /* "pgp"; */

static char prefix[] = "----- =_aaaaaaaaaa";

static char tmpfil1[BUFSIZ];
static char tmpfil2[BUFSIZ];
static char tmpfil3[BUFSIZ];
static FILE *out1 = NULL;
static FILE *out2 = NULL;

static struct addrlist *addrs = NULL;
static struct addrlist *from_addrs = NULL;
static struct addrlist *resent_addrs = NULL;

char *addr_headers[] = {
    "Reply-To",
    "From",
    "Sender",
    "To",
    "Cc",
    "Bcc",
    "Dcc",

    NULLCP
};

#define NOT_INSTALLED 127

/*  */

main(argc, argv)
int argc;
char *argv[];
{
    int i, cnt, pid, tomhn, mimehdr, resent, compnum, state;
    char *cp, *file = NULL, *keyid, buf[BUFSIZ], name[NAMESZ];
    char **ap, **argp, *arguments[MAXARGS];
    FILE *in;
    struct addrlist *ip;

#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", invo_name);
		help(buf, switches);
		done(1);

	    case ALIASW: 
		if (!(cp = *argp++) || *cp == '-')
		    adios(NULLCP, "missing argument to %s", argp[-2]);
		if ((i = alias(cp)) != AK_OK)
		    adios(NULLCP, "aliasing error in %s - %s", cp, akerror(i));
		continue;

	    case SIGNSW:
		signsw++;
		continue;
	    case NSIGNSW:
		signsw = 0;
		continue;

	    case CRYPTSW:
		encryptsw++;
		continue;
	    case NCRPTSW:
		encryptsw = 0;
		continue;

	    case MIMESW:
		mimesw++;
		continue;
	    case NMIMESW:
		mimesw = 0;
		continue;

	    case MHNPROC:
		if (!(mhnproc = *argp++) || *mhnproc == '-')
		    adios(NULLCP, "missing argument to %s", argp[-2]);
		continue;

	    case PGPPROC:
		if (!(pgpproc = *argp++) || *pgpproc == '-')
		    adios(NULLCP, "missing argument to %s", argp[-2]);
		continue;
	    }
	else {
	    if (file)
		adios(NULLCP, "only one file at a time!");
	    else
		file = cp;
	}
    }
    /* for compatibility to "pgped.sh" */
    if (argc == 3 && strcmp(argv[1], "-sign") == 0 && *argv[2] != '-')
	encryptsw = 0;

/*  */

    if ((cp = m_find("Aliasfile"))) { /* allow Aliasfile: profile entry */
	char *dp = NULL;

	for (ap = brkstring(dp = getcpy(cp), " ", "\n"); ap && *ap; ap++)
	    if ((i = alias(*ap)) != AK_OK)
		adios (NULLCP, "aliasing error in %s - %s", *ap, akerror(i));
	if (dp)
	    free(dp);
    }
    (void) alias(AliasFile);

    if (!file || (!mimesw && !signsw && !encryptsw))
	adios(NULLCP, "usage: %s [switches] file", invo_name);

/*  */

    if (mimesw) {
	if ((in = fopen(file, "r")) == NULL)
	    adios(file, "unable to open");

	tomhn = 1;
	state = FLD;
	while ((state = m_getfld(state, name, buf, sizeof(buf), in)) == FLD
	       || state == FLDPLUS || state == FLDEOF) {
	    if (uleq(name, VRSN_FIELD)) {
		tomhn = 0;
		break;
	    }
	}
	fclose(in);

	if (tomhn) {
	    if (!getenv("mhdraft"))
		m_putenv("mhdraft", file);
	    switch (pid = fork()) {
	    case NOTOK:
		adios("fork", "unable to");

	    case OK:
		execlp(mhnproc, r1bindex(mhnproc, '/'),
		       "-nocache", "-noshow", "-nostore", file, NULLCP);
		adios(mhnproc, "unable to exec");

	    default:
		if (pidXwait(pid, r1bindex(mhnproc, '/')))
		    done(1);
		break;
	    }
	}
	if (!signsw && !encryptsw)
	    done(0);
    } else
	tomhn = 0;


/*  */

    if ((in = fopen(file, "r")) == NULL)
	adios(file, "unable to open");
    tmpfil1[0] = tmpfil2[0] = tmpfil3[0] = '\0';

    (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 ((out1 = fopen(tmpfil1, "w")) == NULL) {
	(void) strcpy(tmpfil1, m_tmpfil(invo_name));
	if ((out1 = fopen(tmpfil1, "w")) == NULL) {
	    advise(tmpfil1, "unable to create");
	    goodbye();
	}
    }
    (void) chmod(tmpfil1, 0600);

    (void) strcpy(tmpfil2, m_scratch("", m_maildir(invo_name)));
    if ((out2 = fopen(tmpfil2, "w")) == NULL) {
	(void) strcpy(tmpfil2, m_tmpfil(invo_name));
	if ((out2 = fopen(tmpfil2, "w")) == NULL) {
	    advise(tmpfil2, "unable to create");
	    goodbye();
	}
    }
    (void) chmod(tmpfil2, 0600);

/*  */

    mimehdr = resent = 0;
    for (compnum = 1, state = FLD;;) {
	switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
	case FLD:
	case FLDPLUS:
	case FLDEOF:
	    compnum++;
	    cp = add(buf, NULLCP);
	    while (state == FLDPLUS) {
		state = m_getfld(state, name, buf, sizeof(buf), in);
		cp = add(buf, cp);
	    }
	    if (uleq(name, VRSN_FIELD))
		continue;
	    if (uprf(name, XXX_FIELD_PRF)) {
		if (mimesw) {
		    char *pp;
		    pp = cp + strlen(cp);
		    if (*--pp == '\n')
			*pp = '\0';
		    if (*--pp == '\r')
			*pp = '\0';
		    fprintf(out2, "%s:%s\r\n", name, cp);
		} else {
		    mimehdr = 1;
		    fprintf(out2, "%s:%s", name, cp);
		}
	    } else {
		char **h;
		if (uprf(name, "Resent-")) {
		    for (h = addr_headers; *h; h++)
			if (uleq(name+7, *h))
			    break;
		    if (*h)
			resent_addrs = add_addrlist(resent_addrs, cp);
		    if (uleq(name+7, "To")) /* Resent-To */
			resent = 1;
		} else {
		    for (h = addr_headers; *h; h++)
			if (uleq(name, *h))
			    break;
		    if (*h)
			addrs = add_addrlist(addrs, cp);
		    if (uleq(name, "From"))
			from_addrs = add_addrlist(from_addrs, cp);
		}
		fprintf (out1, "%s:%s", name, cp);
	    }
	    free(cp);
	    continue;

	case BODY:
	case BODYEOF:
	    (void) fseek(in, (long) (-strlen(buf)), 1);
	    break;

	case FILEEOF:
	    advise(NULLCP, "draft has empty body -- no directives!");
	    goodbye();

	case LENERR:
	case FMTERR:
	    advise(NULLCP, "message format error in component #%d", compnum);
	    goodbye();

	default:
	    advise(NULLCP, "getfld() returned %d", state);
	    goodbye();
	}
	break;
    }
    if (mimesw)
	fputs("\r\n", out2);
    else if (mimehdr)
	fputs("\n", out2);

/*  */

    fprintf (out1, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
    if (mimesw) {
	int badprefix, len = strlen(prefix);
	long pos;
	char *pp;

	if ((pp = index(prefix, 'a')) == NULL) {
	    advise(NULLCP, "internal error");
	    goodbye();
	}
	pos = ftell(in);
	badprefix = 0;
	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, out2);
	    if (badprefix || buf[0] != '-' || buf[1] != '-')
		continue;
	    for (cp = buf + strlen(buf) - 1; cp >= buf; cp--)
		if (!isspace(*cp))
		    break;
	    *++cp = '\0';
	    if (strncmp(buf + 2, prefix, len) == 0
		&& isdigit(buf[2 + len]))
		badprefix = 1;
	}
	while (badprefix) {
	    if (*pp < 'z')
		(*pp)++;
	    else
		if (*++pp == 0) {
		    advise(NULLCP,
			   "giving up trying to find a unique delimiter string"
			   );
		    goodbye();
		}
		else
		    (*pp)++;
	    fseek(in, pos, 0);
	    badprefix = 0;
	    while (fgets(buf, sizeof(buf) - 1, in)) {
		if (buf[0] != '-' || buf[1] != '-')
		    continue;
		for (cp = buf + strlen(buf) - 1; cp >= buf; cp--)
		    if (!isspace(*cp))
			break;
		*++cp = '\0';
		if (strncmp(buf + 2, prefix, len) == 0
		    && isdigit(buf[2 + len])) {
		    badprefix = 1;
		    break;
		}
	    }
	}
	if (encryptsw) {
	    fprintf(out1, "%s: multipart/encrypted; ", TYPE_FIELD);
	    fprintf(out1, "protocol=\"application/pgp-encrypted\";\n");
	    fprintf(out1, "\tboundary=\"%s%d\"\n\n", prefix, 0);
	    fprintf(out1, "--%s%d\n", prefix, 0);
	    fprintf(out1, "%s: application/pgp-encrypted\n", TYPE_FIELD);
	    fprintf(out1, "%s: 7bit\n\nVersion: 1\n\n", ENCODING_FIELD);
	    fprintf(out1, "--%s%d\n", prefix, 0);
	    fprintf(out1, "%s: application/octet-stream\n", TYPE_FIELD);
	    fprintf(out1, "%s: 7bit\n\n", ENCODING_FIELD);
	}
    } else {
	while ((cnt = fread(buf, sizeof(char), sizeof(buf), in)) > 0)
	    fwrite(buf, sizeof(char), cnt, out2);
	if (mimehdr) {
	    fprintf(out1, "%s: application/pgp; format=mime\n\n", TYPE_FIELD);
	} else {
	    if (encryptsw)
		fprintf(out1, "%s: application/pgp\n\n", TYPE_FIELD);
	    else
		fprintf(out1, "%s: text/pgp\n\n", TYPE_FIELD);
	}
    }
    fclose(in);
    fclose(out2);
    out2 = NULL;

/*  */

    (void) strcpy(tmpfil3, m_scratch("", m_maildir(invo_name)));
    if ((out2 = fopen(tmpfil3, "w")) == NULL) {
	(void) strcpy(tmpfil3, m_tmpfil(invo_name));
	if ((out2 = fopen(tmpfil3, "w")) == NULL) {
	    advise(tmpfil3, "unable to create");
	    goodbye();
	}
    }
    (void) chmod(tmpfil3, 0600);
    fclose(out2);
    unlink(tmpfil3);

    if (resent)
	addrs = resent_addrs;
    i = 0;
    for (ip = addrs; ip; ip = ip->next)
	i++;
    if ((ap = (char **) malloc(sizeof(char *) * (i * 2 + 9))) == NULL) {
	advise(NULLCP, "out of memory");
	goodbye();
    }

/*  */

    if (! *pgpproc) {
	/* for PGP5 */
	ap[i = 0] = pgpproc = encryptsw ? "pgpe" : "pgps";
	ap[++i] = encryptsw ? (signsw ? "-sat" : "-at")
	    : (mimesw ? "-ab" : "-at");
	ap[++i] = "+language=en";
	ap[++i] = "+armorlines=0";
	if (encryptsw)
	    for (ip = addrs; ip; ip = ip->next) {
		ap[++i] = "-r";
		ap[++i] = ip->address;
	    }
	if (signsw && from_addrs) {
	    ap[++i] = "-u";
	    ap[++i] = from_addrs->address;
	}
	ap[++i] = tmpfil2;
	ap[++i] = "-o";
	ap[++i] = tmpfil3;
	ap[++i] = NULLCP;

	if (!mimesw || encryptsw) {
	    switch (pid = fork()) {
	    case NOTOK:
		advise("fork", "unable to");
		goodbye();

	    case OK:
		execvp(pgpproc, 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, pgpproc))
		    goodbye();
		else
		    pgpproc = "";
		break;
	    }
	} else if (exec_pgp5_for_keyid(pgpproc, ap, &keyid) == NOTOK)
	    /* Let's try old PGP */
	    pgpproc = "pgp";
	else
	    pgpproc = "";
    }
    if (*pgpproc) {
	/* for PGP2 */
	ap[i = 0] = r1bindex(pgpproc, '/');
	ap[++i] = encryptsw ? (signsw ? "-esat" : "-eat")
	    : (mimesw ? "-sab" : "-sat");
	ap[++i] = "+language=en";
	ap[++i] = "+armorlines=0";
	ap[++i] = tmpfil2;
	for (ip = addrs; ip; ip = ip->next)
	    ap[++i] = ip->address;
	if (from_addrs && from_addrs->address) {
	    ap[++i] = "-u";
	    ap[++i] = from_addrs->address;
	}
	ap[++i] = "-o";
	ap[++i] = tmpfil3;
	ap[++i] = NULLCP;

	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;
	}
    }

/*  */

    if (mimesw && !encryptsw) {
	fprintf(out1, "%s: multipart/signed;\n", TYPE_FIELD);
	fprintf(out1, "\tprotocol=\"application/pgp-signature\"; ");
	fprintf(out1, "micalg=\"pgp-%s\";\n",
		*pgpproc ? "md5"
		: get_micalg(from_addrs ? from_addrs->address : NULLCP,
			     keyid));
	fprintf(out1, "\tboundary=\"%s%d\"\n\n", prefix, 0);
	fprintf(out1, "--%s%d\n", prefix, 0);
	if ((in = fopen(tmpfil2, "r")) == NULL) {
	    advise(tmpfil2, "unable to open");
	    goodbye();
	}
	while (fgets(buf, sizeof(buf) - 1, in)) {
	    cp = buf + strlen(buf) - 1;
	    if (*cp-- == '\n' && *cp == '\r') {
		*cp++ = '\n';
		*cp = '\0';
	    }
	    fputs(buf, out1);
	}
	fclose(in);
	fprintf(out1, "\n--%s%d\n", prefix, 0);
	fprintf(out1, "%s: application/pgp-signature\n", TYPE_FIELD);
	fprintf(out1, "%s: 7bit\n\n", ENCODING_FIELD);
    }
    unlink(tmpfil2);

    if ((in = fopen(tmpfil3, "r")) == NULL) {
	advise(tmpfil3, "unable to open");
	goodbye();
    }
    while (fgets(buf, sizeof(buf) - 1, in))
	fputs(buf, out1);
    fclose(in);
    unlink(tmpfil3);
    if (mimesw)
	fprintf(out1, "\n--%s%d--\n", prefix, 0);
    fclose(out1);

    if (!tomhn) {
	sprintf(buf, "%s.orig", m_backup(file));
	if (rename(file, buf) == NOTOK) {
	    advise(buf, "unable to rename %s to", file);
	    goodbye();
	}
    }
    unlink(file);
    if (rename(tmpfil1, file) == NOTOK) {
	int in, out;
	struct stat st;
	if (stat(file, &st) != NOTOK) {
	    advise(file, "unable to rename %s to", tmpfil1);
	    goodbye();
	}
	if ((in = open(tmpfil1, 0)) == NOTOK) {
	    advise(tmpfil1, "unable to open");
	    goodbye();
	}
	if ((out = creat(file, 0600)) == NOTOK) {
	    advise(file, "unable to create");
	    (void) close(in);
	    goodbye();
	}
	cpydata(in, out, tmpfil1, file);
	(void) close(in);
	(void) close(out);
	unlink(tmpfil1);
    }

    done(0);
}

struct addrlist *
add_addrlist(addrp, str)
struct addrlist *addrp;
char *str;
{
    char *cp;
    struct addrlist *ap, **vp;
    struct mailname *lp, *mp, *np, taddr;

    np = &taddr;
    while ((cp = getname(str))) {
	if (!(mp = getm(cp, NULLCP, 0, AD_HOST, NULLCP)))
	    continue;
	np->m_next = mp;
	np = mp;
    }
    np->m_next = NULL;

    np = &taddr;
    for (lp = taddr.m_next; lp; lp = np->m_next) {
	if (lp->m_nohost) {
	    char *pp;
	    pp = akvalue(lp->m_mbox);
	    while ((cp = getname(pp))) {
		if (!(mp = getm(cp, NULLCP, 0, AD_HOST, NULLCP)))
		    continue;
		np->m_next = mp;
		np = mp;
	    }
	    np->m_next = lp->m_next;
	    mnfree(lp);
	} else
	    np = lp;
    }

    for (lp = taddr.m_next; lp; lp = np) {
	switch (lp->m_type) {
	case UUCPHOST:
	    cp = add(lp->m_mbox, add("!", add(lp->m_host, NULLCP)));
	    break;
	case LOCALHOST:
	    cp = add(LocalName(), add("@", add(lp->m_mbox, NULLCP)));
	    break;
	default:
	    cp = add(lp->m_host, add("@", add(lp->m_mbox, NULLCP)));
	    break;
	}
	vp = &addrp;
	for (ap = addrp; ap; ap = ap->next) {
	    if (uleq(ap->address, cp))
		break;
	    vp = &(ap->next);
	}
	if (ap)
	    free(cp);
	else {
	    if ((*vp = (struct addrlist *) malloc(sizeof(struct addrlist)))
		== NULL) {
		advise(NULLCP, "out of memory");
		goodbye();
	    }
	    (*vp)->address = cp;
	    (*vp)->next = NULL;
	}
	np = lp->m_next;
	mnfree(lp);
    }
    return addrp;
}

int
exec_pgp5_for_keyid(prog, ap, keyid)
char *prog, *ap[], **keyid;
{
    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(prog, ap);
	/* maybe PGP is not installed. */
	_exit(NOT_INSTALLED);
    }
    close(pdes[1]);

    cp = ep = buf;
    *keyid = NULLCP;
    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 (! *keyid) {
		    for (xp = cp; *xp; xp++)
			if (strncmp(xp, "bits, Key ID ", 13) == 0)
			    break;
		    if (*xp && (yp = index(xp + 13, ','))) {
			*yp = '\0';
			*keyid = add(xp + 13, NULLCP);
		    }
		}
	    } 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;
}

char *
get_micalg(userid, keyid)
char *userid, *keyid;
{
    int pid, pdes[2];
    char *ap[5], buf[BUFSIZ], *hash = "md5"; /* default */
    FILE *in;

    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]);
	ap[0] = "pgpk";
	ap[1] = "-l";
	ap[2] = "+language=en";
	ap[3] = userid; /* might be NULLCP */
	ap[4] = NULLCP;
	execvp("pgpk", ap);
	adios("pgpk", "unable to exec");
    }
    close(pdes[1]);

    in = fdopen(pdes[0], "r");
    while (fgets(buf, sizeof(buf), in)) {
	if (strncmp(buf, "sec", 3) == 0 /* secret key */
	    && strncmp(buf + 12, keyid, strlen(keyid)) == 0) {
	    if (strncmp(buf + 43, "DSS", 3) == 0)
		hash = "sha1";
	    else if (strncmp(buf + 43, "RSA", 3) == 0)
		hash = "md5";
	}
    }
    fclose(in);

    if (pidXwait(pid, "pgpk"))
	goodbye();

    return hash;
}

static TYPESIG goodbye()
{
    if (out1)
	fclose(out1);
    if (out2)
	fclose(out2);
    if (tmpfil1[0])
	unlink(tmpfil1);
    if (tmpfil2[0])
	unlink(tmpfil2);
    if (tmpfil3[0])
	unlink(tmpfil3);
    done(1);
    /* NOT REACHED */
}