[comp.sources.unix] v11i062: Mail user's shell, Part12/12

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

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

#! /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 12 (of 12)."
# Contents:  bind.c doproc.c init.c viewopts.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'bind.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bind.c'\"
else
echo shar: Extracting \"'bind.c'\" \(11484 characters\)
sed "s/^X//" >'bind.c' <<'END_OF_FILE'
X/* bind.c */
X
X#ifdef CURSES
X
X#include "bindings.h"
X#include "mush.h"
X
X#define MAX_BIND_LEN 20   /* max length a string can be to bind to a command */
X
Xstruct cmd_map {
X    int m_cmd;  /* the command this is mapped to  */
X    char *m_str;  /* the string user types (cbreak) */
X    struct cmd_map *m_next;
X} *cmd_map;
X
Xinit_bindings()
X{
X    add_bind("g", 1);
X    add_bind("w", 2);
X    add_bind("W", 3);
X    add_bind("s", 4);
X    add_bind("S", 5);
X    add_bind("c", 6);
X    add_bind("C", 7);
X    add_bind("d", 8);
X    add_bind("D", 9);
X    add_bind("u", 10);
X    add_bind("U", 11);
X    add_bind("\\CR", 12);
X    add_bind("\\CL", 13);
X    add_bind("j", 14), add_bind("J", 14), add_bind("\\n", 14), add_bind("+",14);
X    add_bind("k", 15), add_bind("K", 15), add_bind("-",15), add_bind("\\CK",15);
X    add_bind("^", 16);
X    add_bind("$", 17);
X    add_bind("{", 18);
X    add_bind("}", 19);
X    add_bind("z", 20);
X    add_bind("Z", 21);
X    add_bind("H", 22);
X    add_bind("(", 23);
X    add_bind(")", 24);
X    add_bind("/", 25);
X    add_bind("\\C_", 26);  /* this is really ^/ */
X    add_bind("\\CN", 27);
X    add_bind("\\CP", 28);
X    add_bind("o" ,29);
X    add_bind("O", 30);
X    add_bind("Q", 31);
X    add_bind("q", 32);
X    add_bind("X", 33);
X    add_bind("x", 34);
X    add_bind("\\CU", 35);
X    add_bind("f", 36);
X    add_bind("!", 37);
X    add_bind(":", 38);
X    add_bind("|", 39);
X    add_bind("%", 40);
X    add_bind("v", 41);
X    add_bind("i", 42);
X    add_bind("a", 43);
X    add_bind("h", 44);
X    add_bind("V", 45);
X    add_bind("M", 46);
X    add_bind("m", 47);
X    add_bind("r", 48);
X    add_bind("R", 49);
X    add_bind("t", 50), add_bind(".", 50), add_bind("p", 50);
X    add_bind("T", 51);
X    add_bind("n", 52);
X    add_bind("b", 53);
X    add_bind("B", 54);
X    add_bind("?", 55); /* C_HELP Must be the last one! */
X}
X
Xstruct cmd_map map_func_names[] = {
X    { C_NULL,		NULL,			NULL_MAP },
X    { C_GOTO_MSG,	"goto msg",		NULL_MAP },
X    { C_WRITE_MSG,	"write",		NULL_MAP },
X    { C_WRITE_LIST,	"write list",		NULL_MAP },
X    { C_SAVE_MSG,	"save",			NULL_MAP },
X    { C_SAVE_LIST,	"save list",		NULL_MAP },
X    { C_COPY_MSG,	"copy",			NULL_MAP },
X    { C_COPY_LIST,	"copy list",		NULL_MAP },
X    { C_DELETE_MSG,	"delete",		NULL_MAP },
X    { C_DELETE_LIST,	"delete list",		NULL_MAP },
X    { C_UNDEL_MSG,	"undelete",		NULL_MAP },
X    { C_UNDEL_LIST,	"undelete list",	NULL_MAP },
X    { C_REVERSE,	"reverse video",	NULL_MAP },
X    { C_REDRAW,		"redraw",		NULL_MAP },
X    { C_NEXT_MSG,	"next msg",		NULL_MAP },
X    { C_PREV_MSG,	"back msg",		NULL_MAP },
X    { C_FIRST_MSG,	"first msg",		NULL_MAP },
X    { C_LAST_MSG,	"last msg",		NULL_MAP },
X    { C_TOP_PAGE,	"top page",		NULL_MAP },
X    { C_BOTTOM_PAGE,	"bottom page",		NULL_MAP },
X    { C_NEXT_SCREEN,	"screen next",		NULL_MAP },
X    { C_PREV_SCREEN,	"screen back",		NULL_MAP },
X    { C_SHOW_HDR,	"show hdr",		NULL_MAP },
X    { C_SOURCE,		"source",		NULL_MAP },
X    { C_SAVEOPTS,	"saveopts",		NULL_MAP },
X    { C_NEXT_SEARCH,	"search up",		NULL_MAP },
X    { C_PREV_SEARCH,	"search down",		NULL_MAP },
X    { C_CONT_SEARCH,	"search cont",		NULL_MAP },
X    { C_PRESERVE,	"preserve",		NULL_MAP },
X    { C_SORT,		"sort",			NULL_MAP },
X    { C_REV_SORT,	"sort reverse",		NULL_MAP },
X    { C_QUIT_HARD,	"quit!",		NULL_MAP },
X    { C_QUIT,		"quit",			NULL_MAP },
X    { C_EXIT_HARD,	"exit!",		NULL_MAP },
X    { C_EXIT,		"exit",			NULL_MAP },
X    { C_UPDATE,		"update",		NULL_MAP },
X    { C_FOLDER,		"folder",		NULL_MAP },
X    { C_SHELL_ESC,	"shell escape",		NULL_MAP },
X    { C_CURSES_ESC,	"line mode",		NULL_MAP },
X    { C_PRINT_MSG,	"lpr",			NULL_MAP },
X    { C_CHDIR,		"chdir",		NULL_MAP },
X    { C_VAR_SET,	"variable",		NULL_MAP },
X    { C_IGNORE,		"ignore",		NULL_MAP },
X    { C_ALIAS,		"alias",		NULL_MAP },
X    { C_OWN_HDR,	"my hdrs",		NULL_MAP },
X    { C_VERSION,	"version",		NULL_MAP },
X    { C_MAIL_FLAGS,	"mail flags",		NULL_MAP },
X    { C_MAIL,		"mail",			NULL_MAP },
X    { C_REPLY_SENDER,	"reply",		NULL_MAP },
X    { C_REPLY_ALL,	"reply all",		NULL_MAP },
X    { C_DISPLAY_MSG,	"display",		NULL_MAP },
X    { C_TOP_MSG,	"top",			NULL_MAP },
X    { C_DISPLAY_NEXT,	"display next",		NULL_MAP },
X    { C_BIND,		"bind",			NULL_MAP },
X    { C_UNBIND,		"unbind",		NULL_MAP },
X    { C_HELP,		"help",			NULL_MAP }
X};
X
Xgetcmd()
X{
X    char 		buf[MAX_BIND_LEN];
X    register int 	c, m, match;
X    register char	*p = buf;
X    register struct cmd_map *list;
X
X    bzero(buf, MAX_BIND_LEN);
X    c = getchar();
X    if (isdigit(c)) {
X	(void) ungetc(c, stdin);
X	return C_GOTO_MSG;
X    }
X    for (;; p += strlen(p), c = getchar()) {
X	if (c == ESC)
X	    (void) strcpy(buf, "\\E");
X	else if (c == '\n' || c == '\r')
X	    (void) strcpy(p, "\\n");
X	else if (c == '\t')
X	    (void) strcpy(p, "\\t");
X	else if (iscntrl(c))
X	    (void) sprintf(p, "\\C%c", upper(unctrl(c)[1]));
X	else
X	    *p = c;
X	m = 0;
X	for (list = cmd_map; list; list = list->m_next)
X	    if ((match = prefix(buf, list->m_str)) == MATCH) {
X		if (debug)
X		    print("\"%s\" ", map_func_names[list->m_cmd].m_str);
X		return list->m_cmd;
X	    } else if (match != NO_MATCH)
X		m++;
X	if (m == 0) {
X	    if (debug)
X		print("No binding for \"%s\" found.", buf);
X	    return 0;
X	}
X    }
X}
X
X/*
X * bind chars or strings to commands -- doesn't touch messages; return -1
X * for curses mode, return -2 to have curses command set cntd_cmd to
X * prevent screen refresh to allow user to read output in case of multilines.
X */
Xbind_it(len, argv)
Xchar **argv;
X{
X    char buf[MAX_BIND_LEN], buf2[30];
X    register int x;
X    int (*oldint)(), (*oldquit)();
X    int unbind = (argv && **argv == 'u');
X    int ret = -1; /* return value */
X
X    if (istool > 1 || argv && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "bind", cmd_help) - 1;
X
X    on_intr();
X
X    if (unbind) {
X	if (!*argv) {
X	    print("Unbind what? ");
X	    if (Getstr(buf, MAX_BIND_LEN-1, 0) <= 0) {
X		off_intr();
X		return -1;
X	    }
X	} else
X	    (void) strcpy(buf, *argv);
X	if (!un_bind(buf))
X	    print("\"%s\" isn't bound to a command.\n", buf);
X	off_intr();
X	return -1;
X    }
X    if (argv && *argv) {
X	(void) strncpy(buf, *argv, MAX_BIND_LEN-1);
X	if (!argv[1]) {
X	    int binding = c_bind(*argv);
X	    if (binding)
X		print("\"%s\" is bound to \"%s\".\n",
X			*argv, map_func_names[binding].m_str);
X	    else
X		print("\"%s\" isn't bound to a command.\n", *argv);
X	    off_intr();
X	    return -1;
X	} else
X	    argv++;
X    } else {
X	print("bind [<CR>=all, -?=help]: ");
X	if ((len = Getstr(buf, MAX_BIND_LEN-1, 0)) == 0) {
X	    if (iscurses)
X		putchar('\n');
X	    (void) c_bind(NULL);
X	    off_intr();
X	    return -2;
X	}
X	if (len < 0) {
X	    off_intr();
X	    return -1;
X	}
X    }
X    /* if a binding was given on the command line */
X    if (argv && *argv)
X	(void) argv_to_string(buf2, argv);
X    else {
X	int binding;
X	
X	if (!strcmp(buf, "-?")) {
X	    if (iscurses)
X		clr_bot_line();
X	    (void) help(0, "bind", cmd_help);
X	    off_intr();
X	    return -2;
X	}
X
X	binding = c_bind(buf);
X
X	for (len = 0; len == 0; ) {
X	    print("\"%s\" = <%s>: New function [<CR> for list]: ",
X		buf, (binding? map_func_names[binding].m_str : "unset"));
X	    len = Getstr(buf2, 29, 0);
X	    if (iscurses)
X		clr_bot_line();
X	    if (len == 0) {
X		char *maps[C_HELP+1], *p, *malloc();
X		int n = 0;
X
X		if (iscurses)
X		    putchar('\n');
X		for (x = 0; x < C_HELP; x++) {
X		    if (!(x % 4))
X			if (!(p = maps[n++] = malloc(81))) {
X			    error("malloc in bind()");
X			    free_vec(maps);
X			    off_intr();
X			    return -1;
X			}
X		    p += strlen(sprintf(p, "%-18.18s  ",
X					map_func_names[x+1].m_str));
X		}
X		maps[n] = NULL;
X		(void) help(0, maps, NULL);
X		free_vec(maps);
X		ret--;
X	    }
X	}
X	/* if list was printed, ret < -1 -- tells cntd_cmd to be set and
X	 * prevents screen from being refreshed (lets user read output
X	 */
X	if (len == -1) {
X	    off_intr();
X	    return ret;
X	}
X    }
X    for (x = 1; x <= C_HELP; x++)
X	if (!strcmp(buf2, map_func_names[x].m_str)) {
X	    int add_to_ret;
X	    if (debug)
X		print("\"%s\" will execute \"%s\".\n", buf, buf2);
X	    add_to_ret = do_bind(buf, map_func_names[x].m_cmd);
X	    /* if do_bind hda no errors, it returned -1.  If we already
X	     * messed up the screen, then ret is less than -1.  return the
X	     * lesser of the two to make sure that cntd_cmd gets set right
X	     */
X	    off_intr();
X	    return min(add_to_ret, ret);
X	}
X    print("\"%s\": Unknown function.\n", buf2);
X    off_intr();
X    return ret;
X}
X
X/*
X * print current key to command bindings if "str" is NULL.
X * else return the integer "m_cmd" which the str is bound to.
X */
Xc_bind(str)
Xregister char *str;
X{
X    register struct cmd_map *opts;
X    register int    incurses = iscurses;
X    register FILE   *pp = NULL_FILE;
X
X    if (!str && !istool) {
X	echo_on();
X	if (!(pp = popen(pager, "w")))
X	    error(pager);
X	else if (incurses)
X	    clr_bot_line(), iscurses = FALSE;
X	turnon(glob_flags, IGN_SIGS);
X	if (pp)
X	    fprintf(pp, "Current key to command bindings:\n\n");
X	else
X	    wprint("Current key to command bindings:\n\n");
X    }
X
X    for (opts = cmd_map; opts; opts = opts->m_next)
X	if (!str)
X	    if (pp)
X		fprintf(pp, "%-20.20s %s\n",
X		    opts->m_str, map_func_names[opts->m_cmd].m_str);
X	    else
X		wprint("%-20.20s %s\n",
X		    opts->m_str, map_func_names[opts->m_cmd].m_str);
X	else
X	    if (strcmp(str, opts->m_str))
X		continue;
X	    else if (opts->m_cmd)
X		return opts->m_cmd;
X	    else
X		return 0;
X    if (pp)
X	(void) pclose(pp);
X    if (incurses)
X	iscurses = TRUE;
X    echo_off();
X    turnoff(glob_flags, IGN_SIGS);
X    return 0;
X}
X
X/*
X * doesn't touch messages: return -1.  Error output causes return < -1.
X */
Xdo_bind(str, func)
Xregister char *str;
X{
X    register struct cmd_map *list;
X    register int match, ret = -1;
X
X    (void) un_bind(str);
X    for (list = cmd_map; list; list = list->m_next)
X	if ((match = prefix(str, list->m_str)) == MATCH)
X	    puts("Something impossible just happened."), ret--;
X	else if (match == A_PREFIX_B)
X	    printf("Warning: \"%s\" prefixes \"%s\" (%s)\n",
X		str, list->m_str, map_func_names[list->m_cmd].m_str), ret--;
X	else if (match == B_PREFIX_A)
X	    printf("Warning: \"%s\" (%s) prefixes: \"%s\"\n",
X		list->m_str, map_func_names[list->m_cmd].m_str, str), ret--;
X    add_bind(str, func);
X    /* errors decrement ret.  If ret returns less than -1, cntd_cmd is set
X     * and no redrawing is done so user can see the warning signs
X     */
X    return ret;
X}
X
Xadd_bind(str, func)
Xregister char *str;
X{
X    register struct cmd_map *tmp;
X    struct cmd_map *calloc();
X
X    /* now make a new option struct and set fields */
X    if (!(tmp = calloc((unsigned)1, sizeof(struct cmd_map)))) {
X	error("calloc");
X	return;
X    }
X    tmp->m_next = cmd_map;
X    cmd_map = tmp;
X
X    tmp->m_str = savestr(str);
X    tmp->m_cmd = func; /* strdup handles the NULL case */
X}
X
Xun_bind(p)
Xregister char *p;
X{
X    register struct cmd_map *list = cmd_map, *tmp;
X
X    if (!list || !*list->m_str || !p || !*p)
X	return 0;
X
X    if (!strcmp(p, cmd_map->m_str)) {
X	cmd_map = cmd_map->m_next;
X	xfree (list->m_str);
X	xfree((char *)list);
X	return 1;
X    }
X    for ( ; list->m_next; list = list->m_next)
X	if (!strcmp(p, list->m_next->m_str)) {
X	    tmp = list->m_next;
X	    list->m_next = list->m_next->m_next;
X	    xfree (tmp->m_str);
X	    xfree ((char *)tmp);
X	    return 1;
X	}
X    return 0;
X}
X
Xprefix(a, b)
Xregister char *a, *b;
X{
X    while (*a && *b && *a == *b)
X	a++, b++;
X    if (!*a && !*b)
X	return MATCH;
X    if (!*a && *b)
X	return A_PREFIX_B;
X    if (*a && !*b)
X	return B_PREFIX_A;
X    return NO_MATCH;
X}
X#endif CURSES
END_OF_FILE
if test 11484 -ne `wc -c <'bind.c'`; then
    echo shar: \"'bind.c'\" unpacked with wrong size!
fi
# end of 'bind.c'
fi
if test -f 'doproc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doproc.c'\"
else
echo shar: Extracting \"'doproc.c'\" \(12405 characters\)
sed "s/^X//" >'doproc.c' <<'END_OF_FILE'
X/* @(#)doproc.c		(c) copyright	10/18/86 (Dan Heller) */
X
X/* do main panel item procedures */
X#include "mush.h"
X
Xrespond_mail(item, value, event)
XPanel_item item;
Xint value;
Xstruct inputevent *event;
X{
X    char buf[80];
X
X    if (value == 4)
X	return help(panel_sw->ts_windowfd, "respond", tool_help);
X    if (ison(glob_flags, IS_GETTING)) {
X	print("Finish editing current message first");
X	return;
X    }
X    if (!msg_cnt) {
X	print("No messages to respond to.\n");
X	return;
X    }
X    print("Responding to message %d", current_msg+1);
X    if (event && event->ie_code == MS_LEFT)
X	value = 0;
X    (void) sprintf(buf, "%s %s %d",
X	(value == 2 || value == 3)? "replyall" : "replysender",
X	(value == 1 || value == 3)? "-i": NO_STRING, current_msg+1);
X    (void) cmd_line(buf, msg_list);
X}
X
X/* following macro is for the next two procedures */
X#define hdr_item (item == sub_hdr_item[0] || item == sub_hdr_item[1] || \
X                  item == sub_hdr_item[2] || item == sub_hdr_item[3] || \
X                  item == sub_hdr_item[4] || item == sub_hdr_item[5])
X
Xdelete_mail(item, val, event)
Xregister Panel_item item;
Xint val;
Xregister struct inputevent *event;
X{
X    register int value = val, c;
X    char buf[92];
X
X    panel_set(item, PANEL_VALUE, 0, 0);
X    if (hdr_item && event->ie_code != MS_LEFT || value == 6)
X	return help(panel_sw->ts_windowfd, "delete", tool_help);
X    /* if selected "delete" in header panel, set value = 4 (delete "range") */
X    if (hdr_item)
X	value = 4;
X    /* delete current message */
X    if (!value || value == 1 && event && event->ie_code == MS_LEFT)
X	if (ison(msg[current_msg].m_flags, DELETE)) {
X	    print("%d Already deleted", current_msg+1);
X	    return;
X	} else {
X	    print("Deleted Message %d. ", current_msg+1);
X	    (void) strcpy(buf, "delete");
X	}
X    else switch(value) {
X	case 1:
X	    print("Really delete everything?");
X	    if ((c = confirm(panel_sw->ts_windowfd)) == 'y' ||
X			 c == MS_LEFT) {
X		print("Deleted All Messages. ");
X		(void) strcpy(buf, "delete *");
X	    } else { print("Whew!"); return; }
X	when 2:
X	    /* undelete current message */
X	    if (isoff(msg[current_msg].m_flags, DELETE)) {
X		print("%d isn't deleted", current_msg+1);
X		return;
X	    }
X	    print("Undeleted Message #%d. ", current_msg+1);
X	    (void) strcpy(buf, "undelete");
X	when 3:
X	    /* undelete all messages */
X	    print("Uneleted All Messages. ");
X	    (void) strcpy (buf, "undelete *");
X	when 4: case 5:
X	    /* delete a range of messages */
X	    (void) sprintf(buf, "%selete \"%s\"", (value == 4)? "d": "und",
X		    panel_get_value(msg_num_item));
X	    panel_set(msg_num_item, PANEL_VALUE, NO_STRING, 0);
X	}
X    (void) cmd_line(buf, msg_list);
X}
X
Xread_mail(item, value, event)
Xregister Panel_item item;
Xregister int value;
Xregister struct inputevent *event;
X{
X    register int this_msg = current_msg;
X
X    /* check "event" in case we were called from select.c
X     * in which case event would be NULL
X     */
X    if (event && event->ie_code == MS_RIGHT &&
X        item && (item == read_item && value ||
X	(item == sub_hdr_item[0] || item == sub_hdr_item[1])))
X	return help(panel_sw->ts_windowfd, "next", tool_help);
X    if (item && (item == sub_hdr_item[4] || item == sub_hdr_item[5]))
X	return help(panel_sw->ts_windowfd, "msg_menu", tool_help);
X    if (!msg_cnt) {
X	print ("No Mail.");
X	return -1;
X    }
X    if (item && item == read_item || ison(msg[current_msg].m_flags, DELETE))
X	(void) next_msg(FALSE, DELETE);
X    if (this_msg != current_msg || ison(msg[current_msg].m_flags, UNREAD) ||
X	    (current_msg < n_array[0] || current_msg > n_array[screen])) {
X	set_isread(current_msg);
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    }
X    display_msg(current_msg, (long)0);
X    return -1;
X}
X
X/* the panel button that says "filename" and "directory", etc... text item */
Xfile_dir(item, event)
XPanel_item item;
Xstruct inputevent *event;
X{
X    register char *p;
X    char buf[128], *which = panel_get(item, PANEL_LABEL_STRING);
X
X    if (!strcmp(which, "folder:"))
X	if (event->ie_code == '\n' || event->ie_code == '\r')
X	    (void) sprintf(buf, "folder %s", panel_get_value(item));
X	else
X	    (void) sprintf(buf, "folder ! %s", panel_get_value(item));
X
X    else if (!strcmp(which, "directory:"))
X	(void) sprintf(buf, "cd %s", panel_get_value(item));
X
X    else if (!msg_cnt)
X	print("No messages to save");
X
X    else if (!strcmp(which, "filename:")) {
X	int x = 1;
X	if (event->ie_code == '\n' || event->ie_code == '\r')
X	    (void) strcpy(buf, "save  ");
X	else
X	    (void) strcpy(buf, "write ");
X	if (!(p = panel_get_value(item)) || !*p &&
X	    (!(p = do_set(set_options, "mbox")) || !*p))
X		p = DEF_MBOX;
X	(void) sprintf(buf+6, "%d %s", current_msg+1, p);
X	print("save message %d in %s? ", current_msg+1, p);
X	if ((x = confirm(print_sw->ts_windowfd)) != 'y' && x != MS_LEFT) {
X	    print("Message not saved");
X	    return;
X	}
X    }
X    (void) cmd_line(buf, msg_list);
X}
X
Xdo_file_dir(item, value, event)
XPanel_item item;
Xint value;
Xstruct inputevent *event;
X{
X    char buf[92];
X    int x; /* used for confirmation */
X
X    if (item == folder_item) {
X	(void) strcpy(buf, "folder ");
X	if (event->ie_code == MS_LEFT) {
X	    panel_set(file_item, PANEL_LABEL_STRING, "folder:", 0);
X	    panel_set(file_item, PANEL_MENU_CHOICE_STRINGS,
X			    "Change without updating current folder", 0, 0);
X	} else {
X	    if (!value)
X		(void) strcat(buf, "%");
X	    else if (value == 1)
X		(void) strcat(buf, "&");
X	    else if (value == 2)
X		(void) strcat(buf, "#");
X	    else {
X		(void) sprintf(buf, "folder %s",
X			      panel_get(item, PANEL_CHOICE_STRING, value));
X		if (!strcmp(buf+8, "Help"))
X		    return help(panel_sw->ts_windowfd, "folder", tool_help);
X	    }
X	}
X    } else if (item == cd_item) {
X	(void) strcpy(buf, "cd ");
X	if (event->ie_code == MS_LEFT || !value) {
X	    panel_set(file_item, PANEL_LABEL_STRING, "directory:", 0);
X	    panel_set(file_item, PANEL_MENU_CHOICE_STRINGS,
X				"Change to specified directory", 0, 0);
X	} else if (value == 1)
X	    (void) strcat(buf, "~");
X	else if (value == 2)
X	    (void) strcat(buf, "+");
X	else
X	    return help(panel_sw->ts_windowfd, "chdir", tool_help);
X    } else if (item == save_item) {
X	(void) strcpy(buf, "save ");
X	if (event->ie_code == MS_LEFT)
X	    if (!strcmp("filename:", panel_get(file_item,PANEL_LABEL_STRING))) {
X		event->ie_code = '\n';  /* let file_dir think it got a \n */
X		return file_dir(file_item, event);
X	    } else {
X		panel_set(file_item, PANEL_LABEL_STRING, "filename:", 0);
X		panel_set(file_item, PANEL_MENU_CHOICE_STRINGS,
X			"Save message WITHOUT headers", 0,0);
X		print("Type in Main Panel Window a filename to save message");
X		return;
X	    }
X	else if (value == 1) {
X	    register char *p = panel_get_value(file_item);
X	    if ((!p || !*p) && (!(p = do_set(set_options, "mbox")) || !*p))
X		p = DEF_MBOX;
X	    print("Save in %s? ", p);
X	    if ((x = confirm(panel_sw->ts_windowfd)) != 'y' && x != MS_LEFT) {
X		print("Message not saved");
X		return;
X	    }
X	    (void) sprintf(buf, "save \"%s\" %s",
X					   panel_get_value(msg_num_item), p);
X	    panel_set(msg_num_item, PANEL_VALUE, NO_STRING, 0);
X	} else {
X	    (void) sprintf(buf, "save %s",
X		panel_get(item, PANEL_CHOICE_STRING, value));
X	    if (!strcmp(buf+6, "Help"))
X		return help(panel_sw->ts_windowfd, "save", tool_help);
X	}
X    }
X    (void) cmd_line(buf, msg_list);
X    panel_set(item, PANEL_VALUE, NO_STRING, 0); /* remove last value */
X}
X
Xtext_done(item, event)
XPanel_item item;
Xstruct inputevent *event;
X{
X    char opt[30], buf[82], cmd[82];
X    register char *p;
X    Panel_item which = NO_ITEM;
X    int set_it;
X
X    if ((event->ie_code == '\n' || event->ie_code == '\r') && 
X				 *strcpy(buf, panel_get_value(item))) {
X	(void) strcpy(opt, panel_get(item, PANEL_LABEL_STRING));
X	set_it = (*opt == 'S');
X	if (!(p = index(opt, ' '))) {
X	    print("Hmmm... there seems to be a problem here.");
X	    return;
X	}
X	++p;
X	switch(lower(*p)) {
X	    case 'o':
X		(void) sprintf(cmd, "%set %s", (set_it)? "s": "uns", buf);
X		which = option_item;
X	    when 'i':
X		(void) sprintf(cmd, "%sgnore %s", (set_it)? "i": "uni", buf);
X		which = ignore_item;
X	    when 'a':
X		(void) sprintf(cmd, "%slias %s", (set_it)? "a": "una", buf);
X		which = alias_item;
X	    otherwise: print("HUH!? (%c)", *p); return;
X	}
X	(void) cmd_line(buf, msg_list);
X    }
X    panel_set(input_item, PANEL_VALUE, NO_STRING, 0); /* remove last value */
X    panel_set(item, PANEL_SHOW_ITEM, FALSE, 0);
X}
X
Xdo_help(item, value, event)
XPanel_item item;
Xregister int value;
Xstruct inputevent *event;
X{
X    register char *p, *helpfile = tool_help;
X    switch(value) {
X	case 1: p = "help";
X	when 2: p = "mouse";
X	when 3: p = "windows";
X	when 4: p = "function keys";
X	when 5: p = "hdr_format", helpfile = cmd_help;
X	when 6: p = "msg_list", helpfile = cmd_help;
X	otherwise: p = "general";
X    }
X    (void) help(panel_sw->ts_windowfd, p, helpfile);
X}
X
Xtoolquit(item, value, event)
XPanel_item item;
Xint value;
Xstruct inputevent *event;
X{
X    register int which;
X
X    if (!value || event->ie_code == MS_LEFT) {
X	do_update(NO_ITEM, 0, NO_EVENT);
X	turnoff(glob_flags, NEW_MAIL);
X	mail_status(0); /* lower flag (if up) print current num of msgs */
X	wmgr_changestate (tool->tl_windowfd, rootfd, TRUE);
X	wmgr_changelevel (tool->tl_windowfd, parentfd, TRUE);
X	return;
X    } else if (value == 2) {
X	(void) help(panel_sw->ts_windowfd, "quit", tool_help);
X	return;
X    }
X    print("Left updates changes. Middle does not. Right aborts quit.");
X    if ((which = confirm(panel_sw->ts_windowfd)) == MS_RIGHT) {
X	print("Quit aborted.");
X	return;
X    }
X    abort_mail(NO_ITEM, 0);
X    if (which == MS_LEFT)
X	lock_cursors(), copyback();
X    else
X	print("Bye bye");
X    cleanup(0);
X}
X
Xdo_lpr(item, value, event)
XPanel_item item;
Xint value;
Xstruct inputevent *event;
X{
X    char buf[128];
X
X    if (event && (event->ie_code == MS_LEFT || value == 1)) {
X	print("Sending message %d to printer...", current_msg+1);
X	(void) strcpy(buf, "lpr ");
X	if (value)
X	    (void) sprintf(buf, "lpr \"%s\"", panel_get_value(msg_num_item));
X	lock_cursors();
X	(void) cmd_line(buf, msg_list);
X	unlock_cursors();
X    } else
X	(void) help(panel_sw->ts_windowfd, "printer", tool_help);
X}
X
Xdo_clear()
X{
X    /* actions that clears window indicates user wants to quit getting opts */
X    if (msg_pix)
X	pr_destroy(msg_pix), msg_pix = (struct pixrect *)NULL;
X    if (getting_opts)
X	getting_opts = 0, unlock_cursors();
X    pw_writebackground(msg_win, 0,0, msg_rect.r_width,msg_rect.r_height,
X		       PIX_CLR);
X    txt.x = 5, txt.y = l_height(curfont) - 1;
X}
X
Xdo_update(item, value, event)
XPanel_item item;
Xregister int value;
Xstruct inputevent *event;
X{
X    char *argv[2];
X    if (event && event->ie_code != MS_LEFT)
X	return help(panel_sw->ts_windowfd, "update", tool_help);
X    argv[0] = "update";
X    argv[1] = NULL;
X    (void) folder(0, argv, NULL);
X}
X
X/* panel selction button to send a letter.
X * add a CR if necessary, and finish up letter
X */
Xdo_send(item, value, event)
XPanel_item item;
Xregister int value;
Xregister struct inputevent *event;
X{
X    if (event->ie_code != MS_LEFT)
X	return help(panel_sw->ts_windowfd, "send", tool_help);
X    if (txt.x > 5) {
X	pw_char(msg_win, txt.x,txt.y, PIX_CLR, fonts[curfont], '_');
X	add_to_letter(rite('\n')); /* if line isn't complete, flush it */
X    }
X    finish_up_letter();
X}
X
Xdo_edit(item, value, event)
XPanel_item item;
Xregister int value;
Xregister struct inputevent *event;
X{
X    char buf[4];
X    if (event->ie_code != MS_LEFT)
X	return help(panel_sw->ts_windowfd, "edit", tool_help);
X    if (txt.x > 5)
X	add_to_letter(rite('\n')); /* flush line for him */
X    add_to_letter(sprintf(buf, "%cv", *escape));
X}
X
Xdo_compose(item, value, event)
XPanel_item item;
Xregister int value;
Xstruct inputevent *event;
X{
X    if (event && event->ie_code != MS_LEFT)
X	return help(panel_sw->ts_windowfd, "compose", tool_help);
X    print("Composing letter.");
X    win_setcursor(msg_sw->ts_windowfd, &write_cursor);
X    do_mail(0, DUBL_NULL, NULL);
X}
X
Xchange_font(item, value, event)
XPanel_item item;
Xregister int value;
Xstruct inputevent event;
X{
X    if (ison(glob_flags, IS_GETTING))
X	pw_char(msg_win, txt.x, txt.y, PIX_SRC^PIX_DST, fonts[curfont], '_');
X    curfont = value % total_fonts;
X    print("New font: %s\n",
X	    (!curfont)? "Normal": (curfont == 1)? "Small": "Large");
X    if (ison(glob_flags, IS_GETTING))
X	pw_char(msg_win, txt.x, txt.y, PIX_SRC^PIX_DST, fonts[curfont], '_');
X    crt = msg_rect.r_height / l_height(curfont);
X}
END_OF_FILE
if test 12405 -ne `wc -c <'doproc.c'`; then
    echo shar: \"'doproc.c'\" unpacked with wrong size!
fi
# end of 'doproc.c'
fi
if test -f 'init.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'init.c'\"
else
echo shar: Extracting \"'init.c'\" \(10998 characters\)
sed "s/^X//" >'init.c' <<'END_OF_FILE'
X/* init.c	(c) copyright 1986 (Dan Heller) */
X
X/* init.c -- functions and whatnot that initialize everything */
X#include "mush.h"
X#include <pwd.h>
X
X#ifdef SUNTOOL
X/* mouse symbols */
Xshort dat_mouse_left[] = {
X#include <images/confirm_left.pr> 
X};
X
Xshort dat_mouse_middle[] = {
X#include <images/confirm_middle.pr> 
X};
X
Xshort dat_mouse_right[] = {
X#include <images/confirm_right.pr> 
X};
X
Xshort dat_mail_icon_1[] = {
X#include "mail.icon.1"
X};
X
Xshort dat_mail_icon_2[] = {
X#include "mail.icon.2"
X};
X
Xshort dat_coffee_cup[] = {
X#include "coffee.cup.pr"
X};
X
Xshort dat_read_cursor[] = {
X#include "glasses.pr"
X};
X
Xshort dat_write_cursor[] = {
X#include "write.pr"
X};
X
Xshort dat_up_arrow[] = {
X#include "up.arrow.pr"
X};
X
Xshort dat_dn_arrow[] = {
X#include "dn.arrow.pr"
X};
X
Xshort dat_envelope[] = {
X#include "envelope.pr"
X};
X
Xshort dat_cycle_cursor[] = {
X#include "cycle.pr"
X};
X
Xshort dat_check_cursor[] = {
X#include "check.pr"
X};
X
Xmpr_static(mail_icon_image1, 64, 64, 1, dat_mail_icon_1);
Xmpr_static(mail_icon_image2, 64, 64, 1, dat_mail_icon_2);
X
Xmpr_static(mouse_left,      16, 16, 1, dat_mouse_left);
Xmpr_static(mouse_middle,    16, 16, 1, dat_mouse_middle);
Xmpr_static(mouse_right,     16, 16, 1, dat_mouse_right);
Xmpr_static(coffee_cup,      16, 16, 1, dat_coffee_cup);
Xmpr_static(glasses_cursor,  16, 16, 1, dat_read_cursor);
Xmpr_static(pencil_cursor,   16, 16, 1, dat_write_cursor);
Xmpr_static(up_arrow,        16, 16, 1, dat_up_arrow);
Xmpr_static(dn_arrow,        16, 16, 1, dat_dn_arrow);
Xmpr_static(envelope_cursor, 16, 16, 1, dat_envelope);
Xmpr_static(cycle,           16, 16, 1, dat_cycle_cursor);
Xmpr_static(check_cursor,    16, 16, 1, dat_check_cursor);
X
Xstruct cursor l_cursor     = { 3, 3, PIX_SRC,         &mouse_left      };
Xstruct cursor m_cursor     = { 3, 3, PIX_SRC,         &mouse_middle    };
Xstruct cursor r_cursor     = { 3, 3, PIX_SRC,         &mouse_right     };
Xstruct cursor coffee       = { 8, 8, PIX_SRC,         &coffee_cup      };
Xstruct cursor read_cursor  = { 8, 8, PIX_SRC|PIX_DST, &glasses_cursor  };
Xstruct cursor write_cursor = { 8, 8, PIX_SRC|PIX_DST, &pencil_cursor   };
Xstruct cursor main_cursor  = { 8, 8, PIX_SRC,         &envelope_cursor };
Xstruct cursor checkmark = { 8, 8, PIX_SRC|PIX_DST, &check_cursor };
X
X/* text and font will be set in mail_status() */
Xstruct icon mail_icon = { 64,  64, (struct pixrect *)NULL,
X            { 0, 0, 64, 64 }, &mail_icon_image1,
X            { 5, 5, 26, 12 }, NULL, (struct pixfont *)NULL, 0 };
X
Xchar *font_files[] = {
X    "serif.r.14", "sail.r.6", "serif.r.16",
X};
X
Xchar *alt_fonts[] = {
X    "gacha.r.8", "sail.r.6", "screen.r.14",
X};
X
X#endif SUNTOOL
X
X#ifdef BSD
X#include <netdb.h>
X#endif BSD
X
Xvoid
Xinit()
X{
X    char 		buf[BUFSIZ], cwd[128], *home;
X    extern char		*getwd(), *getlogin();
X#ifdef SYSV
X    char *getcwd();
X    extern struct passwd *getpwuid();  /* sys-v forgot this in pwd.h! */
X#else
X    char ourhost[128];
X#endif SYSV
X    register char 	*p, *p2 = buf, **argv;
X    struct passwd 	*entry;
X    int			cnt = 0;
X#ifdef BSD
X    struct hostent 	*hp;
X#endif BSD
X
X    home = getenv ("HOME");
X
X    if (!(entry = getpwuid(getuid())))
X	if (p = getlogin())
X	    strdup(login, p);
X	else {
X	    login = "unknown";
X	    print("I don't know you, but that's ok.\n");
X	}
X    else {
X	strdup(login, entry->pw_name);
X	if (!home || !*home)
X	    home = entry->pw_dir;
X	endpwent();
X    }
X    if (!home || !*home || access(home, 2)) {
X	error(home);
X	home = ALTERNATE_HOME;
X	print_more("Using \"%s\" as home.\n", home);
X    }
X
X#ifndef SYSV
X    (void) gethostname(ourhost, sizeof ourhost);
X    if (!(hp = gethostbyname(ourhost)))
X	error("gethostbyname: %s", ourhost);
X    else for (p = hp->h_name; p && *p && cnt < MAX_HOST_NAMES;
X	      p = hp->h_aliases[cnt++])
X	ourname[cnt] = savestr(p);
X    endhostent();
X#endif SYSV
X
X#ifndef SYSV
X    if (getwd(cwd) == NULL)
X#else
X    if (getcwd(cwd, 128) == NULL)
X#endif SYSV
X	error("getcwd: %s", cwd), *cwd = 0;
X
X    p2 += strlen(strcpy(p2, "set "));
X    p2 += strlen(sprintf(p2, "cwd=\"%s\" ", cwd));
X    p2 += strlen(sprintf(p2, "home=\"%s\" ", home));
X    p2 += strlen(sprintf(p2, "prompt=\"%s\" ", DEF_PROMPT));
X    p2 += strlen(sprintf(p2, "mbox=\"%s\" ",   DEF_MBOX));
X    p2 += strlen(sprintf(p2, "folder=\"%s\" ", DEF_FOLDER));
X    p2 += strlen(sprintf(p2, "escape=\"%s\" ", DEF_ESCAPE));
X
X    p = getenv("SHELL");
X    p2 += strlen(sprintf(p2, "shell=\"%s\" ", (p)? p: DEF_SHELL));
X
X    p = getenv("EDITOR");
X    p2 += strlen(sprintf(p2, "editor=\"%s\" ", (p)? p: DEF_EDITOR));
X
X    p = getenv("VISUAL");
X    p2 += strlen(sprintf(p2, "visual=\"%s\" ", (p)? p: DEF_EDITOR));
X
X    p = getenv("PAGER");
X    p2 += strlen(sprintf(p2, "pager=\"%s\" ", (p)? p: DEF_PAGER));
X
X    p = getenv("PRINTER");
X    p2 += strlen(sprintf(p2, "printer=\"%s\" ", (p)? p: DEF_PRINTER));
X
X    crt = 25;
X    /* p2 += strlen(strcat(p2, "crt=\"25\" ")); */
X    screen = 18;
X    /* p2 += strlen(strcat(p2, "screen=\"18\" ")); */
X
X    if (!(argv = make_command(buf, TRPL_NULL, &cnt)))
X	print("error initializing variables.\n");
X    else {
X	(void) set(cnt, argv);
X	free_vec(argv);
X    }
X#ifdef CURSES
X    init_bindings();
X#endif CURSES
X}
X
X/*
X * Source a file, or just the default file.  Since sourcing files
X * means reading possible aliases, don't expand the ! as history
X * by setting the IGN_BANG flag.  Since a command in the sourced file
X * may call source on another file, this routine may be called from
X * within itself.  Continue to ignore ! chars by setting save_bang (local).
X *
X * Try opening the file passed to us.  If not given, check for the correct
X * .rc file which is found in the user's home dir.
X */
Xsource(argc, argv)
Xchar **argv;
X{
X    register char *p, *p2, **newargv;
X    int 	  line_no = 0, if_else = 0, parsing = 1, cont_line = 0;
X    FILE 	 *fp;
X    char 	  file[128], line[BUFSIZ];
X    long	  save_bang = ison(glob_flags, IGN_BANG);
X
X    if (argc && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "source_help", cmd_help);
X    if (argc && *argv)
X	(void) strcpy(file, *argv);
X    else if (p = getenv("MAILRC"))
X	(void) strcpy(file, p);
X    else {
X	char *home = do_set(set_options, "home");
X	if (!home || !*home)
X	    home = ALTERNATE_HOME;
X	if (access(sprintf(file, "%s/%s", home, MAILRC), R_OK)
X          && access(sprintf(file, "%s/%s", home, ALTERNATE_RC), R_OK))
X	(void) strcpy(file, DEFAULT_RC);
X    }
X
X    argc = 0; /* don't ignore ENOENT */
X    p = getpath(file, &argc);
X    if (argc) {
X	if (strcmp(file, DEFAULT_RC))
X	    if (argc == -1)
X		print("%s: %s\n", file, p);
X	    else
X		print("%s is a directory.\n", file);
X	return -1;
X    }
X    if (!(fp = fopen(p, "r"))) {
X	if (errno != ENOENT)
X	    error("Can't open %s", p);
X	return -1;
X    }
X    (void) strcpy(file, p);
X    turnon(glob_flags, IGN_BANG); /* ignore ! when reading record files */
X    while (p = fgets(&line[cont_line], BUFSIZ - cont_line, fp)) {
X	line_no++;
X	if (*(p2 = no_newln(line + cont_line)) == '\\') {
X	    cont_line = p2 - line;
X	    continue;
X	} else
X	    cont_line = 0;
X	/* don't consider comments (#) in lines. check if # is within quotes */
X        if (p = any(p, "\"'#")) {
X	    register int balanced = 1;
X	    while (p && (*p == '\'' || *p == '"') && balanced) {
X		/* first find matching quote */
X		register char *quote = index(p+1, *p);
X		if (!quote) {
X		    print("%s: line %d: unbalanced %c.\n", file, line_no, *p);
X		    balanced = 0;
X		} else
X		    p = any(quote+1, "'\"#");
X	    }
X	    if (!balanced)
X		continue;
X	    if (p && *p == '#')
X		*p = 0; /* found a Comment: null terminate line at comment */
X	}
X	if (!*line || !(newargv = make_command(line, TRPL_NULL, &argc))) {
X	    if (!strncmp(line, "if", 2))
X		if_else++, parsing = FALSE;
X	    continue;
X	}
X	if (!strcmp(newargv[0], "endif")) {
X	    if (!if_else)
X		print("%s: line %d: endif with no \"if\".\n", file, line_no);
X	    else
X		if_else = 0, parsing = 1;
X	    goto bad;
X	} else if (!strcmp(newargv[0], "else")) {
X	    if (!if_else)
X		print("%s: line %d: if-less \"else\".\n", file, line_no);
X	    else
X		parsing = !parsing;
X	    goto bad;
X	} else if (parsing && !strcmp(newargv[0], "if")) {
X	    /* if statements are of the form:
X	     *     if expr
X	     *     if !expr  or  if ! expr
X	     *     if expr == expr   or   if expr != expr
X	     */
X	    int equals = TRUE;
X	    register char *lhs = newargv[1], *rhs = NULL;
X
X	    if (if_else)
X		print("%s: line %d: no nested if statements!\n", file, line_no);
X	    else
X		if_else = 1;
X	    parsing = 0;
X	    if (!lhs || !*lhs) {
X		print("%s: line %d: if what?\n", file, line_no);
X		goto bad;
X	    }
X	    /* "lhs" is the left hand side of the equation
X	     * In this instance, we're doing case 2 above.
X	     */
X	    if (*lhs == '!') {
X		int tmp = argc;
X		equals = FALSE;
X		if (!*++lhs)
X		    if (!(lhs = newargv[2])) {
X			print("%s: %d: syntax error: \"if ! <what?>\"\n",
X			    file, line_no);
X			goto bad;
X		    } else
X			tmp--;
X		if (tmp > 2) {
X		    print("%s: %d: syntax error: \"if !<expr> <more junk>\"\n",
X			file, line_no);
X		    goto bad;
X		}
X	    } else if (argc > 2) {
X		if (argc != 4) {
X		    print("%s: %d: argument count error: line has %d args.\n",
X			file, line_no, argc);
X		    goto bad;
X		}
X		/* now check newargv[1] for == or != */
X		if (!strcmp(newargv[2], "!="))
X		    equals = FALSE;
X		else if (strcmp(newargv[2], "==")) {
X		    print("%s: %d: use `==' or `!=' only.\n", file, line_no);
X		    goto bad;
X		}
X		rhs = newargv[3];
X	    }
X	    if (!strcmp(lhs, "redirect") &&
X		      (ison(glob_flags, REDIRECT) && equals ||
X		       isoff(glob_flags, REDIRECT) && !equals)
X		|| !strcmp(lhs, "istool") &&
X		      (istool && equals || !istool && !equals)
X		|| !strcmp(lhs, "hdrs_only") &&
X		      (hdrs_only && equals || !hdrs_only && !equals)
X		|| !strcmp(lhs, "iscurses") &&
X		      ((iscurses || ison(glob_flags, PRE_CURSES)) && equals ||
X		      (isoff(glob_flags, PRE_CURSES) && !iscurses && !equals)))
X		    parsing = 1;
X	    else if (rhs)
X		if (strcmp(lhs, rhs) && !equals || !strcmp(lhs, rhs) && equals)
X		    parsing = 1;
Xbad:
X	    free_vec(newargv);
X	    continue;
X	}
X	if (parsing && argc > 0)
X	    if (!strcmp(newargv[0], "exit")) {
X		if_else = 0;
X		break;
X	    } else
X		(void) do_command(argc, newargv, msg_list);
X	else
X	    free_vec(newargv);
X    }
X    if (if_else)
X	print("%s: missing endif\n", file);
X    fclose(fp);
X    /* if we entered the routine ignoring !, leave it that way. */
X    if (!save_bang)
X	turnoff(glob_flags, IGN_BANG);
X    return -1;
X}
X
X#ifdef SUNTOOL
X/* open all fonts and place in fonts array. */
Xgetfonts()
X{
X    char tmp[80];
X    register int offset = strlen(FONTDIR) + 1;
X    struct pixfont *pf_open();
X
X    (void) sprintf(tmp, "%s/", FONTDIR);
X    for (total_fonts = 0; total_fonts < MAX_FONTS; total_fonts++) {
X	(void) strcpy(&tmp[offset], font_files[total_fonts]);
X	if (!(fonts[total_fonts] = pf_open(tmp))) {
X	    (void) strcpy(&tmp[offset], alt_fonts[total_fonts]);
X	    if (!(fonts[total_fonts] = pf_open(tmp))) {
X		print("couldn't open font \"%s\"\n", tmp);
X		fonts[total_fonts] = pf_default();
X	    }
X	}
X    }
X}
X#endif SUNTOOL
END_OF_FILE
if test 10998 -ne `wc -c <'init.c'`; then
    echo shar: \"'init.c'\" unpacked with wrong size!
fi
# end of 'init.c'
fi
if test -f 'viewopts.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'viewopts.c'\"
else
echo shar: Extracting \"'viewopts.c'\" \(12717 characters\)
sed "s/^X//" >'viewopts.c' <<'END_OF_FILE'
X/* @(#)viewopts.c	(c) copyright	10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
Xstruct viewopts {
X    char *v_opt;
X    char *v_prompt;
X    int  v_usage;
X#define TOOL  01
X#define TEXT  02
X    char *v_description;
X};
X
X/*
X * struct contains the option, a prompt if it has a string value, whether
X * or not it applies to non suntools, line mode, or both, and a
X * string describing what the option does. If the prompt string starts
X * with a minus sign, then the value can be set without a value. This
X * is there to indicate to option_line to print a toggle (cycle) pixrect
X * and to print TRUE/FALSE telling whether the value is on or off regardless
X * of it's "string" value.
X */
Xstruct viewopts viewopts[] = {
X    { "alwaysignore", NULL, TOOL | TEXT,
X      "alwaysignore the message headers on the 'ignored' list." },
X    { "askcc", NULL, TOOL | TEXT,
X      "Ask for list of Carbon Copy recipients whenever sending mail.", },
X    { "autodelete", NULL, TOOL | TEXT,
X      "Automatically delete ALL READ messages whenever you update mail.", },
X    { "autoedit", NULL, TOOL | TEXT,
X      "Automatically enter editor whenever you REPLY to mail.", },
X    { "autoinclude", NULL, TOOL | TEXT,
X      "Include a copy of author's message each time you reply to mail." },
X    { "autoprint", NULL, TOOL | TEXT,
X      "Display the next message on the list when you delete a message." },
X    { "auto_route", NULL, TOOL | TEXT,
X      "Automatic optimization of uucp paths is done removing redundancies." },
X    { "autosign", "-Filename", TOOL | TEXT,
X      "Add file (~/.signature if set but no value) at end of all letters." },
X    { "crt", "Lines", TEXT,
X      "The number of lines a message must have for 'pager' to be invoked." },
X    { "dead", "Filename", TOOL | TEXT,
X      "The name of the file to store dead mail. ~/dead.letter by default." },
X    { "dot", NULL, TOOL | TEXT,
X      "allow \".\" on a line by itself to send letter." },
X    { "editor", "Editor name/path", TOOL | TEXT,
X      "editor to use by default. Default is evironment EDITOR or \"vi\"" },
X    { "escape", "Character", TOOL | TEXT,
X      "Escape character for extended editing commands. (default = ~)" },
X    { "fixaddr", NULL, TOOL | TEXT,
X      "makes \"replyall\" route recipient addresses through sender's host." },
X    { "folder", "Pathname", TOOL | TEXT,
X      "Full pathname to the directory where personal folders are kept." },
X    { "fortune", "-Flag", TOOL | TEXT,
X      "Add fortune to end of letters. Flag to \"fortune\" is optional" },
X    { "fortunates", "Users", TOOL | TEXT,
X      "Those who will receive fortunes if fortune is set (default: All)." },
X    { "hdr_format", "Format", TOOL | TEXT,
X      "Formatting string for headers. \"headers -?\" or help hdr_format" },
X    { "history", "Number", TEXT,
X      "How many commands to remember (like csh)." },
X    { "hold", NULL, TOOL | TEXT,
X      "Read but not deleted messages are saved in spool -- not mbox." },
X    { "ignore_bang", NULL, TEXT,
X      "Ignore '!' as a history reference. Otherwise, escape by: \\!" },
X    { "ignoreeof", "-Command", TEXT,
X      "Ignores ^D as exit, or (if set), execute \"command\"." },
X    { "indent_str", "String", TOOL | TEXT,
X      "String to offset included messages within your letter", },
X    { "in_reply_to", NULL, TOOL | TEXT,
X      "When responding to mail, add In-Reply-To: to message headers." },
X    { "keepsave", NULL, TOOL | TEXT,
X      "Prevents messages from being marked as `deleted' when you `save'." },
X    { "known_hosts", "Host list", TOOL | TEXT,
X      "List of hosts that your site is known to uucp mail to." },
X    { "lister", "Arguemnts", TOOL | TEXT,
X      "Arguments passed to the 'ls' command." },
X    { "mbox", "Filename", TOOL | TEXT,
X      "Filename to use instead of ~/mbox for default mailbox." },
X    { "metoo", NULL, TOOL | TEXT,
X      "When replying to mail, metoo preserves your name on mailing list." },
X    { "newline", "-Command", TEXT,
X      "Ignore RETURN. If set to a string, execute \"command\"" },
X    { "no_hdr", NULL, TOOL | TEXT,
X      "If set, personalized headers are NOT inserted to outgoing mail." },
X    { "no_reverse", NULL, TOOL | TEXT,
X      "disables reverse video in curses mode -- uses \"bold\" in tool mode." },
X    { "nosave", NULL, TOOL | TEXT,
X      "prevents aborted mail from being saved in dead.letter" },
X    { "pager", "Program", TEXT,
X      "Program name to be used as a pager for messages longer than crt." },
X    { "print_cmd", "Program", TOOL | TEXT,
X      "Alternate program to use to send messages to the printer." },
X    { "printer", "Printer", TOOL | TEXT,
X      "Printer to send messages to. Default is environment PRINTER" },
X    { "prompt", "String", TEXT,
X      "Your prompt.  \"help prompt\" for more information." },
X    { "quiet", NULL, TEXT,
X      "Don't print the version number of Mush on startup." },
X    { "record", "Filename", TOOL | TEXT,
X      "Save all outgoing mail in specified filename" },
X    { "reply_to_hdr", "Headers", TOOL | TEXT,
X      "List of headers to search in messages to construct reply adresses.", },
X    { "screen", "Number of Headers", TEXT,
X      "Number of headers to print in non-suntools (text) mode" },
X    { "screen_win", "Number of Headers", TOOL,
X      "Set the size of the header window." },
X    { "show_deleted", NULL, TOOL | TEXT,
X      "Show deleted messages in headers listings" },
X    { "sort", "-Option", TOOL | TEXT,
X      "Sorting upon startup of mail or `update/folder' (sort -? for help)" },
X    { "squeeze", NULL, TOOL | TEXT,
X      "When reading messages, squeeze all blank lines into one." },
X    { "top", "Lines", TOOL | TEXT,
X      "Number of lines to print of a message for the 'top' command."  },
X    { "unix", NULL, TEXT,
X      "Non-mush commands are considered to be UNIX commands." },
X    { "verify", NULL, TEXT,
X      "Verify to send, re-edit, or abort letter after editing." },
X    { "visual", "Visual editor", TOOL | TEXT,
X      "Visual editor to use by default. \"editor\" is used if not set." },
X    { "warning", NULL, TOOL | TEXT,
X      "Warns when standard variables are set differently from the default." }
X};
X
Xstatic int total_opts;
X
X#ifdef NOT_NOW
X/*
X * put all the tool stuff at the beginning, or all the text stuff at
X * the beginning depending on whether or not we're running as a tool
X * With all the inappropriate variables out of the way, we set total
X * opts to the number of variables which are of the right type and
X * nothing inappropriate will ever be displayed.
X *
X * Note, this doesn't really work right now and I don't wanna fix it now..
X */
Xstatic
Xopt_eliminator(a, b)
Xregister struct viewopts *a, *b;
X{
X    if (istool)
X	return a->v_usage == TOOL;
X    return a->v_usage == TEXT;
X}
X#endif NOT_NOW
X
Xstatic
Xopt_sorter(a, b)
Xregister struct viewopts *a, *b;
X{
X    return !strcmp(a->v_opt, b->v_opt);
X}
X
Xsort_variables()
X{
X    /*
X    register int optnum;
X
X    for (optnum=0; optnum < sizeof viewopts / sizeof(struct viewopts); optnum++)
X	if (istool && viewopts[optnum].v_usage & TOOL
X		|| !istool && viewopts[optnum].v_usage & TEXT)
X	    total_opts++;
X    */
X    total_opts = sizeof viewopts / sizeof (struct viewopts);
X    qsort((char *)viewopts, sizeof viewopts / sizeof (struct viewopts),
X		    sizeof(struct viewopts), opt_sorter);
X}
X
X#ifdef SUNTOOL
X
Xstatic int start_cnt;
X
X#define twenty 	5 + 20*l_width(DEFAULT)
X#define forty 	5 + 40*l_width(DEFAULT)
X#define image_at(x,y,image) pw_rop(msg_win, x, y, 16, 16, PIX_SRC, image, 0,0)
X
X/* print in default text, but increment in large text segments */
Xview_options()
X{
X    if (msg_rect.r_height < 80) {
X	print("Window not big enough to display options.");
X	return;
X    }
X    do_clear();
X    getting_opts = 1, start_cnt = 0;
X    win_setcursor(msg_sw->ts_windowfd, &checkmark);
X    highlight(msg_win, txt.x, txt.y, LARGE,
X	    "    : Toggle Value       : Description       : Menu (Help)");
X    image_at(txt.x +  2 * l_width(DEFAULT), txt.y - 12, &mouse_left);
X    image_at(txt.x + 25 * l_width(DEFAULT), txt.y - 12, &mouse_middle);
X    image_at(txt.x + 48 * l_width(DEFAULT), txt.y - 12, &mouse_right);
X
X    pw_vector(msg_win, 0, txt.y+6, msg_rect.r_width, txt.y+6, PIX_SRC, 1);
X    pw_vector(msg_win, 0, txt.y+8, msg_rect.r_width, txt.y+8, PIX_SRC, 1);
X
X    txt.y += 24;
X
X    pw_text(msg_win, 5,      txt.y, PIX_SRC, fonts[LARGE], "Option");
X    pw_text(msg_win, twenty, txt.y, PIX_SRC, fonts[LARGE], "On/Off");
X    pw_text(msg_win, forty,  txt.y, PIX_SRC, fonts[LARGE], "Values");
X
X    pw_vector(msg_win, 0, txt.y+6, msg_rect.r_width, txt.y+6, PIX_SRC, 1);
X    pw_vector(msg_win, 0, txt.y+8, msg_rect.r_width, txt.y+8, PIX_SRC, 1);
X
X    pw_text(msg_win, 59*l_width(DEFAULT),txt.y,PIX_SRC,fonts[LARGE],"Scroll:");
X    pw_rop(msg_win, 60*l_width(LARGE), txt.y-13,16,16,PIX_SRC, &dn_arrow,0,0);
X    pw_rop(msg_win, 60*l_width(LARGE)+20,txt.y-13,16,16,PIX_SRC, &up_arrow,0,0);
X
X    display_opts(0); /* create the pixrect and all that */
X}
X
Xdisplay_opts(count)
Xregister int count;
X{
X    register int total_displayable = (msg_rect.r_height - 60) / 20;
X
X    if (count < 0 && start_cnt + count < 0) {
X	print("At the beginning");
X	return;
X    } else if (count && start_cnt + count + total_displayable > total_opts) {
X	print("At the end");
X	return;
X    }
X    start_cnt += count;
X    if (!msg_pix) {
X	register int x = (total_opts+1) * 20;
X	if (x < msg_rect.r_height)
X	    x = msg_rect.r_height;
X	if (!(msg_pix = mem_create(msg_rect.r_width, x, 1))) {
X	    error("mem_create");
X	    return;
X	}
X	pr_rop(msg_pix,0,0, msg_rect.r_width-1, x-1, PIX_CLR,0,0,0);
X	for (count = 0; count < total_opts; count++)
X	    option_line(count);
X    }
X    pw_rop(msg_win, 0, 50, msg_rect.r_width - 1, msg_rect.r_height - 50,
X       PIX_SRC, msg_pix, 0, start_cnt * 20);
X}
X
Xvoid
Xtoggle_opt(line)
X{
X    register char *p = viewopts[start_cnt+line].v_prompt;
X
X    if (do_set(set_options, viewopts[start_cnt+line].v_opt))
X	un_set(&set_options, viewopts[start_cnt+line].v_opt);
X    else {
X	if (p) {
X	    txt.x = 5 + 40 * l_width(DEFAULT) +
X		    (1 + strlen(p) - (*p=='-')) * l_width(DEFAULT);
X	    txt.y = 50 + line*20 + l_height(curfont);
X	}
X	if (!p || *p == '-') {
X	    register char *argv[2];
X	    argv[0] = viewopts[start_cnt+line].v_opt;
X	    argv[1] = NULL;
X	    (void) add_option(&set_options, argv);
X	}
X    }
X    option_line(line);
X    display_opts(0);
X    if (txt.x > 5)
X	pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[DEFAULT], '_');
X}
X
Xvoid
Xhelp_opt(line)
X{
X    print(viewopts[start_cnt+line].v_description);
X}
X
Xadd_opt(p, line)
Xregister char *p;
X{
X    char buf[80], **argv;
X    int argc, save_bang = ison(glob_flags, IGN_BANG);
X
X    (void) sprintf(buf, "set %s=\"%s\"", viewopts[start_cnt+line].v_opt, p);
X    turnon(glob_flags, IGN_BANG);
X    if (argv = make_command(buf, DUBL_NULL, &argc))
X	(void) do_command(argc, argv, msg_list);
X    if (!save_bang)
X	turnoff(glob_flags, IGN_BANG);
X    option_line(line); /* make sure new value is entered into database */
X}
X
Xoption_line(count)
Xregister int count;
X{
X    register char *p, *v = do_set(set_options, viewopts[start_cnt+count].v_opt);
X    struct pr_prpos win;
X
X    win.pr = msg_pix;
X    win.pos.y = (start_cnt + count) * 20 + 16;
X    win.pos.x = 5;
X
X    pf_text(win, PIX_SRC, fonts[DEFAULT], blank);
X    pf_text(win, PIX_SRC, fonts[DEFAULT], viewopts[start_cnt+count].v_opt);
X    win.pos.x = twenty+20;
X
X    if (!(p = viewopts[start_cnt+count].v_prompt) || *p == '-') {
X	pr_rop(msg_pix, twenty, win.pos.y-10, 16, 16, PIX_SRC, &cycle, 0, 0);
X	pf_text(win, PIX_SRC, fonts[DEFAULT], (v)? "TRUE  ": "FALSE");
X	win.pos.x++;
X	pf_text(win, PIX_SRC, fonts[DEFAULT], (v)? "TRUE  ": "FALSE");
X    }
X    if (p) {
X	if (*p == '-')
X	    p++;
X	win.pos.x = forty;
X	/* heighlight */
X	pf_text(win, PIX_SRC, fonts[DEFAULT], p);
X	win.pos.x++;
X	pf_text(win, PIX_SRC, fonts[DEFAULT], p);
X        win.pos.x = forty + strlen(p) * l_width(DEFAULT);
X	pf_text(win, PIX_SRC, fonts[DEFAULT], ":");
X	if (v) {
X	    win.pos.x += (2 * l_width(DEFAULT));
X	    pf_text(win, PIX_SRC, fonts[DEFAULT], v);
X	}
X    }
X}
X
X#endif SUNTOOL
X
X/*
X * return a string describing a variable.
X * parameters: count, str, buf.
X * If str != NULL, check str against ALL variables
X * in viewopts array.  The one that matches, set count to it and 
X * print up all the stuff from the viewopts[count] into the buffer
X * space in "buf" and return it.
X */
Xchar *
Xvariable_stuff(count, str, buf)
Xregister char *str, buf[];
X{
X    if (str)
X	for (count = 0; count < total_opts; count++)
X	    if (!strcmp(str, viewopts[count].v_opt))
X		break;
X    if (count >= total_opts) {
X	(void) sprintf(buf, "%s: Not a default %s variable.",
X			   str? str : itoa(count), prog_name);
X	return NULL;
X    }
X    return sprintf(buf, "%12.12s: %s",
X	viewopts[count].v_opt, viewopts[count].v_description);
X}
END_OF_FILE
if test 12717 -ne `wc -c <'viewopts.c'`; then
    echo shar: \"'viewopts.c'\" unpacked with wrong size!
fi
# end of 'viewopts.c'
fi
echo shar: End of archive 12 \(of 12\).
cp /dev/null ark12isdone
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 archiv NUlan>:va