[comp.sources.unix] v11i061: Mail user's shell, Part11/12

rsalz@uunet.UU.NET (Rich Salz) (09/21/87)

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

#! /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 11 (of 12)."
# Contents:  help.c main.c pick.c setopts.c signals.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'help.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'help.c'\"
else
echo shar: Extracting \"'help.c'\" \(9747 characters\)
sed "s/^X//" >'help.c' <<'END_OF_FILE'
X/* @(#)help.c	(c) copyright 10/15/86 (Dan Heller) */
X
X/*
X * This file conatins two main routines:
X *    display_help() and find_help()
X * Both are virtually equivalent in functionality; they are passed
X * a char * or a char **. If a char * is passed, then open "file"
X * argument (containing help strings) and search for %str% and read
X * the following text until %% or EOF into a local buffer.
X * If str is a char **, then that array of strings is used directly.
X *
X * If display_help is used, then the final array of strings used is
X * displayed in the center of the bitmapped console in a box with
X * shading and the user must hit the left mouse button to remove the
X * message.  the fd passed is the fd of the window locking the screen.
X *
X * In text mode, the routine find_help is used (or, if the graphics
X * mode doesn't want to lock the screen to display a message). The
X * same actions occur, but instead of "ifdef"ing up one function, I
X * just made two for readability.
X */
X#include <stdio.h>
X#include "strings.h"
X
X#define NULL_FILE (FILE *)0
X
X#ifdef SUNTOOL
X#include <suntool/tool_hs.h>
X#include <signal.h>
X#include <suntool/fullscreen.h>
X
X#define l_width()	  font->pf_defaultsize.x /* width of letter */
X#define l_height()	  font->pf_defaultsize.y /* height of letter */
X
X#define draw(win,x1,y1,x2,y2,OP) 	pw_vector(win, x1,y1,x2,y2,OP,1)
X#define box(win, x1,y1,x2,y2,OP) \
X	draw(win,x1,y1, x1,y2, OP), \
X	draw(win,x1,y2, x2,y2, OP), \
X	draw(win,x2,y2, x2,y1, OP), \
X	draw(win,x2,y1, x1,y1, OP)
X
X#define DEF_CONT_MSG	"Click LEFT mouse Button to continue."
XDEFINE_CURSOR(oldcursor, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
X
X/* shading */
Xstatic short dat_shade_25[] = {
X#include <images/square_25.pr>
X};
X
Xstatic short dat_shade_50[] = {
X#include <images/square_50.pr>
X};
X
Xstatic short dat_shade_75[] = {
X#include <images/square_75.pr>
X};
X
Xstatic short dat_mouse_left[] = {
X#include <images/confirm_left.pr> 
X};
X
Xmpr_static(shade_25,        16, 16, 1, dat_shade_25);
Xmpr_static(shade_50,        16, 16, 1, dat_shade_50);
Xmpr_static(shade_75,        16, 16, 1, dat_shade_75);
Xmpr_static(confirm_pr,      16, 16, 1, dat_mouse_left);
X
Xstatic struct cursor confirm_cursor = { 3, 3, PIX_SRC, &confirm_pr };
Xstatic struct pixrect *shading;
X
X#else
X
X#include <sys/types.h>
X#define wprint printf
X#define print  printf
X
X#endif /* SUNTOOL */
X
X/* what to print if nothing was found */
Xstatic char *def_msg[] = {
X    "There is no help found for this item.",
X    "Perhaps getting help from another item",
X    "would be of some use.", 0
X};
X
X#define MAXLINES	40
X#define MAXLENGTH	128
Xstatic FILE *help_file;
Xstatic char file_name[128];
X
X#ifdef SUNTOOL
Xdisplay_help(fd, str, file, font)
Xregister caddr_t *str;   /* could be a single or double pointer */
Xregister char *file;
Xregister struct pixfont *font;
X{
X    struct fullscreen *fs;
X    struct inputmask im, old_im;
X    struct inputevent event;
X    struct rect rect;
X    register char *p;
X    register int x, y, z, height;
X    struct pixrect *saved, *save_bits();
X    int width = 0, old_link;
X    char *cont_msg = DEF_CONT_MSG, *getenv();
X    char args[MAXLINES][MAXLENGTH], help_str[40];
X
X    if (!shading)
X	if (p = getenv("SHADE")) {
X	    register int x = atoi(p);
X	    if (x <= 25)
X		shading = &shade_25;
X	    else if (x <= 50)
X		shading = &shade_50;
X	    else
X		shading = &shade_75;
X	} else
X	    shading = &shade_25;
X
X    /* If no file given, take "str" arg as message to print */
X    if (!file || !*file) {
X	file = NULL;
X	for(height = 0; *str && height < MAXLINES-1; height++) {
X	    if (!compose_str(*str, &width))
X		break;
X	    (void) strcpy(args[height], *str++);
X	}
X    } else {
X	if (!*file_name || strcmp(file_name, file)) {
X	    (void) strcpy(file_name, file);
X	    if (help_file)
X		fclose(help_file), help_file = NULL_FILE;
X	}
X	/* file remains open */
X	if (!help_file && !(help_file = fopen(file_name, "r")))
X	    return -1;
X	/* look for %str% in helpfile */
X	(void) sprintf(help_str, "%%%s%%\n", str);
X
X	rewind(help_file);
X
X	while(p = fgets(args[0], MAXLENGTH, help_file))
X	    if (*p == '%' && !strcmp(p, help_str))
X		break;
X
X	if (!p || !fgets(args[0], MAXLENGTH, help_file))
X	    for(height = 0; def_msg[height] && height < MAXLINES-1; height++) {
X		compose_str(def_msg[height], &width);
X		(void) strcpy(args[height], def_msg[height]);
X	    }
X	else for (height = 0; p && *p && strcmp(p, "%%\n"); height++) {
X		compose_str(p, &width);
X		p = fgets(args[height+1], MAXLENGTH, help_file);
X	    }
X    }
X    if (height == MAXLINES - 1)
X	print("Help message is too long!\n");
X
X    fs = fullscreen_init(fd);
X    /* Figure out the height and width in pixels (rect.r_height, rect.r_width)
X     * Remember to provide for the "confirm" line (cont_msg).
X     * extend the new box by 15 pixels on the sides (30 total), top, and bottom.
X     * finally, add 16 pixels for "shadow" -- remove before clearing area
X     * to preserve background and give a shadow-like appearance.
X     */
X    if ((x = strlen(cont_msg)) > width)
X	width = x; /* this x value must be saved! */
X    rect.r_width = (width*l_width()) + 30 + 16;
X    rect.r_height = ((height+1) * l_height()) + 30 + 16;
X    rect.r_left = fs->fs_screenrect.r_left +
X	(fs->fs_screenrect.r_width / 2) - (rect.r_width / 2);
X    rect.r_top = fs->fs_screenrect.r_top +
X	(fs->fs_screenrect.r_height / 2) - (rect.r_height / 2);
X
X    /* save old area */
X    saved = save_bits(fs->fs_pixwin, &rect);
X
X    /* prepare surface, clear the background, and reset rect for shadow */
X    pw_preparesurface(fs->fs_pixwin, &rect);
X    pw_lock(fs->fs_pixwin, &rect);
X    rect.r_width -= 16;
X    rect.r_height -= 16;
X
X    pw_writebackground(fs->fs_pixwin,
X	rect.r_left, rect.r_top, rect.r_width, rect.r_height, PIX_CLR);
X
X    /* make a box that's 5 pixels thick. Then add a thin box inside it */
X    for (z = 0; z < 5; z++)
X	box(fs->fs_pixwin,
X	    rect.r_left+z, rect.r_top+z,
X	    rect.r_left+rect.r_width-z-1, rect.r_top+rect.r_height-z-1,
X	    PIX_SRC);
X    box(fs->fs_pixwin,
X	rect.r_left+z+2, rect.r_top+z+2,
X	rect.r_left+rect.r_width-z-3, rect.r_top+rect.r_height-z-3,
X	PIX_SRC);
X
X    /* shading -- pw_replrop() doesn't work (bug)
X     * NOTE: fs->fs_screenrect.r_top and r_left are negative values
X     */
X    pr_replrop(fs->fs_pixwin->pw_pixrect,
X	   rect.r_left + rect.r_width - fs->fs_screenrect.r_left,
X	   rect.r_top + 16 - fs->fs_screenrect.r_top,
X	   16, rect.r_height-16, PIX_SRC|PIX_DST, shading, 0, 0);
X    pr_replrop(fs->fs_pixwin->pw_pixrect,
X	   rect.r_left + 16 - fs->fs_screenrect.r_left,
X	   rect.r_top+rect.r_height - fs->fs_screenrect.r_top,
X	   rect.r_width, 16, PIX_SRC|PIX_DST, shading, 0, 0);
X
X    if (x > width)
X	x = 15;
X    else
X	x = rect.r_width/2 - (x*l_width())/2;
X    y = rect.r_height - 15;
X
X    /* Print everything in reverse order now; start with the "confirm" string
X     * (which is centered and highlighted)
X     */
X    pw_text(fs->fs_pixwin, rect.r_left+x, rect.r_top+y, PIX_SRC,font, cont_msg);
X    pw_text(fs->fs_pixwin, rect.r_left+x+1, rect.r_top+y, PIX_SRC|PIX_DST, font,
X	    cont_msg);
X
X    y -= (5 + l_height());
X    x = 15;
X
X    /* now print each string in reverse order (start at bottom of box) */
X    for (height--; height >= 0; height--) {
X	pw_text(fs->fs_pixwin, rect.r_left+x, rect.r_top+y,
X	    PIX_SRC, font, args[height]);
X	y -= l_height();
X    }
X
X    pw_unlock(fs->fs_pixwin);
X
X    /* wait for user to read and confirm */
X    win_getinputmask(fd, &old_im, &old_link);
X    input_imnull(&im);
X    im.im_flags |= IM_ASCII;
X    win_setinputcodebit(&im, MS_LEFT);
X    win_setinputcodebit(&im, MS_MIDDLE);
X    win_setinputcodebit(&im, MS_RIGHT);
X    win_setinputmask(fd, &im, &im, WIN_NULLLINK);
X    win_getcursor(fd, &oldcursor);
X    win_setcursor(fd, &confirm_cursor);
X    while (input_readevent(fd, &event) != -1 && event.ie_code != MS_LEFT);
X
X    /* restore old cursor */
X    win_setcursor(fd, &oldcursor);
X
X    /* restore old pixrect (size already restored) */
X    rect.r_height += 16; /* to take care of the shadow */
X    rect.r_width += 16;
X    restore_bits(fs->fs_pixwin, &rect, saved);
X    /* release screen */
X    fullscreen_destroy(fs);
X    win_setinputmask(fd, &old_im, &old_im, old_link);
X    return 0;
X}
X
Xstatic
Xcompose_str(p, width)
Xregister char *p;
Xint *width;
X{
X    register int x;
X    if (!p || !*p)
X	return 0;
X    x = strlen(p);
X    if (p[x-1] == '\n')
X	p[--x] = 0; /* get rid of newline */
X    if (x > *width)
X	*width = x;
X    return 1;
X}
X#endif SUNTOOL
X
Xfind_help(str, file)
Xregister caddr_t *str;
Xregister char *file;
X{
X    register char	*p;
X    char		args[MAXLINES][MAXLENGTH], help_str[40];
X    register int	n, height;
X    extern char		*no_newln();
X
X    /* If no file given, take "str" arg as message to print */
X    if (!file || !*file) {
X	file = NULL;
X	for(height = 0; *str && height < MAXLINES-1; height++)
X	    (void) strcpy(args[height], *str++);
X    } else {
X	if (!*file_name || strcmp(file_name, file)) {
X	    (void) strcpy(file_name, file);
X	    if (help_file)
X		fclose(help_file), help_file = NULL_FILE;
X	}
X	/* file remains open */
X	if (!help_file && !(help_file = fopen(file_name, "r")))
X	    return -1;
X	/* look for %str% in helpfile */
X	(void) sprintf(help_str, "%%%s%%\n", str);
X	rewind(help_file);
X	while(p = fgets(args[0], MAXLENGTH, help_file))
X	    if (*p == '%' && !strcmp(p, help_str))
X		break;
X	if (!p || !fgets(args[0], MAXLENGTH, help_file))
X	    for(height = 0; def_msg[height] && height < MAXLINES-1; height++)
X		(void) strcpy(args[height], def_msg[height]);
X	else for (height = 0; p && *p && strcmp(p, "%%\n"); height++)
X	    p = fgets(args[height+1], MAXLENGTH, help_file);
X    }
X    if (height == MAXLINES - 1)
X	print("Help message is too long!\n");
X
X    for (n = 0; n < height; n++) {
X	(void) no_newln(args[n]);
X	wprint("%s\n", args[n]);
X    }
X
X    return 0;
X}
END_OF_FILE
if test 9747 -ne `wc -c <'help.c'`; then
    echo shar: \"'help.c'\" unpacked with wrong size!
fi
# end of 'help.c'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(10552 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X/* @(#)main.c	(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
Xstatic char *usage_str =
X#ifdef SUNTOOL 
X    "usage: %s [-C] [-i] [-f [folder] ] [-v] [-S] [-t] [-s subject] [users]\n";
X#else
X#ifdef CURSES
X    "usage: %s [-C] [-i] [-f [folder] ] [-v] [-S] [-s subject] [user list]\n";
X#else
X    "usage: %s [-i] [-f [folder] ] [-v] [-S] [-s subject] [user list]\n";
X#endif CURSES
X#endif SUNTOOL
X
X#if defined(sun) && defined(M_DEBUG)
Xcpu()
X{
X    print("CPU time limit exceeded!\n");
X}
X#endif sun && DEBUG
X
X/*ARGSUSED*/   /* we ignore envp */
Xmain(argc, argv)
Xchar **argv;
X{
X    int 	    flg = NO_FLG, n;
X    char 	    f_flags[10], buf[256], *Cc = NULL;
X    register char   *p;
X
X    if (prog_name = rindex(*argv, '/'))
X	prog_name++;
X    else
X	prog_name = *argv;
X
X    (void) signal(SIGBUS,  bus_n_seg);
X    (void) signal(SIGSEGV, bus_n_seg);
X
X    f_flags[0] = 0;
X    mailfile = "";
X
X#if defined(sun) && defined(M_DEBUG)
X    (void) signal(SIGXCPU, cpu);
X
X    if (p = getenv("MALLOC_DEBUG"))
X	malloc_debug(atoi(p));
X    else
X	malloc_debug(0);
X#endif sun && debug
X
X    if (!isatty(0))
X	turnon(glob_flags, REDIRECT);
X    f_flags[0] = '\0';
X
X    n = 0; /* don't ignore no such file or directory */
X    p = getpath(COMMAND_HELP, &n);
X    if (n) {
X	fprintf(stderr, "Warning: can't read %s: %s\n", COMMAND_HELP, p);
X	cmd_help = "cmd_help";
X    } else
X	strdup(cmd_help, p);
X#ifdef SUNTOOL
X    n = 0;
X    p = getpath(TOOL_HELP, &n);
X    if (n) {
X	fprintf(stderr, "Warning: can't read %s: %s\n", TOOL_HELP, p);
X	tool_help = "tool_help";
X    } else
X	strdup(tool_help, p);
X
X    istool = strlen(prog_name) > 3 &&
X		  !strcmp(prog_name+strlen(prog_name)-4, "tool");
X    time_out = 60;
X#endif SUNTOOL
X
X    /*
X     * preparse the command line looking for certain arguments which must
X     * be known before sourcing the .mushrc file.  This should definitely
X     * be optimized -- see the TODO file accompanying this distibution.
X     */
X    n = 1;
X    if (argc > 1) {
X	char **args;
X	for (args = argv; *args; args++)
X#ifdef SUNTOOL
X	    if (!strcmp(*args, "-t"))
X		istool = 1;
X	    else
X#endif SUNTOOL
X	    if (!strcmp(*args, "-C") && !hdrs_only)
X		/* this will only temporarily be turned on! */
X		turnon(glob_flags, PRE_CURSES);
X	    /* headers only?  get args later, just set to a non-null value */
X	    else if (!strncmp(*args, "-H", 2))
X		hdrs_only = NO_STRING, turnoff(glob_flags, PRE_CURSES);
X	    else if (!strcmp(*args, "-d"))
X		debug = 1;
X	    else if (!strcmp(*args, "-n"))
X		n = 0;
X    }
X
X    /*
X     * read mailrc and so forth. Global variables not set there will have
X     * default settings here.  Set them first so user overrides in "source()"
X     */
X    init(); /* must be done before checking mail since "login" is set here */
X
X    /* check to see if we have any mail at all */
X    if (argc < 2 && !istool) { /* istool may be set with one arg: "mushtool" */
X	struct stat statb;
X	if (stat(sprintf(buf, "%s/%s", MAILDIR, login), &statb) ||
X		statb.st_size == 0) {
X	    printf("No mail for %s.\n", login);
X	    exit(1);
X	}
X    }
X    /* -n flag above */
X    if (n)
X	(void) source(0, DUBL_NULL);
X
X#ifdef SUNTOOL
X    if (istool)
X	if (ison(glob_flags, REDIRECT))
X	    puts("You can't redirect input to a tool."), exit(1);
X	else
X	    make_tool(argc, argv), turnon(glob_flags, DO_SHELL);
X#endif SUNTOOL
X
X    for (argv++; *argv && **argv == '-'; argv++)
X	switch (argv[0][1]) {
X	    case 'e':
X		/*
X		 * don't set tty modes -- e.g. echo and cbreak modes aren't
X		 * changed.
X		 */
X		turnon(glob_flags, ECHO_FLAG);
X#ifdef CURSES
X	    when 'C':
X		/* don't init curses -- don't even set iscurses.   */
X		if (istool) {
X		    puts("-C: You are already running in tool mode");
X		    turnoff(glob_flags, PRE_CURSES);
X		} else if (hdrs_only) {
X		    puts("headers only: ignoring -C flag");
X		    turnoff(glob_flags, PRE_CURSES);
X		} else
X		    turnon(glob_flags, PRE_CURSES);
X#endif CURSES
X	    when 'N':
X		(void) strcat(f_flags, "-N ");
X	    when 'r':
X		(void) strcat(f_flags, "-r "); /* folder() argument */
X	    when 'H':
X		if (istool) {
X		    puts("running in tool-mode; -H option ignored.");
X		    break;
X		}
X		turnoff(glob_flags, PRE_CURSES);
X		if (*(hdrs_only = (*argv)+2) != ':')
X		    hdrs_only = ":a";
X		(void) strcat(f_flags, "-N "); /* tell folder not to do_hdrs */
X	    when 'i':
X		/* force interactive even if !isatty(0) */
X		turnoff(glob_flags, REDIRECT);
X	    /* if no argument for this, use mbox in _current directory_ */
X	    when 'f':
X		if (argv[1])
X		    p = *++argv;
X		else if (!(p = do_set(set_options, "mbox")) || !*p)
X		    p = DEF_MBOX;
X		strdup(mailfile, getpath(p, &n));
X		if (n) {
X		    if (n == -1)
X			print("%s: %s\n", p, mailfile);
X		    else
X			print("%s: Is a directory\n", mailfile);
X		    if (!istool)
X			exit(1);
X		    strdup(mailfile, "");
X		}
X	    when '1':
X		if (argv[1])
X		    strdup(cmd_help, *++argv);
X		else
X		    puts("-1 \"filename\""), cleanup(0);
X#ifdef SUNTOOL
X	    when '2':
X		if (argv[1])
X		    strdup(tool_help, *++argv);
X		else
X		    puts("-2 \"filename\""), cleanup(0);
X#endif SUNTOOL
X	    when 's':
X		if (istool)
X		    puts("bad option when run as a tool");
X		else if (argv[1])
X		    (void) strcpy(buf, *++argv);
X		else
X		    puts("-s \"subject\""), cleanup(0);
X	    when 'c':
X		if (istool)
X		    puts("bad option when run as a tool");
X		else if (argv[1])
X		    strdup(Cc, *++argv);
X		else
X		    puts("-c \"cc list\""), exit(1);
X	    when 'S': turnon(glob_flags, DO_SHELL); /* force the shell */
X#ifdef VERBOSE_ARG
X	    when 'v':
X		if (istool)
X		    puts("bad option when run as a tool");
X		turnon(flg, VERBOSE);
X#endif VERBOSE_ARG
X#ifdef SUNTOOL
X            when 'T':
X		if (!*++argv)
X		    continue;
X		if (istool && (time_out = atoi(*argv)) <= 29)
X		    time_out = 30;
X		else
X		    printf("-T flag ignored unless run as tool."), exit(1);
X	    when 't': ;   /* prevent error message */
X#endif SUNTOOL
X	    when 'n': case 'd': ;   /* prevent error messages */
X	    otherwise:
X		print("%s: unknown option: `%c'\n", prog_name,
X		    argv[0][1]? argv[0][1] : '-');
X		print(usage_str, prog_name);
X		if (!istool)
X		    exit(1);
X	}
X
X    /* now we're ready for I/O */
X    if (isoff(glob_flags, REDIRECT)) {
X	/* make sure we can always recover from no echo mode */
X	(void) signal(SIGINT, catch);
X	(void) signal(SIGQUIT, catch);
X	if (istool)
X	    turnon(glob_flags, ECHO_FLAG);
X	savetty();
X#ifdef TIOCGLTC
X	if (isatty(0) && ioctl(0, TIOCGLTC, &ltchars))
X	    error("TIOCGLTC");
X#endif TIOCGLTC
X#ifdef SIGCONT
X	(void) signal(SIGTSTP, stop_start); /* this will take care of SIGCONT */
X#endif SIGCONT
X	/* echo_off() checks to see if echo_flg is set, so don't worry */
X	echo_off();
X    }
X
X    if (*argv) {
X	char recipients[BUFSIZ];
X	if (*mailfile)
X	    puts("You can't specify more than one folder"), cleanup(0);
X	if (istool)
X	    puts("You can't mail someone and run a tool."), cleanup(0);
X	(void) argv_to_string(recipients, argv);
X	/* prompt for subject and Cc list, but not "To: "
X	 * mail_someone() already takes care of redirection.
X	 * if -s or -c options are given, they will be passed.
X	 */
X	if (do_set(set_options, "autosign"))
X	    turnon(flg, SIGN);
X	if (do_set(set_options, "autoedit"))
X	    turnon(flg, EDIT);
X	if (do_set(set_options, "verbose"))
X	    turnon(flg, VERBOSE);
X	if (do_set(set_options, "fortune")) {
X	    p = do_set(set_options, "fortunates");
X	    if (!p || *p && (chk_two_lists(recipients, p, " \t,")
X		   || (Cc && *Cc && chk_two_lists(Cc, p, " \t,"))))
X		turnon(flg, DO_FORTUNE);
X	}
X	/* set now in case user is not running shell, but is running debug */
X	(void) signal(SIGCHLD, sigchldcatcher);
X	(void) mail_someone(recipients, buf, Cc, flg, NULL);
X	/* do shell set from above: "mush -S user" perhaps */
X	if (isoff(glob_flags, DO_SHELL)) {
X	    if (isoff(glob_flags, REDIRECT))
X		echo_on();
X	    exit(0);
X	}
X    }
X    if (ison(glob_flags, REDIRECT)) {
X	puts("You can't redirect input unless you're sending mail.");
X	puts("If you want to run a shell with redirection, use \"-i\"");
X	cleanup(0);
X    }
X    if (!*mailfile) {
X	strdup(mailfile, sprintf(buf, "%s/%s", MAILDIR, login));
X	if (!mail_size() && isoff(glob_flags, DO_SHELL)) {
X	    /* we know it's not the spool file here */
X	    printf("No mail in %s.\n", mailfile);
X	    echo_on(), exit(0);
X	}
X    }
X    /* At this point, we know we're running a shell, so... */
X    if (!hdrs_only) {
X	/* catch will test DO_SHELL and try to longjmp if set.  this is a
X	 * transition state from no-shell to do-shell to ignore sigs to
X	 * avoid a longjmp botch.  Note setjmp isn't called until do_loop().
X	 */
X	turnon(glob_flags, DO_SHELL);
X	turnon(glob_flags, IGN_SIGS);
X#ifdef CURSES
X	if (ison(glob_flags, PRE_CURSES))
X	    (void) curses_init(0, DUBL_NULL);
X	turnoff(glob_flags, PRE_CURSES);
X#endif CURSES
X    }
X
X    /* find a free tmpfile */
X    flg = getpid();
X    if (!(p = do_set(set_options, "home")) || !*p)
X	p = ALTERNATE_HOME;
X    while (!access(sprintf(tempfile, "%s/.%s%d", p, prog_name, flg++), 0))
X	;
X    /* just create the file, make sure it's empty.  It'll close later and
X     * be reopened for reading only.
X     */
X    {
X	int omask = umask(077);
X	if (!(tmpf = fopen(tempfile, "w"))) {
X	    error("Can't create tempfile %s", tempfile);
X	    cleanup(0);
X	}
X	(void) umask(omask);
X    }
X
X    /* do pseudo-intelligent stuff with certain signals */
X    (void) signal(SIGINT,  catch);
X    (void) signal(SIGQUIT, catch);
X    (void) signal(SIGHUP,  catch);
X
X    /* if we're a suntool, then state the version and mark first message
X     * as "read" since it will be displayed right away
X     */
X    if (!hdrs_only && !istool && !do_set(set_options, "quiet"))
X	printf("%s: Type '?' for help.\n", VERSION);
X
X    (void) sprintf(buf, "folder %s %s", f_flags, mailfile);
X    if (argv = make_command(buf, TRPL_NULL, &argc)) {
X	(void) folder(argc, argv, NULL);
X	free_vec(argv);
X    }
X
X    if (hdrs_only) {
X	(void) sprintf(buf, "headers %s", hdrs_only);
X	if (argv = make_command(buf, TRPL_NULL, &argc))
X	    (void) do_hdrs(argc, argv, NULL);
X	cleanup(0);
X    }
X
X    if (istool && msg_cnt)
X	set_isread(current_msg);
X
X    sort_commands();
X    sort_variables();
X
X#ifdef SUNTOOL
X    if (istool) {
X	turnoff(glob_flags, IGN_SIGS);
X	(void) do_hdrs(0, DUBL_NULL, NULL);
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	(void) signal(SIGALRM, check_new_mail);
X	unlock_cursors();
X	while (!(tool->tl_flags & TOOL_DONE))
X	    tool_select(tool, 1);
X	cleanup(0);
X    }
X#endif SUNTOOL
X	do_loop();
X}
X
Xdo_version()
X{
X    print("%s\n", VERSION);
X    return -1;
X}
END_OF_FILE
if test 10552 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'pick.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pick.c'\"
else
echo shar: Extracting \"'pick.c'\" \(10068 characters\)
sed "s/^X//" >'pick.c' <<'END_OF_FILE'
X/* @(#)pick.c	2.4	(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
Xstatic int before, mdy[3], search_from, search_subj, search_to, xflg, icase;
X
Xdo_pick(n, argv, list)
Xregister int n;
Xregister char **argv, list[];
X{
X    if (n > 1 && !strcmp(argv[1], "-?"))
X	return help(0, "pick", cmd_help);
X
X    /* if is_pipe, then the messages to search for are already set.
X     * if not piped, then reverse the bits for all message numbers.
X     * That is, search EACH message. only those matching will be returned.
X     */
X    if (isoff(glob_flags, IS_PIPE))
X	bitput(list, list, msg_cnt, =~) /* macro, turn on all bits */
X    if (pick(n, argv, list, isoff(glob_flags, DO_PIPE)) == -1)
X	return -1;
X    if (isoff(glob_flags, DO_PIPE)) {
X	if (istool)
X	    print("Messages: ");
X	for (n = 0; n < msg_cnt; n++)
X	    if (msg_bit(list, n))
X		if (istool)
X		    print_more("%d ", n+1);
X		else
X		    print("%s\n", compose_hdr(n));
X    }
X    return 0;
X}
X
Xpick(ret, argv, list, verbose)
Xregister int ret;
Xregister char **argv, list[];
X{
X    register char c;
X    int o_before = before, o_mdy[3], o_search_from = search_from,
X	o_search_subj = search_subj, o_search_to = search_to, o_xflg = xflg, n;
X    for (c = 0; c < 3; c++)
X	o_mdy[c] = mdy[c];
X
X    ret = -1;
X    if (!msg_cnt) {
X	print("No Messages.\n");
X	goto bad;
X    }
X
X    icase = before = mdy[0] = search_from = search_subj = xflg = 0;
X    while (*argv && *++argv && **argv == '-')
X	switch(c = argv[0][1]) {
X	    /* users specifies a range */
X	    case 'r': {
X		int X = 2;
X		/* if not a pipe, then clear all bits cuz we only want
X		 * to search the message specified here...
X		 * If it is a pipe, then add to the messages searched for.
X		 */
X		if (isoff(glob_flags, IS_PIPE))
X		    clear_msg_list(list);
X		/*  "-r10-15"
X		 *     ^argv[1][2]  if NULL, then
X		 * list detached from "r" e.g. "-r" "5-20"
X		 */
X		if (!argv[0][X])
X		    argv++, X = 0;
X		(*argv) += X;
X		n = get_msg_list(argv, list);
X		(*argv) -= X;
X		if (n == -1)
X		    goto bad;
X		argv += (n-1); /* we're going to increment another up top */
X	    }
X	    when 'd':
X		if (!*++argv) {
X		    print("specify a date for -%c\n", c);
X		    goto bad;
X		}
X		if (!date1(*argv))
X		    goto bad;
X	    when 's' : case 'f': case 't':
X		if (search_subj + search_from + search_to > 1) {
X		    print("specify one of `s', `f' or `t' only\n");
X		    goto bad;
X	        }
X	        if (c == 's')
X		    search_subj = 1;
X		else if (c == 'f')
X		    search_from = 1;
X		else
X		    search_to = 1;
X	    when 'x' : xflg = 1;
X	    when 'i' : icase = 1;
X	    otherwise:
X		print("pick: unknown flag: %c\n", argv[0][1]);
X		clear_msg_list(list);
X		return -1;
X	}
X    if (verbose) {
X	print_more("Searching for messages");
X	if (mdy[1] == 0)
X	    print(" that %s \"%s\"", (xflg)? "doesn't contain": "contains",
X				(*argv)? *argv: "<previous expression>");
X	if (search_subj)
X	    print_more(" in subject line");
X	else if (search_from)
X	    print_more(" from author names");
X	else if (search_to)
X	    print_more(" from the To: field");
X	if (mdy[1] > 0) {
X	    extern char *month_names[]; /* from dates.c */
X	    print_more(" dated on or %s %s. %d, 19%d.",
X		  (before)? "before": "after",
X		  month_names[mdy[0]], mdy[1], mdy[2]);
X	}
X	print_more("\n");
X    }
X    if (mdy[1] > 0 && icase)
X	print("using date: -i flag ignored.\n");
X    ret = find_pattern(*argv, list);
Xbad:
X    before = o_before, search_from = o_search_from,
X	search_subj = o_search_subj, search_to = o_search_to, xflg = o_xflg;
X    for (c = 0; c < 3; c++)
X	mdy[c] = o_mdy[c];
X    return ret;
X}
X
Xfind_pattern(p, list)
Xregister char *p, list[];
X{
X    register int n, val, i; /* val is return value from regex or re_exec */
X    long bytes = 0;
X    char buf[BUFSIZ];
X    static char *err = (char *)-1;
X#ifndef SYSV
X    char *re_comp();
X#else
X    char *regcmp(), *regex();
X#endif SYSV
X
X    if (p && *p == '\\')
X	p++;  /* take care of escaping special cases (`-', `\') */
X
X    /* specify what we're looking for */
X    if (p && *p) {
X	if (icase)
X	    p = lcase_strcpy(buf, p);
X#ifndef SYSV
X	if (err = re_comp(p)) {
X	    print("re_comp error: %s\n", err);
X	    clear_msg_list(list);
X	    return -1;
X	}
X#else
X	if (err && p)
X	    xfree(err);
X	if (p && !(err = regcmp(p, NULL))) {
X	    print("regcmp error: %s\n", p);
X	    clear_msg_list(list);
X	    return -1;
X	}
X#endif SYSV
X    } else if (err == (char *)-1 && mdy[1] <= 0) {
X	print("No previous regular expression\n");
X	clear_msg_list(list);  /* doesn't matter really */
X	return -1;
X    }
X    /* start searching: set bytes, and message number: n */
X    for (n = 0; n < msg_cnt; n++)
X	if (msg_bit(list, n)) {
X	    if (mdy[1] > 0) {
X		int msg_mdy[3];
X		if (!(p = msg_date(n))) {
X		    unset_msg_bit(list, n);
X		    continue; /* error: don't consider this message */
X		}       /* yr mo da */
X		(void) sscanf(p, "%2d%2d%2d",
X		     &msg_mdy[2], &msg_mdy[0], &msg_mdy[1]);
X		msg_mdy[0]--;
X		Debug("checking %d's date: %d-%d-%d  ",
X			     n+1, msg_mdy[0]+1, msg_mdy[1], msg_mdy[2]);
X		/* start at year and wrap around.
X		 * only when match the day (4), check for == (match)
X		 */
X		for (i = 2; i < 5; i++)
X		    if (before && msg_mdy[i%3] < mdy[i%3]
X			|| !before && msg_mdy[i%3] > mdy[i%3]
X			|| i == 4 && (msg_mdy[i%3] == mdy[i%3])) {
X			    Debug("matched (%s).\n",
X				(i == 2)? "year" : (i == 3)? "month" : "day");
X			    break;
X		    } else if (msg_mdy[i%3] != mdy[i%3]) {
X			Debug("failed.\n");
X			unset_msg_bit(list, n);
X			break;
X		    }
X		continue;
X	    }
X	    /* we must have the right date -- if we're searching for a
X	     * string, find it.
X	     */
X	    (void) fseek(tmpf, msg[n].m_offset, L_SET);
X	    bytes = 0;
X	    while (bytes < msg[n].m_size) {
X		if (!search_subj && !search_from && !search_to &&
X				!(p = fgets(buf, BUFSIZ, tmpf)))
X		    break;
X		else if (search_subj) {
X		    if (!(p = header_field(n, "subject"))) {
X			unset_msg_bit(list, n);
X			break;
X		    }
X		} else if (search_from) {
X		    if (!(p = header_field(n, "from"))) {
X			register char *p2;
X			(void) fseek(tmpf, msg[n].m_offset, L_SET);
X			p2 = fgets(buf, BUFSIZ, tmpf);
X			p = index(p2, ' '), p++;
X			if (p2 = any(p, " \t"))
X			    *p2 = 0;
X		    }
X		} else if (search_to) {
X		    if (!(p = header_field(n, "to"))) {
X			unset_msg_bit(list, n);
X			break;
X		    }
X		}
X		if (icase)
X		    p = lcase_strcpy(buf, p);
X#ifndef SYSV
X		val = re_exec(p);
X#else
X		val = !!regex(err, p, NULL); /* convert value to a boolean */
X#endif SYSV
X		if (val == -1) {   /* doesn't apply in system V */
X		    print("Internal error for pattern search.\n");
X		    clear_msg_list(list); /* it doesn't matter, really */
X		    return -1;
X		}
X		if (xflg)
X		    val = !val;
X		if (!val) {
X		    /* unset the bit if match failed. If it matches later
X		     * in the search, we'll reset to true in the next iteration.
X		     * this doesn't apply for author or subject picks.
X		     */
X		    unset_msg_bit(list, n);
X		    bytes += strlen(p);
X		} else {
X		    set_msg_bit(list, n);
X		    break;
X		}
X		if (search_subj || search_from || search_to)
X		    break;
X	    }
X    }
X    return 0;
X}
X
X#ifdef CURSES
X/*
X * search for a pattern in composed message headers -- also see next function
X * flags ==  0   forward search (prompt).
X * flags == -1   continue search (no prompt).
X * flags ==  1   backward search (prompt).
X */
Xsearch(flags)
Xregister int flags;
X{
X    register char   *p;
X    char   	    pattern[128];
X    register int    this_msg = current_msg, val = 0;
X    static char     *err = (char *)-1, direction;
X    int		    (*oldint)(), (*oldquit)();
X#ifndef SYSV
X    char *re_comp();
X#else SYSV
X    char *regcmp();
X#endif SYSV
X
X    if (msg_cnt <= 1) {
X	print("Not enough messages to invoke a search.\n");
X	return 0;
X    }
X    pattern[0] = '\0';
X    if (flags == -1)
X	print("continue %s search...", direction? "forward" : "backward");
X    else
X	print("%s search: ", flags? "backward" : "forward");
X    if (flags > -1)
X	if (Getstr(pattern, COLS-18, 0) < 0)
X	    return 0;
X	else
X	    direction = !flags;
X#ifndef SYSV
X    if (err = re_comp(pattern)) {
X	print(err);
X	return 0;
X    }
X#else
X    if (err && *pattern)
X	xfree(err);
X    else if (err == (char *)-1 && !*pattern) {
X	print("No previous regular expression.");
X	return 0;
X    }
X    if (*pattern && !(err = regcmp(pattern, NULL))) {
X	print("Error in regcmp in %s", pattern);
X	return 0;
X    }
X#endif SYSV
X    move(LINES-1, 0), refresh();
X    on_intr();
X
X    do  {
X	if (direction)
X	    current_msg = (current_msg+1) % msg_cnt;
X	else
X	    if (--current_msg < 0)
X		current_msg = msg_cnt-1;
X        p = compose_hdr(current_msg);
X#ifndef SYSV
X	val = re_exec(p);
X#else
X	val = !!regex(err, p, NULL); /* convert value to a boolean */
X#endif SYSV
X	if (val == -1)     /* doesn't apply in system V */
X	    print("Internal error for pattern search.\n");
X    } while (!val && current_msg != this_msg && isoff(glob_flags, WAS_INTR));
X
X    if (ison(glob_flags, WAS_INTR)) {
X	print("Pattern search interruped.");
X	current_msg = this_msg;
X    } else if (val == 0)
X	print("Pattern not found.");
X
X    off_intr();
X    return val;
X}
X#endif CURSES
X
X/*
X * parse a user given date string and set mdy[] array with correct
X * values.  Return 0 on failure.
X */
Xdate1(p)
Xregister char *p;
X{
X    register char *p2;
X    long	  t;
X    int 	  i;
X    struct tm 	  *today;
X
X    if (*p == '-') {
X	before = 1;
X	skipspaces(1);
X    }
X    if (!isdigit(*p) && *p != '/') {
X	print("syntax error on date: \"%s\"\n", p);
X	return 0;
X    }
X    (void) time (&t);
X    today = localtime(&t);
X    for (i = 0; i < 3; i++)
X	if (!p || !*p || *p == '/') {
X	    switch(i) {   /* default to today's date */
X		case 0: mdy[0] = today->tm_mon;
X		when 1: mdy[1] = today->tm_mday;
X		when 2: mdy[2] = today->tm_year;
X	    }
X	    if (p && *p)
X		p++;
X	} else {
X	    p2 = (*p)? index(p+1, '/') : NULL;
X	    mdy[i] = atoi(p); /* atoi will stop at the '/' */
X	    if (i == 0 && (--(mdy[0]) < 0 || mdy[0] > 11)) {
X		print("Invalid month: %s\n", p);
X		return 0;
X	    } else if (i == 1 && (mdy[1] < 1 || mdy[1] > 31)) {
X		print("Invalid day: %s\n", p);
X		return 0;
X	    }
X	    if (p = p2) /* set p to p2 and check to see if it's valid */
X		p++;
X	}
X    return 1;
X}
END_OF_FILE
if test 10068 -ne `wc -c <'pick.c'`; then
    echo shar: \"'pick.c'\" unpacked with wrong size!
fi
# end of 'pick.c'
fi
if test -f 'setopts.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'setopts.c'\"
else
echo shar: Extracting \"'setopts.c'\" \(10254 characters\)
sed "s/^X//" >'setopts.c' <<'END_OF_FILE'
X/* setopts.c	(c) copyright 1986 (Dan Heller) */
X
X#include "mush.h"
X
X/* add an option indicated by "set option[=value]" or by "alias name alias" 
X * function is recursive, so multilists get appended accordingly
X */
Xadd_option(list, argv)
Xregister struct options **list;
Xregister char **argv;
X{
X    register struct options *tmp;
X    struct options *calloc();
X    register char *option, *value = NULL;
X
X    if (!(option = *argv))
X	return 1;
X    /* check for one of three forms:
X     * option=value    option = value  option= value
X     * value can be in quotes to preserve whitespace
X     */
X    if (*++argv && !strcmp(*argv, "=")) {
X	if (value = *++argv) /* example: "set foo = " */
X	    ++argv;
X    } else if (value = index(option, '=')) {
X	/* option=value  strip into option="option" value="value"; (quotes?) */
X	register char c, *p2;
X	*value = 0; /* option is now a null termined `option' */
X	if ((c = *++value) == '"' || c == '\'') {
X	    *value++ = 0;
X	    if (!(p2 = index(value, c))) {
X		print("No matching %c for %s.\n", c, option);
X		return 0;
X	    } else
X		*p2 = 0;
X	} else if (!c) {  /* example: "set crt=" */
X	    if (!*argv) {
X		print("No value for %s.\n", option);
X		return 0;
X	    }
X	    value = *argv++;
X	}
X    }
X    /* check to see if option is already set by attempting to unset it */
X    (void) un_set(list, option);
X
X    /* now make a new option struct and set fields */
X    if (!(tmp = calloc((unsigned)1, sizeof(struct options)))) {
X	error("calloc");
X	return -1;
X    }
X    tmp->option = savestr(option);
X    tmp->value = savestr(value); /* strdup handles the NULL case */
X
X    tmp->next = *list;
X    *list = tmp;
X
X    /* check for options which must have values or are used frequently */
X    if (*list == set_options) {
X#if defined(CURSES) || defined(SUNTOOL)
X	if (!strcmp(tmp->option, "no_reverse"))
X	    turnoff(glob_flags, REV_VIDEO);
X	else
X#endif /* CURSES || SUNTOOL */
X	if (!strcmp(tmp->option, "prompt"))
X	    prompt = (tmp->value)? tmp->value : DEF_PROMPT;
X	else if (!strcmp(tmp->option, "escape"))
X	    escape = (tmp->value)? tmp->value : DEF_ESCAPE;
X	else if (!strcmp(tmp->option, "pager"))
X	    pager = (tmp->value)? tmp->value : DEF_PAGER;
X	else if (!strcmp(tmp->option, "editor"))
X	    editor = (tmp->value)? tmp->value : DEF_EDITOR;
X	else if (!strcmp(tmp->option, "hdr_format"))
X	    hdr_format = (tmp->value)? tmp->value : DEF_HDR_FMT;
X	else if (!strcmp(tmp->option, "visual"))
X	    visual = (tmp->value)? tmp->value : DEF_EDITOR;
X	else if (!strcmp(tmp->option, "crt")) {
X	    if (!istool)
X		crt = (tmp->value)? max(atoi(tmp->value), 1): 18;
X	} else if (!strcmp(tmp->option, "screen")) {
X	    screen = (tmp->value)? max(atoi(tmp->value), 1): 18;
X#ifdef CURSES
X	    if (iscurses && screen > LINES-2)
X		screen = LINES-2;
X#endif CURSES
X	} else if (!strcmp(tmp->option, "history"))
X	    init_history((value && *value)? atoi(value) : 1);
X    }
X
X    if (*argv)
X	return add_option(list, argv);
X    return 1;
X}
X
X/*
X * If str is NULL, just print options and their values. Note that numerical
X * values are not converted to int upon return.  If str is not NULL
X * return the string that matched, else return NULL;
X */
Xchar *
Xdo_set(list, str)
Xregister struct options *list;
Xregister char *str;
X{
X    register struct options *opts;
X#ifdef SUNTOOL
X    int x,y;
X
X    if (istool && !str)
X	y = 10 + 2 * l_height(LARGE);
X#endif SUNTOOL
X
X    for (opts = list; opts; opts = opts->next)
X	if (!str) {
X#ifdef SUNTOOL
X	    if (istool)
X		pw_text(msg_win, 5, y, PIX_SRC, fonts[DEFAULT], opts->option);
X	    else
X#endif SUNTOOL
X		fputs(opts->option, stdout);
X	    if (opts->value)
X#ifdef SUNTOOL
X		if (istool) {
X		    x = 30*l_width(DEFAULT);
X		    pw_text(msg_win, x,y, PIX_SRC, fonts[DEFAULT], opts->value);
X		    pw_text(msg_win, x+1, y, PIX_SRC|PIX_DST,
X			     fonts[DEFAULT], opts->value);
X		    x += strlen(opts->value)*l_width(DEFAULT);
X		} else
X#endif SUNTOOL
X		    printf("     \t%s", opts->value);
X#ifdef SUNTOOL
X	    if (istool)
X		Clrtoeol(msg_win, x, y, DEFAULT), y += l_height(DEFAULT);
X	    else
X#endif SUNTOOL
X	    putchar('\n');
X	} else {
X	    if (strcmp(str, opts->option))
X		continue;
X	    if (opts->value)
X		return opts->value;
X	    else
X		return "";
X	}
X    /* if we still haven't matched, check for environment vars */
X    if (str && list == set_options) {
X	register int N, n;
X	for (N = 0; environ[N]; N++) {
X	    char *p = index(environ[N], '=');
X	    if (p)
X		*p = 0;
X	    n = strcmp(str, environ[N]);
X	    if (p)
X		*p = '=';
X	    if (!n)
X		return p+1;
X	}
X    }
X    return NULL;
X}
X
X/*
X * unset the variable described by p in the list "list".
X * if the variable isn't set, then return 0, else return 1.
X */
Xun_set(list, p)
Xregister struct options **list;
Xregister char *p;
X{
X    register struct options *opts = *list, *tmp;
X
X    if (!list || !*list || !p || !*p)
X	return 0;
X    if (*list == set_options) {
X#if defined(CURSES) || defined(SUNTOOL)
X	if (!strcmp(p, "no_reverse"))
X	    turnon(glob_flags, REV_VIDEO);
X	else
X#endif /* CURSES || SUNTOOL */
X	if (!strcmp(p, "prompt"))
X	    prompt = DEF_PROMPT;
X	else if (!strcmp(p, "escape"))
X	    escape = DEF_ESCAPE;
X	else if (!strcmp(p, "pager"))
X	    pager = DEF_PAGER;
X	else if (!strcmp(p, "editor"))
X	    editor = DEF_EDITOR;
X	else if (!strcmp(p, "visual"))
X	    visual = DEF_EDITOR;
X	else if (!strcmp(p, "hdr_format"))
X	    hdr_format = DEF_HDR_FMT;
X	else if (!strcmp(p, "crt"))
X	    crt = 18;
X	else if (!strcmp(p, "screen")) {
X	    screen = 18;
X#ifdef CURSES
X	    if (iscurses && screen > LINES-2)
X		screen = LINES-2;
X#endif CURSES
X	} else if (!strcmp(p, "history"))
X	    init_history(1);
X    }
X
X    if (!strcmp(p, opts->option)) {
X	*list = (*list)->next;
X	xfree (opts->option);
X	if (opts->value)
X	    xfree(opts->value);
X	xfree((char *)opts);
X	return 1;
X    }
X    for ( ; opts->next; opts = opts->next)
X	if (!strcmp(p, opts->next->option)) {
X	    tmp = opts->next;
X	    opts->next = opts->next->next;
X	    xfree (tmp->option);
X	    if (tmp->value)
X		xfree(tmp->value);
X	    xfree ((char *)tmp);
X	    return 1;
X	}
X    return 0;
X}
X
X/* The functions below return -1 since they don't affect
X * messages. This prevents piping from do_loop().
X */
Xset(n, argv)
Xregister int n;
Xregister char **argv;
X{
X    char firstchar = **argv;
X    register char *cmd = *argv;
X    register struct options **list;
X
X    if (*cmd == 'u')
X	cmd += 2;
X    if (*++argv && !strcmp(*argv, "-?"))
X	return help(0, (*cmd == 'i')? "ignore": "set", cmd_help);
X    if (*argv && **argv == '?') {
X	char buf[BUFSIZ];
X	if (!strcmp(*argv, "?all")) {
X	    FILE *pp = NULL_FILE;
X	    turnon(glob_flags, IGN_SIGS);
X	    echo_on();
X	    if (!istool && !(pp = popen(pager, "w")))
X		error(pager);
X	    for (n = 0; variable_stuff(n, NULL, buf); n++)
X		if (pp)
X		    fprintf(pp, "%s\n", buf);
X		else
X		    print("%s\n", buf);
X	    if (pp)
X		pclose(pp);
X	    echo_off();
X	    turnoff(glob_flags, IGN_SIGS);
X	} else {
X	    (void) variable_stuff(0, (*argv)+1, buf);
X	    wprint("%s\n", buf);
X	}
X	return -1;
X    }
X
X    if (firstchar == 'u') {
X	if (!*argv)
X	    print("%s what?\n", cmd);
X	else {
X	    list = (*cmd == 'i')? &ignore_hdr : &set_options;
X	    do  if (!strcmp(*argv, "*"))
X		    while (*list)
X			(void) un_set(list, (*list)->option);
X		else if (!un_set(list, *argv))
X		    print("un%s: %s not set\n",
X			(*cmd == 'i')? "ignore" : "set", *argv);
X	    while (*++argv);
X	}
X	return -1;
X    }
X    if (!*argv)
X	(void) do_set((*cmd == 'i')? ignore_hdr: set_options, NULL);
X    else
X	(void) add_option((*cmd == 'i')? &ignore_hdr: &set_options, argv);
X    return -1;
X}
X
Xalts(argc, argv)
Xregister char **argv;
X{
X    char buf[256], buf2[256], *p;
X    long save_bang = ison(glob_flags, IGN_BANG);
X
X    if (argc && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "alts_help", cmd_help);
X    if (argc > 1) {
X	(void) argv_to_string(buf2, argv);
X	(void) sprintf(buf, "set alternates=\"%s\"",  buf2);
X	turnon(glob_flags, IGN_BANG);
X	if (argv = make_command(buf, TRPL_NULL, &argc))
X	    (void) do_command(argc, argv, msg_list);
X	if (!save_bang)
X	    turnoff(glob_flags, IGN_BANG);
X    } else
X	if (!(p = do_set(set_options, "alternates")))
X	    print("No alternate hostnames set.\n");
X	else
X	    print("Alternate hostnames: %s\n", p);
X    return -1;
X}
X
Xsave_opts(cnt, argv)
Xchar **argv;
X{
X    char file[50], *tmp;
X    register FILE *fp;
X
X    if (cnt && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "source_help", cmd_help);
X    if (cnt && *argv)
X	(void) strcpy(file, *argv);
X    else if (tmp = getenv("MAILRC"))
X	(void) strcpy(file, tmp);
X    else {
X	char *home = do_set(set_options, "home");
X	if (!home || !*home)
X	    home = ALTERNATE_HOME;
X	if (access(sprintf(file, "%s/%s", home, MAILRC), R_OK)
X          && access(sprintf(file, "%s/%s", home, ALTERNATE_RC), R_OK))
X	(void) strcpy(file, DEFAULT_RC);
X    }
X
X    cnt = 1;
X    tmp = getpath(file, &cnt);
X    if (cnt) {
X	if (cnt == -1)
X	    print("%s: %s\n", file, tmp);
X	else
X	    print("%s is a directory.\n", tmp);
X	return -1;
X    }
X    if (!(fp = fopen(tmp, "w"))) {
X	error("Can't open %s", file);
X	return -1;
X    }
X
X    save_list("basic variable settings", set_options, "set", '=', fp);
X
X    save_list("mail headers for outgoing mail", own_hdrs, "my_hdr", 0, fp);
X
X    save_list("aliases", aliases, "alias", 0, fp);
X
X    save_list("headers to ignore", ignore_hdr, "ignore", ' ', fp);
X
X    save_list("command abbreviations", functions, "cmd", ' ', fp);
X
X    save_list("command macros for function keys", fkeys, "fkey", ' ', fp);
X
X    fclose(fp);
X    print("All variables and options saved in %s\n", tmp);
X    return -1;
X}
X
Xsave_list(title, list, command, equals, fp)
Xstruct options *list;
Xregister char *command, *title, equals;
Xregister FILE *fp;
X{
X    register struct options *opts;
X    register char *p;
X
X    if (!list)
X	return;
X    fprintf(fp, "#\n# %s\n#\n", title);
X    for (opts = list; opts; opts = opts->next) {
X	fprintf(fp, "%s %s", command, opts->option);
X	if (opts->value && *opts->value) {
X	    register char *quote;
X	    if (!equals)
X		quote = NO_STRING;
X	    else if (p = any(opts->value, "\"'"))
X		if (*p == '\'') quote = "\"";
X		else quote = "'";
X	    else
X		if (!any(opts->value, " \t;|"))
X		    quote = NO_STRING;
X		else quote = "'";
X	    fputc(equals? equals: ' ', fp);
X	    fprintf(fp, "%s%s%s", quote, opts->value, quote);
X	}
X	fputc('\n', fp);
X    }
X}
END_OF_FILE
if test 10254 -ne `wc -c <'setopts.c'`; then
    echo shar: \"'setopts.c'\" unpacked with wrong size!
fi
# end of 'setopts.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'\" \(9430 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
Xextern char *sys_siglist[];
X#else
X/* sys-v doesn't have normal sys_siglist */
Xstatic 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
Xmsgwin_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
Xhdrwin_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
Xprint_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
Xsigwinchcatcher()
X{
X    tool_sigwinch(tool);
X}
X#endif SUNTOOL
X
Xinterrupt(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*/
Xcatch(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	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	longjmp(jmpbuf, 1);
X}
X
X#ifdef SIGCONT
Xstop_start(sig)
X{
X    Debug("Caught signal: %d", sig);
X    if (sig == SIGCONT) {
X	(void) signal(SIGTSTP, stop_start);
X	(void) signal(SIGCONT, stop_start);
X	if (istool || ison(glob_flags, IGN_SIGS) && !iscurses)
X	    return;
X	echo_off();
X	/* we're not in an editor but we're editing a letter */
X	if (ison(glob_flags, IS_GETTING)) {
X	    if (!exec_pid)
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	    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*/
Xcleanup(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 */
Xcheck_new_mail()
X{
X    int 	   ret_value;
X    char 	   buf[BUFSIZ], buf2[256];
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 last_msg_cnt
X	 * so that when the tool is opened, print() will print the correct
X	 * number of "new" messages.
X	 */
X	if (!istool || !(was_iconic = tool->tl_flags & TOOL_ICONIC))
X#endif SUNTOOL
X	    while (last_msg_cnt < msg_cnt) {
X		char *p2 = reply_to(last_msg_cnt++, FALSE, buf2);
X		if (strlen(p2) + (p - buf) >= BUFSIZ-5) {
X		    (void) strcat(p, "...\n");
X		    /* force a loop 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) {
X	    if (strlen(buf) > COLS-1) {
X		printf("%s --more--", buf), fflush(stdout);
X		(void) getchar();
X		(void) clear();
X		(void) strcpy(buf+COLS-5, " ...");
X		new_hdrs = n_array[screen-1]; /* force new headers */
X	    }
X	    if (new_hdrs - n_array[screen-1] < screen)
X		(void) do_hdrs(0, DUBL_NULL, NULL);
X	}
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	    !is_spool(mailfile) && 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... */
Xbus_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 9430 -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 11 \(of 12\).
cp /dev/null ark11isdone
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