static char rcsid[] = "@(#)$Id: pgp.c,v 1.57 2006/09/20 16:22:21 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.57 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
*
* Initially written by: Michael Elkins <elkins@aero.org>, 1995
*****************************************************************************/
#include "def_elm.h"
#include "s_elm.h"
DEBUG_VAR(Debug,__FILE__,"pgp");
#ifdef USE_PGP
#include <sys/time.h>
#include "menu.h"
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
/* the column in which the userid begins in the 'pgp -kv' command output */
#define PGP2_USERID_OFFSET 30
#define PGP5_USERID_OFFSET 5
static char * PGPSelectKey P_((char *n, char **k, int len));
/* 'n' is the key we are looking for. 'k' is the list of possible matches
which contains 'len' entries. prompt the user for which key s/he really
wants to use. */
static char * PGPSelectKey (n, k, len)
char *n;
char **k;
int len;
{
int i;
char * buf = NULL;
menu_t menu;
struct menu_context *page = new_menu_context();
buf = elm_message(CATGETS(elm_msg_cat, ElmSet, ElmPgpMultipleKeys,
"Multiple keys match '%s':"),
n);
MenuInit (&menu, buf, catgets(elm_msg_cat, ElmSet, ElmPgpSelectKey,
"Select key or 'q' to quit: "),
0);
for (i = 0; i < len; i++)
MenuAdd(&menu, k[i]);
for (;;) {
switch (MenuLoop(&menu,page)) {
case 'q':
MenuDestroy(&menu);
free(buf);
erase_menu_context(&page);
return(0);
case '\n':
case '\r':
MenuDestroy(&menu);
free(buf);
erase_menu_context(&page);
return(k[MenuCurrent(menu)]);
}
}
/* not reached */
}
static void close_pipe P_((struct run_state *rs));
static void close_pipe(rs)
struct run_state *rs;
{
int *array = rs->ext_init_data;
close(array[0]);
}
static int GetPGPKey P_((char *name, char *target,
int targetsize, enum pgp_version v));
static int GetPGPKey (name, target, targetsize, v)
char *name;
char *target;
int targetsize;
enum pgp_version v;
{
/* given "name", return the string to use during the pgp call to specify
the key which the user means. return -1 on error. */
char buf[STRING], address[STRING], *c, **keys=0, *pc, userpart[STRING];
int i=0, keys_len=0, keys_max=0, return_val=0, start=0;
pid_t pid;
FILE *p;
if (!name || !target) {
DPRINT(Debug,9,(&Debug, "GetPGPKey=-1\n"));
return -1;
}
DPRINT(Debug,9,(&Debug, "GetPGPKey: name=%s,v=%d\n",name,v));
if (index(name, '@') == NULL && index(name, '(') == NULL &&
index(name, '<') == NULL) {
/* this is either just a username, or someone's real name. in either
case it only needs to be checked once. */
strfcpy(address, name, sizeof address);
i = 2;
}
else {
get_address_from (name, address, sizeof address);
i=0;
while (address[i] && address[i] != '@') {
userpart[i] = address[i];
i++;
}
userpart[i] = '\0';
i = 0;
}
c = address;
/* the following loop first checks to see if any keys with the full
address, or real name, or finally the username exist */
for (;;) {
int fd[2];
int array[1];
CONST char * argv[10];
int code;
int stat = -1;
struct run_state RS;
while (*c && isspace (*c)) c++; /* move past any leading space! */
DPRINT(Debug,10,(&Debug, "GetPGPKey: c=%s\n",c));
if (pipe (fd) == -1) {
DPRINT(Debug,1,(&Debug,
"GetPGPKey()=-1: ERROR: pipe (errno %d)\n",
errno));
return -1;
}
array[0] = fd[0];
RS.save_errno = 0;
RS.ext_init_data = array;
RS.ext_init = close_pipe;
RS.ext_env = NULL;
switch(v) {
static char path[1000];
int n;
case pgp2:
n = 0;
{
char * pgp2_path_val = give_dt_estr_as_str(&pgp2_path_e,
"pgp2");
if (! pgp2_path_val)
return -1;
argv[n++] = pgp2_path_val;
}
argv[n++] = "+verbose=0";
argv[n++] = "+language=en";
argv[n++] = "-kv";
argv[n++] = c;
argv[n] = NULL;
break;
case pgp5:
n = 0;
{
/* give_dt_estr_as_str adds / to end */
char * pgp5_dir_val = give_dt_estr_as_str(&pgp5_dir_e,
"pgp5-dir");
if (! pgp5_dir_val)
return -1;
elm_sfprintf(path, sizeof path,FRM("%spgpk"),pgp5_dir_val);
}
argv[n++] = path;
argv[n++] = "+verbose=0";
argv[n++] = "+language=en";
argv[n++] = "-l";
argv[n++] = c;
argv[n] = NULL;
break;
case gpg:
n = 0;
{
char * gpg_path_val = give_dt_estr_as_str(&gpg_path_e, "gpg");
if (! gpg_path_val)
return -1;
argv[n++] = gpg_path_val;
}
argv[n++] = "--list-public-keys";
argv[n++] = c;
argv[n++] = NULL;
break;
}
code = start_run(&RS, SY_RUN_STATE_INIT, argv ,
-1,fd[1]);
close (fd[1]);
if (!code) {
DPRINT(Debug,1,(&Debug,
"GetPGPKey()=-1: running pgp/gpg failed\n"));
return -1;
}
p = fdopen (fd[0], "r");
if (p == NULL) {
int tmp;
int err = errno;
DPRINT(Debug,1,(&Debug,
"GetPGPKey()=-1: ERROR: fdopen (errno %d)\n",
err));
kill(RS.pid,SIGTERM);
wait_end(&RS,&tmp);
return -1;
}
code = run_already_done(&RS,&stat);
if (0 != code) {
DPRINT(Debug,5,(&Debug,
"now pgp/gpg is ALREADY completing\n"));
}
retry:
while (fgets(buf, STRING, p) != NULL) {
DPRINT(Debug,10,(&Debug,
"GetPGPKey: %s\n",buf));
switch(v) {
case pgp2:
/* see if we've reached the beginning of the key listings... */
if (!start && strncmp(buf, "pub", 3)==0)
start=1;
if (start) {
/* if we've read all the keys, stop here */
if (buf[0] != 'p' && buf[0] != ' ')
break;
if (keys_len == keys_max)
keys = (char**)DynamicArray((void **)keys,
sizeof(char*),
&keys_max, 5);
pc = rindex(buf, '\n');
if (!pc) /* this shouldn't happen! */
continue;
*pc = '\0';
pc = buf + PGP2_USERID_OFFSET;
keys[keys_len] = safe_strdup(pc);
++keys_len;
}
break;
case gpg:
if (0 == strncmp(buf, "pub ",4)) {
int pos = 4;
char work[SLEN];
start=1;
/* ID */
pos = get_word(buf,pos,work,sizeof work);
if (-1 == pos)
break;
/* DATE */
pos = get_word(buf,pos,work,sizeof work);
if (-1 == pos)
break;
while (isspace(buf[pos]))
pos++;
if (!buf[pos])
break;
/* Ignore [expires: -text (language may be different) */
if ('[' == buf[pos])
break;
if (keys_len == keys_max)
keys = (char**)DynamicArray((void **)keys,
sizeof(char*),
&keys_max, 5);
keys[keys_len] = safe_strdup(buf+pos);
keys_len++;
} else if (start && buf[0] == ' ' ||
0 == strncmp(buf, "uid ",4)) {
int pos = 4;
while (isspace(buf[pos]))
pos++;
if (!buf[pos])
break;
if (keys_len == keys_max)
keys = (char**)DynamicArray((void **)keys,
sizeof(char*),
&keys_max, 5);
keys[keys_len] = safe_strdup(buf+pos);
keys_len++;
} else
start = 0;
break;
case pgp5:
if (strncmp(buf, "uid", 3)==0) {
if (keys_len == keys_max)
keys = (char**)DynamicArray((void **)keys,
sizeof(char*),
&keys_max, 5);
pc = rindex(buf, '\n');
if (!pc) /* this shouldn't happen! */
continue;
*pc = '\0';
pc = buf + PGP5_USERID_OFFSET;
keys[keys_len] = safe_strdup(pc);
++keys_len;
}
}
}
if (ferror(p) && EINTR == errno) {
clearerr(p);
DPRINT(Debug,5,(&Debug,
"Reading of result interrupted (EINTR) -- retrying\n"));
if (0 == code) {
code = run_already_done(&RS,&stat);
if (0 != code) {
DPRINT(Debug,5,(&Debug,
"now pgp/gpg is completing\n"));
}
}
goto retry;
}
fclose(p);
if (0 == code)
code = wait_end(&RS,&stat);
if (code < 0) {
DPRINT(Debug,5,(&Debug,
"pgp/gpg dies on signal %d\n",
-code));
} else {
DPRINT(Debug,5,(&Debug,"pgp/gpgp exited with status %d\n",stat));
}
if (keys_len > 0 || i > 1)
break;
else {
if (i == 0) {
char * z;
strfcpy(address,name, sizeof address);
z = strchr(address,'<'); /* Lousy */
/* if there was no real name, go on to the userpart check */
if (!z || z == address) {
c = userpart;
i++;
} else
*z = '\0';
} else if (i == 1)
c = userpart;
i++;
}
}
if (keys_len == 1) /* perfect match! */
get_address_from(keys[0], target, targetsize);
else if (keys_len > 1) { /* ask the user which, if any, s/he meant */
c = PGPSelectKey(name, keys, keys_len);
if (c)
get_address_from(c, target, targetsize);
else {
target[0] = '\0';
return_val = -1;
}
} else {
target[0] = '\0';
return_val = -1;
}
DestroyDynamicArray((void **)keys);
DPRINT(Debug,9,(&Debug, "GetPGPKey(name=%s)=%d, target=%s\n",
name,return_val,target));
return return_val;
}
static int pgp_call P_((char *filename,int opts,
struct mailing_headers *headers,
enum pgp_version v,
struct menu_context *page));
static int pgp_encrypt P_((char *filename, char *ids, char *sig,
int opts, int metoo,
enum pgp_version v,
struct menu_context *page));
static int pgp_call (filename, opts, headers, v, page)
char *filename;
int opts;
struct mailing_headers *headers;
enum pgp_version v;
struct menu_context *page;
{
char tobuf[VERY_LONG_STRING] = {0};
char frombuf[VERY_LONG_STRING] = {0};
int status;
int r;
int LINES, COLUMNS;
menu_get_sizes(page, &LINES, &COLUMNS);
do {
if (opts & PGP_MESSAGE) {
struct addr_item *x;
/* build up the list of recipients */
tobuf[0] = '\0';
for (x = headers->to.addrs;
x < headers->to.addrs + headers->to.addrs_len;
x++) {
if (tobuf[0])
strfcat(tobuf, ", ", sizeof tobuf);
strfcat(tobuf, x->addr, sizeof tobuf);
}
for (x = headers->cc.addrs;
x < headers->cc.addrs + headers->cc.addrs_len;
x++) {
if (tobuf[0])
strfcat(tobuf, ", ", sizeof tobuf);
strfcat(tobuf, x->addr, sizeof tobuf);
}
for (x = headers->bcc.addrs;
x < headers->bcc.addrs + headers->bcc.addrs_len;
x++) {
if (tobuf[0])
strfcat(tobuf, ", ", sizeof tobuf);
strfcat(tobuf, x->addr, sizeof tobuf);
}
/* If the message is to be encrypted, give the user a chance to
* edit the list of ids to encrypt to since the given address may
* not always be correct.
*/
redraw:
PutLineX (LINES-1-2, 0, CATGETS(elm_msg_cat, ElmSet, ElmPgpTo,
"To: "));
status = optionally_enter(tobuf, LINES-1-2, 4,
OE_APPEND_CURRENT|OE_REDRAW_MARK|
OE_SIG_CHAR /* Ctrl-C */,
sizeof tobuf,
page);
if (REDRAW_MARK == status)
goto redraw;
if (status != 0 || tobuf[0] == '\0')
return FALSE;
}
if (pgp_askpgpsig && (opts & PGP_SIGNED_MESSAGE)) {
/* If the message is to be signed, give the user a chance to
* specify with which signature.
*/
strfcat(frombuf, username, sizeof frombuf);
redraw2:
PutLineX (LINES-1-2, 0, CATGETS(elm_msg_cat, ElmSet, ElmPgpFrom,
"From: "));
status = optionally_enter(frombuf, LINES-1-2, 6,
OE_APPEND_CURRENT|OE_REDRAW_MARK|
OE_SIG_CHAR /* Ctrl-C */,
sizeof frombuf,
page);
if (REDRAW_MARK == status)
goto redraw2;
if (status != 0 || frombuf[0] == '\0')
return FALSE;
}
r = pgp_encrypt (filename, tobuf, frombuf, opts, auto_copy_sent, v,
page);
} while (r < 0);
if (r < 0)
r = 0;
return (r);
}
static void close_it P_((struct run_state *rs));
static void close_it(rs)
struct run_state *rs;
{
int *close_fd = rs->ext_init_data;
if (*close_fd != -1)
close(*close_fd);
}
static int pgp_encrypt (filename, ids, sig, opts, metoo, v, page)
char *filename, *ids, *sig;
int opts, metoo;
enum pgp_version v;
struct menu_context *page;
{
int id_len=0, id_max=0, usepgppass=FALSE, fd[2];
char
keyid[STRING], buf[VERY_LONG_STRING], **id_array=0, *c,
*p;
CONST char ** joined = NULL;
int close_fd;
#define MAX_ARG 1000
CONST char * argv[MAX_ARG];
char * argv0[MAX_ARG];
char * env[2];
int a;
int ret = 0;
int was_redraw = 0; /* FIXME */
struct run_state RS;
int exit_code;
int LINES, COLUMNS;
menu_get_sizes(page, &LINES, &COLUMNS);
DPRINT(Debug,2,(&Debug,
"pgp_encrypt(): ids=\"%s\", signwith=\"%s\", encrypt=%s, sign=%s\n",
ids, sig,
opts & PGP_MESSAGE ? "TRUE" : "FALSE",
opts & PGP_SIGNED_MESSAGE ? "TRUE" : "FALSE"));
p = ids;
/* If this message is to be encrypted, look up the keys of all the
recipients */
if (opts & PGP_MESSAGE) {
while ((c = strtok(p, ",")) != NULL) {
int Len;
while (whitespace(*c))
c++;
if ('\0' == *c)
goto next_recipient;
if (GetPGPKey(c, keyid, sizeof keyid, v) == -1) {
redraw1:
while(1) {
int x_coord, y_coord, ans;
int def_ans = 'q';
MoveCursor (LINES-4, 0);
CleartoEOS ();
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPgpNoMatch,
"Couldn't find key matching '%s'!"),
c);
print_format_center (LINES-3,
CATGETS(elm_msg_cat, ElmSet, ElmPgpKeyError,
"e)dit recipient list, s)kip recipient, q)uit"));
menu_PutLineX (page,LINES-1-3, 0,
CATGETS(elm_msg_cat, ElmSet,
ElmPgpSelect,
"Select [e/s/q]: "));
menu_GetXYLocation(page, &x_coord, &y_coord);
menu_PutLineX (page,x_coord, y_coord,FRM("%c"),def_ans);
menu_MoveCursor(page, x_coord, y_coord);
switch((ans = menu_ReadCh(page,REDRAW_MARK))) {
case '\n':
case '\r':
ans = def_ans;
case REDRAW_MARK:
was_redraw = 1;
menu_ClearScreen(page);
goto redraw1;
}
switch(ans) {
case 'e':
Write_to_screen(CATGETS(elm_msg_cat, ElmSet,
ElmPgpEditRec,
"Edit recipients"));
return -1; /* Indicate KEY error */
case 's':
Write_to_screen(CATGETS(elm_msg_cat, ElmSet,
ElmPgpSkipRec,
"Skip recipients"));
goto next_recipient;
case 'q':
Write_to_screen(CATGETS(elm_msg_cat, ElmSet,
ElmPgpQuit,
"Quit"));
return 0;
}
}
}
if (id_len == id_max)
id_array = (char**)DynamicArray((void **)id_array,
sizeof(char*), &id_max, 25);
Len = strlen(keyid) + 1;
id_array[id_len] = (char*)safe_malloc(Len);
strfcpy(id_array[id_len], keyid, Len);
id_len++;
next_recipient:
p=NULL;
}
/* If all recpients s)kipped */
if (id_len < 1 || !id_array[0]) {
return 0;
}
}
if (id_len == id_max)
id_array = (char**)DynamicArray((void **)id_array,
sizeof(char*), &id_max, 1);
id_array[id_len] = NULL;
if ((opts & PGP_SIGNED_MESSAGE) && pgp_keeppass &&
pgp_goodPassphrase(v)) {
usepgppass = TRUE;
pipe(fd);
}
close_fd = -1;
env[0] = NULL;
RS.ext_env = env;
RS.ext_init_data = &close_fd;
RS.ext_init = close_it;
switch(v) {
case pgp2:
case pgp5:
if (usepgppass) {
static char buffer[20];
elm_sfprintf(buffer, sizeof buffer,FRM("PGPPASSFD=%d"),
fd[0]);
env[0] = buffer;
close_fd = fd[1];
}
env[1] = NULL;
}
/* copy the file into it's final destination */
elm_sfprintf(buf, sizeof buf,
FRM("%s.asc"), filename);
Raw(OFF);
ClearScreen(0);
Write_to_screen(CATGETS(elm_msg_cat, ElmSet,ElmRunningPgp,
"Running PGP..."));
Write_to_screen(FRM("\n\n"));
a = 0;
switch(v) {
static char path[1000];
int i;
case pgp2:
{
char * pgp2_path_val = give_dt_estr_as_str(&pgp2_path_e, "pgp2");
if (! pgp2_path_val) {
Raw(ON);
return FALSE;
}
argv0[a++] = pgp2_path_val;
}
if (metoo)
argv0[a++] = "+encrypttoself=on";
if ((usepgppass || !(opts & PGP_SIGNED_MESSAGE)) &&
!pgp_interactive)
argv0[a++] = "+batchmode";
if (opts & PGP_SIGNED_MESSAGE)
argv0[a++] = "+clearsig=on";
argv0[a++] = "+verbose=0";
switch (opts & (PGP_SIGNED_MESSAGE|PGP_MESSAGE)) {
case PGP_SIGNED_MESSAGE|PGP_MESSAGE:
argv0[a++] = "-atwse";
break;
case PGP_SIGNED_MESSAGE:
argv0[a++] = "-atws";
break;
case PGP_MESSAGE:
argv0[a++] = "-atwe";
break;
}
if (pgp_askpgpsig && (opts & PGP_SIGNED_MESSAGE)) {
argv0[a++] = "-u";
argv0[a++] = sig;
}
argv0[a++] = filename;
argv0[a] = NULL;
joined = join_argv(argv0,id_array);
ret = start_run(&RS,SY_RUN_STATE_ENV|SY_RUN_STATE_INIT|
SY_ENAB_SIGINT,
joined,-1,-1);
break;
case pgp5:
{
/* give_dt_estr_as_str adds / to end */
char * pgp5_dir_val = give_dt_estr_as_str(&pgp5_dir_e,
"pgp5-dir");
if (! pgp5_dir_val) {
Raw(ON);
return FALSE;
}
if (opts & PGP_MESSAGE)
elm_sfprintf(path, sizeof path,FRM("%spgpe"),pgp5_dir_val);
else
elm_sfprintf(path, sizeof path,FRM("%spgps"),pgp5_dir_val);
}
argv[a++] = path;
if (metoo)
argv[a++] = "+encrypttoself=on";
if ((usepgppass || !(opts & PGP_SIGNED_MESSAGE)) &&
!pgp_interactive)
argv[a++] = "+batchmode";
if (opts & PGP_SIGNED_MESSAGE)
argv[a++] = "+clearsig=on";
argv[a++] = "+verbose=0";
switch (opts & (PGP_SIGNED_MESSAGE|PGP_MESSAGE)) {
case PGP_SIGNED_MESSAGE|PGP_MESSAGE:
argv[a++] = "-ats";
break;
case PGP_SIGNED_MESSAGE:
argv[a++] = "-at";
break;
case PGP_MESSAGE:
argv[a++] = "-at";
break;
}
if (pgp_askpgpsig && (opts & PGP_SIGNED_MESSAGE)) {
argv[a++] = "-u";
argv[a++] = sig;
}
argv[a++] = "-o";
argv[a++] = buf;
for (i = 0; a < MAX_ARG -5 && id_array[i]; i++) {
argv[a++] = "-r";
argv[a++] = id_array[i];
}
argv[a++] = filename;
argv[a] = NULL;
ret = start_run(&RS,SY_RUN_STATE_ENV|SY_RUN_STATE_INIT|
SY_ENAB_SIGINT,
argv,-1,-1);
break;
case gpg:
{
char * gpg_path_val = give_dt_estr_as_str(&gpg_path_e, "gpg");
if (! gpg_path_val) {
Raw(ON);
return FALSE;
}
argv[a++] = gpg_path_val;
}
if (usepgppass) {
static char buffer[10];
argv[a++] = "--passphrase-fd";
elm_sfprintf(buffer, sizeof buffer,FRM("%d"),
fd[0]);
argv[a++] = buffer;
close_fd = fd[1];
}
if ((usepgppass || !(opts & PGP_SIGNED_MESSAGE)) &&
!pgp_interactive)
argv[a++] ="--batch";
if (metoo) {
argv[a++] = "--encrypt-to";
if (pgp_askpgpsig && (opts & PGP_SIGNED_MESSAGE)) {
static char buffer[STRING];
elm_sfprintf(buffer, sizeof buffer,FRM("<%s>"),sig);
argv[a++] = buffer;
}
else {
static char buffer[STRING];
elm_sfprintf(buffer, sizeof buffer,
FRM("<%s@%s>"),username,hostfullname);
argv[a++] = buffer;
}
}
argv[a++] = "--no-verbose";
if (pgp_askpgpsig && (opts & PGP_SIGNED_MESSAGE)) {
static char buffer[STRING];
argv[a++] = "--local-user";
elm_sfprintf(buffer, sizeof buffer,FRM("<%s>"),sig);
argv[a++] = buffer;
}
argv[a++] = "--output";
argv[a++] = buf;
for (i = 0; a < MAX_ARG -5 && id_array[i]; i++) {
argv[a++] = "--recipient";
argv[a++] = id_array[i];
}
switch (opts & (PGP_SIGNED_MESSAGE|PGP_MESSAGE)) {
case PGP_SIGNED_MESSAGE|PGP_MESSAGE:
argv[a++] = "--sign";
argv[a++] = "--armor";
argv[a++] = "--encrypt";
break;
case PGP_MESSAGE:
argv[a++] = "--armor";
argv[a++] = "--encrypt";
break;
case PGP_SIGNED_MESSAGE:
argv[a++] = "--clearsign";
break;
}
argv[a++] = filename;
argv[a] = NULL;
ret = start_run(&RS,SY_RUN_STATE_ENV|SY_RUN_STATE_INIT|
SY_ENAB_SIGINT,
argv,-1,-1);
break;
}
if (ret) {
if (usepgppass) {
write(fd[1], pgp_passphrase[v], strlen(pgp_passphrase[v]));
write(fd[1], "\n", 1); /* pgp expects this as a line terminator! */
close(fd[1]);
}
ret = wait_end(&RS,&exit_code);
Raw(ON);
} else {
Raw(ON);
if (RS.save_errno)
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmFailErrno,
"Failed: %.30s: %.40s"),
argv[0],error_description(RS.save_errno));
else
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantStart,
"Can't start %.30s"),
argv[0]);
if (usepgppass) {
close(fd[1]);
}
DestroyDynamicArray((void **)id_array); /* don't need this any more... */
if (joined)
free(joined);
return FALSE;
}
DestroyDynamicArray((void **)id_array); /* don't need this any more... */
if (joined)
free(joined);
if (ret < 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmFailSignal,
"%.30s fail: Signal?"),
argv[0]);
return FALSE;
} else if (ret > 0) {
if (RS.save_errno) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmFailErrno,
"Failed: %.30s: %.40s"),
argv[0],error_description(RS.save_errno));
return FALSE;
} else if (exit_code) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmPgpErrorStatus,
"Pgp returned error status %d"),
exit_code);
if (pgp_keeppass)
pgp_void_passphrase ();
return FALSE;
} else {
if (rename(buf, filename) < 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantRenameTmpFile,
"Could not rename temporary file!"));
return FALSE;
}
}
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmLostErrno,
"%.30s lost: %.40s"),
argv[0],error_description(RS.save_errno));
return TRUE;
}
if (was_redraw) /* FIXME: Should not needed */
menu_trigger_redraw(page);
return opts;
}
int pgp_menu (filename, headers, page)
char *filename;
struct mailing_headers *headers;
struct menu_context *page;
{
int update = TRUE;
enum pgp_version v = (enum pgp_version) give_dt_enumerate_as_int(&send_pgp_version);
enum pgp_version version;
int x_coord = 0, y_coord = 0;
int def_ans = 'q';
int LINES, COLUMNS;
menu_get_sizes(page, &LINES, &COLUMNS);
if (!(version = have_pgp(v)))
return FALSE;
for (;;) {
int ans;
if (update) {
MoveCursor (LINES-4, 0);
CleartoEOS ();
print_format_center(LINES-3,
CATGETS(elm_msg_cat, ElmSet, ElmPgpEncSign,
"e)ncrypt, s)ign, b)oth encrypt and sign or q)uit"));
menu_PutLineX (page,
LINES-4, 0, CATGETS(elm_msg_cat, ElmSet, ElmPgpP,
"pgp: "));
menu_GetXYLocation(page,
&x_coord, &y_coord);
update = FALSE;
}
menu_PutLineX (page,
x_coord, y_coord,FRM("%c"),def_ans);
menu_MoveCursor(page,x_coord, y_coord);
switch((ans = menu_ReadCh(page, REDRAW_MARK))) {
case '\n':
case '\r':
ans = def_ans;
}
if (isascii(ans) && isupper(ans))
ans = tolower(ans);
switch(ans) {
case 'e':
menu_Write_to_screen(page,
CATGETS(elm_msg_cat, ElmSet, ElmPgpEncrypt,
"Encrypt"));
return (pgp_call (filename, PGP_MESSAGE, headers, version, page));
case 's':
menu_Write_to_screen(page,
CATGETS(elm_msg_cat, ElmSet, ElmPgpSign,
"Sign"));
return (pgp_call (filename, PGP_SIGNED_MESSAGE, headers,
version, page));
case 'b':
menu_Write_to_screen(page,
CATGETS(elm_msg_cat, ElmSet, ElmPgpSignEncrypt,
"Sign and Encrypt"));
return (pgp_call (filename, PGP_MESSAGE | PGP_SIGNED_MESSAGE,
headers, version, page));
case 'q':
menu_Write_to_screen(page,
CATGETS(elm_msg_cat, ElmSet, ElmPgpQuit,
"Quit"));
return FALSE;
case REDRAW_MARK:
case ctrl('L'):
update = 1;
}
}
/* not reached */
}
void pgp_mail_public_key (mailbox, aview, page, prompt_area)
struct MailboxView *mailbox;
struct AliasView *aview;
struct menu_context *page;
struct menu_context *prompt_area;
{
/* If redraw is needed use
menu_trigger_redraw(page)
*/
int ret;
struct run_state RS;
CONST char * argv[20];
int argc = 0;
char userid[SLEN], pgpkey[SLEN], tmpfil[STRING], subj[STRING];
int status;
int need_redraw = FALSE;
enum pgp_version v = (enum pgp_version) give_dt_enumerate_as_int(&send_pgp_version);
enum pgp_version version;
int LINES, COLUMNS;
char *tmp;
tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
if (!tmp)
return;
menu_get_sizes(page, &LINES, &COLUMNS);
userid[0] = '\0';
pgpkey[0] = '\0';
if (!(version = have_pgp(v)))
return;
PutLineX(LINES-3, 0,
CATGETS(elm_msg_cat, ElmSet, ElmPgpEntUser,
"Enter userid of public key: "));
CleartoEOS ();
status = optionally_enter(userid, LINES-3, 28, OE_REDRAW_MARK|
OE_SIG_CHAR /* Ctrl-C */,
sizeof userid, page);
while(REDRAW_MARK == status) {
PutLineX(LINES-1-2, 0, CATGETS(elm_msg_cat, ElmSet, ElmPgpEntUser,
"Enter userid of public key: "));
status = optionally_enter(userid, LINES-3, 28,
OE_REDRAW_MARK|OE_APPEND_CURRENT|
OE_SIG_CHAR /* Ctrl-C */,
sizeof userid, page);
need_redraw = TRUE;
}
if ( status != 0) {
if (need_redraw)
menu_trigger_redraw(page);
menu_trigger_redraw(prompt_area);
return;
}
if (GetPGPKey(userid, pgpkey, sizeof pgpkey, version) < 0) {
print_format_center(LINES-1,
CATGETS(elm_msg_cat, ElmSet, ElmPgpSorryUserId,
"Sorry, couldn't find that userid."));
ClearLine(LINES-3);
menu_trigger_redraw(page);
return;
}
elm_sfprintf(tmpfil, sizeof tmpfil,
FRM("%selm.%d.asc"), tmp, getpid());
switch(version) {
static char path[1000];
static char buffer[200];
case pgp2:
{
char * pgp2_path_val = give_dt_estr_as_str(&pgp2_path_e, "pgp2");
if (! pgp2_path_val)
return;
argv[argc++] = pgp2_path_val;
}
argv[argc++] = "+verbose=0";
argv[argc++] = "-kxa";
argv[argc++] = pgpkey;
argv[argc++] = tmpfil;
break;
case pgp5:
{
/* give_dt_estr_as_str adds / to end */
char * pgp5_dir_val = give_dt_estr_as_str(&pgp5_dir_e,
"pgp5-dir");
if (! pgp5_dir_val)
return;
elm_sfprintf(path, sizeof path,FRM("%spgpk"),pgp5_dir_val);
}
argv[argc++] = path;
argv[argc++] = "+verbose=0";
argv[argc++] = "-x";
argv[argc++] = pgpkey;
argv[argc++] = "-o";
argv[argc++] = tmpfil;
break;
case gpg:
{
char * gpg_path_val = give_dt_estr_as_str(&gpg_path_e, "gpg");
if (! gpg_path_val)
return;
argv[argc++] = gpg_path_val;
}
argv[argc++] = "--no-verbose";
argv[argc++] = "--armor";
argv[argc++] = "--output";
argv[argc++] = tmpfil;
argv[argc++] = "--export";
elm_sfprintf(buffer, sizeof buffer,FRM("<%s>"),pgpkey);
argv[argc++] = buffer;
break;
}
argv[argc++] = NULL;
ret = start_run(&RS,SY_NOTTY,argv,-1,-1);
if (ret) {
int exit_code;
ret = run_already_done(&RS,&exit_code);
if (0 == ret) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmRunningPgp,
"Running PGP..."));
ret = wait_end(&RS,&exit_code);
}
if (ret < 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmFailSignal,
"%.30s fail: Signal?"),
argv[0]);
menu_trigger_redraw(page);
return;
} else if (ret > 0) {
if (RS.save_errno) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmFailErrno,
"Failed: %.30s: %.40s"),
argv[0],error_description(RS.save_errno));
menu_trigger_redraw(page);
return;
} else if (exit_code) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmPgpErrorStatus,
"Pgp returned error status %d"),
exit_code);
menu_trigger_redraw(page);
return;
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmPgpDone,
"Running PGP... Done."));
strfcpy(included_file,tmpfil,sizeof included_file);
}
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmLostErrno,
"%.30s lost: %.40s"),
argv[0],error_description(RS.save_errno));
menu_trigger_redraw(page);
return;
}
} else {
if (RS.save_errno)
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmFailErrno,
"Failed: %.30s: %.40s"),
argv[0],error_description(RS.save_errno));
else
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantStart,
"Can't start %.30s"),
argv[0]);
menu_trigger_redraw(page);
return;
}
/* set the default subject for this message */
elm_sfprintf(subj, sizeof subj,
CATGETS(elm_msg_cat, ElmSet, ElmPgpPublicKey,
"PGP public key for %s"),
pgpkey);
pgp_status = PGP_PUBLIC_KEY;
/* Now send the message off! */
send_msg_l(-1,NULL, NULL, subj, 0, 0, mailbox, aview,
page,
prompt_area /* XXX Redraw will be triggered anyway to page*/);
unlink (included_file); /* make sure to clean up. */
included_file[0] = '\0';
pgp_status = 0; /* reset */
menu_trigger_redraw(page);
return;
}
void pgp_extract_public_key (hdr, infile, page)
struct header_rec *hdr;
FILE *infile;
struct menu_context *page;
{
/* If redraw is needed, use
menu_trigger_redraw(page)
*/
char tempfile[STRING];
struct run_state RS;
CONST char *argv[20];
int argc = 0;
FILE *fpout;
int res;
enum pgp_version v = (enum pgp_version) give_dt_enumerate_as_int(&send_pgp_version);
enum pgp_version version;
char * tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
if (!tmp)
return;
if (!hdr)
return;
if (!(version = have_pgp(v)))
return;
elm_sfprintf(tempfile,sizeof tempfile,
FRM("%selm.%d"),tmp,getpid());
fpout=safeopen_rdwr(tempfile);
if (!fpout) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmOpenTmpWriting,
"Could not open temp file %.30s for writing!"),
tempfile);
return;
}
if (!copy_message_f(infile,hdr,
"",fpout,0,NULL)) {
fclose(fpout);
return;
}
fclose(fpout);
switch(version) {
static char path[1000];
case pgp2:
{
char * pgp2_path_val = give_dt_estr_as_str(&pgp2_path_e, "pgp2");
if (! pgp2_path_val)
return;
argv[argc++] = pgp2_path_val;
}
argv[argc++] = "+verbose=0";
argv[argc++] = "-ka";
argv[argc++] = tempfile;
break;
case pgp5:
{
/* give_dt_estr_as_str adds / to end */
char * pgp5_dir_val = give_dt_estr_as_str(&pgp5_dir_e,
"pgp5-dir");
if (!pgp5_dir_val)
return;
elm_sfprintf(path, sizeof path,FRM("%spgpk"),pgp5_dir_val);
}
argv[argc++] = path;
argv[argc++] = "+verbose=0";
argv[argc++] = "-a";
argv[argc++] = tempfile;
break;
case gpg:
{
char * gpg_path_val = give_dt_estr_as_str(&gpg_path_e, "gpg");
if (! gpg_path_val)
return;
argv[argc++] = gpg_path_val;
}
argv[argc++] = "--no-verbose";
argv[argc++] = "--import";
argv[argc++] = tempfile;
break;
}
argv[argc++] = NULL;
res=start_run(&RS,SY_CLRWAIT,argv,-1,-1);
if (res) {
int exit_code;
wait_end(&RS,&exit_code);
}
unlink(tempfile);
menu_trigger_redraw(page);
return;
}
#endif /* USE_PGP */
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1