[comp.sources.unix] v14i035: Mail User's Shell, version 6.0, Part03/14

rsalz@bbn.com (Rich Salz) (04/14/88)

Submitted-by: island!argv@sun.com (Dan Heller)
Posting-number: Volume 14, Issue 35
Archive-name: mush6.0/part03



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 14)."
# Contents:  curs_io.c dates.c execute.c file.c main_panel.c signals.c
# Wrapped by rsalz@fig.bbn.com on Wed Apr 13 20:04:43 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'curs_io.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'curs_io.c'\"
else
echo shar: Extracting \"'curs_io.c'\" \(7380 characters\)
sed "s/^X//" >'curs_io.c' <<'END_OF_FILE'
X/* @(#)curs_io.c	(c) copyright 3/18/87 (Dan Heller) */
X
X/* curs_io.c -- curses based I/O */
X#include "mush.h"
X
X#ifdef CURSES
X#include "bindings.h"
X#endif /* CURSES */
X
char *_unctrl[] = {
X    "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "^I", "^J", "^K",
X    "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V", "^W",
X    "^X", "^Y", "^Z", "^[", "^\\", "^]", "^~", "^_",
X    " ", "!", "\"", "#", "$",  "%", "&", "'", "(", ")", "*", "+", ",", "-",
X    ".", "/", "0",  "1", "2",  "3", "4", "5", "6", "7", "8", "9", ":", ";",
X    "<", "=", ">",  "?", "@",  "A", "B", "C", "D", "E", "F", "G", "H", "I",
X    "J", "K", "L",  "M", "N",  "O", "P", "Q", "R", "S", "T", "U", "V", "W",
X    "X", "Y", "Z",  "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e",
X    "f", "g", "h",  "i", "j",  "k", "l", "m", "n", "o", "p", "q", "r", "s",
X    "t", "u", "v",  "w", "x",  "y", "z", "{", "|", "}", "~", "^?"
X};
X
X#ifdef Addch
X#undef Addch
X#endif /* Addch */
X
X#ifndef CURSES
X
X#define Addch(c) if (isoff(glob_flags, ECHO_FLAG)) \
X		      fputc(c, stdout), fflush(stdout)
X
X#else
X
X/* see end of Getstr */
X#define Addch(c)  \
X    if (iscurses) \
X	addch(c), refresh(); \
X    else if (isoff(glob_flags, ECHO_FLAG)) \
X	fputc(c, stdout), fflush(stdout)
X#endif /* CURSES */
X
X/*
X * get a string of at most 'length' chars.
X * allow backspace-space-backspace, kill word and kill line
X * (options set by user in stty).
X * length is the max length this string can get. offset is from beginning
X * of string.
X * input of ^D returns -1; otherwise, return the number of chars in string.
X */
Getstr(String, length, offset)
char String[];
register int length;
X{
X    register int c, literal_next = FALSE;
X    int count = offset;
X
X    while ((c = getchar()) != '\n' && c != '\r' && c != EOF &&
X	isoff(glob_flags, WAS_INTR)) {
X	/* echo isn't set, so whatever the character, enter it */
X	if (ison(glob_flags, ECHO_FLAG))
X	    if (count < length)
X		String[count++] = c;
X	    else {
X		print("Warning: string too long. Truncated at %d chars.\n",
X		    length);
X		break;
X	    }
X	/* ^D as the first char on a line or two ^D's in a row is EOF */
X	else if (c == CTRL(D) && !count)
X	    break;
X	else if (c == '\\') {
X	    literal_next = TRUE;
X	    Addch(String[count++] = '\\');
X	} else if (literal_next) {
X	    literal_next = FALSE;
X	    if (iscntrl(c) || c == _tty.sg_kill || c == _tty.sg_erase
X#ifdef TIOCGLTC
X    		|| c == ltchars.t_werasc
X#endif /* TIOCGLTC */
X					 )
X		backspace(String, &count);
X	    String[count++] = c;
X	    if (iscntrl(c) || c == _tty.sg_erase) {
X		if (iscntrl(c))
X		    Addch('^');
X		Addch(_unctrl[c][1]);
X	    } else
X		Addch(c);
X	} else if (c == _tty.sg_erase || c == CTRL(H) || c == 127 /*CTRL(?)*/) {
X	    if (count)
X		backspace(String, &count);
X	    /* if iscurses, then backspacing too far is cancelling a function */
X	    else if (!count && iscurses) {
X		String[0] = '\0';
X		return -1;
X	    }
X	} else if (c == _tty.sg_kill) {
X	    if (count) {
X		do backspace(String, &count);
X		while (count);
X	    }
X	} else
X#ifndef TIOCGLTC
X	if (c == CTRL(R)) /* system doesn't have ltchars */
X#else
X	if (c == ltchars.t_rprntc) /* reprint line */
X#endif /* TIOCGLTC */
X	    String[count] = 0, printf("\n%s", String);
X        else
X#ifndef TIOCGLTC
X	if (c == CTRL(W)) /* system doesn't have ltchars */
X#else
X	if (c == ltchars.t_werasc) /* word erase */
X#endif /* TIOCGLTC */
X	    while (count) {
X		backspace(String, &count);
X		if (!count ||
X		    isspace(String[count-1]) && !isspace(String[count]) ||
X		    !isalnum(String[count-1]) && isalnum(String[count]))
X		    break;
X	    }
X	else if (c == '\t')
X	    do  {
X		Addch(' ');
X		String[count] = ' ';
X	    } while (++count % 8 && count < length);
X	else if (count == length)
X	    bell();
X	else {
X	    String[count++] = c;
X	    if (c != '\t' && iscntrl(c)) {
X		Addch('^');
X		Addch(_unctrl[c][1]);
X	    } else
X		Addch(c);
X	}
X    }
X    if (c == CTRL(D) || c == EOF || ison(glob_flags, WAS_INTR)) {
X	if (feof(stdin))
X	    clearerr(stdin);
X	return -1;
X    }
X    if (count && String[count-1] == '\\') {
X	int count2;
X	if (isoff(glob_flags, ECHO_FLAG))
X	    putchar('\n');
X	if ((count2 = Getstr(&String[count-1], length - count + 1, 0)) == -1)
X	    return -1;
X	return count + count2;
X    }
X    if (!iscurses && isoff(glob_flags, ECHO_FLAG))
X	putchar('\n');
X    while (count > 0 && isspace(String[count-1]))
X	--count;
X    String[count] = 0;
X    return count;
X}
X
static
backspace(str, n)
register char *str;
int *n;
X{
X    (*n)--;
X    Addch('\b'); Addch(' '); Addch('\b');
X    if (iscntrl(str[*n])) {
X	Addch('\b'); Addch(' '); Addch('\b');
X    }
X}
X
X#undef Addch
X
X#ifdef CURSES
X/*
X * prompt for a carriage return, but return whatever user types unless
X * it's a character which he might regret (like 'q' or 'x'). Ignore
X * interrupts (kind of) because we have nowhere to longjmp to.  When we
X * return, we'll setjmp again (top of loop.c)
X */
hit_return()
X{
X    int c;
X
X    turnon(glob_flags, IGN_SIGS);
X    iscurses = FALSE;
X    (void) check_new_mail();
X    iscurses = TRUE;
X    mail_status(1), addstr("...continue... "), refresh();
X    c = getcmd();
X    turnoff(glob_flags, IGN_SIGS);
X
X    /* don't let the user type something he might regret */
X    if (c == C_QUIT || c == C_EXIT)
X	return C_NULL;
X    return c;
X}
X
curses_msg_list(str, list, m_list)
register char *str, *list;
char m_list[];
X{
X    register char *p = NULL;
X    int c;
X
X    print(str);
X    c = Getstr(list, COLS-13, 0);
X    move(LINES-1, 0), refresh();
X    if (c <= 0 || !(p = do_range(list, m_list)) ||
X	(p == list && *p && *p != '$' && *p != '^')) {
X	if (p)
X	    print("Invalid message list: %s", p);
X	return 0;
X    }
X    return 1;
X}
X
curs_vars(which)
int which;  /* really, a char */
X{
X    char c, buf[128], buf2[128], *string;
X    struct options **list;
X
X    switch(which) {
X	case C_OWN_HDR : string = "my_hdr", list = &own_hdrs;
X	when C_ALIAS : string = "alias", list = &aliases;
X	when C_IGNORE : string = "ignore", list = &ignore_hdr;
X	when C_VAR_SET : string = "set", list = &set_options;
X	otherwise : clr_bot_line(); return;
X    }
X
X    print("%s [? Set Unset All]: ", string);
X    c = getchar();
X    clr_bot_line();
X    switch (Lower(c)) {
X	/* if help, print help -- if "all", show all settings. */
X	case '?' : case 'a' :
X	    if (c == '?') {
X		if (!strcmp(string, "set")) {
X		    print("which variable? [all <var>]: ");
X		    if ((c = Getstr(buf+1, COLS-40, 0)) < 0)
X			return;
X		    clr_bot_line();
X		    buf[0] = '?';
X		    if (c > 0) {
X			char *argv[3];
X			argv[0] = string;
X			argv[1] = buf;
X			argv[2] = NULL;
X			Lower(buf[1]);
X			if (!strcmp(buf+1, "a"))
X			    (void) strcpy(buf+1, "all");
X			if (!strcmp(buf+1, "all"))
X			    turnon(glob_flags, CNTD_CMD);
X			(void) set(2, argv);
X			return;
X		    }
X		}
X		/* help returns next command (hit_return) */
X		help(0, string, cmd_help);
X		turnon(glob_flags, CNTD_CMD);
X		return;
X	    }
X	    turnon(glob_flags, CNTD_CMD);
X	    (void) do_set(*list, NULL);
X
X	/* if set, prompt for string and let user type */
X	when 's' :
X	    print("set: ");
X	    c = Getstr(buf, COLS-18, 0);
X	    clr_bot_line();
X	    if (c > 0)
X		(void) cmd_line(sprintf(buf2, "%s %s", string, buf), msg_list);
X
X	/* if unset, just as easy as set! */
X	when 'u' :
X	    print("unset: ", string);
X	    if (Getstr(buf, COLS-18, 0) > 0 && !un_set(list, buf))
X		print("%s isn't set", buf);
X    }
X    if (ison(glob_flags, CNTD_CMD))
X	putchar('\n');
X}
X
X#endif /* CURSES */
END_OF_FILE
if test 7380 -ne `wc -c <'curs_io.c'`; then
    echo shar: \"'curs_io.c'\" unpacked with wrong size!
fi
# end of 'curs_io.c'
fi
if test -f 'dates.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dates.c'\"
else
echo shar: Extracting \"'dates.c'\" \(7499 characters\)
sed "s/^X//" >'dates.c' <<'END_OF_FILE'
X/* @(#)dates.c	1.1	(c) copyright 10/15/86 (Dan Heller) */
X
X#include "mush.h"
X
char *day_names[] = {
X    "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"
X};
char *month_names[] = {     /* imported in pick.c */
X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
X};
X
X/* Time() returns a string according to criteria:
X *   if "now" is 0, then the current time is gotten and used.
X *       else, use the time described by now
X *   opts points to a string of args which is parsed until an unknown
X *       arg is found and opts will point to that upon return.
X *   valid args are T (time of day), D (day of week), M (month), Y (year),
X *       N (number of day in month -- couldn't think of a better letter).
X */
char *
Time(opts, now)
register char *opts;
long now;
X{
X    static char time_buf[30];
X    struct tm 	  *T;
X    register char *p = time_buf;
X    long	  x;
X
X    if (!opts)
X	return NULL;
X    if (now)
X	x = now;
X    else
X	(void) time(&x);
X    T = localtime(&x);
X    for (;; opts++) {
X	switch(*opts) {
X	    case 'T':
X		if (ison(glob_flags, MIL_TIME))
X		    (void) sprintf(p, "%2d:%02d", T->tm_hour, T->tm_min);
X		else
X		    (void) sprintf(p, "%d:%02d", (T->tm_hour) ?
X			  ((T->tm_hour <= 12) ? T->tm_hour : T->tm_hour - 12) :
X			  12, T->tm_min);
X	    when 'D': (void) strcpy(p, day_names[T->tm_wday]);
X	    when 'M': (void) strcpy(p, month_names[T->tm_mon]);
X	    when 'Y': (void) sprintf(p, "%d", T->tm_year);
X	    when 'N': (void) sprintf(p, "%d", T->tm_mday);
X	    otherwise: *--p = 0; return time_buf;
X	}
X	p += strlen(p);
X	*p++ = ' ';
X    }
X}
X
X/* find the date of a message and return a string of the same form
X * described by parse_date() below.
X */
char *
msg_date(n)
register int n;
X{
X    register char *p, *p2 = NULL;
X    char line[BUFSIZ];
X
X    /* not in use */
X    /* try the easy way out first -- This is potentially a serious kludge
X     * because not all message-id lines are right. -- most of the time,
X     * this is correct.  it's not correct from messages from strange
X     * mailers (non-sendmail) they do a different format in message-id.
X    if ((p = header_field(n, "message-id")) && (p2 = index(p, '<'))) {
X	p = p2+1;
X	if (p2 = index(p, '.')) {
X	    *p2 = 0;
X	    return p;
X	}
X    }
X     */
X
X    /* else, get the "date" line, if that fails, get the date in "From" line */
X    if ((p = header_field(n, "date")) && (p2 = parse_date(p)))
X	return p2;
X
X    (void) fseek(tmpf, msg[n].m_offset, L_SET);
X    (void) fgets(line, BUFSIZ, tmpf);
X    if (!(p = index(line, ' ')) || !(p2 = index(p+1, ' ')))
X	return NULL;
X    p = p2;
X
X    if (!(p2 = parse_date(p)))
X	print("Message %d has bad date: %s\n", n+1, p);
X    return p2;
X}
X
X/* parse date and return a string that looks like
X *    "%2d%2d%2d%2d%2d", yr,mo,date,hrs,mins
X */
char *
parse_date(p)
register char *p;
X{
X    /* If it's not a month, it can get _long_.  this is also the static
X     * buffer whose address we return.
X     */
X    static char month[64];
X    int Month = 0, Day = 0, Year = 0, Hours = -1, Mins = -1;
X
X    skipspaces(0);
X
X    /* Possible combinations that we could have:
X     *   day_number month_name year_number time timezone ...
X     *   day_name month_name day_number time year_number
X     *   day_name month_name day_number year_number time
X     *   day_name day_number month_name year_number time
X     *   day_number month_name year_number time
X     *   day_number month_name year_number time-timezone (day)
X     *                                       ^no colon separator
X     *   day_name month_name day_number time timezone year_number
X     *   day_number-month_name-year time
X     *   day_name, day_number-month_name-year time
X     *   day_number month_name year_number, time "-"
X     */
X    /* programmer's note -- there are too many scanfs here for some compilers
X     * to put them all into one if statement.  Use goto's :-(
X     */
X    if (sscanf(p, "%*s %s %d %d %d:%d", month,&Day,&Year,&Hours,&Mins) == 5)
X	goto gotit;
X    if (sscanf(p, "%d %s %d %d:%d", &Day,month,&Year,&Hours,&Mins) == 5)
X	goto gotit;
X    if (sscanf(p, "%*s %s %d %d:%d:%*d %d", month,&Day,&Hours,&Mins,&Year) == 5)
X	goto gotit;
X    if (sscanf(p, "%*s %d %s %d %d:%d", &Day,month,&Year,&Hours,&Mins) == 5)
X	goto gotit;
X    if (sscanf(p, "%d %s %d %d:%d", &Day,month,&Year,&Hours,&Mins) == 5)
X	goto gotit;
X    if (sscanf(p, "%d %s %d %2d%2d", &Day,month,&Year,&Hours,&Mins) == 5)
X	goto gotit;
X    if (sscanf(p, "%*s %s %d %d:%d:%*d %*s %d",
X					month, &Day, &Hours, &Mins, &Year) == 5)
X	goto gotit;
X    if (sscanf(p, "%*s %s %d %d:%d %*s %d",
X					month, &Day, &Hours, &Mins, &Year) == 5)
X	goto gotit;
X    if (sscanf(p,"%d-%[^-]-%d %d:%d", &Day, month, &Year, &Hours, &Mins) == 5)
X	goto gotit;
X    if (sscanf(p,"%d %s %d, %d:%d:%*d -",&Day, month, &Year, &Hours, &Mins)== 5)
X	goto gotit;
X    if (sscanf(p,"%*s %d-%[^-]-%d %d:%d",&Day, month, &Year, &Hours, &Mins)== 5)
X	goto gotit;
X    goto didnt_getit;
gotit:
X    if (Year > 1900)
X	Year -= 1900;
X    if ((Month = month_to_n(month)) == -1) {
X	print("bad month: %s\n", p);
X	return NULL;
X    }
X    return sprintf(month, "%02d%02d%02d%02d%02d", Year,Month,Day,Hours,Mins);
didnt_getit:
X    if (ison(glob_flags, WARNING))
X	print("Unknown date format: %s\n", p);
X    return NULL;
X}
X
X/* pass a string in the form described above, put into string.
X * return values in buffers provided they are not null.
X */
char *
date_to_string(Date, Yr, Mon, Day, Wkday, Tm, ret_buf)
char *Date, *Yr, *Mon, *Day, *Wkday, *Tm, *ret_buf;
X{
X
X    static int mtbl[]={0,31,59,90,120,151,181,212,243,273,304,334};
X    unsigned int days_ctr;
X    int yr, mon, day, hr, mins;
X    char a_or_p, *p = ret_buf;
X
X    (void) sscanf(Date, "%2d%2d%2d%2d%02d", &yr, &mon, &day, &hr, &mins);
X    a_or_p = (hr < 12)? 'a': 'p';
X
X    if (Wkday) {
X    	days_ctr = ((yr * 365) + ((yr + 3) / 4) + mtbl[mon-1] + day + 6);
X    	if (mon > 2 && (yr % 4 == 0))
X	    days_ctr++;
X    	(void) (sprintf(Wkday, "%.3s", day_names[days_ctr % 7]));
X    }
X    if (Yr)
X	(void) sprintf(Yr, "19%d", yr);
X    if (Day)
X	(void) sprintf(Day, "%d", day);
X    if (Mon)
X	(void) strcpy(Mon, month_names[mon-1]);
X    p += strlen(sprintf(p, "%s %2.d, ", month_names[mon-1], day));
X    if (ison(glob_flags, MIL_TIME))
X	(void) sprintf(p, "%2d:%02d",hr,mins);
X    else
X	(void) sprintf(p, "%2.d:%02d%cm",
X	      (hr)? (hr <= 12)? hr: hr - 12: 12, mins, a_or_p);
X    if (Tm)
X	(void) strcpy(Tm, p);
X    return ret_buf;
X}
X
X#define JAN	1
X#define FEB	2
X#define MAR	3
X#define APR	4
X#define MAY	5
X#define JUN	6
X#define JUL	7
X#define AUG	8
X#define SEP	9
X#define OCT	10
X#define NOV	11
X#define DEC	12
X
X/* stolen direct from ELM */
month_to_n(name)
register char *name;
X{
X    /** return the month number given the month name... **/
X
X    register char ch;
X
X    switch (lower(*name)) {
X	case 'a' : if ((ch = lower(name[1])) == 'p')
X		       return(APR);
X		   else if (ch == 'u')
X		       return(AUG);
X		   else return(-1);	/* error! */
X	case 'd' : return(DEC);
X	case 'f' : return(FEB);
X	case 'j' : if ((ch = lower(name[1])) == 'a')
X		       return(JAN);
X		   else if (ch == 'u') {
X		     if ((ch = lower(name[2])) == 'n')
X			 return(JUN);
X		     else if (ch == 'l')
X			 return(JUL);
X		     else return(-1);		/* error! */
X		   }
X		   else return(-1);		/* error */
X	case 'm' : if ((ch = lower(name[2])) == 'r')
X		       return(MAR);
X		   else if (ch == 'y')
X		       return(MAY);
X		   else return(-1);		/* error! */
X	case 'n' : return(NOV);
X	case 'o' : return(OCT);
X	case 's' : return(SEP);
X	default  : return(-1);
X    }
X}
END_OF_FILE
if test 7499 -ne `wc -c <'dates.c'`; then
    echo shar: \"'dates.c'\" unpacked with wrong size!
fi
# end of 'dates.c'
fi
if test -f 'execute.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'execute.c'\"
else
echo shar: Extracting \"'execute.c'\" \(5679 characters\)
sed "s/^X//" >'execute.c' <<'END_OF_FILE'
X/* execute.c 	(c) copyright	10/28/86 (Dan Heller) */
X
X#include "mush.h"
X#ifdef BSD
X#include <sys/wait.h>
X#else
X#ifndef SYSV
X#include <wait.h>
X#endif /* SYSV */
X#endif /* BSD */
X
X#ifdef lint
X#include <sys/resource.h>
X#endif /* lint */
X
execute(argv)
char **argv;
X{
X#ifdef SYSV
X    int status;
X#else
X    union wait status;
X#endif /* SYSV */
X#ifdef SIGCONT
X    int	(*oldstop)(), (*oldcont)();
X#endif /* SIGCONT */
X    int pid, (*oldint)(), (*oldquit)();
X
X#ifdef SUNTOOL
X    if (istool) {
X	print("Editing letter...");
X
X	panel_set(abort_item, PANEL_SHOW_ITEM, FALSE, 0);
X	panel_set(send_item,  PANEL_SHOW_ITEM, FALSE, 0);
X	panel_set(edit_item,  PANEL_SHOW_ITEM, FALSE, 0);
X	win_setrect(tty_sw->ts_windowfd, &msg_rect);
X	msg_rect.r_height = 0;
X	win_setrect(msg_sw->ts_windowfd, &msg_rect);
X	if ((exec_pid = ttysw_fork(tty_sw->ts_data, argv,
X	    &tty_sw->ts_io.tio_inputmask,
X	    &tty_sw->ts_io.tio_outputmask,
X	    &tty_sw->ts_io.tio_exceptmask)) == -1)
X		error("%s failed", *argv), sigchldcatcher();
X	Debug("tty pid = %d\n", exec_pid);
X	return;
X    }
X#endif /* SUNTOOL */
X    oldint = signal(SIGINT, SIG_IGN);
X    oldquit = signal(SIGQUIT, SIG_IGN);
X#ifdef SIGCONT
X    oldstop = signal(SIGTSTP, SIG_DFL);
X    oldcont = signal(SIGCONT, SIG_DFL);
X#endif /* SIGCONT */
X    turnon(glob_flags, IGN_SIGS);
X
X    echo_on();
X    if ((exec_pid = vfork()) == 0) {
X	(void) signal(SIGINT, SIG_DFL);
X	(void) signal(SIGQUIT, SIG_DFL);
X	execvp(*argv, argv);
X	if (errno == ENOENT)
X	    print("%s: command not found.\n", *argv);
X	else
X	    error(*argv);
X	_exit(-1);
X    }
X    /* parent's got to do something; sigchldcatcher will do waiting
X     * if other forks die (sendmail), then this wait will catch them,
X     * This loop will really get -1, cuz sigchldcatcher will catch all else.
X     */
X    while ((pid = wait(&status) != -1) && pid != exec_pid)
X	Debug("The exec loop caught a signal? (pid = %d)\n", pid);
X    /* reset our ttymodes */
X    echo_off();
X    (void) signal(SIGINT, oldint);
X    (void) signal(SIGQUIT, oldquit);
X#ifdef SIGCONT
X    (void) signal(SIGTSTP, oldstop);
X    (void) signal(SIGCONT, oldcont);
X#endif /* SIGCONT */
X    turnoff(glob_flags, IGN_SIGS);
X}
X
sigchldcatcher()
X{
X#ifdef SUNTOOL
X    struct rect rect;
X    extern FILE *ed_fp;
X#endif /* SUNTOOL */
X#ifdef SYSV
X    int status;
X#else
X    union wait status;
X#endif /* SYSV */
X    int	   pid;
X
X#ifdef BSD
X    /* The follwoing SHOULDN'T be necessary, but it is!!! ttysw_fork()
X     * returns the pid of the thing that it executes, but that's not the
X     * pid that dies!  There are many procs that might die from ttysw_fork
X     * one of them is the process, another is the tty, etc... other
X     * procs that might die are sendmail, fortune, etc... tool_sigchld()
X     * handles these, but we can't let it have control unless we KNOW the
X     * editor is done.
X     * so if what we catch is not the exec_pid from ttysw_fork(), then
X     * send ourselves a sigchld to go thru this routine again.  mush -d
X     */
X    while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) {
X	Debug("%d died...\n", pid);
X	if (pid == exec_pid)
X	    break;
X    }
X#else
X#ifndef SYSV
X    while ((pid = wait2(&status, WNOHANG)) > 0 && pid != exec_pid)
X	Debug("%d died...\n", pid);
X#else /* SYSV */
X    while ((pid = wait((int *)0)) > 0 && pid != exec_pid)
X	Debug("%d died...\n", pid);
X#endif /* SYSV */
X#endif /* BSD */
X#ifndef SUNTOOL
X    }
X#else /* SUNTOOL */
X    if (pid != exec_pid || exec_pid <= 0) /* if the editor didn't die, return */
X	return;
X    /* editor died -- reset exec_pid so no one thinks we're running */
X    exec_pid = 0;
X    /* only the tool needs to continue from here.  Reset the win */
X    if (istool < 1)
X	return;
X    tool_sigchld(tool);
X    print("Editor done.");
X    win_getrect(tty_sw->ts_windowfd, &msg_rect);
X    if (msg_rect.r_height < 2 * l_height(curfont)) {
X	print_more(" (well, something just happened)");
X	return;
X    }
X    {
X	extern char *edfile;
X	if (!(ed_fp = fopen(edfile, "r+")))
X	    error("can't reopen %s", edfile);
X	(void) fseek(ed_fp, 0L, 2);
X    }
X    /* I'd like to be able to just pw_rop the tty window onto the window
X     * we're going to use now, but I can't access the data struture!
X     *
X     * pw_rop(msg_win, 0, 0, msg_rect.r_width, msg_rect.r_height, PIX_SRC,
X     *        ((struct ??? *)(tty_sw->ts_data))->pr_pixrect, 0, 0);
X     * So, instead, just clear the window and write the last N lines from the
X     * end of the file into the window.
X     */
X    rect.r_top = rect.r_left = rect.r_height = 0;
X    rect.r_width = msg_rect.r_width;
X    win_setrect(tty_sw->ts_windowfd, &rect);
X    win_setrect(msg_sw->ts_windowfd, &msg_rect);
X    do_clear();
X    /* read the last 2K bytes in the file -- search backwards for enough
X     * carriage returns that will fill the window with the end of the letter
X     * written so far and display the text.
X     */
X    {
X	register long where = ftell(ed_fp);
X	register int cr = 0, lines = msg_rect.r_height * l_height(curfont) - 3;
X	char buf[2*BUFSIZ], *p;
X	where = max(0, where-2*BUFSIZ);
X	(void) fseek(ed_fp, where, L_SET);
X	p = buf + read(fileno(ed_fp), buf, 2*BUFSIZ);
X	*p = 0;
X	while (cr < lines && p > buf)
X	    if (*--p == '\n')
X		cr++;
X	if (p > buf)
X	    while (*p != '\n')
X		p++;
X	Addstr(p);
X    }
X    panel_set(comp_item, PANEL_SHOW_ITEM, FALSE, 0);
X    panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
X    panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
X    panel_set(abort_item, PANEL_SHOW_ITEM, TRUE, 0);
X    wprint("(continue editing letter.)\n");
X    type_cursor(PIX_SRC);
X}
X
sigtermcatcher()
X{
X    ttysw_done(tty_sw->ts_data);
X    if (ison(glob_flags, IS_GETTING))
X	rm_edfile(-1);
X    cleanup(SIGTERM);
X}
X#endif /* SUNTOOL */
END_OF_FILE
if test 5679 -ne `wc -c <'execute.c'`; then
    echo shar: \"'execute.c'\" unpacked with wrong size!
fi
# end of 'execute.c'
fi
if test -f 'file.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'file.c'\"
else
echo shar: Extracting \"'file.c'\" \(8484 characters\)
sed "s/^X//" >'file.c' <<'END_OF_FILE'
X/* file.c -- Copyright (1988) Dan Heller */
X
X#include "mush.h"
X#include <pwd.h>
X
X/* takes string 'p' and address of int (isdir).  If p uses the ~ to reference
X * a home directory of somesort, then expand it.  find out what sort of
X * file final path is. set isidr to 1 if a directory, 0 if not, -1 on error
X * return final path. If an error occurrs, return string indicating error.
X * if isdir has a value of 1 when passed, it ignores "No such file or directory"
X */
char *
getpath(p, isdir)
register char *p;
int *isdir;
X{
X    static char buf[BUFSIZ];
X    struct stat stat_buf;
X
X    if (!p || !*p || !strcmp(p, "~")) {
X	char *home = do_set(set_options, "home");
X	if (!home || !*home)
X	    home = ALTERNATE_HOME;
X	(void) strcpy(buf, home);  /* no arg means home */
X    } else if (*p == '~') {
X	if (p[1] != '/') {
X	    /* not our home, but someone else's
X	     * look for ~user or ~user/subpath
X	     * if '/' exists, separate into tmp="user" p="subpath"
X	     */
X	    struct passwd *ent, *getpwnam();
X	    char *p2 = p+1;
X	    if (p = index(p2, '/'))
X		*p++ = 0;
X	    if (!(ent = getpwnam(p2))) {
X		*isdir = -1;
X		return sprintf(buf, "no such user: %s", p2);
X	    }
X	    /* append subpath to pathname */
X	    if (p && *p)
X		(void) sprintf(buf, "%s/%s", ent->pw_dir, p);
X	    /* if *p == NULL, pathname is done (buf), set isdir = 1 */
X	    else {
X		*isdir = 1;
X		return strcpy(buf, ent->pw_dir);
X	    }
X	} else {
X	    char *home = do_set(set_options, "home");
X	    if (!home || !*home)
X		home = ALTERNATE_HOME;
X	    (void) sprintf(buf, "%s/%s", home, p+2);
X	}
X    } else if (*p == '%') {
X	/* if %user, append user name... else, it's just us */
X	(void) sprintf(buf, "%s/", MAILDIR);
X	if (!*++p || *p == ' ' || *p == '\t')
X	    (void) strcat(buf, login);
X	else
X	    (void) strcat(buf, p);
X    } else if (*p == '+') {
X	register char *p2 = do_set(set_options, "folder");
X	if (!p2 || !*p2)
X	    p2 = DEF_FOLDER;
X	(void) sprintf(buf, "%s/%s", p2, ++p);
X	if (*buf == '~') {
X	    int t_isdir = *isdir;
X	    char *t, tmp[256];
X	    (void) strcpy(tmp, buf);
X	    t = getpath(tmp, &t_isdir);
X	    if (t_isdir == -1) {
X		*isdir = -1;
X		return t;
X	    }
X	    /* strcpy(buf, t); --buf already has info because it's static */
X	}
X    } else {  /* allow \ to escape the special chars, +, %, ~ */
X	if (*p == '\\')
X	    p++;
X	(void) strcpy(buf, p);
X    }
X    if (stat(buf, &stat_buf)) {
X	(void) access(buf, F_OK); /* set errno to the "real" reason */
X	if (errno == ENOENT && *isdir == 1) {
X	    *isdir = 0; /* say it's a regular file even tho it doesn't exist */
X	    return buf; /* it may be wanted for creating */
X	}
X	*isdir = -1;
X	return sys_errlist[errno];
X    }
X    *isdir = ((stat_buf.st_mode & S_IFDIR) != 0);
X    return buf;
X}
X
X/*
X * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
X * opens the file with the mode.
X * If the mode is "r" then we read the file into the file pointer at the
X * end (fseek(fp, 2, 0)).  If the file is opened for writing, then read
X * from the beginning of fp and write it into the file.
X * This is usually called to read .signatures into messages (thus,
X * opening .signture with "r" and writing to the end of fp which is probably
X * the sendmail process or the message file pointer) or to write fortunes into
X * the message buffer: reading fp (the popened fortune) and writing into file.
X */
void
file_to_fp(p, fp, mode)
register char *p;
register FILE *fp;
char *mode;
X{
X    int 	x = 1;
X    char 	*file, buf[BUFSIZ];
X    FILE 	*tmp_fp;
X
X    if (!p || !*p) {
X	print("specify filename");
X	return;
X    }
X    file = getpath(p, &x);
X    if (x == -1) { /* on error, file contains error message */
X	wprint(file);
X	return;
X    }
X    wprint("%s: ", file);
X    if (x)   /* if x == 1, then path is a directory */
X	wprint("directory.\n");
X    else if (!(tmp_fp = fopen(file, mode))) {
X	wprint("%s\n", sys_errlist[errno]);
X	return;
X    } else if (*mode != 'r') {
X	rewind(fp);
X	for(x = 0; fgets(buf, BUFSIZ, fp); x++)
X	    fputs(buf, tmp_fp);
X    } else
X	for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
X	    fputs(buf, fp);
X    wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
X				  x, (x == 1)? "": "s");
X    fflush(fp);
X    fclose(tmp_fp);
X}
X
X/* clear all contents of the file.  Careful that the file is opened for
X * _writing_ --tempfile is opened for reading, so don't try to empty it
X * if you're using ftruncate.   Return -1 on error, 0 on success.
X */
emptyfile(fp, fname)
register FILE **fp;
register char *fname;
X{
X    Debug("Emptying \"%s\"\n", fname);
X#ifndef SYSV
X    return ftruncate(fileno(*fp), 0L);
X#else
X    {
X	int omask = umask(077), ret;
X	fclose(*fp);
X	if (!(*fp = fopen(fname, "w")))
X	    ret = -1;
X	ret = 0;
X	(void) umask(omask);
X	return ret;
X    }
X#endif /* SYSV */
X}
X
X/*
X * Finds out how many file descriptors are opened.  Useful for making sure
X * no files got opened in subprocedures which were not subsequently closed.
X */
nopenfiles(argc)
X{
X    register int nfiles = 0;
X#ifdef MAXFILES
X    register int size = MAXFILES;
X#else
X    register int size = getdtablesize();
X#endif /* MAXFILES */
X
X    if (argc < 2)
X	print("open file descriptors:");
X    while (--size >= 0)
X        if (fcntl(size, F_GETFL, 0) != -1) {
X	    if (argc < 2)
X		print_more(" %d", size);
X            ++nfiles;
X        }
X    if (argc < 2)
X	print("\n");
X    return nfiles;
X}
X
X/*
X * Open a path for writing or appending -- return a FILE pointer.
X * If program is TRUE, then use popen, not fopen and don't check 
X * to see if the file is writable.
X */
FILE *
open_file(p, program)
register char *p;
X{
X    register FILE *newfile = NULL_FILE;
X    register char *tmp;
X    int x = 1;
X
X    if (program || *p == '/')
X	tmp = p, x = 0;
X    else
X	tmp = getpath(p, &x);
X    if (x == 1)
X	print("%s is a directory.\n", tmp);
X    else if (x == -1)
X	print("%s: %s\n", p, tmp);
X    else {
X	register char *mode = NULL;
X	/* if it doesn't exist open for "w" */
X	if (program || Access(tmp, F_OK))
X	    mode = "w";
X	/* if we can't write to it, forget it */
X	else if (Access(tmp, W_OK))
X	    error(tmp);
X	else
X	    mode = "a";
X	if (mode)
X	    if (program) {
X		if (!(newfile = popen(tmp, mode))) {
X		    error("Can't execute %s\n", tmp);
X		    return newfile;
X		}
X	    } else
X		if (!(newfile = fopen(tmp, mode)))
X		    error("Can't write to %s", tmp);
X	    else
X		Debug("Successfully opened %s\n", tmp);
X    }
X    return newfile;
X}
X
X/*
X * find_files gets a set of addresses and an array of
X * file pointers and the maximum size that array can be.
X * The object is to find the files or programs listed in "s", attempt
X * to fopen/popen them and save their filepointers in the array. If the
X * size is 0, then just extract the file names and give error messages
X * for each one since they will not be opened. Return the number of
X * files opened and delete all files (opened or not) from the list in
X * "s".  Tokens beginning with a "/, ~, or + are files; tokens beginning
X * with a | are programs.
X * The string "s" is modified to be a list of address -- all names AND
X * files are stripped out of the list.
X */
find_files(s, files, size)
register char *s;
FILE *files[];
X{
X    register int     total = 0, prog;
X    char 	     file[BUFSIZ], buf[BUFSIZ], *start = s, c;
X    register char    *p, *b = buf;
X
X    do  {
X	if (!(p = get_name_n_addr(s, NULL, file)))
X	    break;
X	c = *p, *p = 0;
X	/* It's a file -- try to open it.  This doesn't get written back
X	 * onto "buf" since it is supposed to be extracted anyway.
X	 */
X	if (*file == '+' || *file == '~' || *file == '|' || *file == '/') {
X	    prog = (*file == '|');
X	    if (size && total < size) {
X		/* either open "file" or &file[1] */
X		if (files[total] = open_file(&file[prog], prog))
X		    total++;
X	    } else
X		print("No open space for %s\n", file);
X	} else {
X	    b += Strcpy(b, s);
X	    *b++ = ',', *b++ = ' ';
X	}
X	for (*p = c, s = p; *s == ',' || isspace(*s); s++)
X	    ;
X    } while (*s);
X    for (*b-- = 0; b > buf && (*b == ',' || isspace(*b)); b--)
X	*b = 0;
X    (void) strcpy(start, buf);
X    return total;
X}
X
X/*
X * access(2) has an undocumented feature which ignores suid.  If you are
X * su'ed and try to read your mail, you will be unable to because access()
X * will give the illusion that you cannot read/write to your mbox.  Solve
X * the problem by using stat() instead.
X */
Access(file, mode)
register char *file;
X{
X    struct stat buf;
X
X    if (stat(file, &buf) == -1)
X	return -1;
X    if (mode == R_OK)
X	return (buf.st_mode & 0400)? 0 : -1;
X    if (mode == W_OK)
X	return (buf.st_mode & 0200)? 0 : -1;
X    return 0;
X}
END_OF_FILE
if test 8484 -ne `wc -c <'file.c'`; then
    echo shar: \"'file.c'\" unpacked with wrong size!
fi
# end of 'file.c'
fi
if test -f 'main_panel.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main_panel.c'\"
else
echo shar: Extracting \"'main_panel.c'\" \(9189 characters\)
sed "s/^X//" >'main_panel.c' <<'END_OF_FILE'
X/* "@(#)main_panel.c	(c) copyright	10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
make_main_panel(choice_args, button_args)
char **choice_args, **button_args;
X{
X    /* main panel stuff: */
X    panel_sw = panel_create(tool,
X	PANEL_HEIGHT, 80,
X	0);
X    main_panel = (Panel)panel_sw->ts_data;
X
X    quit_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			4,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Done", 6, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Done",
X	PANEL_CHOICE_STRINGS, 		"Close to Icon",
X					"Quit Tool",
X					"Help",
X					0,
X	PANEL_NOTIFY_PROC, 		toolquit,
X	0);
X
X    help_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			79,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Help", 4, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Available Help",
X	PANEL_CHOICE_STRINGS, 		"General",
X					"Help with \"help\"",
X					"The Mouse",
X					"Windows",
X					"Function Keys",
X					"Message headers",
X					"Message lists",
X					0,
X	PANEL_NOTIFY_PROC, 		do_help,
X	0);
X
X    read_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			136,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Next", 4, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Next Message",
X	PANEL_CHOICE_STRINGS, 		"Read Next", "Help", 0,
X	PANEL_NOTIFY_PROC, 		read_mail,
X	0);
X
X    respond_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			193,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Reply", 5, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Respond to Current Message",
X	PANEL_CHOICE_STRINGS, 		"Sender Only",
X					"Sender Only (include msg)",
X					"All Recipients",
X					"All Recipients (include msg)",
X					"Help", 0,
X	PANEL_NOTIFY_PROC, 		respond_mail,
X	0);
X
X    delete_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			259,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Delete", 6, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Delete/Undelete Messages",
X	PANEL_CHOICE_STRINGS, 		"Delete",
X					"Undelete",
X					"Help", 0,
X	PANEL_NOTIFY_PROC, 		delete_mail,
X	0);
X
X    sort_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			334,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Sort", 4, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Sort Messages",
X	PANEL_CHOICE_STRINGS, 		"By Date",
X					"By Author",
X					"By Subject",
X					"By Subject (ignore Re:)",
X					"By Status",
X					"Help", 0,
X	PANEL_NOTIFY_PROC, 		do_sort,
X	0);
X
X    option_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			391,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Opts", 4, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Mail Options",
X	PANEL_CHOICE_STRINGS, 		"Set Options", "Function keys",
X					"Help", 0,
X	PANEL_NOTIFY_PROC, 		p_set_opts,
X	0);
X
X    alias_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			448,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Aliases", 7, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Mail Aliases",
X	PANEL_CHOICE_STRINGS, 		"Current Aliases",
X					"Add/Change alias",
X					"Unalias", "Help", 0,
X	PANEL_NOTIFY_PROC, 		p_set_opts,
X	0);
X
X    comp_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			532,
X	PANEL_ITEM_Y,			4,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Compose", 8, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Compose a letter",
X	PANEL_CHOICE_STRINGS, 		"Help", 0,
X	PANEL_NOTIFY_PROC, 		do_compose,
X	0);
X
X    file_item = panel_create_item(main_panel, PANEL_TEXT,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			4,
X	PANEL_ITEM_Y,			30,
X	PANEL_LABEL_FONT, 		fonts[DEFAULT],
X	PANEL_SHOW_MENU,		TRUE,
X	PANEL_LABEL_STRING, 		"filename:",
X	PANEL_MENU_CHOICE_STRINGS,	"Save message without message header",0,
X	PANEL_VALUE_DISPLAY_LENGTH, 	35,
X	PANEL_NOTIFY_STRING, 		"\n\r",
X	PANEL_NOTIFY_PROC, 		file_dir,
X	0);
X
X    input_item = panel_create_item(main_panel, PANEL_TEXT,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			373,
X	PANEL_ITEM_Y,			30,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_SHOW_MENU, 		TRUE,
X	PANEL_LABEL_FONT, 		fonts[DEFAULT],
X	PANEL_VALUE_DISPLAY_LENGTH, 	20,
X	PANEL_NOTIFY_STRING, 		"\n\r",
X	PANEL_NOTIFY_PROC, 		text_done,
X	0);
X
X    print_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			4,
X	PANEL_ITEM_Y,			50,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Printer", 7, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Printing Messages",
X	PANEL_CHOICE_STRINGS, 		"Help", 0,
X	PANEL_NOTIFY_PROC, 		do_lpr,
X	0);
X
X    folder_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			88,
X	PANEL_ITEM_Y,			50,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "folder", 6, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Change folder",
X	PANEL_CHOICE_STRINGS, 		"System Mailbox",
X					"Main Mailbox",
X					"Last Accessed Folder",
X					0,
X	PANEL_NOTIFY_PROC, 		do_file_dir,
X	0);
X
X    add_folder_to_menu(folder_item, 3);
X
X    save_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			163,
X	PANEL_ITEM_Y,			50,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Save", 4, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Save messages",
X	PANEL_CHOICE_STRINGS, 		"~/mbox", 0,
X	PANEL_NOTIFY_PROC, 		do_file_dir,
X	0);
X
X    add_folder_to_menu(save_item, 1);
X
X    cd_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			220,
X	PANEL_ITEM_Y,			50,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "chdir", 5, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Change Working Directory",
X	PANEL_CHOICE_STRINGS, 		"Print Current directory",
X					"HOME directory",
X					"Private Mail directory.",
X					"Help", 0,
X	PANEL_NOTIFY_PROC, 		do_file_dir,
X	0);
X
X    update_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			286,
X	PANEL_ITEM_Y,			50,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Update", 6, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Updating folders",
X	PANEL_CHOICE_STRINGS, 		"Help", 0,
X	PANEL_NOTIFY_PROC, 		do_update,
X	0);
X
X    send_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			361,
X	PANEL_ITEM_Y,			50,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Send", 6, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Send Letter",
X	PANEL_CHOICE_STRINGS, 		"Help", 0,
X	PANEL_NOTIFY_PROC, 		do_send,
X	0);
X
X    edit_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			436,
X	PANEL_ITEM_Y,			50,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Editor", 4, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Editing",
X	PANEL_CHOICE_STRINGS, 		"Help", 0,
X	PANEL_NOTIFY_PROC, 		do_edit,
X	0);
X
X    abort_item = panel_create_item(main_panel, PANEL_BUTTON,
X	PANEL_ATTRIBUTE_LIST, 		button_args,
X	PANEL_ITEM_X,			511,
X	PANEL_ITEM_Y,			50,
X	PANEL_SHOW_ITEM, 		FALSE,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Abort", 5, fonts[LARGE]),
X	PANEL_NOTIFY_PROC, 		abort_mail,
X	0);
X
X    font_item = panel_create_item(main_panel, PANEL_CHOICE,
X	PANEL_ATTRIBUTE_LIST, 		choice_args,
X	PANEL_ITEM_X,			577,
X	PANEL_ITEM_Y,			50,
X	PANEL_LABEL_IMAGE,
X	    panel_button_image(main_panel, "Fonts", 5, fonts[LARGE]),
X	PANEL_MENU_TITLE_STRING, 	"Fonts",
X	PANEL_SHOW_MENU_MARK, 		TRUE,
X	PANEL_CHOICE_FONTS, 		fonts[0], fonts[1], fonts[2], 0,
X	PANEL_CHOICE_STRINGS, 		"Default", "Small", "Large", 0,
X	PANEL_NOTIFY_PROC, 		change_font,
X	0);
X}
X
X/*
X * Open the user's mail folder (either user set or default path) and find all
X * the files (assumed to be mail folders) and add them to the menu list of
X * folders to use.
X */
add_folder_to_menu(item, n)
struct panel_item *item;
register int 	  n;
X{
X    register FILE 	*pp = NULL_FILE;
X    register char	*p, *tmp = NULL;
X    int			x = 0;
X    char 		buf[128], path[128];
X
X    if (!(p = do_set(set_options, "folder")) || !*p)
X	p = DEF_FOLDER;
X    if (p) {
X	tmp = getpath(p, &x);
X	if (x == -1) {
X	    if (errno != ENOENT)
X		print("%s: %s\n", p, tmp);
X	    tmp = NULL;
X	}
X    }
X    if (p = tmp) {
X	p = sprintf(buf, "%s %s", LS_COMMAND, p);
X	if (!(pp = popen(buf, "r")))
X	    error(buf);
X	else {
X	    *path = '+';
X	    while (fgets(path+1, 128, pp)) {
X		struct stat s_buf;
X		if (p = index(path+1, '\n'))
X		    *p = 0;
X		(void) sprintf(buf, "%s/%s", tmp, path+1);
X		if (stat(buf, &s_buf) || s_buf.st_mode & S_IFDIR)
X		    continue;
X		panel_set(item, PANEL_CHOICE_STRING, n++, path, 0);
X	    }
X	    pclose(pp);
X	}
X    }
X    panel_set(item, PANEL_CHOICE_STRING, n, "Help", 0);
X}
END_OF_FILE
if test 9189 -ne `wc -c <'main_panel.c'`; then
    echo shar: \"'main_panel.c'\" unpacked with wrong size!
fi
# end of 'main_panel.c'
fi
if test -f 'signals.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'signals.c'\"
else
echo shar: Extracting \"'signals.c'\" \(9615 characters\)
sed "s/^X//" >'signals.c' <<'END_OF_FILE'
X/* @(#)signals.c	(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
X#ifndef SYSV
extern char *sys_siglist[];
X#else
X/* sys-v doesn't have normal sys_siglist */
static char	*sys_siglist[] = {
X/* no error */  "no error",
X/* SIGHUP */	"hangup",
X/* SIGINT */	"interrupt (rubout)",
X/* SIGQUIT */	"quit (ASCII FS)",
X/* SIGILL */	"illegal instruction (not reset when caught)",
X/* SIGTRAP */	"trace trap (not reset when caught)",
X/* SIGIOT */	"IOT instruction",
X/* SIGEMT */	"EMT instruction",
X/* SIGFPE */	"floating point exception",
X/* SIGKILL */	"kill (cannot be caught or ignored)",
X/* SIGBUS */	"bus error",
X/* SIGSEGV */	"segmentation violation",
X/* SIGSYS */	"bad argument to system call",
X/* SIGPIPE */	"write on a pipe with no one to read it",
X/* SIGALRM */	"alarm clock",
X/* SIGTERM */	"software termination signal from kill",
X/* SIGUSR1 */	"user defined signal 1",
X/* SIGUSR2 */	"user defined signal 2",
X/* SIGCLD */	"death of a child",
X/* SIGPWR */	"power-fail restart"
X};
X#endif /* SYSV */
X
X#ifdef SUNTOOL
msgwin_handlesigwinch()
X{
X    register struct rect rect;
X    if (exec_pid)
X	return;
X    rect = msg_rect;
X    pw_damaged(msg_win);
X    /* this prevents old screen from being lost when editor finishes */
X    if (isoff(glob_flags, IS_GETTING))
X	gfxsw_interpretesigwinch(msg_sw->ts_data);
X    gfxsw_handlesigwinch(msg_sw->ts_data);
X    pw_repairretained(msg_win);
X    pw_donedamaged(msg_win);
X    win_getrect(msg_sw->ts_windowfd, &msg_rect);
X    crt = msg_rect.r_height / l_height(curfont);
X    if (rect.r_height != msg_rect.r_height || rect.r_width != rect.r_width)
X	if (getting_opts == 1)
X	    display_opts(0);
X	else if (getting_opts == 2)
X	    set_fkeys();
X	else if (msg_pix)
X	    scroll_win(0);
X}
X
hdrwin_handlesigwinch()
X{
X    register struct rect rect;
X    rect = hdr_rect;
X    pw_damaged(hdr_win);
X    gfxsw_interpretesigwinch(hdr_sw->ts_data);
X    gfxsw_handlesigwinch(hdr_sw->ts_data);
X    pw_repairretained(hdr_win);
X    pw_donedamaged(hdr_win);
X    win_getrect(hdr_sw->ts_windowfd, &hdr_rect);
X    if (rect.r_width != hdr_rect.r_width || rect.r_height != hdr_rect.r_height){
X	pw_writebackground(hdr_win, 0,0,
X			   hdr_rect.r_width, hdr_rect.r_height, PIX_CLR);
X	screen = hdr_rect.r_height/l_height(DEFAULT);
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    }
X}
X
print_sigwinch()
X{
X    pw_damaged(print_win);
X    gfxsw_handlesigwinch(print_sw->ts_data);
X    pw_writebackground(print_win, 0,0,
X        win_getwidth(print_sw->ts_windowfd),
X	win_getheight(print_sw->ts_windowfd), PIX_CLR);
X    pw_donedamaged(print_win);
X    print(NULL);  /* reprint whatever was there before damage */
X}
X
sigwinchcatcher()
X{
X    tool_sigwinch(tool);
X}
X#endif /* SUNTOOL */
X
interrupt(sig)
X{
X    Debug("interrupt() caught: %d\n", sig);
X    turnon(glob_flags, WAS_INTR);
X}
X
X/*
X * catch signals to reset state of the machine.  Always print signal caught.
X * If signals are ignored, return.  If we're running the shell, longjmp back.
X */
X/*ARGSUSED*/
catch(sig)
X{
X    Debug("Caught signal: %d\n", sig);
X    (void) signal(sig, catch);
X    if (ison(glob_flags, IGN_SIGS) && sig != SIGTERM && sig != SIGHUP)
X	return;
X    print("%s: %s\n", prog_name, sys_siglist[sig]);
X    turnoff(glob_flags, IS_PIPE);
X    if (istool || sig == SIGTERM || sig == SIGHUP) {
X	if (istool) /* istool is 2 if tool is complete */
X	    istool = 1;
X	(void) setjmp(jmpbuf);
X	if (ison(glob_flags, IS_GETTING))
X	    rm_edfile(-1);
X	cleanup(sig);
X    }
X    if (ison(glob_flags, DO_SHELL)) {
X	turnoff(glob_flags, IS_GETTING);
X	longjmp(jmpbuf, 1);
X    } else
X	puts("exiting"), cleanup(sig);
X}
X
X#ifdef SIGCONT
stop_start(sig)
X{
X    extern FILE *ed_fp;
X
X    Debug("Caught signal: %d", sig);
X    if (sig == SIGCONT) {
X	(void) signal(SIGTSTP, stop_start);
X	(void) signal(SIGCONT, stop_start);
X	echo_off();
X	if (istool || ison(glob_flags, IGN_SIGS) && !iscurses)
X	    return;
X	/* we're not in an editor but we're editing a letter */
X	if (ison(glob_flags, IS_GETTING)) {
X	    if (ed_fp)
X		print("(Continue editing letter)\n");
X	}
X#ifdef CURSES
X	else if (iscurses)
X	    if (ison(glob_flags, IGN_SIGS)) {
X		clr_bot_line();
X		if (msg_list)
X		    puts(compose_hdr(current_msg));
X		mail_status(1), addstr("...continue... ");
X		refresh();
X	    } else {
X		int curlin = max(1, current_msg - n_array[0] + 1);
X		redraw();
X		print("Continue");
X		move(curlin, 0);
X		refresh();
X		/* make sure we lose reverse video on continuation */
X		if (ison(glob_flags, REV_VIDEO) && msg_cnt) {
X		    char buf[256];
X		    (void) strncpy(buf, compose_hdr(current_msg), COLS-1);
X		    buf[COLS-1] = 0; /* strncpy does not null terminate */
X		    mvaddstr(curlin, 0, buf);
X		}
X	    }
X#endif /* CURSES */
X  	else
X	    mail_status(1), fflush(stdout);
X    } else {
X#ifdef CURSES
X	if (iscurses) {
X	    /* when user stops mush, the current header is not in reverse
X	     * video -- note that a refresh() has not been called in curses.c!
X	     * so, make sure that when a continue is called, the reverse video
X	     * for the current message returns.
X	     */
X	    turnon(glob_flags, WAS_INTR);
X	    if (isoff(glob_flags, IGN_SIGS) && ison(glob_flags, REV_VIDEO) &&
X		    msg_cnt) {
X		int curlin = max(1, current_msg - n_array[0] + 1);
X		char buf[256];
X		(void) strncpy(buf, stdscr->_y[curlin], COLS-1);
X		buf[COLS-1] = 0; /* strncpy does not null terminate */
X		STANDOUT(curlin, 0, buf);
X	    }
X	    print("Stopping...");
X	}
X#endif /* CURSES */
X	echo_on();
X	(void) signal(SIGTSTP, SIG_DFL);
X	(void) signal(SIGCONT, stop_start);
X	(void) kill(getpid(), sig);
X    }
X}
X#endif /* SIGCONT */
X
X/*ARGSUSED*/
cleanup(sig)
X{
X    char buf[128], c = ison(glob_flags, IGN_SIGS)? 'n' : 'y';
X
X#ifdef CURSES
X    if (iscurses)
X	iscurses = FALSE, endwin();
X#endif /* CURSES */
X
X    echo_on();
X
X    if (ison(glob_flags, IS_GETTING))
X	turnoff(glob_flags, IS_GETTING), dead_letter();
X    if ((sig == SIGSEGV || sig == SIGBUS) && isoff(glob_flags, IGN_SIGS)
X	&& *tempfile) {
X	fprintf(stderr, "remove %s [y]? ", tempfile), fflush(stderr);
X	if (fgets(buf, 128, stdin))
X	    c = lower(*buf);
X    }
X    if (c != 'n' && *tempfile && unlink(tempfile) && !sig && errno != ENOENT)
X	error(tempfile);
X#ifdef SUNTOOL
X    if (istool && tool)
X	tool_destroy(tool);
X#endif /* SUNTOOL */
X    if (sig == SIGSEGV || sig == SIGBUS) {
X	if (isoff(glob_flags, IGN_SIGS)) {
X	    fprintf(stderr, "coredump [n]? "), fflush(stderr);
X	    if (fgets(buf, 128, stdin))
X		c = lower(*buf);
X	}
X	if (c == 'y')
X	    puts("dumping core for debugging"), abort();
X    }
X    exit(sig);
X}
X
X/*
X * if new mail comes in, print who it's from.  sprintf it all into one
X * buffer and print that instead of separate print statements to allow
X * the tool mode to make one print statment. The reason for this is that
X * when the tool is refreshed (caused by a resize, reopen, move, top, etc)
X * the last thing printed is displayed -- display the entire line.
X */
check_new_mail()
X{
X    int 	   ret_value;
X    char 	   buf[BUFSIZ];
X    register char  *p = buf;
X    static long    last_spool_size = -1;
X
X#ifdef SUNTOOL
X    static int is_iconic, was_iconic;
X
X    if (istool) {
X	timerclear(&(mail_timer.it_interval));
X	timerclear(&(mail_timer.it_value));
X	mail_timer.it_value.tv_sec = time_out;
X	setitimer(ITIMER_REAL, &mail_timer, NULL);
X    }
X#endif /* SUNTOOL */
X    /* if fullscreen access in progress (help), don't do anything */
X    if (ret_value = mail_size()) {
X#ifdef CURSES
X	int new_hdrs = last_msg_cnt;
X#endif /* CURSES */
X#ifdef SUNTOOL
X	/* if our status has changed from icon to toolform, then
X	 * there will already be a message stating number of new
X	 * messages.  reset `n' to msg_cnt so we don't restate
X	 * the same # of new messages upon receipt of yet another new message.
X	 */
X	if (istool && !(is_iconic = (tool->tl_flags&TOOL_ICONIC)) && was_iconic)
X	    last_msg_cnt = msg_cnt;
X#endif /* SUNTOOL */
X	turnon(glob_flags, NEW_MAIL);
X	getmail(); /* msg_cnt gets incremented here */
X	if (istool) {
X	    mail_status(0);
X	    (void) do_hdrs(0, DUBL_NULL, NULL);
X	}
X	p += Strcpy(p, "New mail ");
X	if (msg_cnt - last_msg_cnt <= 1)
X	    p += strlen(sprintf(p, "(#%d) ", msg_cnt));
X	else
X	    p += strlen(sprintf(p, "(#%d thru #%d)\n", last_msg_cnt+1,msg_cnt));
X#ifdef SUNTOOL
X	/*
X	 * If mush is in tool mode and in icon form, don't update
X	 * last_msg_cnt so that when the tool is opened, print() will
X	 * print the correct number of "new" messages.
X	 */
X	if (!istool || !(was_iconic = tool->tl_flags & TOOL_ICONIC))
X#endif /* SUNTOOL */
X	    if (iscurses && isoff(glob_flags, CNTD_CMD))
X		last_msg_cnt = msg_cnt;
X	    else while (last_msg_cnt < msg_cnt) {
X		char *p2 = compose_hdr(last_msg_cnt++) + 9;
X		if (strlen(p2) + (p - buf) >= BUFSIZ-5) {
X		    (void) strcat(p, "...\n");
X		    /* force a break by setting last_msg_cnt correctly */
X		    last_msg_cnt = msg_cnt;
X		} else
X		    p += strlen(sprintf(p, " %s\n", p2));
X	    }
X#ifdef CURSES
X	if (iscurses && isoff(glob_flags, CNTD_CMD)) {
X	    if (new_hdrs - n_array[screen-1] < screen)
X		(void) do_hdrs(0, DUBL_NULL, NULL);
X	    print("%s ...", buf);
X	} else
X#endif /* CURSES */
X	    print("%s", buf); /* buf might have %'s in them!!! */
X    } else
X#ifdef SUNTOOL
X	if (!istool || !is_iconic)
X#endif /* SUNTOOL */
X	    turnoff(glob_flags, NEW_MAIL);
X    if (last_spool_size > -1 && /* handle first case */
X	    strcmp(mailfile, spoolfile) && last_spool_size < spool_size)
X	print("You have new mail in your system mailbox.\n"), ret_value = 1;
X    last_spool_size = spool_size;
X    return ret_value;
X}
X
X/*ARGSUSED*/   /* we ignore the sigstack, cpu-usage, etc... */
bus_n_seg(sig)
X{
X    fprintf(stderr, "%s: %s\n", prog_name,
X	(sig == SIGSEGV)? "Segmentation violation": "Bus error");
X    cleanup(sig);
X}
END_OF_FILE
if test 9615 -ne `wc -c <'signals.c'`; then
    echo shar: \"'signals.c'\" unpacked with wrong size!
fi
# end of 'signals.c'
fi
echo shar: End of archive 3 \(of 14\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 14 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.