From decwrl!ucbvax!ucsd!usc!cs.utexas.edu!mailrus!uunet!allbery Mon May  7 07:39:16 PDT 1990
Article 1518 of comp.sources.misc:
Path: decwrl!ucbvax!ucsd!usc!cs.utexas.edu!mailrus!uunet!allbery
From: argv@Eng.Sun.COM (Dan Heller)
Newsgroups: comp.sources.misc
Subject: v12i038: Mail User's Shell, Part10/19
Message-ID: <87541@uunet.UU.NET>
Date: 5 May 90 17:21:02 GMT
Sender: allbery@uunet.UU.NET
Lines: 1712
Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)

Posting-number: Volume 12, Issue 38
Submitted-by: argv@Eng.Sun.COM (Dan Heller)
Archive-name: mush/part10

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 10 (of 19)."
# Contents:  mush/curses.c mush/mush.h mush/version.h
# Wrapped by argv@turnpike on Wed May  2 13:59:31 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'mush/curses.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mush/curses.c'\"
else
echo shar: Extracting \"'mush/curses.c'\" \(28433 characters\)
sed "s/^X//" >'mush/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#ifdef SUNTOOL
X    if (istool) {
X	print("Sorry, can't change to curses mode from tool.\n");
X	return -1;
X    } else
X#endif /* SUNTOOL */
X    if (!is_shell) {
X	/*
X	 * Can't start curses, but we can prepare to.
X	 * Also allow -C switch to be shut off.
X	 */
X	if (argv && *argv && !lcase_strncmp(*argv, "off", -1))
X	    turnoff(glob_flags, PRE_CURSES);
X	else
X	    turnon(glob_flags, PRE_CURSES);
X	return 0;
X    } else if (argc && (iscurses || ison(glob_flags, PRE_CURSES))) {
X	print("You are already using curses mode.\n");
X	return -1;
X    } else if (ison(glob_flags, IS_GETTING)) {
X	print("Finish your letter first.\n");
X	return -1;
X    }
X
X#ifndef attrset		/* terminfo version of curses */
X    /* you can not start curses in no echo mode.. must be in normal mode */
X    echom();
X    nocrmode();
X#endif /* attrset */
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 !defined(SYSV) && !defined(USG)
X    if (!UP || !*UP)
X#else /* ~SYSV && ~USG */
X    if (!stdscr)
X#endif /* ~SYSV && ~USG */
X		 {
X	print("Terminal type %s can not use the curses interface.\n", ttytype);
X	return -1;
X    }
X    iscurses = TRUE;
X    noechom(); /* reset tty state -- */
X    crmode(); /* do not use "echo_on/off()" */
X    scrollok(stdscr, TRUE);
X    /* if the user hasn't set his screen explicitly, set it for him */
X    set_screen_size();
X    if (crt > LINES - 1 || !do_set(set_options, "crt")) {
X	crt = LINES;
X	(void)cmd_line(sprintf(buf, "\\set screen = %d crt = %d", screen, crt),
X	    msg_list);
X    } else
X	(void)cmd_line(sprintf(buf, "\\set screen = %d", screen), msg_list);
X    if (argc) {
X	(void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1), msg_list);
X	(void) curses_help_msg(TRUE);
X    }
X    if (!do_set(set_options, "no_reverse"))
X	turnon(glob_flags, REV_VIDEO);
X    turnoff(glob_flags, CONT_PRNT);
X    return 0; /* doesn't affect messages */
X}
X
Xstruct cmd_map *active_cmd;	/* See bindings.h for description */
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 needs to be done. This
X * new command is returned to caller and may be passed back.
X *
X * The flag CNTD_CMD (continued command) is set 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 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 because 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, curlin;
X    static int  redo = 0;  /* set if headers should be redrawn */
X
X    if (c != 0)
X	turnon(glob_flags, CNTD_CMD);
X    else
X	turnoff(glob_flags, CNTD_CMD);
X    clear_msg_list(msg_list); /* play it safe */
X    if (isoff(glob_flags, CNTD_CMD)) {
X	(void) check_new_mail();
X	curlin = max(1, current_msg - n_array[0] + 1);
X	scrn_line(curlin, buf);
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    if (c == C_WRITE_LIST || c == C_SAVE_LIST || c == C_COPY_LIST
X	   || c == C_DELETE_LIST || c == C_UNDEL_LIST) {
X	if (msg_cnt < 1) {
X	    mac_flush();
X	    print("Not enough messages.");
X	    c = C_NULL;
X	} else if (c == C_DELETE_LIST && ison(glob_flags, READ_ONLY)) {
X	    mac_flush();
X	    print("Folder is read-only.");
X	    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_COPY_LIST)? "copy" :
X		(c == C_DELETE_LIST)? "delete" : "undelete"), list, msg_list))
X	    c = C_NULL;
X	if (ison(glob_flags, CNTD_CMD))
X	    putchar('\n');
X    }
X
X    /* first do non-mail command type stuff */
X    switch (c) {
X	case C_ERROR :
X	    bell();
X	    mac_flush();
X
X	when C_NULL :
X	    if (isoff(glob_flags, CNTD_CMD))
X		bell();
X
X	/* goto a specific message number */
X	when C_GOTO_MSG :
X	    if (curses_msg_list(strcpy(buf, "goto msg: "), list, msg_list)) {
X		/*
X		 * Reset the current message in case a 
X		 * backquoted command (like `from`) changed it
X		 */
X		n = current_msg;
X		do if (++n >= msg_cnt)
X		    n = 0;
X		while (n != current_msg && !msg_bit(msg_list, n));
X		if (n == current_msg && !msg_bit(msg_list, n)) {
X		    mac_flush(); /* bail out if in macro processing */
X		    print("Message not found.");
X		}
X		else if ((current_msg = n) < n_array[0]
X			|| n > n_array[screen-1])
X		    redo = 1;
X	    } else {
X		mac_flush();
X		bell();
X	    }
X	    if (ison(glob_flags, CNTD_CMD) && msg_cnt)
X		print("%-.*s", COLS-2, compose_hdr(current_msg));
X	    if (ison(glob_flags, CNTD_CMD))
X		putchar('\n');
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 : redo = 1;
X
X	/*
X	 * screen movement
X	 */
X	when C_NEXT_MSG :
X	    if (current_msg + 2 > msg_cnt ||
X		isoff(glob_flags, CNTD_CMD) && curlin == LINES-2) {
X		mac_flush();	/* Bail out if in macro processing */
X		bell();		/* reached the end */
X	    } else {
X		if (ison(glob_flags, CNTD_CMD)) {
X		    if (++current_msg > n_array[screen-1])
X			redo = 1;
X		    print("%-.*s", COLS-2, compose_hdr(current_msg));
X		    putchar('\n');
X		} else {
X		    if (++current_msg > n_array[screen-1])
X			n_array[screen++] = current_msg;
X		    move(++curlin, 0);
X		    printw("%-.*s", COLS-2, compose_hdr(current_msg));
X		    clrtoeol();
X		}
X	    }
X
X	when C_PREV_MSG :
X	    if (isoff(glob_flags, CNTD_CMD) && curlin == 1 || current_msg == 0)
X	    {
X		mac_flush();	/* Bail out if in macro processing */
X		bell();  	/* at the beginning */
X	    } else {
X		if (--current_msg < n_array[0])
X		    redo = 1;
X		if (ison(glob_flags, CNTD_CMD)) {
X		    print("%-.*s", COLS-2, compose_hdr(current_msg));
X		    putchar('\n');
X		}
X	    }
X
X	when C_FIRST_MSG : case C_LAST_MSG :
X	    if (!msg_cnt) {
X		mac_flush();
X		bell();
X		break;
X	    }
X	    n = current_msg;
X	    move(LINES-1, 0), refresh();
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 (isoff(glob_flags, CNTD_CMD))
X		    (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
X			     msg_list);
X		else
X		    redo = 1;
X	    if (ison(glob_flags, CNTD_CMD) && n != current_msg)
X		print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
X
X	/* top and bottom of headers screen */
X	when C_TOP_PAGE : case C_BOTTOM_PAGE :
X	    if (msg_cnt && isoff(glob_flags, 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		mac_flush();
X		bell();
X	    }
X
X	when C_NEXT_SCREEN : /* next page */
X	    move(LINES-1, 0), refresh();
X	    if (msg_cnt-1 > n_array[screen-1]) {
X		clear();
X		set_screen_size();
X		(void) cmd_line(strcpy(buf, "\\headers +"), msg_list);
X		if (current_msg < n_array[0])
X		    current_msg = n_array[0];
X		(void) curses_help_msg(TRUE);
X		return redo = 0;
X	    } else {
X		mac_flush();
X		bell();
X	    }
X
X	when C_PREV_SCREEN : /* previous page */
X	    move(LINES-1, 0), refresh();
X	    if (n_array[0] > 0) {
X		clear();
X		set_screen_size();
X		(void) cmd_line(strcpy(buf, "\\headers -"), msg_list);
X		if (current_msg > n_array[screen-1])
X		    current_msg = n_array[screen-1];
X		(void) curses_help_msg(TRUE);
X		return redo = 0;
X	    } else {
X		mac_flush();
X		bell();
X	    }
X
X	/* read from/save to record file (.mushrc) */
X	when C_SOURCE : case C_SAVEOPTS : {
X	    int argc;
X	    char *argv[3];
X	    print("%s filename [default]: ",
X		(c == C_SOURCE)? "source" : "save options to");
X	    argc = Getstr(file, LINES-40, 0);
X	    clr_bot_line();
X	    if (argc < 0)
X		break;
X	    if (argc > 0)
X		argv[1] = file, argc = 2;
X	    else
X		argc = 1;
X	    argv[argc] = NULL;
X	    turnon(glob_flags, PRE_CURSES);
X	    if (c == C_SOURCE) {
X		(void) source(argc, argv);
X		mac_flush(); /* can't change things in mid-macro */
X		redo = isoff(glob_flags, CNTD_CMD);
X	    } else
X		(void) save_opts(argc, argv);
X	    turnoff(glob_flags, PRE_CURSES);
X	}
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 (ison(glob_flags, CNTD_CMD))
X		putchar('\n');
X	    if (c == 0)
X		break;
X	    if (ison(glob_flags, CNTD_CMD))
X		print("%-.*s",COLS-2, compose_hdr(current_msg)), putchar('\n');
X	    if (n_array[0] > current_msg || n_array[screen-1] < current_msg) {
X		redo = 1;
X		if (isoff(glob_flags, 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 (ison(glob_flags, CNTD_CMD))
X		    putchar('\n');
X		break;
X	    }
X	    if (ison(glob_flags, READ_ONLY)) {
X		mac_flush();
X		print("Folder is read-only.");
X		if (ison(glob_flags, CNTD_CMD))
X		    putchar('\n');
X		break;
X	    }
X	    Debug("current message = %d", current_msg + 1);
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 (isoff(glob_flags, CNTD_CMD) && (msg_cnt < screen ||
X			n >= n_array[0] && n <= n_array[screen-1])) {
X			move(max(1, n - n_array[0] + 1), 0);
X			printw("%-.*s", COLS-1, compose_hdr(n));
X		    } else
X			redo = 1;
X		}
X	    if (ison(glob_flags, CNTD_CMD) || *list) {
X		/* print(), THEN putchar() -- overwrite line */
X		if (ison(glob_flags, CNTD_CMD)) {
X		    print("%sdeleted %s",
X		    (c == C_DELETE_MSG || c == C_DELETE_LIST)? "":"un", list);
X		    putchar('\n');
X		}
X		if (c == C_DELETE_MSG || c == C_DELETE_LIST) {
X		    if (ison(msg[current_msg].m_flags, DELETE) ||
X			    ison(msg[current_msg].m_flags, SAVED))
X			(void) next_msg();
X		    if (isoff(msg[current_msg].m_flags, DELETE) &&
X			    do_set(set_options, "autoprint"))
X			return C_DISPLAY_MSG;
X		}
X		if (ison(glob_flags, CNTD_CMD))
X		    puts(compose_hdr(current_msg));
X		else if (current_msg < n_array[0]
X			|| current_msg > n_array[screen-1])
X		    redo = 1;
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	    if (!msg_cnt) {
X		print("No messages.");
X		if (ison(glob_flags, CNTD_CMD))
X		    putchar('\n');
X		break;
X	    }
X	    print(sprintf(buf, "filename to %s%s: ", p,
X		(c != C_WRITE_MSG && c != C_WRITE_LIST)? " [mbox]" : ""));
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		p = file; skipspaces(0);
X		argv[1] = (*p) ? p : NULL;
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		/* Turn on piping to make save_msg look at msg_list */
X		turnon(glob_flags, IS_PIPE);
X		if (save_msg(1 + (*file != '\0'), argv, msg_list) < 0)
X		    *list = 0;
X		turnoff(glob_flags, IS_PIPE);
X		if (ison(glob_flags, CNTD_CMD))
X		    redo = 1, putchar('\n'), puts(compose_hdr(current_msg));
X		if (*list)
X		    iscurses = redo = TRUE, turnon(glob_flags, CNTD_CMD);
X		else if (isoff(glob_flags, CNTD_CMD) && msg_cnt) {
X		    move(curlin, 0);
X		    printw("%-.*s", COLS-1, compose_hdr(current_msg));
X		    }
X	    } else {
X		print("No messages saved.");
X		if (ison(glob_flags, 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 (ison(glob_flags, 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	    turnon(glob_flags, DO_UPDATE);
X	    if (ison(glob_flags, CNTD_CMD)) {
X		wprint("%-.*s\n", COLS-1, compose_hdr(current_msg));
X		redo = 1;
X	    } else {
X		move(curlin, 0);
X		printw("%-.*s", COLS-1, compose_hdr(current_msg));
X	    }
X
X	/* order messages (sort) and redisplay 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(
X		"Order messages by [author, date, length, Status, subject]: "
X		);
X	    if ((c = m_getchar()) == 'a' || c == 'd' || c == 'l' ||
X		    c == 'S' || c == 's' || c == 'R') {
X		print("reordering messages...");
X		(void) cmd_line(sprintf(buf, "%s %c", file, c), msg_list);
X		print_more("done.");
X		if (ison(glob_flags, 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) mush_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	    clr_bot_line();
X	    redo = (c == C_UPDATE);
X	    if (!vrfy_update(&redo))
X		if (c == C_UPDATE)
X		    break;
X	    if (isoff(glob_flags, CNTD_CMD))
X		(void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
X				msg_list);
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		SIGRET (*oldint)(), (*oldquit)();
X		on_intr();
X		print("New folder (?=list): ");
X		c = Getstr(file, COLS-22, 0);
X		off_intr();
X		if (c > 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			turnon(glob_flags, CNTD_CMD), iscurses = 1;
X			continue;
X		    }
X		    clearok(stdscr, FALSE);
X		    /* if vrfy_update doesn't verify, but folder command fails,
X		     * then we need to reset the updatability of current folder
X		     */
X		    c = (ison(glob_flags, DO_UPDATE))? TRUE : FALSE;
X		    if (strcmp(file, "-?")) {
X			redo = 1; /* so vrfy_update() won't quit */
X			(void) vrfy_update(&redo);
X		    }
X		    move(LINES-1, 0), refresh();
X		    if (cmd_line(sprintf(buf, "folder ! -N %s", file),
X			     msg_list) == -1) {
X			if (c) /* remember state of updatability of folder */
X			    turnon(glob_flags, DO_UPDATE);
X			if (ison(glob_flags, CNTD_CMD))
X			    putchar('\n');
X		    } else
X			redo = 1, turnoff(glob_flags, CNTD_CMD);
X		    break;
X		} else {
X		    print("\"%s\" unchanged.", mailfile);
X		    if (ison(glob_flags, 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		turnon(glob_flags, CNTD_CMD);
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	    /* The "source" and "curses" commands need some indication
X	     * that we are in curses mode, so use the PRE_CURSES flag.
X	     */
X	    turnon(glob_flags, PRE_CURSES);
X	    (void) cmd_line(buf, msg_list);
X	    /* they may have affected message status or had text output */
X	    turnon(glob_flags, CNTD_CMD), redo = 1;
X	    turnoff(glob_flags, PRE_CURSES);
X	    iscurses = TRUE;
X	    if (msg_cnt)
X		puts(compose_hdr(current_msg));
X
X	/* send message to printer, redo to display 'p' status */
X	when C_PRINT_MSG : redo = (lpr(0, DUBL_NULL, msg_list) == 0);
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 (ison(glob_flags, 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 is reset if there's output! */
X
X	when C_VERSION :
X	    (void) do_version();
X	    if (ison(glob_flags, CNTD_CMD))
X		putchar('\n');
X
X	when C_MAIL_FLAGS :
X	    print("flags [-?]: ");
X	    if ((c = Getstr(file, COLS-12, 0)) < 0)
X		break;
X	    putchar('\n');
X	    if (c == 0)
X		(void) strcpy(file, "-?");
X	    else
X		redo = 1; /* In case of -f flag, to display the 'f' status */
X	/* Fall thru */
X	case C_MAIL : {
X	    u_long flgs = glob_flags;
X	    turnon(glob_flags, IGN_BANG);
X	    clr_bot_line();
X	    iscurses = FALSE;
X	    (void) cmd_line(sprintf(buf, "mail %s", file), msg_list);
X	    glob_flags = flgs;
X	    iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
X	    if (msg_cnt)
X		print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
X	}
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	    if (isoff(msg[current_msg].m_flags, REPLIED))
X		redo = 1;
X	    (void) cmd_line(sprintf(buf, "%s %d", p, current_msg+1),
X		msg_list);
X	    if (msg_cnt)
X		puts(compose_hdr(current_msg));
X	    iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
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 (ison(glob_flags, CNTD_CMD))
X		    putchar('\n');
X		break;
X	    }
X	    clr_bot_line();
X	    iscurses = FALSE;
X	    if (ison(glob_flags, 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		/* "next" screws up the screen whether it displays or not */
X		(void) cmd_line(strcpy(buf, "next"), msg_list);
X		c = 0;
X	    }
X	    if (c > -1)
X		turnon(glob_flags, CNTD_CMD), redo = 1;
X	    iscurses = TRUE;
X	    puts(compose_hdr(current_msg));
X
X	/* bind a key or string to a curses-mode command */
X	when C_BIND :  case C_UNBIND : case C_MAP : case C_BIND_MACRO :
X	case C_MAP_BANG : {
X	    char *argv[2];
X	    argv[0] = (c == C_BIND) ? "bind" :
X		      (c == C_UNBIND) ? "unbind" :
X		      (c == C_MAP) ? "map" :
X		      (c == C_MAP_BANG) ? "map!" : "bind-macro";
X	    argv[1] = NULL;
X	    if (bind_it(1, argv) < -1)
X		turnon(glob_flags, CNTD_CMD);
X	    else if (ison(glob_flags, CNTD_CMD)) /* if it was set anyway */
X		putchar('\n');
X	    else
X		(void) curses_help_msg(TRUE);
X	}
X
X	when C_MACRO : 
X	    turnon(glob_flags, IN_MACRO);
X	    /* Current macro should already be in the mac_stack, so
X	     * all we have to do here is look for the next character
X	     */
X
X	/* help stuff */
X	when C_HELP :
X	    move(LINES-1, 0), refresh();
X	    (void) help(0, "curses", cmd_help);
X	    turnon(glob_flags, CNTD_CMD);
X	    if (msg_cnt)
X		puts(compose_hdr(current_msg));
X
X	otherwise :
X	    mac_flush();
X	    bell();
X	    if (ison(glob_flags, 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 (ison(glob_flags, 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	set_screen_size(); /* it may have changed */
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	(void) curses_help_msg(TRUE);
X	redo = 0;
X    }
X    return 0;
X}
X
Xvrfy_update(redo)
Xint *redo;
X{
X    char buf[16];
X    int c;
X
X    /* update current folder */
X    if (ison(glob_flags, DO_UPDATE)) {
X	if (ison(glob_flags, READ_ONLY)) {
X	    mac_flush();
X	    print("Folder is read-only.");
X	    if (ison(glob_flags, CNTD_CMD))
X		putchar('\n');
X	    return 0;
X	}
X	print("Update folder [y]? ");
X	if ((c = getchar()) != 'y' && c != 'Y' && c != '\n' && !isspace(c)) {
X	    print("Folder unchanged.");
X	    if (ison(glob_flags, CNTD_CMD))
X		putchar('\n');
X	    return 0;
X	}
X    } else if (*redo)
X	return 1;
X    if (cmd_line(strcpy(buf, *redo? "update" : "quit"), msg_list) != -1
X	    && ison(glob_flags, CNTD_CMD))
X	*redo = 1, turnoff(glob_flags, CNTD_CMD);
X    turnoff(glob_flags, DO_UPDATE);
X    return 1; /* make sure bottom line is clear and no reverse video */
X}
X
Xscrn_line(line, buf)
Xchar *buf;
X{
X#ifndef A_CHARTEXT
X    (void) strncpy(buf, stdscr->_y[line], COLS-1);
X    buf[COLS-1] = 0; /* strncpy does not null terminate */
X#else
X    int n;
X
X    for (n = 0; n < COLS; n++)
X	if ((buf[n] = (mvinch(line, n) & A_CHARTEXT)) == '\0')
X	    break;
X    buf[n] = '\0';
X#endif /* A_CHARTEXT */
X}
X
X/*
X * Generate the help message from the variable curses_help.
X *  If visible is true, the message is displayed,
X *  otherwise its size (in lines) is computed and returned.
X */
Xcurses_help_msg(visible)
Xint visible;
X{
X    int count, i, len, siz = 0, mxm = 0;
X    static int old_siz = 0;
X    register struct cmd_map *list;
X    extern struct cmd_map map_func_names[];
X    char *curs_help = do_set(set_options, "curses_help"), **format;
X
X    if (!curs_help) {
X	if (old_siz && visible) {
X	    int bot = min(n_array[screen-1], msg_cnt-1);
X	    move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
X	    old_siz = 0;
X	}
X	return 0;
X    } else if (!*curs_help)
X	curs_help = DEF_CURSES_HELP;
X    /* Split the help string into words */
X    if (!(format = mk_argv(curs_help, &count, FALSE)) || count <= 0)
X	return 0;
X    /* Generate a help message for each word */
X    for (i = 0; i < count; i++) {
X	char buf[MAX_BIND_LEN*2+MAX_LONG_CMD+5], asc[MAX_BIND_LEN*2];
X
X	buf[0] = '\0'; /* default to empty in case of no match */
X	for (list = cmd_map; list; list = list->m_next) {
X	    if (!strcmp(format[i], map_func_names[list->m_cmd].m_str)) {
X		len = strlen(sprintf(buf, "(%s) %s  ",
X				ctrl_strcpy(asc, list->m_str, FALSE),
X				map_func_names[list->m_cmd].m_str));
X		if (len > mxm)
X		    mxm = len;
X		break;
X	    }
X	}
X	strdup(format[i], buf); /* replace word with its "definition" */
X    }
X    /* Columnate the output nicely */
X    if (mxm > 0) {
X	len = (COLS - 1) / mxm;
X	if (len == 0) {
X	    if (visible)
X		print("Curses help message too long!");
X	    return 0;
X	}
X	siz = count / len;
X	if (count % len)
X	    siz++;
X	if (siz > LINES / 3) {
X	    if (visible)
X		print("Curses help message too long!");
X	    return 0;
X	}
X	if (visible) {
X	    int next = LINES - 1 - siz;
X	    if (old_siz > siz) {
X		int bot = min(n_array[screen-1], msg_cnt-1);
X		move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
X	    }
X	    old_siz = siz;
X	    for (i = 0; i < count; i++) {
X		if (!(i % len))
X		    move(next, 0), clrtoeol(), ++next;
X		if (format[i][0])
X		    printw("%-*.*s", mxm, mxm, format[i]);
X	    }
X	    refresh();
X	}
X    }
X    free_vec(format);
X    return siz;
X}
X
Xset_screen_size()
X{
X    int hlp_siz = LINES - 2 - curses_help_msg(FALSE); 
X
X    if (!do_set(set_options, "screen"))
X#ifdef USG
X	switch (_tty.sg_ospeed & CBAUD)
X#else /* USG */
X	switch (_tty.sg_ospeed)
X#endif /* USG */
X	{
X	    case B300 :  screen = min(hlp_siz, 7);
X	    when B1200 : screen = min(hlp_siz, 14);
X	    when B2400 : screen = min(hlp_siz, 22);
X	    otherwise :  screen = hlp_siz;
X	}
X    else
X	screen = min(screen, hlp_siz);
X}
X
X/*
X * prompt for a carriage return, but return whatever user types unless
X * it's a character which he might regret (like 'q' or 'x'). Ignore
X * interrupts (kind of) because we have nowhere to longjmp to.  When we
X * return, we'll setjmp again (top of loop.c)
X */
Xhit_return()
X{
X    int c;
X
X    turnon(glob_flags, IGN_SIGS);
X    iscurses = FALSE;
X    (void) check_new_mail();
X    iscurses = TRUE;
X    mail_status(1), addstr("...continue... "), refresh();
X    c = getcmd();
X    turnoff(glob_flags, IGN_SIGS);
X
X    /* don't let the user type something he might regret */
X    if (c == C_QUIT || c == C_EXIT)
X	return C_NULL;
X    return c;
X}
X
Xcurses_msg_list(str, list, m_list)
Xregister char *str, *list;
Xchar m_list[];
X{
X    register char *p = NULL;
X    int c, sv_cur_msg = current_msg;
X
X    print(str);
X    c = Getstr(list, COLS-13, 0);
X    move(LINES-1, 0), refresh();
X    if (c <= 0 || !(p = do_range(list, m_list)) ||
X	(p == list && *p && *p != '$' && *p != '^')) {
X	if (p)
X	    print("Invalid message list: %s", p);
X	current_msg = sv_cur_msg;
X	return 0;
X    }
X    current_msg = sv_cur_msg;
X    return 1;
X}
X
Xcurs_vars(which)
Xint which;  /* really, a char */
X{
X    char c, buf[128], buf2[128], *string;
X    struct options **list;
X
X    switch(which) {
X	case C_OWN_HDR : string = "my_hdr", list = &own_hdrs;
X	when C_ALIAS : string = "alias", list = &aliases;
X	when C_IGNORE : string = "ignore", list = &ignore_hdr;
X	when C_VAR_SET : string = "set", list = &set_options;
X	otherwise : clr_bot_line(); return;
X    }
X
X    print("%s [? Set Unset All]: ", string);
X    c = m_getchar();
X    clr_bot_line();
X    switch (Lower(c)) {
X	/* if help, print help -- if "all", show all settings. */
X	case '?' : case 'a' :
X	    if (c == '?') {
X		if (!strcmp(string, "set")) {
X		    print("which variable? [all <var>]: ");
X		    if ((c = Getstr(buf+1, COLS-40, 0)) < 0)
X			return;
X		    clr_bot_line();
X		    buf[0] = '?';
X		    if (c > 0) {
X			char *argv[3];
X			argv[0] = string;
X			argv[1] = buf;
X			argv[2] = NULL;
X			Lower(buf[1]);
X			if (!strcmp(buf+1, "a"))
X			    (void) strcpy(buf+1, "all");
X			if (!strcmp(buf+1, "all"))
X			    turnon(glob_flags, CNTD_CMD);
X			(void) set(2, argv, (char *) 0);
X			break;
X		    }
X		}
X		/* help returns next command (hit_return) */
X		(void) help(0, string, cmd_help);
X		turnon(glob_flags, CNTD_CMD);
X		return;
X	    }
X	    turnon(glob_flags, CNTD_CMD);
X	    (void) do_set(*list, NULL);
X
X	/* if set, prompt for string and let user type */
X	when 's' :
X	    print("set: ");
X	    c = Getstr(buf, COLS-18, 0);
X	    clr_bot_line();
X	    if (c > 0)
X		(void) cmd_line(sprintf(buf2, "%s %s", string, buf), msg_list);
X
X	/* if unset, just as easy as set! */
X	when 'u' :
X	    print("unset: ", string);
X	    if (Getstr(buf, COLS-18, 0) > 0 && !un_set(list, buf))
X		print("%s isn't set", buf);
X    }
X    if (ison(glob_flags, CNTD_CMD))
X	putchar('\n');
X    else
X	(void) curses_help_msg(TRUE);
X}
X#endif /* CURSES */
END_OF_FILE
if test 28433 -ne `wc -c <'mush/curses.c'`; then
    echo shar: \"'mush/curses.c'\" unpacked with wrong size!
fi
# end of 'mush/curses.c'
fi
if test -f 'mush/mush.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mush/mush.h'\"
else
echo shar: Extracting \"'mush/mush.h'\" \(22786 characters\)
sed "s/^X//" >'mush/mush.h' <<'END_OF_FILE'
X/* @(#)mush.h	(c) copyright 1986 (Dan Heller) */
X
X#include "config.h"
X
X#ifdef CURSES
X
X#ifdef USG
X#    define _USG
X#    undef USG
X#endif /* USG */
X#ifdef SYSV
X#    define _SYSV
X#    undef SYSV
X#endif /* SYSV */
X#include <curses.h>
X#if !defined(USG) && defined(_USG)
X#    define USG
X#endif /* USG */
X#if !defined(SYSV) && defined(_SYSV)
X#    define SYSV
X#endif /* SYSV */
X
X#else /* CURSES */
X#include <stdio.h>
X#if defined(SYSV) && defined(USG)
X#include <termio.h>
X#endif /* SYSV && USG */
X#endif /* CURSES */
X
X#include <ctype.h>
X#include <errno.h>
X#include <setjmp.h>
X#include "strings.h"
X
X#ifdef BSD
X#define fputs Fputs	/* See comments in print.c */
X#endif /* BSD */
X
Xextern char
X    *malloc(),		/* allocate memory */
X    *calloc(),		/* allocate and clear memory */
X    *realloc();		/* re-allocate memory */
X
Xextern void
X    free_vec(),		/* free a malloc'ed argv */
X    xfree();		/* free malloc'ed pointers */
X
X#if defined(SUNTOOL) || defined(SUN_3_5) || defined(SUN_4_0) || defined(SUN_4_1)
X#if !defined(BSD) && !defined(SYSV)
X#    define BSD /* default to BSD */
X#endif /* !BSD && !SYSV */
X#if !defined(SUN_3_5) && !defined(SUN_4_0)
X#    define SUN_4_0 /* default to sun 4.0 */
X#endif /* !SUN_3_5 && !SUN_4_0 */
X#ifdef SUN_4_0
X#    undef SUN_3_5
X#    undef SIGRET
X#    define SIGRET void
X#endif /* SUN_4_0 */
X#endif /* SUNTOOL || SUN_3_5 || SUN_4_0 */
X
X#ifdef SUNTOOL
X#    include <suntool/sunview.h>
X#ifdef SUN_4_0
X#    include <suntool/alert.h>
X#endif /* SUN_4_0 */
X#    include <suntool/textsw.h>
X#    include <sys/ioctl.h>   /* for ltchars */
X#else
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/panel.h>
X#    include <suntool/canvas.h>
X#    include <suntool/tty.h>
X#    include <suntool/menu.h>
X#    include <suntool/icon.h>
X#    include <suntool/scrollbar.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 /* NOFILE */
X#endif /* _NFILE */
X
X#ifndef MAXPATHLEN
X#define MAXPATHLEN BUFSIZ
X#endif /* MAXPATHLEN */
X
X#ifdef CTRL
X#undef CTRL
X#endif /* CTRL */
X#define CTRL(c)		((c) & 037)
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)	(void) (fputc(c, stdout), fflush(stdout))
X#ifdef SUNTOOL
Xextern int bell();
X#else /* SUNTOOL */
X#define bell()		(void) (fputc('\007', stderr), fflush(stderr))
X#endif /* SUNTOOL */
X
X/* For error recovery purposes, send keyboard generated signals to a special
X * routine (interrupt) to set a global flag (WAS_INTR) and return to the
X * calling routine which is responsible for checking the flag.  For both
X * on_intr() and off_intr() macros, initialize WAS_INTR to false.
X */
X#define on_intr() \
X    turnoff(glob_flags, WAS_INTR), oldint = signal(SIGINT, intrpt), \
X    oldquit = signal(SIGQUIT, intrpt)
X
X#define off_intr() \
X    (void) (turnoff(glob_flags, WAS_INTR), signal(SIGINT, oldint), \
X	    signal(SIGQUIT, oldquit))
X
X/* Don't flush input when setting echo or cbreak modes (allow typeahead) */
X#ifdef TIOCSETN
X#ifdef stty
X#undef stty
X#endif /* stty */
X#define stty(fd, sgttybuf)	ioctl(fd, TIOCSETN, sgttybuf)
X#endif /* TIOCSETN */
X
X/* for system-V machines that run termio */
X#if defined(SYSV) && defined(USG)
Xunsigned char vmin, vtime;
X#define sg_erase  c_cc[2]
X#define sg_flags  c_lflag
X#define sg_kill   c_cc[3]
X#define sg_ospeed c_cflag
X#define gtty(fd, SGTTYbuf)	ioctl(fd, TCGETA, SGTTYbuf)
X#undef stty
X#define stty(fd, SGTTYbuf)	ioctl(fd, TCSETAW, SGTTYbuf)
X#define echon()    (_tty.sg_flags |= (ECHO|ECHOE),    stty(0, &_tty))
X#define echoff()   (_tty.sg_flags &= ~ECHO,   stty(0, &_tty))
X#define cbrkon()   \
X	(_tty.sg_flags &= ~ICANON, _tty.c_cc[VMIN] = 1, stty(0, &_tty))
X#define cbrkoff()  \
X	(_tty.sg_flags |= ICANON,_tty.c_cc[VMIN] = vmin,_tty.c_iflag |= ICRNL, \
X		_tty.c_cc[VTIME] = vtime, stty(0, &_tty))
X#define savetty()  \
X	(void) gtty(0, &_tty), vtime = _tty.c_cc[VTIME], vmin = _tty.c_cc[VMIN]
X#define cbreak()   cbrkon()
X#define nocbreak() cbrkoff()
X
X/* If curses isn't defined, declare our 'tty' and macros for echo/cbreak */
X#ifndef CURSES
Xtypedef struct termio SGTTY;
X#define echom()    echon()
X#define noechom()  echoff()
X#define crmode()   cbrkon()
X#define nocrmode() cbrkoff()
X
X#else /* CURSES */
X/* If curses is defined, use the echo/cbreak commands in library only
X * if curses is running.  If curses isn't running, use macros above.
X */
X#define echom()    ((iscurses) ? echo(): echon())
X#define noechom()  ((iscurses) ? noecho(): echoff())
X#define crmode()   ((iscurses) ? cbreak() : cbrkon())
X#define nocrmode() ((iscurses) ? nocbreak() : cbrkoff())
X#endif /* CURSES */
X#endif /* SYSV && USG */
X
X#if !defined(USG)
X#ifndef CURSES
X/* if curses is not defined, simulate the same tty based macros */
Xtypedef struct sgttyb SGTTY;
X/* Do real ioctl calls to set the tty modes */
X#define crmode()   (_tty.sg_flags |= CBREAK,  stty(0, &_tty))
X#define nocrmode() (_tty.sg_flags &= ~CBREAK, stty(0, &_tty))
X#define echom()    (_tty.sg_flags |= ECHO,    stty(0, &_tty))
X#define noechom()  (_tty.sg_flags &= ~ECHO,   stty(0, &_tty))
X#define savetty()  (void) gtty(0, &_tty)
X#else /* CURSES */
X#define echom()    echo()
X#define noechom()  noecho()
X#endif /* ~CURSES */
X#endif /* ~USG */
X
X/* With all that out of the way, we can now declare our tty type */
XSGTTY _tty;
X
Xextern char
X    del_line,		/* tty delete line character */
X    del_word,		/* tty delete word character */
X    del_char,		/* backspace */
X    reprint_line,	/* usually ^R */
X    eofc,		/* usually ^D */
X    lit_next,		/* usually ^V */
X    complete,		/* word completion, usually ESC */
X    complist;		/* completion listing, usually tab */
X
X/* These macros now turn on/off echo/cbreak independent of the UNIX running */
X#define echo_on()	\
X    if (_tty.sg_flags && isoff(glob_flags, ECHO_FLAG)) nocrmode(), echom()
X#define echo_off()	\
X    if (_tty.sg_flags && isoff(glob_flags, ECHO_FLAG)) crmode(), noechom()
X
X#define strdup(dst, src) (xfree (dst), dst = savestr(src))
X#define Debug		if (debug == 0) {;} else (void) wprint
X
X#ifdef SYSV
X#ifndef L_SET
X#define L_SET	0
X#endif /* L_SET */
X#ifndef F_OK
X#define F_OK	000
X#define R_OK	004
X#define W_OK	002
X#define E_OK	001
X#endif /* F_OK */
X#ifdef u_long
X#undef u_long
X#endif /* u_long */
X#define u_long	unsigned long
X#ifndef HPUX
X#define vfork   fork
X#endif /* HPUX */
X#ifndef SIGCHLD
X#define SIGCHLD SIGCLD
X#endif /* SIGCHLD */
X#endif /* SYSV */
X
X#if !defined(SUNTOOL) && !defined(CURSES)
X
X#define TRUE		  1
X#define FALSE		  0
X#define print		  (void) printf
X#define wprint		  (void) printf
X#define print_more	  (void) 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	(void) printf
X#endif /* CURSES && (!SUNTOOL) */
X
X#ifdef SUNTOOL
X/* stdout may be closed */
X#define printf wprint
X#endif /* SUNTOOL */
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#define ArraySize(o)	  (sizeof(o) / sizeof(*o))
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_XOR		PIX_SRC ^ PIX_DST
X#define ID		event_id(event)
X#define l_width()	mush_font->pf_defaultsize.x /* width of letter */
X#define l_height()	mush_font->pf_defaultsize.y /* height of letter */
X#define Clrtoeol(w,x,y)	((void) pw_text(w, x, y, PIX_SRC, mush_font, blank))
X
X/* Miscellaneous old-SunView cleanup */
X#ifndef TTY_ARGV_DO_NOT_FORK
X#define TTY_ARGV_DO_NOT_FORK (-1)
X#endif
X
X#endif /* SUNTOOL */
X
X/* bits and pieces */
X#define turnon(flg,val)   ((flg) |= (u_long)(val))
X#define turnoff(flg,val)  ((flg) &= ~(u_long)(val))
X#define ison(flg,val)     ((u_long)(flg) & (u_long)(val))
X#define isoff(flg,val)    (!ison((flg), (val)))
X#define set_replied(n)	  \
X	if (isoff(msg[n].m_flags, REPLIED)) \
X	    turnon(glob_flags, DO_UPDATE), turnon(msg[n].m_flags, REPLIED)
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#define in_pipe() (ison(glob_flags, DO_PIPE|IS_PIPE))
X#define in_macro() (ison(glob_flags, LINE_MACRO|IN_MACRO))
X#define line_macro(s) (void) (turnon(glob_flags, LINE_MACRO), mac_push(s))
X#define curs_macro(s) (void) (turnon(glob_flags, IN_MACRO), mac_push(s))
X#define Ungetstr(s) (void) (turnon(glob_flags, QUOTE_MACRO), mac_push(s))
X
X/* global conditions */
X#define is_shell (mailfile && *mailfile)
X
X/* msg lists represented by bits (8 should be replaced by sizeof(char) */
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		do { 						\
X		    register char *s1 = S1, *s2 = S2; 		\
X		    register int len = Len; 			\
X		    while(len--) 				\
X			*s2++ op *s1++; 			\
X		} while (0)
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#define ismsgnum(c)       (isdigit(c)||c=='.'||c=='^'||c=='$'||c=='*')
X#define skipmsglist(n)\
X    for(p += (n); ismsgnum(*p) || index(" \t,-{`}", *p); ++p)\
X	if (*p != '`' || !p[1]) {;} else do ++p; while (*p && *p != '`')
X
X/* define a macro to declare unsigned-long bits */
X#define ULBIT(bit)		((u_long)1 << (u_long)(bit))
X
X/* various flags */
Xu_long   glob_flags;	/* global boolean flags thruout the whole program */
X#define DO_UPDATE   ULBIT(0) /* folder has been modified -- update it */
X#define REV_VIDEO   ULBIT(1) /* reverse video for curses or toolmode */
X#define CONT_PRNT   ULBIT(2) /* continue to print without a '\n' */
X#define DO_SHELL    ULBIT(3) /* run a shell even if no mail? (true if tool) */
X#define DO_PIPE     ULBIT(4) /* if commands are piping to other commands */
X#define IS_PIPE     ULBIT(5) /* true if commands' "input" comes from a pipe */
X#define IGN_SIGS    ULBIT(6) /* true if catch() should not longjmp */
X#define IGN_BANG    ULBIT(7) /* ignore ! as a history reference */
X#define ECHO_FLAG   ULBIT(8) /* if true, echo|cbreak is ON, echo typing (-e) */
X#define IS_GETTING  ULBIT(9) /* true if we're getting input for a letter */
X#define PRE_CURSES  ULBIT(10) /* true if curses will run, but hasn't started */
X#define READ_ONLY   ULBIT(11) /* -r passed to folder() for read only */
X#define REDIRECT    ULBIT(12) /* true if stdin is being redirected */
X#define WAS_INTR    ULBIT(13) /* catch interrupts, set this flag (signals.c) */
X#define WARNING     ULBIT(14) /* if set, various warning messages are printed */
X#define NEW_MAIL    ULBIT(15) /* new mail has arrived; mush is busy or closed */
X#define CNTD_CMD    ULBIT(16) /* curses.c -- promotes "...continue..." prompt */
X#define IS_SENDING  ULBIT(17) /* was run to send mail, not run as a shell */
X#define MIL_TIME    ULBIT(19) /* if $mil_time is set, use 24hr time fmt */
X#define DATE_RECV   ULBIT(20) /* $date_received: show date received on msgs */
X#define IN_MACRO    ULBIT(21) /* input is currently being read from a macro */
X#define LINE_MACRO  ULBIT(22) /* escape to line mode from curses in progress */
X#define QUOTE_MACRO ULBIT(23) /* protect current macro from recursive expan.. */
X#define NEW_FRAME   ULBIT(24) /* toolmode should build a new frame for pager */
X#define HELP_TEXT   ULBIT(25) /* create textsw frame for paging help messages */
X
X/* flags to control composition */
X#define VERBOSE		ULBIT(0)  /* verbose flag for sendmail */
X#define INCLUDE		ULBIT(1)  /* include msg in response */
X#define INCLUDE_H	ULBIT(2)  /* include msg with header */
X#define EDIT		ULBIT(3)  /* enter editor by default on mailing */
X#define SIGN		ULBIT(4)  /* auto-include ~/.signature in mail */
X#define DO_FORTUNE	ULBIT(5)  /* add a fortune at end of msgs */
X#define EDIT_HDRS	ULBIT(6)  /* user edits headers using editor */
X#define SEND_NOW	ULBIT(7)  /* send without further changes */
X#define NO_SIGN		ULBIT(8)  /* override SIGN and DO_FORTUNE */
X
X/* msg flags */
X#define PRINTED		ULBIT(4)  /* sent through lpr command */
X#define NO_HEADER	ULBIT(6)  /* don't print header of message */
X#define DELETE		ULBIT(7)
X#define OLD		ULBIT(8)
X#define UNREAD		ULBIT(9)
X#define UPDATE_STATUS	ULBIT(10) /* change status of msg when copyback */
X#define NO_PAGE		ULBIT(11) /* don't page this message */
X#define INDENT		ULBIT(12) /* indent included msg with string */
X#define NO_IGNORE	ULBIT(13) /* don't ignore headers */
X#define PRESERVE	ULBIT(14) /* preserve in mailbox unless deleted */
X#define M_TOP		ULBIT(14) /* just print the top of msg (same as pre) */
X#define FORWARD		ULBIT(15) /* Forward messages into the message buffer */
X#define REPLIED		ULBIT(16) /* Messages that have been replied to */
X#define NEW_SUBJECT	ULBIT(17) /* new subject regardless of $ask (mail -s) */
X#define SAVED		ULBIT(18) /* when message has been saved */
X#ifdef MSG_SEPARATOR
X#define NO_SEPARATOR	ULBIT(19) /* don't include message separator lines */
X#endif /* MSG_SEPARATOR */
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    char   *m_date_recv;/* Date user received msg (see dates.c for fmt) */
X    char   *m_date_sent;/* Date author sent msg (see dates.c for fmt) */
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
X#define chk_option(v,f)	chk_two_lists(do_set(set_options,(v)), (f), "\t ,")
X
Xstruct cmd {
X    char *command;
X    int (*func)();
X};
Xextern struct cmd ucb_cmds[];
Xextern struct cmd cmds[], hidden_cmds[];
X
XFILE
X    *tmpf,		/* temporary holding place for all mail */
X    *mask_fopen(),	/* open a file with umask 077 (permissions 600) */
X    *open_file(),	/* open a file or program for write/append */
X    *lock_fopen(),	/* open and lock a file as an atomic operation */
X    *popen();		/* this should be in stdio.h */
X
Xextern char
X    *sys_errlist[],    /* system's list of global error messages */
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[MAXPATHLEN],	/* path to filename of temporary file */
X    msg_list[MAXMSGS_BITS],	/* MAXMSGS bits of boolean storage */
X    **alternates,	/* alternates list --see alts() */
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,		/* the name and aliases of the current host */
X    **known_hosts,	/* the names of all hosts connected via uucp */
X    *prompt,		/* the prompt string -- may have %d */
X    *format_prompt(),	/* function to format prompts from the prompt string */
X    *escape,		/* the "tilde escape" when inputting text to letter */
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    *spoolfile,		/* MAILDIR/$USER in a string -- this is used a lot */
X    *msg_get(),		/* find start of message and return From_ line */
X    *do_range(),	/* parse a string converting to a "range" of numbers */
X    *getpath(),		/* static char returning path (expanding ~, +, %, #) */
X    *getdir(),		/* uses getpath() to expand and test directory names */
X    *do_set(),		/* set/unset an option, alias, ignored-hdr */
X    *reverse(),		/* reverse a string */
X    *trim_filename(),	/* remove or condense leading file name path */
X    *prog_name,
X
X    /* from loop.c */
X    **make_command(),	/* build a command vector (argv) */
X    **mk_argv(),	/* given a string, make a vector */
X    *variable_stuff(),	/* return information about variables */
X    *check_internal(),	/* test or evaluate internal variables */
X
X    /* from dates.c */
X    *Time(),		/* returns string expression of time (takes args) */
X    *date_to_ctime(),	/* convert a date into ctime() format */
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    *rfc_date(),	/* create a date string compliant to RFC822 */
X
X    /* from hdrs.c */
X    *cc_to(),     	/* when responding, return str which is the cc-list */
X    *compose_hdr(),	/* passes hdr_format to format_hdr() for displays */
X    *format_hdr(),	/* returns a formatted line describing passed msg # */
X    *header_field(),    /* the line in msg described by arg (message header) */
X    *reply_to(),	/* who do we reply to when responding */
X    *subject_to(),      /* when responding, return str which is the subject */
X
X    /* addrs.c */
X    *alias_to_address(),/* convert a name[list] to "real" names */
X    *bang_form(),	/* construct a !-style form of an address */
X    *get_name_n_addr(), /* get name and addr from a well-formed address */
X    *set_header(), 	/* [interactive] proc to set/display to/subject/cc */
X    *wrap_addrs();	/* insert newlines in between headers */
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    wrapcolumn,		/* compose mode line wrap, measured from left */
X
X    close_lock(), 	/* unlock and close a file opened by lock_fopen() */
X
X    mush_quit(), do_alias(), respond(), cd(), sh(), stop(),
X    folder(), folders(), merge_folders(), do_undigest(),
X    save_msg(), delete(), do_mail(), lpr(), alts(), set(), do_hdrs(),
X    save_opts(), preserve(), sort(), readmsg(), edit_msg(), eval_cmd(),
X    do_pick(), print_help(), question_mark(), do_from(), my_stty(),
X    do_version(), disp_hist(), source(), do_echo(), ls(), pipe_msg(),
X    await(), nopenfiles(), file_to_fp(),
X    check_new_mail(), get_new_mail(), show_new_mail(),
X    Setenv(), Unsetenv(), Printenv(), msg_flags(), toggle_debug();
X
X#ifndef SIGRET
X#define SIGRET int
X#endif /* SIGRET */
XSIGRET
X    rm_edfile(),	/* remove letter-compose file on interrupts */
X    stop_start(),	/* handle job control signals */
X    bus_n_seg(),	/* handle runtime segfaults -- exit gracefully */
X    sigchldcatcher(),	/* account for terminated child processes */
X    catch(),		/* catch user (keyboard) generated signals */
X    intrpt();		/* handle interrupts when we don't want to */
X
Xlong
X    spool_size,		/* size of spool mail regardless of current folder */
X    last_size,		/* the last size of the mailfile since last check */
X    time();		/* satisfy lint */
X
Xvoid
X    error(), getmail(), mail_status(), sign_letter(),
X    init(), display_msg(), cleanup(), fs_error();
X    /* printf(), fclose(), fflush(), fputs(), fputc() */
X#ifdef TIOCGLTC
Xstruct ltchars ltchars;			/* tty character settings */
X#endif /* TIOCGLTC */
X#ifdef BSD /* (TIOCGETC) */
Xstruct tchars  tchars;			/* more tty character settings */
X#endif /* BSD (TIOCGETC) */
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#endif /* CURSES */
X
Xint
X    mac_push(),		/* set up a string as a macro */
X    bind_it();		/* bind strings to functions or macros */
X
Xvoid
X    mac_flush();	/* Abandon macro processing (on error) */
X
X#ifdef SUNTOOL
Xvoid
X    timeout_cursors(), do_file_dir(), toggle_mail_items(), ok_box(),
X    read_mail(), opts_panel_item(), view_options(), toolquit(), wprint(),
X    update_list_textsw(), check_icons();
X
Xchar
X    *find_key(),	/* pass x,y coords to find which function key assoc. */
X    *panel_get(),      	/* returns what has been typed in a panel item */
X    *tool_help,		/* help for tool-related things (sometimes, overlap) */
X    *more_prompt,	/* when NULL, we're paging a msg; else pager prompt */
X    blank[128];		/* use to clear to end of line */
X
Xint
X    time_out,		/* time out interval to wait for new mail */
X    is_iconic;		/* set if the mushview window is iconic. */
X
XNotify_value
X    do_check(),		/* check for new mail on timeout */
X    destroy_proc(),	/* Destroy procedure. */
X    scroll_textwin(),	/* Do fancy TEXTSW scrolling */
X    edit_msg_textwin();	/* Auto-positioning in compose TEXTSW */
X
XFrame tool;		/* Main frame. */
XFrame compose_frame;    /* Compose frame. */
XTextsw pager_textsw;	/* for "paging" messages and other lists.. */
XTextsw mfprint_sw;	/* Textsw in main mush frame for wprint() */
XTextsw cprint_sw;	/* Textsw in compose frame for wprint() */
XTextsw wprint_sw;	/* Current text subwindow for wprint() */
XCanvas hdr_sw; 		/* Canvas for message headers */
XTty tty_sw; 		/* subwindow which forks a shell (usually editor) */
X
XPixwin
X    *hdr_win;		/* pixwin for message headers */
X
Xstruct pixfont *mush_font;	/* array of fonts */
X
Xstruct itimerval mail_timer;	/* frequency to check for new mail */
X
Xextern Cursor l_cursor, m_cursor, r_cursor;
Xextern Icon mail_icon;
X
X/* When trapping events that represent scrolling actions */
Xtypedef enum {
X    MUSH_SCROLL_TO,
X    MUSH_SCROLL_RELATIVE,
X    MUSH_SCROLL_IGNORE,
X    MUSH_SCROLL_PASS_EVENT
X} Scroll_action;
X#endif /* SUNTOOL */
END_OF_FILE
if test 22786 -ne `wc -c <'mush/mush.h'`; then
    echo shar: \"'mush/mush.h'\" unpacked with wrong size!
fi
# end of 'mush/mush.h'
fi
if test -f 'mush/version.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mush/version.h'\"
else
echo shar: Extracting \"'mush/version.h'\" \(182 characters\)
sed "s/^X//" >'mush/version.h' <<'END_OF_FILE'
X/* @(#)version.h	(c) Copyright 1989 (Dan Heller) */
X
X#define MUSHNAME	"Mail User's Shell"
X#define RELEASE_DATE	"5/02/90"
X#define RELEASE		7
X#define REVISION	"1"
X#define PATCHLEVEL	1
END_OF_FILE
if test 182 -ne `wc -c <'mush/version.h'`; then
    echo shar: \"'mush/version.h'\" unpacked with wrong size!
fi
# end of 'mush/version.h'
fi
echo shar: End of archive 10 \(of 19\).
cp /dev/null ark10isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 19 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


