[comp.sources.unix] v11i052: Mail user's shell, Part02/12

rs@uunet.UU.NET (Rich Salz) (09/18/87)

Submitted-by: island!argv@Sun.COM (Dan Heller)
Posting-number: Volume 11, Issue 52
Archive-name: mush5.7/Part02

#! /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 2 (of 12)."
# Contents:  aliases.c curs_io.c dates.c execute.c folders.c
#   main_panel.c rite.c sort.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'aliases.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'aliases.c'\"
else
echo shar: Extracting \"'aliases.c'\" \(4554 characters\)
sed "s/^X//" >'aliases.c' <<'END_OF_FILE'
X/* (c) copyright @(#)aliases.c	2.4	10/15/86 (Dan Heller) */
X
X#include "mush.h"
X
X/*
X * do_alias handles aliases, header settings, functions, and fkeys.
X * since they're all handled in the same manner, the same routine is
X * used. argv[0] determines which to use.
X * alias is given here as an example
X *
X * alias           identify all aliases
X * alias name      identify alias
X * alias name arg1 arg2 arg3... -> name="arg1 arg2 arg3"; call set_option
X * unalias arg1 [arg2 arg3 ... ]        unalias args
X *
X * same is true for dealing with your own headers.
X * (also the expand command)
X * always return -1 since it nas no effect on messages
X */
Xdo_alias(argc, argv)
Xregister char **argv;
X{
X    register char *cmd = *argv, *p;
X    struct options **list;
X    char firstchar = *cmd, buf[BUFSIZ];
X
X    if (argc == 0)
X	return -1;
X    if (firstchar == 'u')
X	firstchar = cmd[2];
X    if (*++argv && !strcmp(*argv, "-?")) { /* doesn't apply for fkeys */
X	register char *help_str;
X	if (firstchar == 'a' || firstchar == 'e')
X	    help_str = "alias";
X	else if (firstchar == 'c')
X	    help_str = "func_help";
X	else if (firstchar == 'f')
X	    help_str = "fkey_help";
X	else
X	    help_str = "own_hdrs";
X	return help(0, help_str, cmd_help);
X    }
X
X    if (firstchar == 'a')
X	list = &aliases;
X    else if (firstchar == 'c')
X	list = &functions;
X    else if (firstchar == 'f')
X	list = &fkeys;
X    else
X	list = &own_hdrs;
X
X    if (*cmd == 'u') {
X	if (!*argv)
X	    print("%s what?\n", cmd);
X	/* unset a list separated by spaces or ',' */
X	else while (*argv) {
X	    if (!strcmp(*argv, "*")) /* unset everything */
X		while (*list)
X		    (void) un_set(list, (*list)->option);
X	    else if (!un_set(list, *argv))
X		print("\"%s\" isn't set\n", *argv);
X	    argv++;
X	}
X	return -1;
X    }
X
X    if (!*argv && *cmd != 'e') {
X	/* just type out all the aliases or own_hdrs */
X	(void) do_set(*list, NULL);
X	return -1;
X    }
X
X    if (*cmd == 'e') {   /* command was "expand" (aliases only) */
X	if (!*argv)
X	    print("expand which alias?\n");
X	else
X	    do  {
X		print("%s: ", *argv);
X		if (p = alias_to_address(*argv))
X		    print("%s\n", p);
X	    } while (*++argv);
X	return -1;
X    }
X
X    /* at this point, *argv now points to a variable name ...
X     * check for hdr -- if so, *argv better end with a ':' (check *p)
X     */
X    if (list == &own_hdrs && !(p = index(*argv, ':'))) {
X	print("header labels must end with a ':' (%s)\n", *argv);
X	return -1;
X    }
X    if (!argv[1] && !index(*argv, '='))
X	if (p = do_set(*list, *argv))
X	    print("%s\n", p);
X	else
X	    print("%s is not set\n", *argv);
X    else {
X	(void) argv_to_string(buf, argv);
X	if ((p = any(buf, " \t=")) && *p != '=')
X	    *p = '=';
X	argv[0] = buf;
X	argv[1] = NULL;
X	(void) add_option(list, argv);
X    }
X    return -1;
X}
X
X/* takes string 's' which can be a name or list of names separated by
X * spaces or commas and checks to see if each is aliased to something else.
X * return address of the static buf.
X */
Xchar *
Xalias_to_address(s)
Xregister char *s;
X{
X    static char buf[BUFSIZ];
X    register char *p = s, *p2, *tmp;
X    char newbuf[BUFSIZ];
X    static int recursive;
X
X    if (!aliases)
X	return s;
X    if (!s || !*s) {
X	print("No recipeints!?!\n");
X	return NULL;
X    }
X    skipspaces(0);
X    if (!recursive) {
X	bzero(buf, BUFSIZ);
X	p2 = buf;  /* if we're starting all this, p2 starts at &buf[0] */
X    } else
X	p2 = buf+strlen(buf);   /* else, pick up where we left off */
X
X    if (++recursive == 30) {
X	print("alias references too many addresses!\n");
X	recursive = 0;
X	return NULL;
X    }
X    /* find a comma, space, or newline -- if none exists, still go thru once */
X    for (s = p; (p = any(s, ", \n")) || *s; s = p) {
X	if (p)
X	    *p++ = 0;  /* null terminate, comma/space/newline was found */
X	else
X	    for(p = s; *p; p++);   /* last in list; go to end of string */
X
X	/* if this is an alias, recurse this routine to expand it out */
X	if ((tmp = do_set(aliases, s)) && *tmp) {
X	    if (!alias_to_address(strcpy(newbuf, tmp)))
X		return NULL;
X	    else
X		p2 = buf+strlen(buf);
X	/* Now, make sure the buffer doesn't overflow */
X	} else if (strlen(s) + (p2-buf) + 2 > BUFSIZ) {  /* add " "  + NULL */
X	    print("address length too long.\n");
X	    recursive = 0;
X	    return NULL;
X	} else {
X	    /* append the new alias (or unchanged address) onto the buffer */
X	    p2 += Strcpy(p2, s);
X	    p2 += Strcpy(p2, ", "); /* two Strcpy's is faster than sprintf */
X	}
X	skipspaces(0);
X    }
X    if (recursive)
X	recursive--;
X    if (!recursive)
X	*(p2-2) = 0;  /* get rid of last ", " if end of recursion */
X    return buf;
X}
END_OF_FILE
if test 4554 -ne `wc -c <'aliases.c'`; then
    echo shar: \"'aliases.c'\" unpacked with wrong size!
fi
# end of 'aliases.c'
fi
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'\" \(5704 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
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 */
X#define backspace() 	{ Addch('\b'); Addch(' '); Addch('\b'); }
X
XGetstr(String, length, offset)
Xchar String[];
Xregister int length;
X{
X    register int c;
X    register int count = offset;
X
X    while ((c = getchar()) != '\n' && c != 4 /* ^D */ && 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) && count < length)
X	    String[count++] = c;
X	else if (c == _tty.sg_erase || c == 8 || c == 127) {
X	    if (count) {
X		backspace() /* macro */
X		count--;
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
X		    backspace()  /* macro */
X		while (--count);
X	    }
X	} else
X#ifndef TIOCGLTC
X	if (c == '\022') /* 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 == '\027') /* system doesn't have ltchars */
X#else
X	if (c == ltchars.t_werasc) /* word erase */
X#endif TIOCGLTC
X	    while (count) {
X		backspace();
X		String[count--] = 0;
X		if (!count || (String[count-1]== ' '&& !isspace(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 if (c > 31 && c != 127) {
X	    Addch(c);
X	    String[count++] = c;
X	}
X    }
X    if (c == 4 || c == EOF || ison(glob_flags, WAS_INTR)) {     /* ^D */
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
X#undef backspace
X#undef Addch
X
X#ifdef CURSES
X/* curses based "more" like option */
Xvoid
Xc_more()
X{
X    register char c;
X
X    print_more("--more--");
X    while ((c = getchar()) != ' ' && c != '\n')
X	bell();
X    if (!iscurses && c != '\n')
X	while (getchar() != '\n');
X}
X
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 */
Xhit_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 0;
X    return c;
X}
X
Xcurses_msg_list(str, list, m_list)
Xregister char *str, *list;
Xchar m_list[];
X{
X    register char *p = NULL;
X
X    print(str);
X    if (Getstr(list, COLS-13, 0) <= 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    move(LINES-1, 0), refresh();
X    return 1;
X}
X
Xcurs_vars(which, cntd_cmd)
Xint which;  /* really, a char */
Xint *cntd_cmd;
X{
X    char c, buf[128], buf2[128], *string;
X    struct options **list;
X
X    switch(which) {
X	case C_OWN_HDR : string = "own_hdrs", 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, COLS-40, 0)) < 0)
X			return;
X		    clr_bot_line();
X		    if (c > 0) {
X			Lower(*buf);
X			if (!strcmp(buf, "a"))
X			    (void) strcpy(buf, "all");
X			if (!strcmp(buf, "all"))
X			    *cntd_cmd = 1;
X			(void) cmd_line(sprintf(buf2, "set ?%s", buf),msg_list);
X			return;
X		    }
X		}
X		/* help returns next command (hit_return) */
X		help(0, string, cmd_help);
X		*cntd_cmd = 1;
X		return;
X	    }
X	    *cntd_cmd = 1;
X	    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		if (*cntd_cmd)
X		    putchar('\n');
X	    }
X    }
X}
X
X#endif CURSES
END_OF_FILE
if test 5704 -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'\" \(6037 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
Xchar *day_names[] = {
X    "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"
X};
Xchar *month_names[] = {     /* imported in pick.c */
X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X    "July", "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 */
Xchar *
XTime(opts, now)
Xregister char *opts;
Xlong 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': (void) sprintf(p, "%d:%02d", (T->tm_hour) ?
X		      ((T->tm_hour <= 12) ? T->tm_hour : T->tm_hour - 12) : 12,
X			  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 */
Xchar *
Xmsg_date(n)
Xregister int n;
X{
X    register char *p, *p2 = NULL;
X    char line[256];
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 */
Xchar *
Xparse_date(p)
Xregister char *p;
X{
X    static char buf[11];
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     */
X    if (sscanf(p, "%d %s %2d %d:%d", &Day,buf,&Year,&Hours,&Mins) == 5
X	||
X	sscanf(p, "%*s %s %d %d:%d:%*d %d", buf,&Day,&Hours,&Mins,&Year) == 5
X	||
X	sscanf(p, "%*s %s %d %d %d:%d", buf,&Day,&Year,&Hours,&Mins) == 5
X	||
X	sscanf(p, "%*s %d %s %d %d:%d", &Day,buf,&Year,&Hours,&Mins) == 5
X	||
X	sscanf(p, "%d %s %d %d:%d", &Day,buf,&Year,&Hours,&Mins) == 5
X	||
X	sscanf(p, "%d %s %d %2d%2d", &Day,buf,&Year,&Hours,&Mins) == 5
X	||
X	sscanf(p, "%*s %s %d %d:%d:%*d %*s %d", 
X					buf, &Day, &Hours, &Mins, &Year) == 5
X	||
X	sscanf(p,"%d-%[^-]-%d %d:%d", &Day, buf, &Year, &Hours, &Mins) == 5
X	||
X	sscanf(p,"%*s %d-%[^-]-%d %d:%d", &Day, buf, &Year, &Hours, &Mins) == 5) {
X	if (Year > 1900)
X	    Year -= 1900;
X	if ((Month = month_to_n(buf)) == -1) {
X	    print("bad month: %s\n", p);
X	    return NULL;
X	}
X	return sprintf(buf, "%02d%02d%02d%02d%02d", Year,Month,Day,Hours,Mins);
X    }
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. "yr" is
X * not used, but is here anyway in case you want to modify it to use it.
X */
Xchar *
Xdate_to_string(Date)
Xchar *Date;
X{
X    static char buf[30];
X    int yr, mon, day, hr, mins;
X    char a_or_p, *p = 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    p += strlen(sprintf(p, "%s %2.d, ", month_names[mon-1], day));
X    (void) sprintf(p, "%2.d:%02d%cm",
X	  (hr)? (hr <= 12)? hr: hr - 12: 12, mins, a_or_p);
X    return 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 */
Xmonth_to_n(name)
Xregister 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 6037 -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'\" \(4414 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
Xexecute(argv)
Xchar **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
Xsigchldcatcher()
X{
X#ifdef SUNTOOL
X    struct rect rect;
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) {
X	print_more(" (well, something just happened)");
X	return;
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    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    pw_char(msg_win, txt.x,txt.y, PIX_SRC, fonts[curfont], '_');
X}
X
Xsigtermcatcher()
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 4414 -ne `wc -c <'execute.c'`; then
    echo shar: \"'execute.c'\" unpacked with wrong size!
fi
# end of 'execute.c'
fi
if test -f 'folders.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'folders.c'\"
else
echo shar: Extracting \"'folders.c'\" \(4933 characters\)
sed "s/^X//" >'folders.c' <<'END_OF_FILE'
X/* @(#)folders.c	(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
X/* folder %[user]  --new mailfile is the spool/mail/login file [user].
X * folder #  --new mailfile is the folder previous to the current folder
X * folder &  --new mailfile is ~/mbox (or whatever "mbox" is set to)
X * folder +file --new mailfile is in the directory "folder"; name is 'file'
X * folder "path" --full path name or the one in current working directory.
X *
X * in all cases, changes are updated unless a '!' is specified after the
X * folder command (e.g. "f!", "folder !" "fo!" .. all permutations)
X * as usual, if new mail has arrived before the file is copied back, then
X * user will be notified beforehand.
X *
X * RETURN -1 on error -- else return 0. All bits in msg_list are set to true.
X */
Xfolder(argc, argv, list)
Xregister char **argv, list[];
X{
X    int n, updating = !strcmp(*argv, "update"), do_read_only = 0, no_hdrs = 0;
X    static char oldfolder[256];
X    char *tmp, *newfolder = NULL, buf[256];
X
X    if (ison(glob_flags, DO_PIPE)) {
X	print("You can't pipe to the folder command");
X	return -1;
X    }
X    while (*++argv && (**argv == '-' || **argv == '!'))
X	if (!strcmp(*argv, "-?"))
X	    return help(0, "folder_help", cmd_help);
X	else if (!strcmp(*argv, "-N"))
X	    no_hdrs = 1;
X	else if (!strcmp(*argv, "-r"))
X	    do_read_only = 1;
X	else if (!strcmp(*argv, "!"))
X	    turnoff(glob_flags, DO_UPDATE);
X
X    if (updating)
X	(void) strcpy(buf, mailfile);
X    else {
X	if (!*argv) {
X	    print("%s\n", mailfile);
X	    return 0;
X	}
X	if (!strcmp(*argv, "#"))
X	    if (!*oldfolder) {
X		print("No previous folder\n");
X		return -1;
X	    } else
X		newfolder = oldfolder;
X	else if (!strcmp(*argv, "&")) {
X	    if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
X		newfolder = DEF_MBOX;
X	} else
X	    newfolder = *argv;
X	n = 0;
X	tmp = getpath(newfolder, &n);
X	if (n == -1) {
X	    print("%s: %s\n", newfolder, tmp);
X	    return -1;
X	} else if (n == 1) {
X	    print("%s: is a directory\n", tmp);
X	    return -1;
X	}
X	/* strcpy so copyback() below (which calls getpath) doesn't change
X	 * the data that tmp intended to point to.
X	 */
X	(void) strcpy(buf, tmp);
X    }
X    if (access(buf, R_OK)) {
X	error("Can't open %s", buf);
X	return -1;
X    }
X    if (access(buf, W_OK))
X	do_read_only = 1;
X#ifdef SUNTOOL
X    if (istool) lock_cursors();
X#endif SUNTOOL
X    if (ison(glob_flags, DO_UPDATE) && !copyback()) {
X#ifdef SUNTOOL
X	if (istool) unlock_cursors();
X#endif SUNTOOL
X	/* could be an error, but new mail probably came in */
X	return -1;
X    }
X    (void) strcpy(oldfolder, mailfile);
X    strdup(mailfile, buf);
X    do_read_only? turnon(glob_flags,READ_ONLY) : turnoff(glob_flags,READ_ONLY);
X    last_size = spool_size = 0L;
X    msg_cnt = 0;
X    turnoff(glob_flags, CONT_PRNT);
X
X    turnon(glob_flags, IGN_SIGS);
X    /* clear the tempfile */
X    fclose(tmpf);
X    if (!(tmpf = fopen(tempfile, "w"))) {
X	error("error truncating %s", tempfile);
X	turnoff(glob_flags, IGN_SIGS);
X	return -1;
X    }
X    getmail();
X    last_msg_cnt = msg_cnt;  /* for check_new_mail */
X    (void) mail_size();
X#ifdef SUNTOOL
X    if (istool) {
X	panel_set(next_scr, PANEL_SHOW_ITEM, FALSE, 0);
X	panel_set(prev_scr, PANEL_SHOW_ITEM, FALSE, 0);
X	pw_rop(hdr_win, 0,0, hdr_rect.r_width, hdr_rect.r_height,PIX_CLR,0,0,0);
X    }
X#endif SUNTOOL
X    current_msg = 0;
X    turnoff(glob_flags, IGN_SIGS);
X
X    /* now sort messages according a user_defined default */
X    if (!updating && msg_cnt > 1 && is_spool(mailfile) &&
X		(tmp = do_set(set_options, "sort"))) {
X	(void) sprintf(buf, "sort %s", tmp);
X	if (argv = make_command(buf, TRPL_NULL, &argc)) {
X	    /* msg_list can't be null for do_command and since we're not
X	     * interested in the result, call sort directly
X	     */
X	    (void) sort(argc, argv, NULL);
X	    free_vec(argv);
X	}
X    }
X    turnoff(glob_flags, DO_UPDATE);
X
X    while (current_msg < msg_cnt && isoff(msg[current_msg].m_flags, UNREAD))
X	current_msg++;
X    if (current_msg == msg_cnt)
X	current_msg = 0;
X
X    if (!istool && !iscurses)
X	mail_status(0);
X    /* be quite if we're piping */
X    if ((istool || !updating) && isoff(glob_flags, IS_PIPE) &&
X	(istool || !no_hdrs) && msg_cnt)
X	(void) cmd_line(sprintf(buf, "headers %d", current_msg+1), msg_list);
X#ifdef SUNTOOL
X    if (istool) {
X	if (!msg_cnt)
X	    print("No Mail in %s\n", mailfile);
X	else if (isoff(glob_flags, IS_GETTING) && !getting_opts)
X	    display_msg(current_msg, (long)0);
X	unlock_cursors();
X    }
X#endif SUNTOOL
X    if (list) {
X	clear_msg_list(list);
X	bitput(list, list, msg_cnt, =~) /* macro */
X    }
X    return 0;
X}
X
Xfolders(argc, argv)
Xregister char **argv;
X{
X    register char *p;
X    char buf[128], unused[MAXMSGS_BITS];
X
X    if (!(p = do_set(set_options, "folder")) || !*p) {
X	print("You have no folder variable set.\n");
X	return -1;
X    }
X    (void) sprintf(buf, "ls %s", p);
X    if (argv = make_command(buf, TRPL_NULL, &argc))
X	(void) do_command(argc, argv, unused);
X    return -1;
X}
END_OF_FILE
if test 4933 -ne `wc -c <'folders.c'`; then
    echo shar: \"'folders.c'\" unpacked with wrong size!
fi
# end of 'folders.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'\" \(9355 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
Xmake_main_panel(choice_args, button_args)
Xchar **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 current message",
X					"Delete All Messages",
X					"Undelete current message",
X					"Undelete All Messages",
X					"Delete message \"range\"",
X					"Undelete message \"Range\"",
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, 		"Save in ~/mbox",
X					"Save message \"range\"",
X					0,
X	PANEL_NOTIFY_PROC, 		do_file_dir,
X	0);
X
X    add_folder_to_menu(save_item, 2);
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 */
Xadd_folder_to_menu(item, n)
Xstruct panel_item *item;
Xregister int 	  n;
X{
X    register FILE 	*pp = NULL_FILE;
X    register char 	*p = do_set(set_options, "folder");
X    register char	*tmp = NULL;
X    int			x = 0;
X    char 		buf[128], path[128];
X
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	}
X    }
X    panel_set(item, PANEL_CHOICE_STRING, n, "Help", 0);
X}
END_OF_FILE
if test 9355 -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 'rite.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rite.c'\"
else
echo shar: Extracting \"'rite.c'\" \(4613 characters\)
sed "s/^X//" >'rite.c' <<'END_OF_FILE'
X/* rite.c	(c) copyright 1986 (Dan Heller) */
X
X#include "mush.h"
X
X#define LASTLINE 	  (msg_rect.r_height - l_height(LARGE)-5)
X
Xstatic 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
Xstatic char String[BUFSIZ];
Xstatic int count, backchars, save_orig_x;
X
Xchar *
Xrite(c)
Xregister char c;
X{
X    static int literal_next;
X
X    if (c == ltchars.t_lnextc || literal_next) {
X	if (literal_next)
X	    Addch(c);
X	else /* don't call Addch to prevent cursor from advancing */
X	    pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], '^');
X	literal_next = !literal_next;
X	return NULL;
X    }
X    literal_next = 0;
X    if (c == _tty.sg_erase) {
X	if (count)
X	    backspace(), String[count--] = 0;
X    } else if (c == _tty.sg_kill) {
X	if (count) {
X	    Clrtoeol(msg_win, txt.x = save_orig_x, txt.y,curfont);
X	    String[count=0] = 0;
X	}
X    } else if (c == ltchars.t_werasc)
X	while (count) {
X	    backspace();
X	    String[count--] = 0;
X	    if (!count || (String[count-1]==' ' && !isspace(String[count])))
X		break;
X	}
X    else if (c == '\n' || c == '\r' || c == 13) {
X	String[count] = 0;
X	if ((txt.y += l_height(curfont)) >= LASTLINE && !getting_opts)
X	    scroll_win(1);
X	/* else Clrtoeol(msg_win, txt.x, txt.y, curfont); */
X	count = 0, txt.x = 5;
X	return String;
X    } else if (c == 12) {
X	if (ison(glob_flags, IS_GETTING))
X	    Addch(c);
X	else do_clear();
X    } else if (count == BUFSIZ-1)
X	print("Text too long for String!"), count--;
X    else if (c == '\t')
X	do Addch(' ');
X	while (count % 8 && count < BUFSIZ);
X    else
X	Addch(c);
X    return NULL;
X}
X
Xbackspace()
X{
X    if (backchars) {
X	pw_text(msg_win, save_orig_x, txt.y, PIX_SRC, fonts[curfont],
X		&String[--backchars]);
X	Clrtoeol(msg_win, msg_rect.r_width-10-l_width(curfont), txt.y, curfont);
X    } else if ((txt.x -= l_width(curfont)) >= 5)
X	pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], ' ');
X    else
X	txt.x = 5;
X}
X
Xstatic
XAddch(c)
Xregister char c;
X{
X    if (!count)
X	save_orig_x = txt.x, bzero(String, BUFSIZ);
X    if (c > 31 && c != 127)
X	String[count++] = c;
X    else {
X	Addch('^');
X	Addch(_unctrl[c][1]);
X	return;
X    }
X    pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], c);
X    if ((txt.x += l_width(curfont)) <= msg_rect.r_width-5-l_width(curfont))
X	return;
X    if (getting_opts) {
X	pw_text(msg_win, save_orig_x, txt.y, PIX_SRC, fonts[curfont],
X		&String[++backchars]);
X	txt.x -= l_width(curfont);
X	pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], ' ');
X    } else {
X	txt.x = 5;
X	if ((txt.y += l_height(curfont)) >= LASTLINE)
X	    scroll_win(1);
X    }
X}
X
XAddstr(s)
Xregister char *s;
X{
X    char buf[BUFSIZ];
X    register int cnt = 0, max_len;
X    register char *p = buf, newline = 0;
X
X    max_len = (msg_rect.r_width - 10) / l_width(curfont) + 1;
X
X    while ((*p = *s++) && *p != '\n' && cnt < max_len)
X	if (*p == '\t')
X	    do *p++ = ' ';
X	    while (++cnt % 8);
X	else p++, cnt++;
X    *p = 0;
X
X    if (*--s)
X	newline = *s, *s = 0; /* newline may or may not be a '\n' */
X    else
X	s = 0;
X
X    if (*buf) {
X	if (msg_pix) {
X	    struct pr_prpos pixr;
X	    pixr.pr = msg_pix;
X	    pixr.pos = txt;
X	    pf_text(pixr, PIX_SRC, fonts[curfont], buf);
X	} else
X	    pw_text(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], buf);
X	txt.x += cnt * l_width(curfont);
X    }
X    if (newline) {
X	if (newline != '\n')
X	    *s = newline;
X	if ((txt.y += l_height(curfont)) >= LASTLINE && !msg_pix)
X	    scroll_win(1);
X	txt.x = 5;
X	if (newline == '\n' && !*++s)
X	    return;
X	Addstr(s);
X    }
X}
X
Xtool_more(p)
Xregister char *p;
X{
X    int percent;
X    /* we are typing -- scrool the window */
X    if (!msg_pix) {
X	scroll_win(1);
X	return;
X    }
X    if (p)
X	print(p);
X    else {
X	if ((percent = (still_more * 100) / msg_pix->pr_size.y) >= 100)
X	    print( "--End of Message %d--", current_msg+1);
X	else
X	    print("--Message %d--(%d%%)", current_msg+1, percent);
X	if (ison(glob_flags, IS_GETTING))
X	    print_more(" ('q' returns to type-in mode)");
X    }
X}
END_OF_FILE
if test 4613 -ne `wc -c <'rite.c'`; then
    echo shar: \"'rite.c'\" unpacked with wrong size!
fi
# end of 'rite.c'
fi
if test -f 'sort.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sort.c'\"
else
echo shar: Extracting \"'sort.c'\" \(5125 characters\)
sed "s/^X//" >'sort.c' <<'END_OF_FILE'
X/* signals.c 1.1	(c) copyright 1986 (Dan Heller) */
X
X#include "mush.h"
X/* #define MYQSORT */
X
Xstatic int order;
Xstatic jmp_buf sortbuf;
X
Xsort(argc, argv, list)
Xregister int argc;
Xregister char *argv[], list[];
X{
X    int status_cmp(), author_cmp(), date_cmp(), subject_cmp(), subj_with_re();
X    int (*oldint)(), (*oldquit)();
X    int (*how)() = status_cmp;
X    int n, offset = -1, range = 0;
X
X    order = 1;
X
X    while (argc && *++argv) {
X	n = 0;
X	while (argv[0][n])
X	    switch(argv[0][n++]) {
X		case '-': order = -1;
X		when 'd': how = date_cmp;
X		when 'a': how = author_cmp;
X		when 's': how = subject_cmp;
X		when 'R': how = subj_with_re;
X		when 'S': how = status_cmp;
X		otherwise: return help(0, "sort_help", cmd_help);
X	    }
X    }
X    if (msg_cnt <= 1) {
X	print("Not enough messages to sort.\n");
X	return -1;
X    }
X    on_intr();
X
X    if (list && ison(glob_flags, IS_PIPE)) {
X	for (n = 0; n < msg_cnt; n++)
X	    if (msg_bit(list, n)) {
X		if (offset < 0)
X		    offset = n;
X		range++;
X	    } else if (offset >= 0)
X		break;
X    } else
X	offset = 0, range = msg_cnt;
X
X    if (range < 2)
X	print("Range not broad enough to sort anything\n");
X    else {
X	Debug("Sorting %d messages starting at message %d\n", range, offset+1);
X
X	if (setjmp(sortbuf) == 0)
X	    qsort((char *)&msg[offset], range, sizeof (struct msg), how);
X	else
X	    print("WARNING: Sorting interrupted: unpredictable order.\n");
X	turnon(glob_flags, DO_UPDATE);
X    }
X    off_intr();
X    return -1;
X}
X
X#ifdef MYQSORT
Xqsort(base, len, siz, compar)
Xregister struct msg *base;
Xint (*compar)();
X{
X     register int i, swapping;
X     struct msg temp;
X
X     do  {
X	 swapping = 0;
X	 for (i = 0; i < len-1; ++i) {
X	     if (compar(base+i, base+i+1) > 0) {
X		 temp = base[i];
X		 base[i] = base[i+1];
X		 base[i+1] = temp;
X		 swapping = 1;
X	     }
X	 }
X     } while (swapping);
X}
X#endif MYSORT
X
Xstatus_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X    if (ison(glob_flags, WAS_INTR))
X	longjmp(sortbuf, 1);
X    if (msg1 < msg || msg2 < msg) {
X	wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg);
X	return 0;
X    }
X    if (msg1->m_flags == msg2->m_flags)
X        return 0;
X    if (ison(msg1->m_flags, DELETE) && isoff(msg2->m_flags, DELETE))
X	return order;
X    if (isoff(msg1->m_flags, DELETE) && ison(msg2->m_flags, DELETE))
X	return -order;
X    if (isoff(msg1->m_flags, OLD) && ison(msg2->m_flags, OLD))
X	return -order;
X    if (ison(msg1->m_flags, OLD) && isoff(msg2->m_flags, OLD))
X	return order;
X    if (ison(msg1->m_flags, UNREAD) && isoff(msg2->m_flags, UNREAD))
X	return -order;
X    if (isoff(msg1->m_flags, UNREAD) && ison(msg2->m_flags, UNREAD))
X	return order;
X    if (ison(msg1->m_flags,PRESERVE) && isoff(msg2->m_flags,PRESERVE))
X	return -order;
X    if (isoff(msg1->m_flags,PRESERVE) && ison(msg2->m_flags,PRESERVE))
X	return order;
X
X    return order;
X}
X
Xauthor_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X    char buf1[BUFSIZ], buf2[BUFSIZ];
X
X    if (ison(glob_flags, WAS_INTR))
X	longjmp(sortbuf, 1);
X    if (msg1 < msg || msg2 < msg) {
X	wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg);
X	return 0;
X    }
X    (void) reply_to(msg1 - msg, 0, buf1); /* "0" for "author only" */
X    (void) reply_to(msg2 - msg, 0, buf2);
X    Debug("author: msg %d: %s, msg %d: %s\n", msg1-msg, buf1, msg2-msg, buf2);
X    return strcmp(buf1, buf2) * order;
X}
X
X/*
X * compare subject strings from two messages.
X * If Re is appended, so be it -- if user wants to ignore Re: use 'R' flag.
X */
Xsubj_with_re(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X    char buf1[256], buf2[256];
X
X    if (ison(glob_flags, WAS_INTR))
X	longjmp(sortbuf, 1);
X    if (msg1 < msg || msg2 < msg) {
X	wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg);
X	return 0;
X    }
X    (void) subject_to(msg1 - msg, buf1);
X    (void) subject_to(msg2 - msg, buf2);
X    Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n", msg1-msg,buf1,msg2-msg,buf2);
X    return strcmp(buf1, buf2) * order;
X}
X
X/*
X * Subject comparison ignoring Re:  subject_to() appends an Re: if there is
X * any subject whatsoever.  If so, skip 4 chars.  If not, set to ""
X */
Xsubject_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X    char buf1[256], buf2[256], *p1, *p2;
X
X    if (ison(glob_flags, WAS_INTR))
X	longjmp(sortbuf, 1);
X    if (msg1 < msg || msg2 < msg) {
X	wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg);
X	return 0;
X    }
X    if (p1 = subject_to(msg1 - msg, buf1))
X	p1 += 4;
X    else
X	p1 = "";
X    if (p2 = subject_to(msg2 - msg, buf2))
X	p2 += 4;
X    else
X	p2 = "";
X    Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n", msg1-msg, p1, msg2-msg, p2);
X    return strcmp(p1, p2) * order;
X}
X
Xdate_cmp(msg1, msg2)
Xregister struct msg *msg1, *msg2;
X{
X    char buf1[11], buf2[11];
X
X    if (ison(glob_flags, WAS_INTR))
X	longjmp(sortbuf, 1);
X    if (msg1 < msg || msg2 < msg) {
X	wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg);
X	return 0;
X    }
X    (void) strcpy(buf1, msg_date(msg1-msg));
X    (void) strcpy(buf2, msg_date(msg2-msg));
X    Debug("dates: msg %d: %s, msg %d: %s\n", msg1-msg, buf1, msg2-msg, buf2);
X    return strcmp(buf1, buf2) * order;
X}
END_OF_FILE
if test 5125 -ne `wc -c <'sort.c'`; then
    echo shar: \"'sort.c'\" unpacked with wrong size!
fi
# end of 'sort.c'
fi
echo shar: End of archive 2 \(of 12\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 12 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