[comp.sources.unix] v11i056: Mail user's shell, Part06/12

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

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

#! /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 6 (of 12)."
# Contents:  curses.c msgs.c mush.h
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'curses.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'curses.c'\"
else
echo shar: Extracting \"'curses.c'\" \(17549 characters\)
sed "s/^X//" >'curses.c' <<'END_OF_FILE'
X/* @(#)curses.c	(c) copyright 3/18/87 (Dan Heller) */
X
X/* curses.c -- routine to deal with the curses interface */
X#ifdef CURSES
X
X#include "mush.h"
X#include "bindings.h"
X
Xcurses_init(argc, argv)
Xregister char **argv;
X{
X    char buf[80];
X    extern char *UP, ttytype[];
X
X    if (argv && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "curses", cmd_help);
X    if (iscurses) {
X	print("You can't run curses from the curses mode (silly).");
X	return -1;
X    }
X    if (ison(glob_flags, IS_GETTING)) {
X	print("Finish your letter first.\n");
X	return -1;
X    }
X#ifdef SUNTOOL
X    if (istool) {
X	print("My, aren't we the adventuresome type!");
X	timerclear(&(mail_timer.it_interval));
X	timerclear(&(mail_timer.it_value));
X	tool_destroy(tool), istool = FALSE;
X	curses_init(0, 0);
X	do_loop(); /* doesn't return */
X    }
X#endif SUNTOOL
X
X    /* you can not start curses in no echo mode.. must be in normal mode */
X    echo(), nocrmode();
X    (void) initscr();
X#ifdef SIGCONT
X    /* initscr will play with signals -- make sure they're set right. */
X    (void) signal(SIGTSTP, stop_start);
X    (void) signal(SIGCONT, stop_start);
X#endif SIGCONT
X    if (!UP || !*UP) {
X	print("Terminal type %s can not use the curses interface.\n", ttytype);
X	return -1;
X    }
X    iscurses = TRUE;
X    noecho(), crmode(); /* reset tty state -- do not use "echo_on/off()" */
X    scrollok(stdscr, TRUE);
X    /* if the user hasn't set his screen explicitely, set it for him */
X    if (!do_set(set_options, "screen"))
X	switch (_tty.sg_ospeed) {
X	    case B300 : screen = min(LINES-2, 7);
X	    when B1200 : screen = min(LINES-2, 14);
X	    when B2400 : screen = min(LINES-2, 22);
X	    otherwise : screen = LINES-2;
X	}
X    else
X	screen = min(screen, LINES-2);
X    crt = LINES;
X    if (argc)
X	(void) cmd_line(sprintf(buf, "headers %d", current_msg+1), msg_list);
X    if (!do_set(set_options, "no_reverse"))
X	turnon(glob_flags, REV_VIDEO);
X    turnoff(glob_flags, CONT_PRNT);
X    return -1; /* doesn't affect messages */
X}
X
X/*
X * get input in cbreak mode and execute the appropriate command.
X * when the command is done (usually), the user is prompted to
X * hit any key to continue. At this point, the user may enter a
X * new command so no screen refreshing needds to be done. This
X * new command is returned to caller and may be passed back.
X *
X * The variable "cntd_cmd" (continued command) is set to true if
X * this routine is called with the passed parameter (c) > 0. If
X * so, then the character passed is the character input by the
X * user at the last "hit return" prompt indicating that he wants
X * to execute a new command and not draw the screen.
X *
X * cntd_cmd is also set to true if the command that the user invokes
X * causes any sort of output that requires a screen refresh.  The
X * variable redo is set to 1 if the header page not only requires
X * redrawing, but updating ... (new call to do_hdrs)
X *
X * calls that say: print("%s", compose_hdr(current_msg)) are constructed
X * that way cuz if the header has a `%' in it, then print will try to
X * expand it.
X */
Xcurses_command(c)
Xregister int c;
X{
X    char 	buf[BUFSIZ], file[128], list[128];
X    int 	n, cntd_cmd = (c > 0), curlin;
X    static int  redo;  /* set if headers should be redrawn */
X
X    clear_msg_list(msg_list); /* play it safe */
X    if (!cntd_cmd) {
X	(void) check_new_mail();
X	curlin = max(1, current_msg - n_array[0] + 1);
X	(void) strncpy(buf, stdscr->_y[curlin], COLS-1);
X	buf[COLS-1] = 0; /* strncpy does not null terminate */
X	if (ison(glob_flags, REV_VIDEO) && msg_cnt)
X	    STANDOUT(curlin, 0, buf);
X	mail_status(0);
X	move(curlin, 0), refresh();
X	/* reprint to remove reverse video from current line (don't refresh) */
X	if (ison(glob_flags, REV_VIDEO))
X	    mvaddstr(curlin, 0, buf);
X	c = getcmd(); /* get input AFTER line redrawn without reverse video */
X    }
X    buf[0] = list[0] = file[0] = '\0';
X
X    /* goto a specific line number */
X    if (c == C_GOTO_MSG) {
X	c = C_NULL;
X	if (msg_cnt <= 1)
X	    print("Not enough messages.");
X	else if (curses_msg_list(strcpy(buf, "goto msg: "), list, msg_list)) {
X	    for (n = 0; !msg_bit(msg_list, n); n++)
X		;
X	    if ((current_msg = n) < n_array[0] || n > n_array[screen-1])
X		redo = 1;
X	}
X	if (cntd_cmd && msg_cnt)
X	    print("%s", compose_hdr(current_msg));
X	if (cntd_cmd)
X	    putchar('\n');
X    } else if (c == C_WRITE_LIST || c == C_SAVE_LIST || c == C_COPY_LIST
X			       || c == C_DELETE_LIST || c == C_UNDEL_LIST) {
X	
X	if (msg_cnt <= 1)
X	    print("Not enough messages."), c = C_NULL;
X	else if (!curses_msg_list(sprintf(buf, "%s msg list: ",
X		(c == C_WRITE_LIST)? "write" : (c == C_SAVE_LIST)?  "save" :
X		(c == C_DELETE_LIST)? "delete" : "undelete"), list, msg_list))
X	    c = C_NULL;
X	if (cntd_cmd)
X	    putchar('\n');
X    }
X
X    /* first do non-mail command stype stuff */
X    switch (c) {
X	case C_NULL : ;
X
X	/* screen optimization stuff */
X	when C_REVERSE :
X	    if (ison(glob_flags, REV_VIDEO))
X		turnoff(glob_flags, REV_VIDEO);
X	    else
X		turnon(glob_flags, REV_VIDEO);
X
X	when C_REDRAW : if (!redo) redraw();
X
X	/*
X	 * screen movement
X	 */
X	when C_NEXT_MSG :
X	/* case 'j' : case 'J' : case '+' : case '\n' : /* next */
X	    if (current_msg + 2 > msg_cnt || !cntd_cmd && curlin == screen)
X		bell(); /* reached the end */
X	    else {
X		if (++current_msg > n_array[screen-1])
X		    redo = 1;
X		if (cntd_cmd)
X		    print("%s", compose_hdr(current_msg)), putchar('\n');
X	    }
X	when C_PREV_MSG :
X	/* when 'k' : case 'K' : case '-' : case CTRL(k) : /* previous */
X	    if (!cntd_cmd && curlin == 1 || current_msg == 0)
X		bell();  /* at the beginning */
X	    else {
X		if (--current_msg < n_array[0])
X		    redo = 1;
X		if (cntd_cmd)
X		    print("%s", compose_hdr(current_msg)), putchar('\n');
X	    }
X	when C_FIRST_MSG : case C_LAST_MSG :
X	    n = current_msg;
X	    if (c == C_FIRST_MSG && (current_msg = 0) < n_array[0] ||
X		c == C_LAST_MSG && (current_msg = msg_cnt-1)> n_array[screen-1])
X		if (!cntd_cmd)
X		    (void) cmd_line(sprintf(buf, "headers %d", current_msg+1),
X			     msg_list);
X		else
X		    redo = 1;
X	    if (cntd_cmd && n != current_msg)
X		print("%s", compose_hdr(current_msg)), putchar('\n');
X	/* top and bottom of headers screen */
X	when C_TOP_PAGE : case C_BOTTOM_PAGE :
X	    if (!cntd_cmd)
X		if (c == C_TOP_PAGE)
X		    current_msg = n_array[0];
X		else
X		    current_msg = min(n_array[screen-1], msg_cnt-1);
X	    else
X		bell();
X	when C_NEXT_SCREEN : /* next page */
X	    if (msg_cnt > screen) {
X		(void) cmd_line(strcpy(buf, "headers +"), msg_list);
X		current_msg = n_array[0];
X		return redo = 0;
X	    } else
X		bell();
X	when C_PREV_SCREEN : /* previous page */
X	    if (current_msg > 0 || cntd_cmd)
X		(void) cmd_line(strcpy(buf, "headers -"), msg_list), redo = 0;
X	    current_msg = (msg_cnt <= 1)? 0 : n_array[0];
X	    return 0;
X	    /* break;  (not stated for lint) */
X
X	case C_SHOW_HDR :
X	    if (cntd_cmd && msg_cnt)
X		puts(compose_hdr(current_msg));
X
X	/* read from/save to record file (.mushrc) */
X	when C_SOURCE : case C_SAVEOPTS :
X	    print("%s filename [default]: ",
X		(c == C_SOURCE)? "source" : "save options to");
X	    if (Getstr(file, LINES-40, 0) < 0) {
X		clr_bot_line();
X		return 0;
X	    }
X	    iscurses = FALSE;
X	    turnon(glob_flags, PRE_CURSES);
X	    (void) cmd_line(sprintf(buf, "%s %s",
X		(c == C_SOURCE) ? "source" : "saveopts", file), msg_list);
X	    iscurses = TRUE;
X	    turnoff(glob_flags, PRE_CURSES);
X	    cntd_cmd = 1;
X
X	/*
X	 * search commands
X	 */
X	when C_NEXT_SEARCH : case C_PREV_SEARCH : case C_CONT_SEARCH :
X	    if (c != C_CONT_SEARCH)
X		c = search(0 + (c == C_PREV_SEARCH));
X	    else
X		c = search(-1);
X	    if (cntd_cmd)
X		putchar('\n');
X	    if (c == 0)
X		break;
X	    if (cntd_cmd)
X		print("%s", compose_hdr(current_msg)), putchar('\n');
X	    if (n_array[0] > current_msg || n_array[screen-1] < current_msg) {
X		redo = 1;
X		if (!cntd_cmd)
X		    (void) cmd_line(sprintf(buf, "headers %d",
X					    current_msg+1), msg_list);
X	    }
X
X	/*
X	 * actions on messages
X	 */
X	/* delete/undelete */
X	when C_DELETE_MSG : case C_DELETE_LIST :
X	case C_UNDEL_MSG : case C_UNDEL_LIST :
X	    if (!msg_cnt) {
X		print("No messages.");
X		if (cntd_cmd)
X		    putchar('\n');
X		break;
X	    }
X	    if (!*list)
X		set_msg_bit(msg_list, current_msg);
X	    turnon(glob_flags, DO_UPDATE);
X	    for (n = 0; n < msg_cnt; n++)
X		if (msg_bit(msg_list, n)) {
X		    if (c == C_DELETE_MSG || c == C_DELETE_LIST)
X			turnon(msg[n].m_flags, DELETE);
X		    else
X			turnoff(msg[n].m_flags, DELETE);
X		    if (!cntd_cmd && msg_cnt < screen ||
X			!cntd_cmd && n >= n_array[0] && n <= n_array[screen-1])
X			mvaddstr(max(1, n - n_array[0] + 1), 0, compose_hdr(n));
X		    else
X			redo = 1;
X		}
X	    if (cntd_cmd || *list) {
X		if (cntd_cmd) { /* print(), THEN putchar() -- overwrite line */
X		    print("%sdeleted %s",
X		    (c == C_DELETE_MSG || c == C_DELETE_LIST)? "":"un", list);
X		    putchar('\n');
X		}
X		if (ison(msg[current_msg].m_flags, DELETE))
X		    (void) next_msg(FALSE, DELETE);
X		if (do_set(set_options, "autoprint"))
X		    return C_DISPLAY_MSG;
X		if (cntd_cmd)
X		    puts(compose_hdr(current_msg));
X	    }
X
X	/*
X	 * write/save messages.  If a list is necessary, the user already
X	 * entered it above since he must have used a capital letter. If so,
X	 * list will contain good data (already been validated above).
X	 * if a list is given, set iscurses to 0 so that print statements
X	 * will scroll and the user sees the multiple output. else, one
X	 * line can go on the bottom line just fine.
X	 */
X	when C_WRITE_MSG : case C_SAVE_MSG : case C_COPY_MSG :
X	case C_WRITE_LIST : case C_SAVE_LIST : case C_COPY_LIST : {
X	    register char *p =
X		(c == C_WRITE_MSG || c == C_WRITE_LIST)? "write" :
X		(c == C_SAVE_MSG  || c == C_SAVE_LIST)?  "save"  : "copy";
X	    print(sprintf(buf, "filename to %s [mbox]: ", p));
X	    if (Getstr(file, COLS-1-strlen(buf), 0) >= 0) {
X		char *argv[3];
X		clr_bot_line();
X		argv[0] = strcpy(buf, p);
X		argv[1] = file;
X		argv[2] = NULL;
X		if (!*list)
X		    set_msg_bit(msg_list, current_msg);
X		move(LINES-1, 0), refresh();
X		if (*list)
X		    iscurses = FALSE;
X		turnon(glob_flags, IS_PIPE);
X		if (save_msg(2, argv, msg_list) < 0)
X		    *list = 0;
X		turnoff(glob_flags, IS_PIPE);
X		if (cntd_cmd)
X		    putchar('\n'), puts(compose_hdr(current_msg));
X		if (*list)
X		    iscurses = cntd_cmd = redo = TRUE;
X		else if (!cntd_cmd && msg_cnt)
X		    mvaddstr(curlin, 0, compose_hdr(current_msg));
X	    } else {
X		print("No messages saved.");
X		if (cntd_cmd)
X		    putchar('\n');
X	    }
X	}
X
X	/* preserve message */
X	when C_PRESERVE :
X	    if (!msg_cnt) {
X		print("No messages.");
X		if (cntd_cmd)
X		    putchar('\n');
X		break;
X	    }
X	    if (ison(msg[current_msg].m_flags, PRESERVE))
X		turnoff(msg[current_msg].m_flags, PRESERVE);
X	    else
X		turnon(msg[current_msg].m_flags, PRESERVE);
X	    if (cntd_cmd) {
X		print("%s", compose_hdr(current_msg)), putchar('\n');
X		redo = 1;
X	    } else
X		mvaddstr(curlin, 0, compose_hdr(current_msg));
X
X	/* order messages (sort) and rediesplay the headers */
X	when C_SORT : case C_REV_SORT :
X	    (void) strcpy(file, "sort");
X	    if (c == C_REV_SORT) {
X		print("Reverse "), turnon(glob_flags, CONT_PRNT);
X		(void) strcat(file, " -");
X	    }
X	    print("Order messages by [Status, date, subject, author]: ");
X	    if ((c = getchar()) == 's' || c == 'S' || c == 'd' || c == 'a') {
X		print("reordering messages...");
X		(void) cmd_line(sprintf(buf, "%s %c", file, c), msg_list);
X		print_more("done.");
X		if (cntd_cmd)
X		    putchar('\n'), puts(compose_hdr(current_msg));
X		redo = 1;
X	    } else
X		clr_bot_line();
X
X	when C_QUIT_HARD :
X	    (void) quit(0, DUBL_NULL);
X	    redo = 1; /* new mail must have come in */
X
X	/* quit or update -- vrfy_update (returns 1 if updated) */
X	when C_QUIT : case C_UPDATE :
X	    if (!vrfy_update(&cntd_cmd, &redo))
X		if (c == C_UPDATE)
X		    break;
X		else
X		    turnoff(glob_flags, DO_UPDATE);
X	    if (c == C_QUIT) {
X		putchar('\n');
X		cleanup(0);
X		redo = 1;
X	    }
X
X	when C_EXIT : case C_EXIT_HARD :
X	    clr_bot_line();
X	    iscurses = FALSE;
X	    if (c != C_EXIT && c != C_EXIT_HARD)
X		putchar('\n');
X	    cleanup(0);
X
X	/* change to a new folder */
X	when C_FOLDER :
X	    for (;;) {
X		print("New folder (?=list): ");
X		if (Getstr(file, COLS-22, 0) > 0) {
X		    if (!strcmp(file, "?")) {
X			clr_bot_line();
X			iscurses = 0;
X			puts("folders in your folder directory:");
X			(void) cmd_line(strcpy(buf, "folders"), msg_list);
X	puts("Precede folder names with a +. `%' to specify system mailbox.");
X			cntd_cmd = iscurses = 1;
X			continue;
X		    }
X		    clearok(stdscr, FALSE);
X		    if (strcmp(file, "-?"))
X			vrfy_update(&cntd_cmd, &redo);
X		    move(LINES-1, 0), refresh();
X		    if (cmd_line(sprintf(buf, "folder ! -N %s", file),
X			     msg_list) == -1) {
X			/* error message was printed; leave room to read it */
X			putchar('\n');
X			cntd_cmd = 1, redo = 0;
X		    } else
X			redo = 1, cntd_cmd = 0;
X		    break;
X		} else {
X		    print("\"%s\" unchanged.", mailfile);
X		    if (cntd_cmd)
X			putchar('\n');
X		    break;
X		}
X	    }
X
X	/* shell escape */
X	when C_SHELL_ESC :
X	    print("Shell command: ");
X	    if (Getstr(file, COLS-24, 0) < 0)
X		clr_bot_line();
X	    else {
X		putchar('\n');
X		iscurses = FALSE;
X		(void) cmd_line(sprintf(buf, "sh %s", file), msg_list);
X		iscurses = TRUE;
X		cntd_cmd = 1;
X	    }
X
X	/* do a line-mode like command */
X	when C_CURSES_ESC :
X	    print(":");
X	    if (Getstr(buf, COLS-2, 0) < 0)
X		break;
X	    putchar('\n');
X	    iscurses = FALSE;
X	    if (!*buf) {
X		/* return -1 because iscurses = 0 is not enough! */
X		redo = 0;
X		endwin(); /* this turns echoing back on! */
X		echo_off();
X		return -1;
X	    }
X	    (void) cmd_line(buf, msg_list);
X	    /* they may have affected message status or had text output */
X	    cntd_cmd = redo = 1;
X	    iscurses = TRUE;
X	    if (msg_cnt)
X		puts(compose_hdr(current_msg));
X
X	/* send message to printer */
X	when C_PRINT_MSG : lpr(0, DUBL_NULL, msg_list);
X
X	/* cd */
X	when C_CHDIR :
X	    print("chdir to [.]: ");
X	    if (Getstr(file, COLS-12, 0) < 0)
X		break;
X	    clr_bot_line();
X	    (void) cmd_line(sprintf(buf, "cd %s", file), msg_list);
X	    if (cntd_cmd)
X		putchar('\n');
X
X	/* variable settings */
X	when C_VAR_SET : case C_IGNORE : case C_ALIAS : case C_OWN_HDR :
X	    curs_vars(c, &cntd_cmd); /* cntd_cmd is reset if there's output! */
X
X	when C_VERSION :
X	    do_version(); /* duh */
X	    if (cntd_cmd)
X		putchar('\n');
X
X	when C_MAIL_FLAGS :
X	    print("flags [-?]: ");
X	    if ((c = Getstr(file, COLS-50, 0)) < 0)
X		break;
X	    putchar('\n');
X	    if (c == 0)
X		(void) strcpy(file, "-?");
X	/* Fall thru */
X	case C_MAIL :
X	    clr_bot_line();
X	    iscurses = FALSE;
X	    (void) cmd_line(sprintf(buf, "mail %s", file), msg_list);
X	    iscurses = TRUE, cntd_cmd = 1;
X	    if (msg_cnt)
X		print("%s", compose_hdr(current_msg)), putchar('\n');
X
X	/* reply to mail */
X	when C_REPLY_SENDER : case C_REPLY_ALL : {
X	    register char *p = (c == C_REPLY_ALL)? "replyall" : "replysender";
X	    clr_bot_line();
X	    iscurses = FALSE;
X	    (void) cmd_line(sprintf(buf, "%s %d", p, current_msg+1),
X		msg_list);
X	    iscurses = TRUE, cntd_cmd = 1;
X	    if (msg_cnt)
X		print("%s", compose_hdr(current_msg)), putchar('\n');
X	}
X
X	/* type out a message */
X	when C_DISPLAY_MSG : case C_TOP_MSG : case C_DISPLAY_NEXT :
X	    if (!msg_cnt ||
X		c != C_DISPLAY_NEXT && ison(msg[current_msg].m_flags, DELETE)) {
X		if (!msg_cnt)
X		    print("No messages.");
X		else
X		    print("Message %d deleted; type 'u' to undelete.",
X				      current_msg+1);
X		if (cntd_cmd)
X		    putchar('\n');
X		break;
X	    }
X	    clr_bot_line();
X	    iscurses = FALSE;
X	    if (cntd_cmd)
X		putchar('\n');
X	    if (c == C_DISPLAY_MSG)
X		c = cmd_line(strcpy(buf, "type"), msg_list);
X	    else if (c == C_TOP_MSG)
X		c = cmd_line(strcpy(buf, "top"), msg_list);
X	    else
X		c = cmd_line(strcpy(buf, "next"), msg_list);
X	    if (c > -1)
X		cntd_cmd = redo = 1;
X	    iscurses = TRUE;
X	    puts(compose_hdr(current_msg));
X
X	/* bind a key or string to a command */
X	when C_BIND :  case C_UNBIND : {
X	    char *argv[2];
X	    argv[0] = (c == C_BIND) ? "bind" : "unbind";
X	    argv[1] = NULL;
X	    if (bind_it(0, argv) < -1)
X		cntd_cmd = 1;
X	    else if (cntd_cmd) /* if it was already set anyway */
X		putchar('\n');
X	}
X
X	/* help stuff */
X	when C_HELP :
X	    (void) c_bind(NULL);
X	    cntd_cmd = 1;
X	    if (msg_cnt)
X		puts(compose_hdr(current_msg));
X
X	/* now do interactive stuff as if run from the mush shell */
X	otherwise :
X	    bell();
X	    if (cntd_cmd) {
X		/* use print instead of puts to overwrite hit_return msg */
X		print("unknown command"), putchar('\n');
X		redo = 1;
X	    }
X    }
X
X    if (cntd_cmd) {
X	int old_cnt = msg_cnt;
X	if (!(c = hit_return()) && !redo && msg_cnt == old_cnt)
X	    redraw();
X	clr_bot_line();
X	if (old_cnt !=  msg_cnt)
X	    redo = 1;
X	if (c)
X	    return c;
X    }
X    if (redo) {
X	n = current_msg;
X	clear();
X	if (msg_cnt < screen || n_array[0] < n && n < n_array[screen-1])
X	    (void) do_hdrs(0, DUBL_NULL, NULL);
X	else
X	    (void) cmd_line(sprintf(buf, "headers %d", n+1), msg_list);
X	redo = 0;
X    }
X    return 0;
X}
X
Xvrfy_update(cntd_cmd, redo)
Xint *cntd_cmd, *redo;
X{
X    char buf[16];
X    int c;
X
X    /* update current folder */
X    if (ison(glob_flags, DO_UPDATE)) {
X	print("Update %s [y]? ", mailfile);
X	if ((c = getchar()) == 'n' || c == 'N' || c == 7 || c == 127 || c == 4){
X	    print("%s unmodified.", mailfile);
X	    if (*cntd_cmd)
X		putchar('\n');
X	    return 0;
X	}
X	(void) cmd_line(strcpy(buf, "update"), msg_list);
X	if (*cntd_cmd)
X	    *redo = 1, *cntd_cmd = 0;
X    }
X    turnoff(glob_flags, DO_UPDATE);
X    return 1; /* make sure bottom line is clear and no reverse video */
X}
X#endif CURSES
END_OF_FILE
if test 17549 -ne `wc -c <'curses.c'`; then
    echo shar: \"'curses.c'\" unpacked with wrong size!
fi
# end of 'curses.c'
fi
if test -f 'msgs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'msgs.c'\"
else
echo shar: Extracting \"'msgs.c'\" \(16268 characters\)
sed "s/^X//" >'msgs.c' <<'END_OF_FILE'
X/* @(#)msgs.c	(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X#ifdef SYSV
X#include <sys/locking.h>
X#endif SYSV
X
Xvoid
Xdisplay_msg(n, flg)
Xregister int n;
Xlong flg;
X{
X    register FILE *pp;
X
X    if (ison(msg[n].m_flags, DELETE)) {
X	print("Message %d deleted; ", n+1);
X	if (istool)
X	    print_more("Select UNDELETE to read.");
X	else if (iscurses)
X	    print_more("Type 'u' to undelete.");
X	else
X	    print("Type 'undelete %d' to undelete\n", n+1);
X	return;
X    }
X    set_isread(n);
X    if (ison(flg, TOP)) {
X	turnon(flg, NO_HEADER);
X	print("Top of "), turnon(glob_flags, CONT_PRNT);
X    }
X
X    if (!istool && isoff(flg, NO_PAGE) &&
X	    crt < msg[n].m_lines && isoff(flg, TOP)) {
X	turnon(glob_flags, IGN_SIGS);
X	echo_on();
X	if (!(pp = popen(pager, "w")))
X	    error(pager);
X	else {
X	    fprintf(pp, "Message #%d (%d lines)\n", n+1, msg[n].m_lines);
X	    (void) copy_msg(n, pp, flg);
X	    (void) pclose(pp);
X	}
X	echo_off();
X	turnoff(glob_flags, IGN_SIGS);
X    } else {
X	print("Message #%d (%d lines)\n", n+1, msg[n].m_lines);
X	(void) copy_msg(n, stdout, flg);
X    }
X}
X
X/*
X * copy message 'n' to file "fp" according to various flag arguments
X * return number of lines copied or -1 if system error on fputs.
X */
Xcopy_msg(n, fp, flags)
Xregister int n;
Xlong flags;
Xregister FILE *fp;
X{
X    register int  ignoring = 0, lines = 0;
X    register char *indent_str;
X    int  on_hdr = 1, top, squeeze = FALSE;
X    char 	  line[BUFSIZ];
X
X    still_more = 0;
X    if (ison(flags, TOP)) {
X	register char *p = do_set(set_options, "toplines");
X	top = (p)? atoi(p) : crt;
X    }
X    if (do_set(set_options, "alwaysignore"))
X	turnoff(flags, NO_IGNORE);
X    if (isoff(flags, NO_IGNORE) && do_set(set_options, "squeeze"))
X	squeeze = TRUE;
X
X#ifdef SUNTOOL
X    if (istool && fp == stdout) {
X	register int x = (msg[n].m_lines + 2) * l_height(curfont);
X	if (x > 32765) { /* to overcome a bug in pixrects that sun won't fix */
X	    print("message too big to display using this font");
X	    return 0;
X	}
X	if (x < msg_rect.r_height) /* make it at least as big as the window */
X	    x = msg_rect.r_height;
X	do_clear();
X	lock_cursors();
X	if (!(msg_pix = mem_create(msg_rect.r_width, x, 1))) {
X	    error("mem_create");
X	    return 0;
X	}
X	pr_rop(msg_pix, 0,0, msg_rect.r_width-1, x-1, PIX_CLR, 0,0,0);
X	on_hdr = 1;
X    }
X#endif SUNTOOL
X    if (ison(flags, INDENT) &&
X       (!(indent_str = do_set(set_options, "indent_str")) ||
X	!strcmp(indent_str, "indent_str")))
X	indent_str = DEF_INDENT_STR;
X    (void) fseek(tmpf, msg[n].m_offset, L_SET);
X    while (still_more < msg[n].m_size && fgets(line, BUFSIZ, tmpf)) {
X	still_more += strlen(line);
X
X	/*
X	 * If squeeze is one, all blanks lines squeeze down to one blank line.
X	 * If squeeze is two, squeezing is in progress. Otherwise, wait for \n.
X	 */
X	if (*line == '\n') {
X	    if (on_hdr)    /* blank line -- end of header */
X		turnoff(flags, NO_HEADER), on_hdr = 0;
X	    if (squeeze > 1)
X		continue;
X	    else if (squeeze)
X		squeeze = 2;
X	} else if (squeeze > 1)
X	    squeeze = 1;
X
X	if (ison(flags, UPDATE_STATUS))
X	    if (!strncmp(line, "Status:", 7))
X		continue; /* ignore this and other "Status" lines */
X	    else if (!on_hdr) {
X		/* preserve NEW/UNREAD status on preserved messages */
X		if (isoff(msg[n].m_flags, PRESERVE)) {
X		    (void) strcpy(line, "Status: O");
X		    if (isoff(msg[n].m_flags, UNREAD))
X			(void) strcat(line, "R");
X		    (void) strcat(line, "\n");
X		    fputs(line, fp);
X		    (void) strcpy(line, "\n");
X		}
X		turnoff(flags, UPDATE_STATUS);
X	    }
X	if (on_hdr && isoff(flags, NO_IGNORE)) {
X	    register char *p = any(line, " \t:");
X	    if (!p)
X		ignoring = 0, on_hdr = 0;
X	    else if (ignoring)
X		if (*p != ':') {
X		    Debug("Ignoring: %s", line);
X		    continue;
X		}
X		else
X		    ignoring = 0;
X	    if (p && *p == ':') {
X		register struct options *opts;
X		*p = 0;
X		ignoring = 0;
X		for (opts = ignore_hdr; opts; opts = opts->next)
X		    if (!lcase_strcmp(opts->option, line)) {
X			ignoring = 1;
X			break;
X		    }
X		*p = ':';
X		if (ignoring) {
X		    Debug("Ignoring: %s", line);
X		    continue;
X		}
X	    }
X	}
X	if (!on_hdr && ison(flags, TOP) && !--top)
X	    break;
X	if (isoff(flags, NO_HEADER)) {
X	    /* note that function returns the number of lines */
X	    lines++;
X#ifdef SUNTOOL
X	    if (istool && fp == stdout) {
X		Addstr(line);
X		continue;
X	    }
X#endif SUNTOOL
X	    if (ison(flags, INDENT))
X		fputs(indent_str, fp);
X	    (void) fputs(line, fp);
X	    if (errno == ENOSPC)
X		return -1;
X	}
X    }
X#ifdef SUNTOOL
X    if (istool && fp == stdout) {
X	unlock_cursors();
X	txt.y = still_more = msg_rect.r_height;
X	scroll_win(0);  /* causes a display */
X    }
X#endif SUNTOOL
X    return lines;
X}
X
X/* get mail from whatever the mailfile points to. open a tempfile for
X * appending, then close it and reopen it for read-only.  some systems
X * have flakey read/write access.
X */
Xvoid
Xgetmail()
X{
X    register FILE	*mail_fp;
X    int 	lines = 0, get_status = 1;
X    long 	ftell(), bytes;
X    char	line[BUFSIZ];
X
X    if (!(mail_fp = fopen(mailfile, "r"))) {
X	error("Cannot open %s", mailfile);
X	return;
X    }
X    /*
X     * since this file is usually open for read-only, close it and then
X     * reopen it for appending.  This is done to compensate for errors
X     * in XENIX and to play it safe with non-essentially writable files.
X     * see more notes below (end of proc).
X     */
X    (void) fclose(tmpf);
X    {
X	int	omask = umask(077);
X	tmpf = fopen(tempfile, "a");
X	(void) umask(omask);
X	if (!tmpf) {
X	    error("can't open %s for appending", tempfile);
X	    (void) fclose(mail_fp);
X	    return;
X	}
X    }
X#ifdef SYSV
X    (void) locking(fileno(mail_fp), LK_LOCK,  0);
X#else
X#ifdef BSD
X    if (flock(fileno(mail_fp), LOCK_SH))  /* if file is locked, flock waits */
X	error("WARNING: could not lock %s", mailfile);
X#endif BSD
X#endif SYSV
X
X    (void) fseek(mail_fp, ftell(tmpf), 0);
X
X    while (fgets(line, BUFSIZ, mail_fp) != NULL) {
X	if (!strncmp(line, "From ", 5)) {
X	    if (msg_cnt == MAXMSGS-1) {
X		print("WARNING: exceeded %d messages.\n", MAXMSGS);
X		print("You should split \"%s\" into smaller files.\n",mailfile);
X		/* make sure that tempfile isn't removed!! */
X		turnon(glob_flags, IGN_SIGS);
X		cleanup(0); /* probably a more elegant way to exit, but... */
X	    }
X	    bytes = ftell(tmpf);
X	    /* finish up message structure from previous message.
X	     * if this is incorporating new mail, check "lines" to
X	     * see if previous message has already been set!
X	     */
X	    if (msg_cnt && lines) {
X		msg[msg_cnt-1].m_size = bytes - msg[msg_cnt-1].m_offset;
X		msg[msg_cnt-1].m_lines = lines;
X	    }
X	    msg[msg_cnt].m_offset = bytes;
X	    msg[msg_cnt].m_flags = lines = 0;
X	    turnon(msg[msg_cnt].m_flags, UNREAD); /* initialize */
X
X	    fputs(line, tmpf);
X	    if (errno == ENOSPC)
X		fs_error();
X
X	    /* we've read the "From " line, now read the rest of
X	     * the message headers till we get to a blank line.
X	     */
X	    while (fgets(line, BUFSIZ, mail_fp) && (*line != '\n')) {
X		register char *p = line;
X		if (get_status && !(get_status = strncmp(p, "Status:", 7))) {
X		    turnon(msg[msg_cnt].m_flags, OLD);
X		    for (p += 8 ; *p != '\n'; p++)
X			switch(*p) {
X			    case 'R': turnoff(msg[msg_cnt].m_flags, UNREAD);
X			}
X		}
X		fputs(line, tmpf), lines++;
X		if (errno == ENOSPC)
X		    fs_error();
X	    }
X	    msg_cnt++, get_status = 1;
X	}
X	fputs(line, tmpf), lines++;
X	if (errno == ENOSPC)
X	    fs_error();
X    }
X    /* msg_cnt may be 0 if there is an error with the format of mailfile */
X    if (msg_cnt) {
X	msg[msg_cnt-1].m_size = ftell(tmpf) - msg[msg_cnt-1].m_offset;
X	msg[msg_cnt-1].m_lines = lines;
X    }
X#ifdef SYSV
X    locking(fileno(mail_fp), LK_UNLCK, 0);
X#endif /* SYSV */
X    fclose(mail_fp);			/* implicit unlock */
X    /* I've had problems with sys-v opening a file for read/write. I'd
X     * try fgets after a seek to an arbitrary place and get NULL. "w+"
X     * could be broken (XENIX), so play it safe anyway.
X     */
X    fclose(tmpf);
X    if (!(tmpf = fopen(tempfile, "r")))
X	error("can't open %s for reading", tempfile);
X}
X
Xfs_error()
X{
X    error("WARNING: can't write to \"%s\"", tempfile);
X    print("Read the manual on what to do on full file systems.\n");
X    cleanup(0);
X}
X
X/*
X * copy temp or whatever back to mailfile
X * Return 0 if new mail came and user doesn't want to exit.
X */
Xcopyback()
X{
X    register int	new = 0, i, j=0, k=0;
X    register long 	flg = 0;
X    register FILE 	*mbox = NULL_FILE, *mail_fp;
X    char 		*mbox_file, action = 0;
X    int 		hold = 0, delete_it = 0, dont_unlink = FALSE;
X
X#ifdef SUNTOOL
X    if (istool) {
X	timerclear(&(mail_timer.it_interval));
X	timerclear(&(mail_timer.it_value));
X    }
X#endif SUNTOOL
X    if (ison(glob_flags, READ_ONLY)) {
X	print("Can't update %s: read only\n", mailfile);
X	return 1;
X    }
X    if (check_new_mail()) {
X	new = 1;
X	if (!istool) {
X	    char buf[256];
X	    if (iscurses)
X		putchar('\n');
X	    print("Really quit? "), fflush(stdout);
X	    buf[0] = 0;
X	    if (!Getstr(buf, 256, 0) || lower(*buf) != 'y')
X		return 0;
X	}
X    } else if (!msg_cnt) /* prevent unnecessary overwrite */
X	return 0;
X    /* open mbox if: "autodelete" AND "hold" are NOT set. */
X    if (is_spool(mailfile)
X	    && !(delete_it = !!do_set(set_options, "autodelete"))
X	    && !(hold = !!do_set(set_options, "hold"))) {
X	register char *p;
X	int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
X
X	if (!(p = do_set(set_options, "mbox")))
X	    p = DEF_MBOX;
X	mbox_file = getpath(p, &x);
X	if (x) {
X	    if (x > 0)
X		print("%s is a directory.\n", mbox_file);
X	    else
X		print("can't open %s: %s\n", p, mbox_file);
X	    mbox = NULL_FILE;
X	} else {
X	    char *mode = "a";
X	    if (access(mbox_file, 0)) /* does it exist? */
X		mode = "w"; /* no, create it. */
X	    else if (access(mbox_file, 2))   /* if yes, can we write in it? */
X		error("can't open %s", mbox_file); /* if no, print why not */
X	    if (!(mbox = fopen(mbox_file, mode)))
X		error("can't open %s", mbox_file);
X	}
X    }
X    /* reopen the mailfile; make sure it's not readable */
X    {
X	int omask = umask(077);
X	mail_fp = fopen(mailfile, "w");
X	(void) umask(omask);
X	if (!mail_fp) {
X	    error("can't rewrite %s", mailfile);
X	    return 0;
X	}
X    }
X    turnon(glob_flags, IGN_SIGS);
X    print("Updating \"%s\"", mailfile), fflush(stdout);
X#ifdef SYSV
X    (void) locking(fileno(mail_fp), LK_LOCK,  0);
X#else
X#ifdef BSD
X    if (flock(fileno(mail_fp), LOCK_EX))
X	error("WARNING: could not lock %s", mailfile);
X#endif BSD
X#endif SYSV
X    turnon(flg, UPDATE_STATUS);
X    turnon(flg, NO_IGNORE);
X
X    for (i = 0; i < msg_cnt; i++)
X	/* check to see if message is marked for deletion or, if read and not
X	 * preserved, delete it if autodelete is set. Otherwise, save the
X	 * message in the spool file if hold is set. If all fails, save in mbox.
X	 */
X	if (ison(msg[i].m_flags, DELETE)
X	    || isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE) 
X		&& delete_it) {
X	    Debug("%s %d",
X		(action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
X	    continue;
X	} else if (ison(msg[i].m_flags, UNREAD) ||
X		 ison(msg[i].m_flags, PRESERVE) || hold || !mbox) {
X	    j++;
X	    Debug("%s %d",
X		(action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
X	    if (copy_msg(i, mail_fp, flg) == -1) {
X		error("WARNING: could not write back to spool");
X		print("ALL mail left in %s\n", tempfile);
X		print("Spool mailbox may be corrupted.\n");
X		if (new)
X		    print("New mail may be lost. :-(\n");
X		dont_unlink = TRUE;
X		break;
X	    }
X	} else if (is_spool(mailfile)) {   /* copy back to mbox if spooldir */
X	    k++;
X	    if (copy_msg(i, mbox, flg) == -1) {
X		error("WARNING: could not write to mbox");
X		print("Unresolved mail left in %s\n", tempfile);
X		dont_unlink = TRUE;
X		break;
X	    }
X	    Debug("%s %d",
X		(action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
X	}
X    Debug("\n%s", mailfile);
X#ifdef SYSV
X    locking(fileno(mail_fp), LK_UNLCK, 0);
X#endif SYSV
X    fclose(mail_fp);		/* implicit unlock for BSD */
X    if (mbox)
X	fclose(mbox);
X    if (j) {
X	long times[2];
X	times[1] = time(&times[0]) - (long)2;
X	if (is_spool(mailfile) && utime(mailfile, times))
X	    error("utime");
X	print_more(": saved %d message%s\n", j, (j==1)? NO_STRING: "s");
X    } else if (!is_spool(mailfile) && !dont_unlink && !new)
X	if (unlink(mailfile))
X	    turnon(glob_flags, CONT_PRNT), error(": cannot remove");
X	else
X	    print_more(": removed\n");
X    else
X	print_more(": empty\n");
X    if (k)
X	print("saved %d message%s in %s\n",k,(k==1)? NO_STRING: "s",mbox_file);
X    if (new && !istool)
X	print("New mail has arrived.\n");
X    turnoff(glob_flags, IGN_SIGS);
X#ifdef SUNTOOL
X    if (istool) {
X	mail_timer.it_value.tv_sec = time_out;
X	setitimer(ITIMER_REAL, &mail_timer, NULL);
X    }
X#endif SUNTOOL
X    return 1;
X}
X
Xmail_size()
X{
X    struct stat buf;
X    if (!is_spool(mailfile)) {
X	char tmp[128];
X	if (!stat(sprintf(tmp, "%s/%s", MAILDIR, login), &buf))
X	    spool_size = buf.st_size;
X    }
X    if (!*mailfile)
X	return 0;
X    if (stat(mailfile, &buf)) {
X	if (errno != ENOENT)
X	    error("Can't stat %s", mailfile);
X	return 0;
X    }
X    if (is_spool(mailfile))
X	spool_size = buf.st_size;
X    if (buf.st_size > last_size) {
X	last_size = buf.st_size;
X	return 1;
X    }
X    return 0;
X}
X
Xvoid
Xmail_status(as_prompt)
X{
X    static char buf[256];
X    register int cnt = 0, new = 0, unread = 0, deleted = 0;
X
X    for ( ; cnt < msg_cnt; cnt++) {
X	if (ison(msg[cnt].m_flags, UNREAD))
X	    unread++;
X	if (ison(msg[cnt].m_flags, DELETE))
X	    deleted++;
X	if (isoff(msg[cnt].m_flags, OLD))
X	    new++;
X    }
X    if (as_prompt) {
X	register char *p, *b = buf;
X	for (p = prompt; *p; p++)
X	    if (*p == '\\')
X		switch (*++p) {
X		    case 'n': case 'r': *b++ = '\n';
X		    when 't': *b++ = '\t';
X		    otherwise: *b++ = *p;
X		}
X	    else if (*p == '%')
X		switch (*++p) {
X		    case 'm':
X			b += strlen(sprintf(b,"%d",(msg_cnt)? current_msg+1:0));
X		    when 't':
X			b += strlen(sprintf(b, "%d", msg_cnt));
X		    when 'd':
X			b += strlen(sprintf(b, "%d", deleted));
X		    when 'u':
X			b += strlen(sprintf(b, "%d", unread));
X		    when 'n':
X			b += strlen(sprintf(b, "%d", new));
X		    when 'f':
X			b += Strcpy(b, mailfile);
X			if (ison(glob_flags, READ_ONLY))
X			    b += Strcpy(b, " [read only]");
X		    when 'T': case 'D': case 'Y': case 'M': case 'N':
X			b += Strcpy(b, Time(p, (long)0));
X		    otherwise: *b++ = *p;
X		}
X	    else if (*p == '!')
X		b += strlen(sprintf(b, "%d", hist_no+1));
X	    else
X		*b++ = *p;
X	*b = 0;
X	print("%s", buf); /* buf MIGHT have a % in it... don't pass as fmt */
X	return;
X    }
X    (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
X	mailfile, ison(glob_flags, READ_ONLY)? " [read only]" : "",
X	msg_cnt, (msg_cnt != 1)? "s": NO_STRING, new, unread);
X    if (istool || iscurses)
X	(void) sprintf(buf+strlen(buf), ", %d deleted", deleted);
X#ifdef SUNTOOL
X    if (istool) {
X	static char ic_text[4];
X	extern struct pixrect mail_icon_image1, mail_icon_image2;
X	(void) sprintf(ic_text, "%3d", msg_cnt);
X	tool_set_attributes(tool,
X	    WIN_LABEL, buf,
X	    WIN_ICON_LABEL, ic_text,
X	    WIN_ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
X		&mail_icon_image2 : &mail_icon_image1,
X	    0);
X    } else
X#endif SUNTOOL
X#ifdef CURSES
X	if (iscurses)
X	    mvprintw(0, 0, "%-3d %-*s",
X		((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
X	else
X#endif CURSES
X	    puts(buf);
X    return;
X}
X
X/* return -1 since function doesn't affect messages */
Xcheck_flags(flags)
Xu_long flags;
X{
X    print_more(" ");
X    if (ison(flags, VERBOSE))
X	print_more("VERBOSE ");
X    if (ison(flags, INCLUDE))
X	print_more("INCLUDE ");
X    if (ison(flags, INCLUDE_H))
X	print_more("INCLUDE_H ");
X    if (ison(flags, EDIT))
X	print_more("EDIT ");
X    if (ison(flags, SIGN))
X	print_more("SIGN ");
X    if (ison(flags, DO_FORTUNE))
X	print_more("DO_FORTUNE ");
X    if (ison(flags, NO_HEADER))
X	print_more("NO_HEADER ");
X    if (ison(flags, DELETE))
X	print_more("DELETE ");
X    if (ison(flags, OLD))
X	print_more("OLD ");
X    if (ison(flags, UNREAD))
X	print_more("UNREAD ");
X    if (ison(flags, UPDATE_STATUS))
X	print_more("UPDATE_STATUS ");
X    if (ison(flags, NO_PAGE))
X	print_more("NO_PAGE ");
X    if (ison(flags, INDENT))
X	print_more("INDENT ");
X    if (ison(flags, NO_IGNORE))
X	print_more("NO_IGNORE ");
X    if (ison(flags, PRESERVE))
X	print_more("PRESERVE ");
X    print_more("\n");
X    return -1;
X}
END_OF_FILE
if test 16268 -ne `wc -c <'msgs.c'`; then
    echo shar: \"'msgs.c'\" unpacked with wrong size!
fi
# end of 'msgs.c'
fi
if test -f 'mush.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mush.h'\"
else
echo shar: Extracting \"'mush.h'\" \(17878 characters\)
sed "s/^X//" >'mush.h' <<'END_OF_FILE'
X/* @(#)mush.h	(c) copyright 1986 (Dan Heller) */
X
X#define VERSION "Mail User's Shell (Vers 5.7) Sun Sep  6 19:10:48 PDT 1987"
X
X#include "config.h"
X
X#ifdef CURSES
X#include <curses.h>
X#else CURSES
X#include <stdio.h>
X#endif /* CURSES */
X
X#include <ctype.h>
X#include <errno.h>
X#include <setjmp.h>
X#include "strings.h"
X
X#ifdef SUNTOOL
X#    include <suntool/tool_hs.h>
X#else  SUNTOOL
X#    include <sys/types.h>
X#    include <signal.h>
X#    ifndef SYSV
X#        include <sys/time.h>
X#	 include <sys/ioctl.h>   /* for ltchars */
X#    else
X#        include <time.h>
X#        include <fcntl.h>
X#    endif /* SYSV */
X#endif /* SUNTOOL */
X
X#include <sys/stat.h>
X#include <sys/file.h>
X
X#ifdef SUNTOOL
X#    include <suntool/gfxsw.h>
X#    include <suntool/panel.h>
X#    include <suntool/ttysw.h>
X#    include <suntool/ttytlsw.h>
X#    include <suntool/menu.h>
X#    include <suntool/icon_load.h>
X#endif /* SUNTOOL */
X
X/* if no maximum number of files can be found, we'll use getdtablesize() */
X#ifdef _NFILE
X#    define MAXFILES _NFILE
X#else
X#ifdef NOFILE
X#    define MAXFILES NOFILE
X#endif
X#endif
X
X#ifndef CTRL
X#define CTRL(c)		('c' & 037)
X#endif
X
X#define ESC 		'\033'
X
X#define NO_STRING	""
X#ifdef  NULL
X#undef  NULL
X#endif /*  NULL */
X#define NULL		(char *)0
X#define NULL_FILE	(FILE *)0
X#define DUBL_NULL	(char **)0
X#define TRPL_NULL	(char ***)0
X#ifdef putchar
X#undef putchar
X#endif /* putchar */
X#define putchar(c)	fputc(c, stdout)
X#define bell() 		fputc('\007', stderr)
X
X#define on_intr() \
X    turnoff(glob_flags, WAS_INTR), oldint = signal(SIGINT, interrupt), \
X    oldquit = signal(SIGQUIT, interrupt)
X
X#define off_intr() \
X    turnoff(glob_flags, WAS_INTR), (void) signal(SIGINT, oldint), \
X    (void) signal(SIGQUIT, oldquit)
X
X/* Don't flush input when setting echo or cbreak modes (allow typeahead) */
X#ifdef TIOCSETN
X#define stty(fd, sgttybuf)	(ioctl(fd, TIOCSETN, sgttybuf))
X#endif /* TIOCSETN */
X
X#ifndef CURSES
X/* if curses is not defined, simulate the same tty based macros */
Xstruct sgttyb _tty;
X
X#define crmode()   (_tty.sg_flags |= CBREAK,  stty(0, &_tty))
X#define nocrmode() (_tty.sg_flags &= ~CBREAK, stty(0, &_tty))
X#define echo()     (_tty.sg_flags |= ECHO,    stty(0, &_tty))
X#define noecho()   (_tty.sg_flags &= ~ECHO,   stty(0, &_tty))
X#define savetty()  (void) gtty(0, &_tty)
X#endif /* ~CURSES */
X
X#define echo_on()	\
X    if (_tty.sg_flags && isoff(glob_flags, ECHO_FLAG)) echo(), nocrmode()
X#define echo_off()	\
X    if (_tty.sg_flags && isoff(glob_flags, ECHO_FLAG)) noecho(), crmode()
X
X#define strdup(dst, src) (xfree (dst), dst = savestr(src))
X#define Debug		if (debug) printf
X
X#ifdef SYSV
X#define L_SET	0
X#define F_OK	000
X#define R_OK	004
X#define W_OK	002
X#define E_OK	001
X#define u_long  ulong_t
X#define vfork   fork
X#define SIGCHLD SIGCLD
X#endif /*  SYSV */
X
X#if !defined(SUNTOOL) && !defined(CURSES)
X
X#define TRUE		  1
X#define FALSE		  0
X#define print		  printf
X#define wprint		  printf
X#define print_more	  printf
X
X#endif /* SUNTOOL && !CURSES */
X
X#ifndef max
X#define max(a,b) (((a) > (b)) ? (a) : (b))
X#define min(a,b) (((a) < (b)) ? (a) : (b))
X#endif /*  max */
X
X#if defined(CURSES) && !defined(SUNTOOL)
X#define wprint printf
X#endif /* !SUNTOOL && CURSES */
X
X#if defined(CURSES) || defined(SUNTOOL)
X#define print_more	  turnon(glob_flags, CONT_PRNT), print
Xvoid print();		/* printf to window or curses or tty accordingly */
X#endif /* CURSES || SUNTOOL */
X
X#ifdef  SUNTOOL
X
X#define NO_ITEM		  (Panel_item)0
X#define NO_EVENT	  (struct inputevent *)0
X#define TIME_OUT	  60           /* sleep 60 secs between mailchecks */
X#define PIX_OR		  PIX_SRC ^ PIX_DST
X#define ID 		  event.ie_code
X#define l_width(font)	  fonts[font]->pf_defaultsize.x /* width of letter */
X#define l_height(font)	  fonts[font]->pf_defaultsize.y /* height of letter */
X#define Clrtoeol(w,x,y,f) pw_text(w, x, y, PIX_SRC, fonts[f], blank)
X
X#define highlight(win,x,y,font,s) \
X    pw_text(win,x,y, PIX_SRC, fonts[font],s), \
X    pw_text(win,x+1,y, \
X	(ison(glob_flags, REV_VIDEO))? PIX_NOT(PIX_SRC): PIX_SRC|PIX_DST, \
X	fonts[font],s)
X
X/* Fonts */
X#define FONTDIR		  "/usr/lib/fonts/fixedwidthfonts"
X#define DEFAULT		  0
X#define SMALL	 	  1
X#define LARGE 		  2
X#define MAX_FONTS	  3
X
X#endif /* SUNTOOL */
X
X/* bits and pieces */
X#define turnon(flg,val)   ((flg) |= ((u_long)1 << ((u_long)(val)-1L)))
X#define turnoff(flg,val)  ((flg) &= ~((u_long)1 << ((u_long)(val)-1L)))
X#define ison(flg,val)     ((u_long)(flg) & ((u_long)1 << ((u_long)(val)-1L)))
X#define isoff(flg,val)    (!ison((flg), (val)))
X#define set_isread(n)	  \
X	if (ison(msg[n].m_flags, UNREAD)) \
X	    turnon(glob_flags, DO_UPDATE), turnoff(msg[n].m_flags, UNREAD)
X
X/* msg lists represented by bits */
X#define clear_msg_list(list)  	(void) bzero(list, (msg_cnt+7)/8)
X#define msg_bit(list, n)	((list[(n) / 8] >> ((n) % 8)) & 1)
X#define set_msg_bit(list, n)	(list[(n) / 8] |= (1 << ((n) % 8)))
X#define unset_msg_bit(list, n)  (list[(n) / 8] &= ~(1 << ((n) % 8)))
X#define bput(S1, S2, Len, op)   				\
X		{ 						\
X		    register char *s1 = S1, *s2 = S2; 		\
X		    register int len = Len; 			\
X		    while(len--) 				\
X			*s2++ op *s1++; 			\
X		}
X#define bitput(m1,m2,len,op)	bput(m1, m2, (((len)+7)/8), op)
X
X/* convenience and/or readability */
X#define when		  break;case
X#define otherwise	  break;default
X#define lower(c)	  (isupper(c)? tolower(c): c)
X#define Lower(c)	  (c = lower(c))
X#define upper(c)	  (islower(c)? toupper(c): c)
X#define Upper(c)	  (c = upper(c))
X#define skipspaces(n)     for(p += (n); *p == ' ' || *p == '\t'; ++p)
X#define skipdigits(n)     for(p += (n); isdigit(*p); ++p)
X
X#define NO_FLG		0
X
X/* various flags */
Xlong   glob_flags;	/* global boolean flags thruout the whole program */
X#define DO_UPDATE   1	/* check for changes to avoid unnecessary copyback */
X#define REV_VIDEO   2	/* reverse video for curses or toolmode */
X#define CONT_PRNT   3	/* continue to print (maybe a printf) without a '\n' */
X#define DO_SHELL    4	/* run a shell even if no mail? (true if tool) */
X#define DO_PIPE     5	/* true if commands are piping to another command */
X#define IS_PIPE     6	/* true if commands' "input" is piped from another */
X#define IGN_SIGS    7	/* true if catch() should not longjump */
X#define IGN_BANG    8	/* ignore ! as a history reference (see source()) */
X#define ECHO_FLAG   9	/* if true, echo|cbreak is ON, don't echo typing (-e) */
X#define IS_GETTING 10	/* true if we're getting input for a letter */
X#define PRE_CURSES 11	/* true if curses will be run, but hasn't started yet */
X#define READ_ONLY  12	/* -r passed to folder() (or main) setting read only */
X#define REDIRECT   13	/* true if stdin is being redirected */
X#define WAS_INTR   14	/* catch interrupts, set this flag (signals.c) */
X#define WARNING    15   /* if set, various warning messages may be printed */
X#define NEW_MAIL   17   /* new mail has arrived; user is busy or in icon mode */
X
X#define VERBOSE		1       /* verbose flag for sendmail */
X#define INCLUDE		2       /* include msg in response */
X#define INCLUDE_H	3	/* include msg with header */
X#define EDIT		4	/* enter editor by defualt on mailing */
X#define SIGN		5	/* auto-include ~/.signature in mail */
X#define DO_FORTUNE	6	/* add a fortune at end of msgs */
X
X/* msg flags */
X#define NO_HEADER	7	/* don't print header of message (top, write) */
X#define DELETE		8
X#define OLD	        9
X#define UNREAD		10
X#define UPDATE_STATUS	11	/* change status of msg when copyback */
X#define NO_PAGE		12	/* don't page this message */
X#define INDENT		13	/* indent included msg with string */
X#define NO_IGNORE	14	/* don't ignore headers */
X#define PRESERVE	15      /* preserve in mailbox unless deleted */
X#define TOP		15	/* just print the top of the message */
X#define FORWARD		16	/* Forward messages into the message buffer */
X
X#define	MAXMSGS_BITS	MAXMSGS/sizeof(char)	/* number of bits for bitmap */
X
Xstruct msg {
X    u_long m_flags;
X    long   m_offset;               /* offset in tempfile of msg */
X    long   m_size;                 /* number of bytes in msg */
X    int    m_lines;                /* number of lines in msg */
X} msg[MAXMSGS];
X
Xstruct options {
X    char *option;
X    char *value;
X    struct options *next;
X} *set_options, *aliases, *ignore_hdr, *functions, *fkeys, *own_hdrs;
X#ifdef CURSES
Xstruct options *bindings;
X#endif /* CURSES */
X
Xstruct cmd {
X    char *command;
X    int (*func)();
X};
Xextern struct cmd ucb_cmds[];
Xextern struct cmd cmds[], hidden_cmds[];
X#ifdef SUNTOOL
Xextern struct cmd fkey_cmds[];
X#endif /* SUNTOOL */
X
XFILE
X    *tmpf,		/* temporary holding place for all mail */
X    *open_file(),	/* open a file or program for write/append */
X    *popen();		/* this should be in stdio.h */
X
Xextern char
X    *sys_errlist[],    /* system's list of global error messages */
X#ifdef SUNTOOL
X    *font_files[], 	/* the names of the files fonts are kept in */
X    *alt_fonts[], 	/* fonts to use if first ones don't work */
X#endif /* SUNTOOL */
X    **environ;		/* user's environment variables */
X
Xextern int errno;	/* global system error number */
Xjmp_buf jmpbuf;		/* longjmp to jmpbuf on sigs (not in tool) */
X
Xchar
X    debug,		/* debug causes various print statements in code */
X    tempfile[40],	/* path to filename of temporary file */
X    msg_list[MAXMSGS_BITS],	/* MAXMSGS bits of boolean storage */
X    *cmd_help,		/* filename of location for "command -?" commands. */
X    *login,		/* login name of user */
X    *mailfile,		/* path to filename of current mailfile */
X    *ourname[MAX_HOST_NAMES],	/* the name and aliases of the current host */
X    *prompt,		/* the prompt string -- may have %d */
X    *escape,		/* the escape character when without editor */
X    *editor,	 	/* string describing editor to use (default vi) */
X    *hdrs_only,		/* true if -H flag was given --set to args */
X    *hdr_format,	/* set to the header format string; referenced a lot */
X    *visual,	 	/* string describing visual editor to use */
X    *pager,	 	/* string describing pager to use (default more) */
X    *argv_to_string(),	/* convert a vector of strings into one string */
X    **make_command(),	/* build a command vector (argv) */
X    **mk_argv(),	/* given a string, make a vector */
X    *itoa(),		/* return a string representation of a number */
X    *lcase_strcpy(),	/* just like strcpy, but convert all chars to lower */
X    *variable_stuff(),	/* return information about variables */
X    *no_newln(),	/* remove newline and extra whitespace - return end */
X    *savestr(),		/* strcpy arg into malloc-ed memory; return address */
X    *date_to_string(),	/* returns a string described by parse_date() */
X    *msg_date(),	/* return a string of the date of a message */
X    *parse_date(),	/* parse an ascii date, and return message-id str */
X    *Time(),		/* returns string expression of time (takes args) */
X    *do_range(),	/* parse a string converting to a "range" of numbers */
X    *getpath(),		/* static char returning path (expanding ~, +, %, #) */
X    *compose_hdr(),	/* returns a formatted line describing passed msg # */
X    *my_atoi(), 	/* do an atoi, but return the last char parsed */
X    *do_set(),		/* set/unset an option, alias, ignored-hdr */
X    *reply_to(),	/* who do we reply to when responding */
X    *cc_to(),     	/* when responding, return str which is the cc-list */
X    *subject_to(),      /* when responding, return str which is the subject */
X    *header_field(),    /* the line in msg described by arg (message header) */
X    *alias_to_address(),/* convert a name[list] to "real" names */
X    *set_header(), 	/* [interactive] proc to set/display to/subject/cc */
X    *getenv(), *prog_name;
X
Xint
X    last_msg_cnt,	/* when checking for new mail, save the last msg_cnt */
X    msg_cnt,		/* total number of messages */
X    crt,		/* min number of lines msg contains to invoke pager */
X    current_msg,	/* the current message we're dealing with */
X    exec_pid,		/* pid of a command that has been "exec"ed */
X    hist_no,		/* command's history number */
X    iscurses;		/* if we're running curses */
X    istool,		/* argv[0] == "xxxxtool", ranges from 0 to 2 */
X    n_array[128],	/* array of message numbers in the header window */
X    screen,		/* number of headers window can handle */
X
X    quit(), cleanup(), catch(), do_alias(), respond(), cd(), sh(), stop(),
X    folder(), save_msg(), delete(), do_mail(), lpr(), alts(), set(), do_hdrs(),
X    rm_edfile(), pick(), save_opts(), preserve(), sort(), readmsg(),
X    do_pick(), print_help(), folders(), question_mark(), do_from(), my_stty(),
X    do_version(), disp_hist(), source(), do_echo(), sigchldcatcher(), ls(),
X    nopenfiles(), Setenv(), Unsetenv(), Printenv(), bus_n_seg(), msg_flags(),
X    toggle_debug(), stop_start(), interrupt();
X
Xlong
X    still_more,		/* there is still more message to display */
X    spool_size,		/* size of sppol mail regardless of current folder */
X    last_size,		/* the lastsize of the mailfile since last check */
X    time();		/* satisfy lint */
X
Xvoid
X    xfree(), free_vec(), error(), getmail(), mail_status(),
X    file_to_fp(), init(), display_msg(), c_more();
X    /* printf(), fclose(), fflush(), fputs(), fputc() */
X#ifndef CURSES
Xstruct sgttyb _tty;			/* tty characteristics */
X#endif /* CURSES */
X#ifdef TIOCGLTC
Xstruct ltchars ltchars;			/* tty character settings */
X#endif /* TIOCGLTC */
X
X#ifdef CURSES
X
X#define STANDOUT(y,x,s) standout(), mvaddstr(y,x,s), standend()
X#define redraw()	clearok(curscr, TRUE), wrefresh(curscr)
X
Xint
X    curses_init(),	/* interpret commands via the curses interface */
X    bind_it();		/* bind chars or strings to functions */
X#endif /* CURSES */
X
X#ifdef SUNTOOL
Xvoid
X    lock_cursors(), unlock_cursors(), scroll_win(),
X    set_fkeys(), set_key(), toggle_opt(), help_opt();
X
Xchar
X    *rite(),		/* rite a char to msg_win: return string if c == '\n' */
X    *find_key(),	/* pass x,y coords to find which function key assoc. */
X    *key_set_to(),	/* pass fkey string, return string describing func */
X    *panel_get(),      	/* returns what has been typed in a panel item */
X    *tool_help,		/* help for tool-related things (sometimes, overlap) */
X    blank[128];		/* use to clear to end of line */
X
Xint
X    time_out,		/* time out interval to wait for new mail */
X    rootfd,		/* the root window's fd */
X    parentfd,		/* the parent's window fd */
X    getting_opts,	/* true if getting/setting opts from msg_win */
X    curfont,		/* the current font to use for mail message window */
X    total_fonts,	/* total number of fonts available */
X    get_hdr_field,	/* bitmask of header fields to be gotten */
X
X    msg_io(), msgwin_handlesigwinch(), hdr_io(), hdrwin_handlesigwinch(),
X    sigchldcatcher(), sigtermcatcher(), sigwinchcatcher(), do_sort(),
X    do_compose(), do_edit(), read_mail(), delete_mail(), respond_mail(),
X    do_hdr(), display_hdrs(), print_sigwinch(), p_set_opts(),
X    tool_mgmt(), do_help(), text_done(), msg_num_done(), do_lpr(),
X    toolquit(), change_font(), do_clear(), do_update(),
X    file_dir(), do_file_dir(), do_send(), abort_mail(), check_new_mail(),
X    fkey_cmd(), fkey_settings();
X
Xstruct tchars  tchars;			/* more tty character settings */
X
Xstruct tool *tool;      /* main tool structure */
Xstruct toolsw
X    *panel_sw,		/* main panel subwindow */
X    *hdr_sw, 		/* subwindow for message headers */
X    *hdr_panel_sw,	/* panel for headers */
X    *tty_sw, 		/* subwindow which forks a shell (usually editor) */
X    *print_sw, 		/* subwindow for print statements */
X    *msg_sw; 		/* main subwindow to display messages and more */
X
Xstruct pixwin
X    *msg_win,		/* main pixwin for message display and more */
X    *hdr_win,		/* pixwin for message headers */
X    *print_win;		/* pixwin for printing messages ( print() ) */
X
Xstruct pr_pos txt;   			/* current position of text written */
Xstruct rect msg_rect, hdr_rect;         /* sizes of the main and hdr rects */
Xstruct pixfont *fonts[MAX_FONTS];	/* array of fonts */
X
XPanel
X    main_panel,		/* the main panel dealing with generic items */
X    hdr_panel;		/* panel which contains message header specific items */
X
XPanel_item
X    abort_item,		/* abort mail in progress */
X    alias_item,		/* set/view/change current mail aliases */
X    cd_item,		/* changes file_item to cd (for cd-ing) */
X    comp_item,		/* compose a letter */
X    delete_item,	/* delete/undelete messages */
X    edit_item,		/* edit a message */
X    font_item,		/* choose which font to use */
X    folder_item,	/* change folders */
X    file_item, 		/* text item for files or directories (forlder/cd) */
X    hdr_display,	/* format message headers are displayed */
X    help_item,		/* choose this to get various help */
X    ignore_item,	/* set/view/change message headers to be ignored */
X    input_item,		/* text item to get values for set/unsetting values */
X    msg_num_item,	/* text item to explicity state which message to read */
X    next_scr,		/* display the next screenful of message headers */
X    option_item,	/* set/view/unset mail options */
X    prev_scr,		/* display the previous screen of messages */
X    print_item,		/* send current message to the printer */
X    quit_item,		/* quit tool/close to icon */
X    read_item,		/* read the current message */
X    respond_item,	/* respond to messages */
X    save_item,		/* saves messages; uses text item input_item */
X    send_item,		/* when composing letter, this will send it off */
X    sort_item,		/* sort routine... */
X    sub_hdr_item[6],	/* display items that just sit there and give help */
X    update_item;	/* commit changes to folder */
X
Xstruct itimerval mail_timer;	/* frequency to check for new mail */
X
X			/* mouse symbols and data */
X/* left, middle and right mouse pixrects */
Xstruct cursor
X    l_cursor, m_cursor, r_cursor, coffee, read_cursor, write_cursor,
X    main_cursor, checkmark;
X
Xstruct pixrect *msg_pix; /* pixrect holding text of a message */
Xextern struct pixrect mouse_left, mouse_middle, mouse_right;
Xextern struct pixrect dn_arrow, up_arrow, cycle, shade_50;
X
Xextern struct icon mail_icon;
X#endif /* SUNTOOL */
END_OF_FILE
if test 17878 -ne `wc -c <'mush.h'`; then
    echo shar: \"'mush.h'\" unpacked with wrong size!
fi
# end of 'mush.h'
fi
echo shar: End of archive 6 \(of 12\).
cp /dev/null ark6isdone
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 0t