static char rcsid[] = "@(#)$Id: syscall.c,v 1.55 2006/05/30 16:33:21 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.55 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
******************************************************************************
* The Elm Mail System
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*****************************************************************************/
/** These routines are used for user-level system calls, including the
'!' command and the '|' commands...
**/
#include "def_elm.h"
#include "s_elm.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"system");
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
#ifndef I_UNISTD
void _exit();
#endif
#ifdef ALLOW_SUBSHELL
void subshell(mailbox, page, prompt_area)
struct MailboxView *mailbox;
struct menu_context *page;
struct menu_context *prompt_area;
{
/** spawn a subshell with either the specified command
If redraw is needes use menu_trigger_redraw()
**/
char command[SLEN];
int redraw = FALSE;
int old_raw, helpful, ret, status;
struct menu_context *cpage;
int li,co;
int LINES, COLUMNS;
int line;
int ul = give_dt_enumerate_as_int(&user_level);
menu_get_sizes(prompt_area, &li, &co);
helpful = (ul == 0);
if (helpful)
menu_PutLineX(prompt_area,0, co-40,
CATGETS(elm_msg_cat, ElmSet,
ElmUseShellName,
"(Use the shell name for a shell.)"));
menu_PutLineX(prompt_area,1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmShellCommand,
"Shell command: "));
menu_CleartoEOS(prompt_area);
/* FIXME --optionally_enter* should use prompt_area */
line = menu_GetAbsLine(prompt_area,1);
command[0] = '\0';
status = optionally_enter(command, line, 15, OE_REDRAW_MARK|
OE_SIG_CHAR /* Ctrl-C */,
sizeof command, page);
while (REDRAW_MARK == status) {
menu_ClearScreen(page); /* Clear possible redraw mark */
/* Call refresh routines of children */
menu_redraw_children(page);
if (menu_need_redraw(prompt_area))
menu_ClearScreen(prompt_area); /* Clear redraw mark from prompt_area*/
/* NOTICE: using menu_trigger_redraw(page) on here
may cause redraw loop!
*/
redraw = TRUE;
menu_PutLineX(prompt_area,1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmShellCommand,
"Shell command: "));
status = optionally_enter(command, line, 15,
OE_REDRAW_MARK|OE_APPEND_CURRENT|
OE_SIG_CHAR /* Ctrl-C */,
sizeof command, page);
}
if (0 != status || command[0] == 0) {
if (helpful)
menu_MoveCursor(prompt_area,0,co-40);
else
menu_MoveCursor(prompt_area,1,0);
menu_CleartoEOS(prompt_area);
if (redraw)
menu_trigger_redraw(page);
else
menu_trigger_redraw(prompt_area);
return;
}
menu_get_sizes(page, &LINES, &COLUMNS);
menu_MoveCursor(page,LINES-1,0);
menu_CleartoEOLN(page);
if ((old_raw = RawState()) == ON)
Raw(OFF);
/* softkeys_off(); */
umask(original_umask); /* restore original umask so users new files are ok */
ret = system_call(command, SY_USER_SHELL|SY_ENAB_SIGINT|SY_DUMPSTATE,
mailbox);
umask(077); /* now put it back to private for mail files */
cpage = Raw(ON | NO_TITE);
menu_get_sizes(cpage, &LINES, &COLUMNS);
redraw2:
menu_PutLineX(cpage,LINES-1, 0, CATGETS(elm_msg_cat, ElmSet,
ElmPressAnyKeyToReturn,
"\n\nPress any key to return to ELM: "));
if (menu_ReadCh(cpage, REDRAW_MARK) == REDRAW_MARK) {
menu_ClearScreen(cpage); /* Reset possible redraw flag */
goto redraw2;
}
menu_Write_to_screen(cpage, FRM("\r\n"));
Raw(OFF | NO_TITE); /* Done even if old_raw == ON, to get ti/te right */
if (old_raw == ON)
Raw(ON);
/* softkeys_on(); */
if (ret)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmReturnCodeWas,
"Return code was %d."),
ret);
menu_trigger_redraw(page);
return;
}
#endif /* ALLOW_SUBSHELL */
/** The following might be encoded into the "options" parameter:
SY_USER_SHELL When set, we will use the user-defined
"shell" instead of "/bin/sh" for the
shell escape.
SY_ENV_SHELL When set, put "SHELL=[name-of-shell]" in
the child's environment. This hack makes
mail transport programs work right even
for users with restricted shells.
SY_ENAB_SIGHUP When set, we will set SIGHUP, SIGTSTP, and
SIGCONT to their default behaviour during
the shell escape rather than ignoring them.
This is particularly important with stuff
like `vi' so it can preserve the session on
a SIGHUP and do its thing with job control.
SY_ENAB_SIGINT This option implies SY_ENAB_SIGHUP. In
addition to the signals listed above, this
option will also set SIGINT and SIGQUIT
to their default behaviour rather than
ignoring them.
SY_DUMPSTATE Create a state file for use by the "readmsg"
program. This is so that if "readmsg" is
invoked it can figure out what folder we are
in and what message(s) are selected.
SY_ENV_METAMAIL When set, put "MM_CHARSET=[display_charset]"
to environ.
**/
int system_call(string, options, mailbox)
char *string;
VOLATILE int options;
struct MailboxView *mailbox;
{
/** execute 'string', setting uid to userid... **/
int pfd[2], stat, w;
int pid = -1;
VOLATILE int iteration;
/* figure out what shell we are using here */
S__ status;
register SIGHAND_TYPE (*istat) P_((int)), (*qstat) P_((int));
#ifdef SIGTSTP
register SIGHAND_TYPE (*oldstop) P_((int)), (*oldstart) P_((int));
#endif
char *sh = "/bin/sh";
/* flush any pending output */
FlushBuffer();
DPRINT(Debug,2, (&Debug,
"System Call: command=%s\n", string));
if (options & SY_USER_SHELL) {
char * s = give_dt_estr_as_str(&shell_e,"shell");
if (s)
sh = s;
DPRINT(Debug,2, (&Debug,
" Using user's shell=%s\n", sh));
}
/* if we aren't reading a folder then a state dump is meaningless */
if (mail_only)
options &= ~SY_DUMPSTATE;
/* see if we need to dump out the folder state */
if (mailbox && (options & SY_DUMPSTATE)) {
if (create_folder_state_file(mailbox) != 0)
return -1;
}
/*
* Note the neat trick with close-on-exec pipes.
* If the child's exec() succeeds, then the pipe read returns zero.
* Otherwise, it returns the zero byte written by the child
* after the exec() is attempted. This is the cleanest way I know
* to discover whether an exec() failed. --CHS
*/
if (pipe(pfd) == -1) {
perror("pipe");
return -1;
}
fcntl(pfd[0], F_SETFD, 1);
fcntl(pfd[1], F_SETFD, 1);
istat = signal(SIGINT, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
/* set SIGWINCH to SIG_DFL only on chlid
so that Elm will call menu_context_resize()
when it is waiting child to complete ...
*/
#ifdef SIGTSTP
oldstop = signal(SIGTSTP, SIG_DFL);
oldstart = signal(SIGCONT, SIG_DFL);
#endif
stat = -1; /* Assume failure. */
for (iteration = 0; iteration < 5; ++iteration) {
if (iteration > 0)
sleep(2);
#ifdef VFORK
if (options&SY_ENV_SHELL || options&SY_ENV_METAMAIL)
pid = fork();
else
pid = vfork();
#else
pid = fork();
#endif
if (pid != -1)
break;
}
if (pid == -1) {
perror("fork");
close(pfd[0]);
close(pfd[1]);
}
else if (pid == 0) {
/*
* Set group and user back to their original values.
* Note that group must be set first.
*/
if (-1 == setgid(groupid)) {
int err = errno;
fprintf(stderr,"system_call: setgid(%d) FAILED: %s\n",
groupid,error_description(err));
fflush(stderr);
write(pfd[1], "", 1);
_exit(127);
}
if (-1 == setuid(userid)) {
int err = errno;
fprintf(stderr,"system_call: setuid(%d) FAILED: %s\n",
userid,error_description(err));
fflush(stderr);
write(pfd[1], "", 1);
_exit(127);
}
#ifdef SIGWINCH
/* set SIGWINCH to SIG_DFL only on chlid
so that Elm will call menu_context_resize()
when it is waiting child to complete ...
*/
signal(SIGWINCH, SIG_DFL);
#endif
set_child_signals(options);
set_child_env(options);
/* Go for it. */
if (string) execl(sh, argv_zero(sh), "-c", string, (char *) 0);
else execl(sh, argv_zero(sh), (char *) 0);
/* If exec fails, we write a byte to the pipe before exiting. */
perror(sh);
write(pfd[1], "", 1);
_exit(127);
}
else {
int rd;
char ch;
/* Try to read a byte from the pipe. */
close(pfd[1]);
rd = read(pfd[0], &ch, 1);
close(pfd[0]);
while ((w = my_wait(pid,&status)) != pid)
if (w == -1 && errno != EINTR)
break;
/* If we read a byte from the pipe, the exec failed. */
if (rd > 0)
stat = -1;
else if (w == pid) {
int sig = convert_status(status,&stat);
if (sig)
stat = -1;
}
}
(void) signal(SIGINT, istat);
(void) signal(SIGQUIT, qstat);
#ifdef SIGTSTP
(void) signal(SIGTSTP, oldstop);
(void) signal(SIGCONT, oldstart);
#endif
/* cleanup any folder state file we made */
if (options & SY_DUMPSTATE)
(void) remove_folder_state_file();
return(stat);
}
void do_pipe(mailbox, page, prompt_area)
struct MailboxView *mailbox;
struct menu_context *page;
struct menu_context *prompt_area;
{
/** pipe the current message or tagged messages to
the specified sequence..
if redraw is needed use menu_trigger_redraw()
**/
char command[SLEN], buffer[SLEN], *prompt;
register int ret;
int old_raw;
int redraw = FALSE;
int status;
int LINES, COLUMNS;
struct menu_context *cpage;
int line;
char * readmsg_v = give_dt_estr_as_str(&readmsg_e, "readmsg");
if (!readmsg_v) {
return;
}
menu_get_sizes(page, &LINES, &COLUMNS);
/* TODO: Fix this mess ... */
prompt = catgets(elm_msg_cat, ElmSet, ElmPipeTo, "Pipe to: ");
menu_PutLine0(prompt_area,1, 0, prompt);
command[0] = '\0';
/* FIXME --optionally_enter* should use prompt_area */
line = menu_GetAbsLine(prompt_area,1);
status = optionally_enter(command, line, strlen(prompt),
OE_REDRAW_MARK|
OE_SIG_CHAR /* Ctrl-C */, sizeof command,
page);
while (status == REDRAW_MARK) {
menu_ClearScreen(page); /* Clear possible redraw mark */
/* Call refresh routines of children */
menu_redraw_children(page);
if (menu_need_redraw(prompt_area))
menu_ClearScreen(prompt_area); /* Clear redraw mark from prompt_area*/
/* NOTICE: using menu_trigger_redraw(page) on here
may cause redraw loop!
*/
redraw = TRUE;
menu_PutLine0(prompt_area,1, 0, prompt);
status = optionally_enter(command, line, strlen(prompt),
OE_REDRAW_MARK|OE_APPEND_CURRENT|
OE_SIG_CHAR /* Ctrl-C */,
sizeof command, page);
}
if (0 != status || command[0] == '\0') {
menu_MoveCursor(prompt_area,1,0);
menu_CleartoEOLN(prompt_area);
if (redraw)
menu_trigger_redraw(page);
else
menu_trigger_redraw(prompt_area);
return;
}
MoveCursor(LINES-1,0);
CleartoEOLN();
if (( old_raw = RawState()) == ON)
Raw(OFF);
sprintf(buffer, "%s -Irh|%s", readmsg_v, command);
ret = system_call(buffer, SY_USER_SHELL|SY_ENAB_SIGINT|SY_DUMPSTATE,
mailbox);
cpage = Raw(ON | NO_TITE);
menu_get_sizes(cpage, &LINES, &COLUMNS);
redraw2:
InvalidateLocation();
menu_PutLineX(cpage,LINES-1, 0,
CATGETS(elm_msg_cat, ElmSet,
ElmPressAnyKeyToReturn,
"\n\nPress any key to return to ELM: "));
if (menu_ReadCh(cpage, REDRAW_MARK) == REDRAW_MARK) {
menu_ClearScreen(cpage); /* Reset possible redraw flag */
goto redraw2;
}
menu_Write_to_screen(cpage,FRM("\r\n"));
Raw(OFF | NO_TITE); /* Done even if old_raw == ON, to get ti/te right */
if (old_raw == ON)
Raw(ON);
if (ret != 0)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmReturnCodeWas,
"Return code was %d."),
ret);
menu_trigger_redraw(page);
return;
}
char * have_printout() {
char * printout_val = give_dt_estr_as_str(&printout_e,"print");
char * return_value = printout_val;
if (! printout_val ||
strcmp(printout_val,"none") == 0 ||
printout_val[0] == '\0') {
return_value = NULL;
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPrintDontKnowHow,
"Don't know how to print - option \"print\" undefined!"));
} else if (printout_val[0] == '/') {
char *test = safe_strdup(printout_val),*ptr;
if (NULL != (ptr = strpbrk(test," \t;|")))
*ptr = '\0';
DPRINT(Debug,5, (&Debug,
"have_printout(%s) -- test=%s\n",
printout_val,test));
if (-1 == access(test,EXECUTE_ACCESS)) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPrintCantExecute,
"Can't execute \"print\": %.50s: %.30s"),
test, error_description(err));
DPRINT(Debug,5, (&Debug,
"have_printout: no access %s: %s\n",test,
error_description(err)));
sleep_message();
return_value = NULL;
}
free(test);
}
DPRINT(Debug,5, (&Debug,
"have_printout=%s\n",
return_value ? return_value : "<NULL>"));
return return_value;
}
void print_text(pause_on_scroll, mailbox, page, header_area)
int pause_on_scroll;
struct MailboxView *mailbox;
struct menu_context *page;
struct menu_context *header_area;
{
/* If redraw is needed use
menu_trigger_redraw(page)
*/
int tagged = 0, i, old_raw;
int redraw_it = 0;
char *fname = NULL;
char * cmd = NULL;
FILE * tmpfp = NULL;
int nlines = 0;
char buffer[STRING];
int retcode = -1;
int res = 0;
struct run_state RS;
CONST char * argv[4];
int mc;
struct menu_common MENU;
int LINES, COLUMNS;
char *tmp;
char * printout_val;
menu_get_sizes(page,&LINES, &COLUMNS);
set_mcommon_from_mbxview(&MENU,mailbox);
/*
* Make sure we know how to print.
*/
if (!(printout_val=have_printout()) || !mailbox)
return;
tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
if (!tmp)
return;
fname = elm_message(FRM("%sprintdecode-%d"),
tmp, getpid ());
if (NULL == (tmpfp = safeopen_rdwr(fname))) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCreate,
"Failed to create file for decoding."));
goto clean;
}
mc = get_message_count(mailbox);
for (i=0; i < mc; i++) {
if (ison_status_message(mailbox,i,status_basic,TAGGED)) {
tagged++;
}
}
if (tagged == 0) {
int current = get_current(mailbox);
tagged = 1;
setf_status_message(mailbox,current-1,status_basic,TAGGED);
}
for (i=0; i < mc; i++) {
if (ison_status_message(mailbox,i,status_basic,TAGGED)) {
struct header_rec * hdr;
FILE *F;
/* save each tagged msg */
if (give_message_data(mailbox,i,&hdr,&F,NULL,
mime_parse_routine)) {
if (!copy_message_f(F,hdr,
"", tmpfp,
CM_DECODE | CM_FILT_HDR |
CM_REMOVE_ENVELOPE,
system_charset)) {
/* FAIL */
fclose(tmpfp);
goto clean_1;
}
/* Need redraw -- PGP output ?*/
if (raw_off_called()) {
redraw_it = TRUE;
}
clearf_status_message(mailbox,i,status_basic,TAGGED);
if (!redraw_it) {
if (header_area) {
struct menu_common MENU;
int vis;
set_mcommon_from_mbxview(&MENU,mailbox);
vis = compute_visible(i+1, &MENU);
/* update screen, if needed */
menu_header_status_update(header_area,vis-1);
}
}
}
}
}
if (EOF == fclose(tmpfp))
goto clean_1;
/*
* Setup print command. Select old or new behavior based
* upon the presence of "%s" in the print command string.
*/
if (in_string(printout_val, "%s")) {
cmd = elm_message(FRM(printout_val), fname);
} else {
cmd = elm_message(FRM("(%s) < %s"),printout_val,fname);
}
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = cmd;
argv[3] = NULL;
/*
* Put keyboard into normal state.
*/
if ((old_raw = RawState()) == ON) {
/* SY_NOTTY causes that run_state does not reposition cursor ... */
MoveCursor(LINES-3,0); CleartoEOS();
Raw(OFF | NO_TITE);
}
/* softkeys_off(); */
/*
* Run the print command in a pipe and grab the output.
*/
res = start_run(&RS,
SY_ENAB_SIGHUP|SY_ENAB_SIGINT|
SY_RUN_STATE_OPIPE|SY_RUN_STATE_EPIPE|
SY_NOTTY,
argv,-1,-1);
if (0 == res) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPrintPipeFailed,
"Cannot create pipe to print command."));
goto clean_2;
}
while (fgets(buffer, sizeof(buffer), RS.pfd) != NULL) {
fputs(buffer, stdout);
++nlines;
}
DPRINT(Debug,4, (&Debug, "print_msg: nlines=%d\n", nlines));
/*
* See if there were enough lines printed to trash the screen.
*/
if (pause_on_scroll && nlines > 1) {
struct menu_context *cpage;
cpage = Raw(ON | NO_TITE);
menu_get_sizes(cpage,&LINES, &COLUMNS);
redraw:
menu_Write_to_screen(cpage,
CATGETS(elm_msg_cat, ElmSet, ElmPrintPressAKey,
"\nPress any key to continue:"));
FlushBuffer();
if (menu_ReadCh(cpage,REDRAW_MARK) == REDRAW_MARK) {
menu_ClearScreen(cpage); /* Reset possible redraw flag */
redraw_it = TRUE;
goto redraw;
}
Raw(OFF | NO_TITE);
}
if (0 != (res = wait_end(&RS,&retcode))) {
/*
* Display a status message.
*/
Raw(old_raw | NO_TITE);
if (res > 0) { /* ret < 0 is signal ... */
if (retcode == 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPrintJobSpooled,
"Print job has been spooled."));
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPrintFailStatus,
"Printout failed with status 0x%04x."),
(retcode));
}
}
} else
Raw(old_raw | NO_TITE);
/*
* Hack alert: The only place we use "pause_on_scroll" false is when
* printing while reading a mail message. This newline prevents the
* above message from being wiped out by the command prompt.
*/
if (!pause_on_scroll)
menu_Write_to_screen(page,FRM("\n"));
if (nlines> 1)
redraw_it = 1;
clean_2:
free(cmd);
clean_1:
unlink(fname);
clean:
if (fname)
free(fname);
return;
}
void print_msg(pause_on_scroll, mailbox, page)
int pause_on_scroll;
struct MailboxView *mailbox;
struct menu_context *page;
{
/*
* Print the tagged messages, or the current message if none are
* tagged. Message(s) are passed passed into the command specified
* by "printout". An error is given if "printout" is undefined.
*
* Printing will be done through a pipe so we can print the number
* of lines output. This is used to determine whether the screen
* got trashed by the print command. One limitation is that only
* stdout lines are counted, not stderr output.
*
* If redraw is needed use
* menu_trigger_redraw(page)
*
* Further, if the display is trashed and "pause_on_scroll"
* is true then we'll give a "hit any key" prompt before returning.
*
* This routine has two modes of behavior, depending upon whether
* there is a "%s" embedded in the "printout" string. If there,
* the old Elm behavior is used (a temp file is used, all output
* from the print command is chucked out). If there isn't a "%s"
* then the new behavior is used (message(s) piped right into
* print command, output is left attached to the terminal).
*
* The old behaviour is bizarre. I hope we can ditch it someday.
*/
char buffer[STRING];
int nlines, retcode, old_raw;
char * filename = NULL;
int res = 0;
struct run_state RS;
CONST char * argv[4];
char * printout_val;
int LINES, COLUMNS;
char * readmsg_v = give_dt_estr_as_str(&readmsg_e, "readmsg");
if (!readmsg_v) {
return;
}
menu_get_sizes(page, &LINES, &COLUMNS);
DPRINT(Debug,4, (&Debug,
"print_msg: pause_on_scroll=%d\n",
pause_on_scroll));
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = buffer;
argv[3] = NULL;
/*
* Make sure we know how to print.
*/
if (!(printout_val=have_printout()))
return;
/*
* Setup print command. Select old or new behavior based
* upon the presence of "%s" in the print command string.
*/
if (in_string(printout_val, "%s")) {
char * printbuffer;
char * tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
if (!tmp)
tmp = "/tmp/";
/*
* Temp file name used by "old style" printing.
*/
filename = elm_message(FRM("%s%s%d"),
tmp, temp_print, getpid());
printbuffer = elm_message(FRM(printout_val), filename);
elm_sfprintf(buffer,sizeof buffer,
FRM("%s -Ip > %s; %s"),
readmsg_v, filename, printbuffer);
free(printbuffer);
} else {
elm_sfprintf(buffer,sizeof buffer,
FRM("%s -Ip | %s"), readmsg_v, printout_val);
}
/*
* Create information for "readmsg" command.
* -- start_run() does not support SY_DUMPSTATE
*/
if (create_folder_state_file(mailbox) != 0)
goto free_it;
/*
* Put keyboard into normal state.
*/
if ((old_raw = RawState()) == ON) {
/* SY_NOTTY causes that run_state does not reposition cursor ... */
MoveCursor(LINES-3,0); CleartoEOS();
Raw(OFF | NO_TITE);
}
/* softkeys_off(); */
/*
* Run the print command in a pipe and grab the output.
*/
nlines = 0;
res = start_run(&RS,
SY_ENAB_SIGHUP|SY_ENAB_SIGINT|
SY_RUN_STATE_OPIPE|SY_RUN_STATE_EPIPE|
SY_NOTTY,
argv,-1,-1);
if (0 == res) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPrintPipeFailed,
"Cannot create pipe to print command."));
goto done;
}
while (fgets(buffer, sizeof(buffer), RS.pfd) != NULL) {
fputs(buffer, stdout);
++nlines;
}
DPRINT(Debug,4, (&Debug,
"print_msg: nlines=%d\n", nlines));
/*
* See if there were enough lines printed to trash the screen.
*/
if (pause_on_scroll && nlines > 1) {
struct menu_context *cpage;
cpage = Raw(ON | NO_TITE);
menu_get_sizes(cpage, &LINES, &COLUMNS);
redraw:
menu_Write_to_screen(cpage,
CATGETS(elm_msg_cat, ElmSet, ElmPrintPressAKey,
"\nPress any key to continue:"));
FlushBuffer();
if (menu_ReadCh(page,REDRAW_MARK) == REDRAW_MARK) {
menu_ClearScreen(page); /* Reset possible redraw flag */
nlines = 2;
goto redraw;
}
Raw(OFF | NO_TITE);
}
if (0 != (res = wait_end(&RS,&retcode))) {
/*
* Display a status message.
*/
Raw(old_raw | NO_TITE);
if (res > 0) { /* ret < 0 is signal ... */
if (retcode == 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPrintJobSpooled,
"Print job has been spooled."));
} else {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPrintFailStatus,
"Printout failed with status 0x%04x."),
(retcode));
}
}
} else
Raw(old_raw | NO_TITE);
/*
* Hack alert: The only place we use "pause_on_scroll" false is when
* printing while reading a mail message. This newline prevents the
* above message from being wiped out by the command prompt.
*/
if (!pause_on_scroll)
menu_Write_to_screen(page,FRM("\n"));
done:
/* softkeys_on(); */
if (filename) {
(void) unlink(filename);
free(filename);
}
(void) remove_folder_state_file();
if (nlines > 1)
menu_trigger_redraw(page);
free_it:
return;
}
static char folder_state_env_param[SLEN], *folder_state_fname;
/*
* Setup a folder state file for external utilities (e.g. "readmsg").
* Returns zero if the file was created, -1 if an error occurred. A
* diagnostic will have been printed on an error return.
*
* The state file contains the following:
*
* - An "F" record with the pathname to the current folder.
*
* - An "N" record with a count of the number of messages in the folder.
*
* - A set of "I" records indicating the seek index of the messages
* in the folder. The first "I" record will contain the seek index
* of message number one, and so on. The "I" records will be in
* sorting order and not necessarily mbox order. The number of "I"
* records will match the value indicated in the "N" record.
*
* - A "C" record with a count of the total number of messages selected.
*
* - A set of "S" records indicating message number(s) which have been
* selected. If messages have been tagged then there will be one
* "S" record for each selected message. If no messages have been
* tagged then either: there will be a single "S" record with the
* current message number, or there will be no "S" records if the
* folder is empty. The number of "S" records will match the value
* indicated in the "C" record.
*/
int create_folder_state_file(mailbox)
struct MailboxView *mailbox;
{
int count, i;
FILE *fp;
int sc;
/* format an environ param with the state file and pick out file name */
sprintf(folder_state_env_param, "%s=%s%s%d",
FOLDER_STATE_ENV, default_temp, temp_state, getpid());
folder_state_fname = folder_state_env_param + strlen(FOLDER_STATE_ENV) +1;
/* open up the folder state file for writing */
if ((fp = safeopen(folder_state_fname)) == NULL) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotCreateFolderState,
"Cannot create folder state file \"%s\"."),
folder_state_fname);
return -1;
}
write_mailbox_info(fp,mailbox);
/* file is done */
(void) fclose(fp);
/* put pointer to the file in the environment */
if (putenv(folder_state_env_param) != 0) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCannotCreateEnvParam,
"Cannot create environment parameter \"%s\"."),
FOLDER_STATE_ENV);
return -1;
}
return 0;
}
int remove_folder_state_file()
{
/*
* We simply leave the FOLDER_STATE_ENV environment variable set.
* It's too much work trying to pull it out of the environment, and
* the load_folder_state_file() does not mind if the environment
* variable points to a non-existent file.
*/
return unlink(folder_state_fname);
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1