[comp.sources.unix] v14i040: Mail User's Shell, version 6.0, Part08/14

rsalz@bbn.com (Rich Salz) (04/15/88)

Submitted-by: island!argv@sun.com (Dan Heller)
Posting-number: Volume 14, Issue 40
Archive-name: mush6.0/part08

#! /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 8 (of 14)."
# Contents:  commands.c mush.h
# Wrapped by rsalz@fig.bbn.com on Wed Apr 13 20:04:50 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'commands.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'commands.c'\"
else
echo shar: Extracting \"'commands.c'\" \(21317 characters\)
sed "s/^X//" >'commands.c' <<'END_OF_FILE'
X/* @(#)cmds.c	(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
X/*
X * Note that all of the routines in here act upon and return 0 or -1.
X * if -1, then the main loop will clear message lists.
X */
X
struct cmd cmds[] = {
X#ifdef SIGSTOP
X    { "stop", stop },
X#endif /* SIGSTOP */
X    { "?", 	  question_mark },{ "sh", sh },
X    { "alias", 	  do_alias    },  { "unalias",	do_alias   },
X    { "expand",	  do_alias    },  { "cmd", 	do_alias   },
X    { "uncmd", 	  do_alias    },  { "from",	do_from    },
X    { "un_hdr",	  do_alias    },  { "my_hdr",  	do_alias   },
X    { "fkey", 	  do_alias    },  { "unfkey", 	do_alias   },
X    { "set", 	  set         },  { "unset", 	set 	   },
X    { "ignore",	  set         },  { "unignore", set 	   },
X    { "version",  do_version  },  { "help",	print_help },
X    { "pick", 	  do_pick     },  { "sort", 	sort 	   },
X    { "next",	  readmsg     },  { "previous", readmsg    },
X    { "type",     readmsg     },  { "print",	readmsg    },
X    { "history",  disp_hist   },  { "top",	readmsg	   },
X    { "saveopts", save_opts   },  { "source",   source 	   },
X    { "headers",  do_hdrs     },  { "ls",	ls	   },
X    { "folder",   folder      },  { "update",   folder     },
X    { "cd", 	  cd          },  { "pwd",	cd 	   },
X    { "exit",	  quit        },  { "quit", 	quit 	   },
X    { "write", 	  save_msg    },  { "save", 	save_msg   },
X    { "copy", 	  save_msg    },  { "folders",  folders    },
X#ifdef CURSES
X    { "curses",   curses_init },  { "bind", bind_it   }, { "unbind", bind_it },
X#endif /* CURSES */
X    { "preserve", preserve    },  { "unpreserve",  preserve   },
X    { "replyall", respond     },  { "replysender", respond    },
X    { "delete",	  delete      },  { "undelete",    delete     },
X    { "mail", 	  do_mail     },  { "echo",	   do_echo    },
X    { "lpr",      lpr	      },  { "alternates",  alts       },
X    { NULL, quit }
X};
X
struct cmd ucb_cmds[] = {
X    { "t",   readmsg   }, { "n",  readmsg  }, { "p", readmsg  },
X    { "+",   readmsg   }, { "-",  readmsg  }, { "P", readmsg  },
X    { "Print", readmsg }, { "T",  readmsg  }, { "Type", readmsg },
X    { "x",   quit      }, { "xit", quit    }, { "q",  quit    },
X    { ":a",  do_hdrs   }, { ":d", do_hdrs  }, { ":r", do_hdrs },
X    { ":o",  do_hdrs   }, { ":u", do_hdrs  }, { ":n", do_hdrs },
X    { "z",   do_hdrs   }, { "z-", do_hdrs  }, { "z+", do_hdrs },
X    { "h",   do_hdrs   }, { "H",  do_hdrs  },
X    { "f",   do_from   }, { "m",  do_mail  }, { "alts", alts  },
X    { "d",   delete    }, { "dt", delete   }, { "dp", delete  },
X    { "u",   delete    }, { "fo", folder   },
X    { "s",   save_msg  }, { "co", save_msg }, { "w", save_msg },
X    { "pre", preserve  }, { "unpre", preserve },
X    { "R",   respond   }, { "r",   respond },
X    { "reply", respond }, { "respond", respond },
X    { NULL, quit }
X};
X
struct cmd hidden_cmds[] = {
X    { "debug", toggle_debug }, { "open", 	nopenfiles },
X    { "flags", msg_flags    }, { "stty",	my_stty    },
X    { "setenv",	Setenv      }, { "unsetenv", 	Unsetenv   },
X    { "printenv", Printenv  },
X    { NULL, quit }
X};
X
toggle_debug(argc, argv)
char **argv;
X{
X    if (argc < 2) /* no value -- toggle "debug" (off/on) */
X	debug = !debug;
X    else
X	debug = atoi(*++argv);
X    print("debugging value: %d\n", debug);
X    return -1;
X}
X
X/* if + was specified, then print messages without headers.
X * n or \n (which will be NULL) will print next unread or undeleted message.
X */
readmsg(x, argv, list)
register char **argv, list[];
X{
X    register char *p = x? *argv : NULL;
X    register long flg = 0;
X    extern FILE *ed_fp;
X
X    if (x && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "readmsg", cmd_help);
X    /* View a message as long as user isn't in the editor.  If is_getting
X     * is set, then the user is typing in a letter (or something else not
X     * threatening in tool mode).  If ed_fp is not null, then we've got the
X     * file open for typing.  If it's NULL, then an editor is going.
X     */
X    if (ison(glob_flags, IS_GETTING) && !ed_fp) {
X	print("Not while you're in the editor, you don't.\n");
X	return -1;
X    }
X    if (!msg_cnt) {
X	print("No messages.\n");
X	return -1;
X    }
X    if (x)
X	if (!strcmp(p, "top"))
X	    turnon(flg, TOP);
X	else if (*p == '+') {
X	    turnon(flg, NO_PAGE);
X	    turnon(flg, NO_HEADER);
X	} else if (isupper(*p))
X	    turnon(flg, NO_IGNORE);
X
X    if (x && (x = get_msg_list(argv, list)) == -1)
X	return -1;
X    else if (x == 0) {  /* no arguments were parsed (or given) */
X	/* get_msg_list sets current msg on */
X	unset_msg_bit(list, current_msg);
X	/* most commands move to the "next" message. type and print don't */
X	if ((!p || !*p || *p == 'n' || *p == '+') && current_msg < msg_cnt &&
X				    isoff(msg[current_msg].m_flags, UNREAD))
X	    current_msg++;
X	if (p && (*p == '-' || !strcmp(p, "previous"))) {
X	    while (--current_msg >= 0 && ison(msg[current_msg].m_flags, DELETE))
X		;
X	    if (current_msg < 0) {
X		print("No previous message.\n");
X		current_msg = 0;
X		return -1;
X	    }
X	} else {
X	    /*
X	     * To be compatible with ucb-mail, find the next available unread
X	     * message.  If at the end, only wrap around if "wrap" is set.
X	     */
X	    if (current_msg == msg_cnt && do_set(set_options, "wrap"))
X		current_msg = 0;
X	    /* "type" or "print" prints the current only -- "next" goes on.. */
X	    if (!p || !*p || *p == 'n')
X		while (current_msg < msg_cnt &&
X		    ison(msg[current_msg].m_flags, DELETE))
X			current_msg++;
X	    if (current_msg >= msg_cnt) {
X		print("No more messages.\n");
X		current_msg = msg_cnt - 1;
X		return -1;
X	    }
X	}
X	set_msg_bit(list, current_msg);
X    }
X    /* If we're piping messages, just return the message list */
X    if (ison(glob_flags, DO_PIPE))
X	return 0;
X    current_msg = 0;
X    for (x = 0; x < msg_cnt; x++)
X	if (msg_bit(list, x)) {
X	    current_msg = x;
X#ifdef SUNTOOL
X	    if (istool > 1) {
X		read_mail(NO_ITEM, 0, NO_EVENT);
X		return 0;
X	    }
X#endif /* SUNTOOL */
X	    display_msg(x, flg);
X	}
X    return 0;
X}
X
preserve(n, argv, list)
register int n;		/* no use for argc, so use space for a local variable */
register char **argv, list[];
X{
X    register int unpre;
X
X    unpre = !strncmp(*argv, "un", 2);
X    if (*++argv && !strcmp(*argv, "-?"))
X	return help(0, "preserve_help", cmd_help);
X    if (get_msg_list(argv, list) == -1)
X	return -1;
X    for (n = 0; n < msg_cnt; n++)
X	if (msg_bit(list, n))
X	    if (unpre) {
X		if (ison(msg[n].m_flags, PRESERVE)) {
X		    turnoff(msg[n].m_flags, PRESERVE);
X		    turnon(glob_flags, DO_UPDATE);
X		}
X	    } else {
X		if (isoff(msg[n].m_flags, PRESERVE) ||
X		    ison(msg[n].m_flags, DELETE)) {
X		    turnon(msg[n].m_flags, PRESERVE);
X		    turnon(glob_flags, DO_UPDATE);
X		    turnoff(msg[n].m_flags, DELETE);
X		}
X	    }
X    if (istool)
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    return 0;
X}
X
lpr(n, argv, list)
register int n;  /* no use for argc, so use its address space for a variable */
register char **argv, list[];
X{
X    register FILE	*pp;
X    register long 	flags = 0;
X    char		print_cmd[128], *printer, c, *cmd;
X    int			total = 0, (*oldint)(), (*oldquit)();
X
X    turnon(flags, NO_IGNORE);
X    if (!(printer = do_set(set_options, "printer")) || !*printer)
X	printer = DEF_PRINTER;
X    while (argv && *++argv && **argv == '-') {
X	n = 1;
X	while (c = argv[0][n++])
X	    switch(c) {
X		case 'n': turnon(flags, NO_HEADER);
X		when 'h': turnoff(flags, NO_IGNORE);
X		when 'P': case 'd':
X		    if (!argv[0][n]) {
X		        print("specify printer!\n");
X		        return -1;
X		    }
X		    printer = argv[0] + n;
X		    n += strlen(printer);
X		otherwise: return help(0, "lpr", cmd_help);
X	    }
X    }
X    if (get_msg_list(argv, list) == -1)
X	return -1;
X
X    if (cmd = do_set(set_options, "print_cmd"))
X	(void) strcpy(print_cmd, cmd);
X    else
X#ifdef SYSV
X	(void) sprintf(print_cmd, "%s -d%s", LPR, printer);
X#else
X	(void) sprintf(print_cmd, "%s -P%s", LPR, printer);
X#endif /* SYSV */
X    Debug("print command: %s\n", print_cmd);
X    if (!(pp = popen(print_cmd, "w"))) {
X	error("cannot print");
X	return -1;
X    }
X    on_intr();
X    for (n = 0; isoff(glob_flags, WAS_INTR) && n < msg_cnt; n++) {
X	if (msg_bit(list, n)) {
X	    if (total++)
X		fputc('\f', pp); /* send a formfeed for multiple copies */
X	    print("printing message %d...", n+1);
X	    print_more("(%d lines)\n", copy_msg(n, pp, flags));
X	}
X    }
X    off_intr();
X    (void) pclose(pp);
X    print_more("%d message%s printed ", total, (total==1)? "": "s");
X    if (cmd)
X	print_more("through \"%s\".\n", cmd);
X    else
X	print_more("at \"%s\".\n", printer);
X    return 0;
X}
X
X/* save [msg_list] [file] */
save_msg(n, argv, list)   /* argc isn't used, so use space for variable 'n' */
register char **argv, list[];
X{
X    register FILE	*mail_fp;
X    register char 	*file = NULL, *mode, firstchar = **argv, *tmp;
X    int 		msg_number, force;
X    long 		flg = 0;
X
X    if (*++argv && !strcmp(*argv, "-?"))
X	return help(0, "save_help", cmd_help);
X    if (force = (*argv && !strcmp(*argv, "!")))
X	argv++;
X    if ((n = get_msg_list(argv, list)) == -1)
X	return -1;
X    argv += n;
X    if (*argv && *(file = *argv) == '\\')
X	file++;
X    else if (!file) {
X	/* if no filename specified, save in ~/mbox */
X	if (firstchar == 'w') {
X	    /* mbox should have headers. If he really wants it, specify it */
X	    print("Must specify file name for 'w'\n");
X	    return -1;
X	}
X	if (!(file = do_set(set_options, "mbox")) || !*file)
X	    file = DEF_MBOX;
X    }
X    n = 1; /* tell getpath to ignore no such file or directory */
X    tmp = getpath(file, &n);
X    if (n < 0) {
X	print("%s: %s\n", file, tmp);
X	return -1;
X    } else if (n) {
X	print("%s is a directory\n", file);
X	return -1;
X    }
X    file = tmp;
X    if (force || Access(file, F_OK))
X	mode = "w", force = 0;
X    else
X	mode = "a";
X
X    if (!(mail_fp = fopen(file, mode))) {
X	error("cannot save in \"%s\"", file);
X	return -1;
X    }
X#ifdef SUNTOOL
X    if (istool)
X	lock_cursors();
X#endif /* SUNTOOL */
X    turnon(flg, NO_IGNORE);
X    if (firstchar == 'w')
X	turnon(flg, NO_HEADER);
X    else
X	turnon(flg, UPDATE_STATUS);
X    if (do_set(set_options, "keepsave"))
X	firstchar = 'c';
X    for (n = msg_number = 0; msg_number < msg_cnt; msg_number++)
X	if (msg_bit(list, msg_number)) {
X            print("%sing msg %d... ",
X		(firstchar == 's')? "Sav" : "Writ", msg_number+1);
X	    print_more("(%d lines)\n", copy_msg(msg_number, mail_fp, flg));
X	    /* only mark "deleted" if mailfile is /usr/spool/mail and
X	     * we're not "copying.  If keepsave is set, then firstchar
X	     * will have already been changed to 'c'
X	     */
X	    if (!strcmp(mailfile, spoolfile) && firstchar != 'c' &&
X		isoff(glob_flags, READ_ONLY))
X		turnon(msg[msg_number].m_flags, DELETE);
X	    n++;
X	}
X    fclose(mail_fp);
X    print_more("%s %d msg%s to %s\n",
X	    (*mode == 'a')? "Appended" : "Saved", n, (n != 1)? "s": "", file);
X    if (!strcmp(mailfile, spoolfile))
X	turnon(glob_flags, DO_UPDATE);
X#ifdef SUNTOOL
X    if (istool) {
X	unlock_cursors();
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X	add_folder_to_menu(folder_item, 3);
X	add_folder_to_menu(save_item, 1);
X    }
X#endif /* SUNTOOL */
X    return 0;
X}
X
respond(n, argv, list)
register int n;  /* no use for argc, so use its address space for a variable */
register char **argv, *list;
X{
X    register char *cmd = *argv;
X    char list1[MAXMSGS_BITS];
X
X    if (*++argv && !strcmp(*argv, "-?"))
X	return help(0, "respond_help", cmd_help);
X    if ((n = get_msg_list(argv, list)) == -1)
X	return -1;
X    /* make into our own list so ~: commands don't overwrite this list */
X    bitput(list, list1, MAXMSGS, =);
X    /* back up one arg to replace "cmd" in the new argv[0] */
X    argv += (n-1);
X    if (!strcmp(cmd, "replyall"))
X	Upper(*cmd);
X    strdup(argv[0], cmd);
X    current_msg = -1;
X    for (n = 0; n < msg_cnt; n++)
X	if (msg_bit(list1, n)) {
X	    if (current_msg > -1 && istool) {
X		print("tool mode can not respond to multiple messages.");
X		continue;
X	    }
X	    current_msg = n;
X	    set_isread(n);
X	    if (do_mail(1 /* ignored */, argv, list) == -1)
X		return -1;
X	    set_replied(n); /* only if mail got delivered */
X#ifdef SUNTOOL
X	    if (istool)
X		do_hdrs(0, DUBL_NULL, NULL);
X#endif /* SUNTOOL */
X	}
X    return 0;
X}
X
X/* cd to a particular directory specified by "p" */
cd(x, argv) /* argc, unused -- use space for a non-register variable */
register char **argv;
X{
X    char cwd[MAXPATHLEN], buf[MAXPATHLEN];
X    register char *path, *p = argv[1], *cdpath = NULL, *p2;
X#ifdef SYSV
X    char *getcwd();
X#else
X    char *getwd();
X#endif /* SYSV */
X    int err = 0;
X
X    if (!strcmp(*argv, "pwd") && (p = do_set(set_options, "cwd")) && *p) {
X	print("%s\n", p);
X	return -1;
X    }
X    if (!p || !*p) /* if no args, pwd = ".", cd = ~ */
X	p = (**argv == 'p')? "." : "~";
X    /* if a full path was not specified, loop thru cdpath */
X    if (**argv != 'p' && *p != '/' && *p != '~' && *p != '+')
X	cdpath = do_set(set_options, "cdpath");
X    do  {
X	if (cdpath) {
X	    char c;
X	    if (p2 = any(cdpath, " \t"))
X		c = *p2, *p2 = 0;
X	    (void) sprintf(buf, "%s/%s", cdpath, p);
X	    if (cdpath = p2) /* assign and compare to NULL */
X		*p2 = c;
X	    while (cdpath && isspace(*cdpath))
X		cdpath++;
X	} else
X	    (void) strcpy(buf, p);
X	x = 0;
X	path = getpath(buf, &x);
X	if (x != 1 || chdir(path) == -1)
X	    err = errno;
X	else
X	    err = 0;
X    } while (err && cdpath && *cdpath);
X    if (err)
X	error(p);
X#ifdef SYSV
X    if (getcwd(cwd, 128) == NULL)
X#else
X    if (getwd(cwd) == NULL)
X#endif /* SYSV */
X	print("can't get cwd: %s.\n", cwd), err++;
X    else {
X	char **new_argv;
X	(void) sprintf(buf, "set cwd = \"%s\"", cwd);
X	Debug("%s\n", buf);
X	if (new_argv = mk_argv(buf, &x, 1))
X	    (void) add_option(&set_options, new_argv), free_vec(new_argv);
X    }
X    if (istool || iscurses || err) {
X	if (err)
X	    turnon(glob_flags, CONT_PRNT);
X	print("Working dir: %s\n", cwd);
X    }
X    return -1;
X}
X
quit(argc, argv)
char **argv;
X{
X    u_long updated = ison(glob_flags, DO_UPDATE);
X
X    if (argc > 1 && !strcmp(argv[1], "-?"))
X	return help(0, "quit_help", cmd_help);
X    if ((!argc || (*argv && **argv == 'q')) && ison(glob_flags, DO_UPDATE)
X	&& !copyback())
X	return -1;
X#ifdef CURSES
X    if (iscurses) {
X	/* we may already be on the bottom line; some cases won't be */
X	move(LINES-1, 0), refresh();
X	if (updated)
X	    putchar('\n');
X    }
X#endif /* CURSES */
X    cleanup(0);
X#ifdef lint
X    return 0;
X#endif /* lint */
X}
X
delete(argc, argv, list)
register int argc;
register char **argv, list[];
X{
X    register int prnt_next, undel = argc && **argv == 'u';
X    int old_msg = current_msg;
X
X    prnt_next = (argv && (!strcmp(*argv, "dt") || !strcmp(*argv, "dp")));
X
X    if (argc && *++argv && !strcmp(*argv, "-?")) {
X	print("usage: delete/undelete [msg_list]\n");
X	return -1;
X    }
X
X    if (ison(glob_flags, READ_ONLY)) {
X	print("Folder is read-only\n");
X	return -1;
X    }
X
X    if (get_msg_list(argv, list) == -1)
X	return -1;
X    for (argc = 0; argc < msg_cnt; argc++)
X	if (msg_bit(list, argc))
X	    if (undel)
X		turnoff(msg[argc].m_flags, DELETE);
X	    else
X		turnon(msg[argc].m_flags, DELETE);
X
X    /* only if current_msg has been affected && not in curses mode */
X    if (prnt_next == 0 && !iscurses && msg_bit(list, current_msg))
X	prnt_next = !!do_set(set_options, "autoprint"); /* change to boolean */
X
X    turnon(glob_flags, DO_UPDATE);
X
X    /* goto next available message if current was just deleted.
X     * If there are no more messages, turnoff prnt_next.
X     */
X    if (!iscurses && !undel && ison(msg[current_msg].m_flags, DELETE))
X	next_msg();
X
X    if (prnt_next && !undel && !iscurses)
X	if (old_msg != current_msg && isoff(msg[current_msg].m_flags, DELETE))
X	    display_msg(current_msg, (long)0);
X	else
X	    print("No more messages.\n"), current_msg = old_msg;
X#ifdef SUNTOOL
X    if (istool)
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X#endif /* SUNTOOL */
X    return 0;
X}
X
X/*
X * historically from the "from" command in ucb-mail, this just prints
X * the composed header of the messages set in list or in pipe.
X */
do_from(n, argv, list)
char **argv, list[];
X{
X    int inc_cur_msg = 0;
X
X    if (argv && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "from", cmd_help);
X    if (argv && *argv && (!strcmp(*argv, "+") || !strcmp(*argv, "-")))
X	if (!strcmp(*argv, "+")) {
X	    if (!*++argv && current_msg < msg_cnt-1)
X		current_msg++;
X	    inc_cur_msg = 1;
X	} else if (!strcmp(*argv, "-")) {
X	    if (!*++argv && current_msg > 0)
X		current_msg--;
X	    inc_cur_msg = -1;
X	}
X    if (get_msg_list(argv, list) == -1)
X	return -1;
X    for (n = 0; n < msg_cnt; n++)
X	if (msg_bit(list, n)) {
X	    wprint("%s\n", compose_hdr(n));
X	    /* if -/+ given, set current message pointer to this message */
X	    if (inc_cur_msg) {
X		current_msg = n;
X		/* if - was given, then set to first listed message.
X		 * otherwise, + means last listed message -- let it go...
X		 */
X		if (inc_cur_msg < 0)
X		    inc_cur_msg = 0;
X	    }
X	}
X    return 0;
X}
X
X/*
X * Do an ls from the system.
X * Read from a popen and use wprint in case the tool does this command.
X * The folders command uses this command.
X */
ls(x, argv)
char **argv;
X{
X    register char  *p, *tmp;
X    char	   buf[128];
X    register FILE  *pp;
X
X    if (*++argv && !strcmp(*argv, "-?"))
X	return help(0, "ls", cmd_help);
X    if (!(p = do_set(set_options, "lister")))
X	p = "";
X    (void) sprintf(buf, "%s -C%s ", LS_COMMAND, p);
X    p = buf+strlen(buf);
X    for ( ; *argv; ++argv) {
X	x = 0;
X	if (**argv != '-')
X	    tmp = getpath(*argv, &x);
X	else
X	    tmp = *argv;
X	if (x == -1) {
X	    wprint("%s: %s\n", *argv, tmp);
X	    return -1;
X	}
X	p += strlen(sprintf(p, " %s", tmp));
X    }
X    if (!(pp = popen(buf, "r"))) {
X	error(buf);
X	return -1;
X    }
X    turnon(glob_flags, IGN_SIGS);
X    while (fgets(buf, 127, pp))
X	wprint(buf);
X    (void) pclose(pp);
X    turnoff(glob_flags, IGN_SIGS);
X    return 0;
X}
X
sh(un_used, argv)
char **argv;
X{
X    register char *p;
X    char buf[128];
X
X    if (istool > 1 || *++argv && !strcmp(*argv, "-?"))
X	return help(0, "shell", cmd_help);
X    if (!(p = do_set(set_options, "shell"))
X	&& !(p = do_set(set_options, "SHELL")))
X	p = DEF_SHELL;
X    if (!*argv)
X	(void) strcpy(buf, p);
X    else
X	(void) argv_to_string(buf, argv);
X    echo_on();
X    (void) system(buf);
X    echo_off();
X    return 0;
X}
X
static
sorter(cmd1, cmd2)
register struct cmd *cmd1, *cmd2;
X{
X    return strcmp(cmd1->command, cmd2->command);
X}
X
question_mark(x, argv)
char **argv;
X{
X    int n = 0;
X    char *Cmds[50], *p, *malloc(), buf[30];
X
X    qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1,
X			sizeof(struct cmd), sorter);
X
X    if (!*++argv) {
X	for (x = 0; cmds[x].command; x++) {
X	    if (!(x % 5))
X		if (!(p = Cmds[n++] = malloc(80))) {
X		    error("malloc in question_mark()");
X		    free_vec(Cmds);
X		    return -1;
X		}
X	    p += strlen(sprintf(p, "%-11.11s  ", cmds[x].command));
X	}
X	Cmds[n++] = savestr("Type: `command -?' for help with most commands.");
X	Cmds[n] = NULL;
X	(void) help(0, Cmds, NULL);
X	free_vec(Cmds);
X    } else {
X	for (x = 0; cmds[x].command; x++)
X	    if (!strcmp(*argv, cmds[x].command))
X		return cmd_line(sprintf(buf, "%s -?", *argv), msg_list);
X	print("Unknown command: %s\n", *argv);
X    }
X    return -1;
X}
X
X#ifdef SIGSTOP
stop(argc, argv)
char **argv;
X{
X    if (istool)
X	print("Not a tool-based option.");
X    if (argc && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "stop", cmd_help);
X    if (kill(getpid(), SIGTSTP) == -1)
X	error("couldn't stop myself");
X    return -1;
X}
X#endif /* SIGSTOP */
X
extern char **environ;
static int spaces = 0;
X
Setenv(i, argv)
char **argv;
X{
X    char *newstr;
X
X    if (i < 2 || i > 3 || !strcmp(argv[1], "-?"))
X	return help(0, "setenv", cmd_help);
X
X    if (i == 3) {
X	newstr = malloc(strlen(argv[1]) + strlen(argv[2]) + 2);
X	(void) sprintf(newstr, "%s=%s", argv[1], argv[2]);
X    } else {
X	newstr = malloc(strlen(argv[1]) + 2);
X	(void) sprintf(newstr, "%s=", argv[1]);
X    }
X
X    (void) Unsetenv(2, argv);
X
X    for (i = 0; environ[i]; i++);
X    if (!spaces) {
X	char **new_environ = (char **)malloc((i+2) * sizeof(char *));
X	/* add 1 for the new item, and 1 for null-termination */
X	if (!new_environ) {
X	    free(newstr);
X	    return -1;
X	}
X	spaces = 1;
X	for (i = 0; new_environ[i] = environ[i]; i++);
X	xfree(environ);
X	environ = new_environ;
X    }
X    environ[i] = newstr;
X    environ[i+1] = NULL;
X    spaces--;
X    return -1;
X}
X
Unsetenv(n, argv)
char **argv;
X{
X    char **envp, **last;
X
X    if (n != 2 || !strcmp(argv[1], "-?"))
X	return help(0, "unsetenv", cmd_help);
X
X    n = strlen(argv[1]);
X    for (last = environ; *last; last++);
X    last--;
X
X    for (envp = environ; envp <= last; envp++) {
X	if (strncmp(argv[1], *envp, n) == 0 && (*envp)[n] == '=') {
X	    xfree(*envp);
X	    *envp = *last;
X	    *last-- = NULL;
X	    spaces++;
X	}
X    }
X    return -1;
X}
X
Printenv()
X{
X    char **e = environ;
X    while (*e)
X	wprint("%s\n", *e++);
X    return -1;
X}
X
X/*
X * internal stty call to allow the user to change his tty character
X * settings.  sorry, no way to change cbreak/echo modes.  Save echo_flg
X * so that execute() won't reset it.
X */
my_stty(un_used, argv)
char **argv;
X{
X    u_long save_echo = ison(glob_flags, ECHO_FLAG);
X
X    turnon(glob_flags, ECHO_FLAG);
X    execute(argv);
X    if (save_echo)
X	turnon(glob_flags, ECHO_FLAG);
X    else
X	turnoff(glob_flags, ECHO_FLAG);
X
X    savetty();
X#ifdef TIOCGLTC
X    if (ioctl(0, TIOCGLTC, &ltchars))
X	error("TIOCGLTC");
X#endif /* TIOCGLTC */
X    echo_off();
X    return -1;
X}
END_OF_FILE
if test 21317 -ne `wc -c <'commands.c'`; then
    echo shar: \"'commands.c'\" unpacked with wrong size!
fi
# end of 'commands.c'
fi
if test -f 'mush.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mush.h'\"
else
echo shar: Extracting \"'mush.h'\" \(20902 characters\)
sed "s/^X//" >'mush.h' <<'END_OF_FILE'
X/* @(#)mush.h	(c) copyright 1986 (Dan Heller) */
X
X#define VERSION "Mail User's Shell (Vers 6.0) Sat Apr  2 19:36:07 PST 1988"
X
X#include "config.h"
X
X#ifdef CURSES
X#ifdef USG
X#    define _USG
X#    undef USG
X#endif /* USG */
X#include <curses.h>
X#if !defined(USG) && defined(_USG)
X#    define USG
X#    undef _USG
X#endif /* USG && _USG */
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 SUNTOOL
X#    include <suntool/tool_hs.h>
X#else  /* SUNTOOL */
X#    include <sys/types.h>
X#    include <signal.h>
X#    ifndef SYSV
X#        include <sys/time.h>
X#	 include <sys/ioctl.h>   /* for ltchars */
X#    else
X#        include <time.h>
X#        include <fcntl.h>
X#    endif /* SYSV */
X#endif /* SUNTOOL */
X
X#include <sys/stat.h>
X#include <sys/file.h>
X
X#ifdef SUNTOOL
X#    include <suntool/gfxsw.h>
X#    include <suntool/panel.h>
X#    include <suntool/ttysw.h>
X#    include <suntool/ttytlsw.h>
X#    include <suntool/menu.h>
X#    include <suntool/icon_load.h>
X#endif /* SUNTOOL */
X
X/* if no maximum number of files can be found, we'll use getdtablesize() */
X#ifdef _NFILE
X#    define MAXFILES _NFILE
X#else
X#ifdef NOFILE
X#    define MAXFILES NOFILE
X#endif /* NOFILE */
X#endif /* NFILE */
X
X#ifndef CTRL
X#define CTRL(c)		('c' & 037)
X#endif /* CTRL */
X
X#define ESC 		'\033'
X
X#define NO_STRING	""
X#ifdef  NULL
X#undef  NULL
X#endif /* NULL */
X#define NULL		(char *)0
X#define NULL_FILE	(FILE *)0
X#define DUBL_NULL	(char **)0
X#define TRPL_NULL	(char ***)0
X#ifdef putchar
X#undef putchar
X#endif /* putchar */
X#define putchar(c)	fputc(c, stdout)
X#define bell() 		fputc('\007', stderr)
X
X/* 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, interrupt), \
X    oldquit = signal(SIGQUIT, interrupt)
X
X#define off_intr() \
X    turnoff(glob_flags, WAS_INTR), (void) signal(SIGINT, oldint), \
X    (void) signal(SIGQUIT, oldquit)
X
X/* Don't flush input when setting echo or cbreak modes (allow typeahead) */
X#ifdef TIOCSETN
X#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)
unsigned char vmin;
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, stty(0, &_tty))
X#define savetty()  (void) gtty(0, &_tty), 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
typedef 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 cursees 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 */
typedef 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 */
SGTTY _tty;
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) printf
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 */
typedef	unsigned long	u_long;
X#define vfork   fork
X#ifdef SIGCHLD
X#undef SIGCHLD
X#endif /* SIGCHLD */
X#define SIGCHLD SIGCLD
X#endif /* SYSV */
X
X#if !defined(SUNTOOL) && !defined(CURSES)
X
X#define TRUE		  1
X#define FALSE		  0
X#define print		  printf
X#define wprint		  printf
X#define print_more	  printf
X
X#endif /* SUNTOOL && !CURSES */
X
X#ifndef max
X#define max(a,b) (((a) > (b)) ? (a) : (b))
X#define min(a,b) (((a) < (b)) ? (a) : (b))
X#endif /* max */
X
X#if defined(CURSES) && !defined(SUNTOOL)
X#define wprint printf
X#endif /* !SUNTOOL && CURSES */
X
X#if defined(CURSES) || defined(SUNTOOL)
X#define print_more	  turnon(glob_flags, CONT_PRNT), print
void print();		/* printf to window or curses or tty accordingly */
X#endif /* CURSES || SUNTOOL */
X
X#ifdef  SUNTOOL
X
X#define NO_ITEM		  (Panel_item)0
X#define NO_EVENT	  (struct inputevent *)0
X#define TIME_OUT	  60           /* sleep 60 secs between mailchecks */
X#define PIX_XOR		  PIX_SRC ^ PIX_DST
X#define ID 		  event.ie_code
X#define l_width(font)	  fonts[font]->pf_defaultsize.x /* width of letter */
X#define l_height(font)	  fonts[font]->pf_defaultsize.y /* height of letter */
X#define Clrtoeol(w,x,y,f) pw_text(w, x, y, PIX_SRC, fonts[f], blank)
X#define type_cursor(op)   pw_char(msg_win, txt.x,txt.y, op, fonts[curfont],'_')
X
X#define highlight(win,x,y,font,s) \
X    pw_text(win,x,y, PIX_SRC, fonts[font],s), \
X    pw_text(win,x+1,y, \
X	(ison(glob_flags, REV_VIDEO))? PIX_NOT(PIX_SRC): PIX_SRC|PIX_DST, \
X	fonts[font],s)
X
X/* Fonts */
X#define FONTDIR		  "/usr/lib/fonts/fixedwidthfonts"
X#define DEFAULT		  0
X#define SMALL	 	  1
X#define LARGE 		  2
X#define MAX_FONTS	  3
X
X#endif /* SUNTOOL */
X
X/* bits and pieces */
X#define turnon(flg,val)   ((flg) |= ((u_long)1 << ((u_long)(val)-1L)))
X#define turnoff(flg,val)  ((flg) &= ~((u_long)1 << ((u_long)(val)-1L)))
X#define ison(flg,val)     ((u_long)(flg) & ((u_long)1 << ((u_long)(val)-1L)))
X#define isoff(flg,val)    (!ison((flg), (val)))
X#define set_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/* 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		{ 						\
X		    register char *s1 = S1, *s2 = S2; 		\
X		    register int len = Len; 			\
X		    while(len--) 				\
X			*s2++ op *s1++; 			\
X		}
X#define bitput(m1,m2,len,op)	bput(m1, m2, (((len)+7)/8), op)
X
X/* convenience and/or readability */
X#define when		  break;case
X#define otherwise	  break;default
X#define lower(c)	  (isupper(c)? tolower(c): c)
X#define Lower(c)	  (c = lower(c))
X#define upper(c)	  (islower(c)? toupper(c): c)
X#define Upper(c)	  (c = upper(c))
X#define skipspaces(n)     for(p += (n); *p == ' ' || *p == '\t'; ++p)
X#define skipdigits(n)     for(p += (n); isdigit(*p); ++p)
X
X#define NO_FLG		0
X
X/* various flags */
long   glob_flags;	/* global boolean flags thruout the whole program */
X#define DO_UPDATE   1	/* check for changes to avoid unnecessary copyback */
X#define REV_VIDEO   2	/* reverse video for curses or toolmode */
X#define CONT_PRNT   3	/* continue to print (maybe a printf) without a '\n' */
X#define DO_SHELL    4	/* run a shell even if no mail? (true if tool) */
X#define DO_PIPE     5	/* true if commands are piping to another command */
X#define IS_PIPE     6	/* true if commands' "input" is piped from another */
X#define IGN_SIGS    7	/* true if catch() should not longjump */
X#define IGN_BANG    8	/* ignore ! as a history reference (see source()) */
X#define ECHO_FLAG   9	/* if true, echo|cbreak is ON, echo typing (-e) */
X#define IS_GETTING 10	/* true if we're getting input for a letter */
X#define PRE_CURSES 11	/* true if curses will be run, but hasn't started yet */
X#define READ_ONLY  12	/* -r passed to folder() (or main) setting read only */
X#define REDIRECT   13	/* true if stdin is being redirected */
X#define WAS_INTR   14	/* catch interrupts, set this flag (signals.c) */
X#define WARNING    15   /* if set, various warning messages may be printed */
X#define NEW_MAIL   17   /* new mail has arrived; user is busy or in icon mode */
X#define CNTD_CMD   18   /* curses.c -- "...continue..." prompt in curses */
X#define IS_SENDING 19   /* was started to send mail, not to be run as a shell */
X#define MIL_TIME   20	/* if $mil_time is set, use 24hr military time fmt */
X
X#define VERBOSE		1       /* verbose flag for sendmail */
X#define INCLUDE		2       /* include msg in response */
X#define INCLUDE_H	3	/* include msg with header */
X#define EDIT		4	/* enter editor by defualt on mailing */
X#define SIGN		5	/* auto-include ~/.signature in mail */
X#define DO_FORTUNE	6	/* add a fortune at end of msgs */
X
X/* msg flags */
X#define NO_HEADER	7	/* don't print header of message (top, write) */
X#define DELETE		8
X#define OLD	        9
X#define UNREAD		10
X#define UPDATE_STATUS	11	/* change status of msg when copyback */
X#define NO_PAGE		12	/* don't page this message */
X#define INDENT		13	/* indent included msg with string */
X#define NO_IGNORE	14	/* don't ignore headers */
X#define PRESERVE	15      /* preserve in mailbox unless deleted */
X#define TOP		15	/* just print the top of msg (same as pre) */
X#define FORWARD		16	/* Forward messages into the message buffer */
X#define REPLIED		17	/* Messages that have been replied to */
X#define NEW_SUBJECT	18	/* new subject regardless of $ask (mail -s) */
X
X#define	MAXMSGS_BITS	MAXMSGS/sizeof(char)	/* number of bits for bitmap */
X
struct msg {
X    u_long m_flags;
X    long   m_offset;               /* offset in tempfile of msg */
X    long   m_size;                 /* number of bytes in msg */
X    int    m_lines;                /* number of lines in msg */
X} msg[MAXMSGS];
X
struct options {
X    char *option;
X    char *value;
X    struct options *next;
X} *set_options, *aliases, *ignore_hdr, *functions, *fkeys, *own_hdrs;
X#ifdef CURSES
struct options *bindings;
X#endif /* CURSES */
X
struct cmd {
X    char *command;
X    int (*func)();
X};
extern struct cmd ucb_cmds[];
extern struct cmd cmds[], hidden_cmds[];
X#ifdef SUNTOOL
extern struct cmd fkey_cmds[];
X#endif /* SUNTOOL */
X
FILE
X    *tmpf,		/* temporary holding place for all mail */
X    *open_file(),	/* open a file or program for write/append */
X    *popen();		/* this should be in stdio.h */
X
extern char
X    *sys_errlist[],    /* system's list of global error messages */
X#ifdef SUNTOOL
X    *font_files[], 	/* the names of the files fonts are kept in */
X    *alt_fonts[], 	/* fonts to use if first ones don't work */
X#endif /* SUNTOOL */
X    **environ;		/* user's environment variables */
X
extern int errno;	/* global system error number */
jmp_buf jmpbuf;		/* longjmp to jmpbuf on sigs (not in tool) */
X
char
X    debug,		/* debug causes various print statements in code */
X    tempfile[40],	/* path to filename of temporary file */
X    msg_list[MAXMSGS_BITS],	/* MAXMSGS bits of boolean storage */
X    *cmd_help,		/* filename of location for "command -?" commands. */
X    *get_name_n_addr(), /* get name and addr from a well-formed address */
X    *login,		/* login name of user */
X    *mailfile,		/* path to filename of current mailfile */
X    *ourname[MAX_HOST_NAMES],	/* the name and aliases of the current host */
X    *prompt,		/* the prompt string -- may have %d */
X    *escape,		/* the "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    *argv_to_string(),	/* convert a vector of strings into one string */
X    **make_command(),	/* build a command vector (argv) */
X    **mk_argv(),	/* given a string, make a vector */
X    *itoa(),		/* return a string representation of a number */
X    *lcase_strcpy(),	/* just like strcpy, but convert all chars to lower */
X    *variable_stuff(),	/* return information about variables */
X    *no_newln(),	/* remove newline and extra whitespace - return end */
X    *savestr(),		/* strcpy arg into malloc-ed memory; return address */
X    *spoolfile,		/* MAILDIR/$USER in a string -- this is used a lot */
X    *date_to_string(),	/* returns a string described by parse_date() */
X    *msg_date(),	/* return a string of the date of a message */
X    *parse_date(),	/* parse an ascii date, and return message-id str */
X    *Time(),		/* returns string expression of time (takes args) */
X    *do_range(),	/* parse a string converting to a "range" of numbers */
X    *getpath(),		/* static char returning path (expanding ~, +, %, #) */
X    *compose_hdr(),	/* returns a formatted line describing passed msg # */
X    *my_atoi(), 	/* do an atoi, but return the last char parsed */
X    *do_set(),		/* set/unset an option, alias, ignored-hdr */
X    *reply_to(),	/* who do we reply to when responding */
X    *reply_hdr(),	/* compose In-Reply-to: hdr according to format */
X    *cc_to(),     	/* when responding, return str which is the cc-list */
X    *subject_to(),      /* when responding, return str which is the subject */
X    *header_field(),    /* the line in msg described by arg (message header) */
X    *alias_to_address(),/* convert a name[list] to "real" names */
X    *set_header(), 	/* [interactive] proc to set/display to/subject/cc */
X    *getenv(), *prog_name;
X
int
X    last_msg_cnt,	/* when checking for new mail, save the last msg_cnt */
X    msg_cnt,		/* total number of messages */
X    crt,		/* min number of lines msg contains to invoke pager */
X    current_msg,	/* the current message we're dealing with */
X    exec_pid,		/* pid of a command that has been "exec"ed */
X    hist_no,		/* command's history number */
X    iscurses,		/* if we're running curses */
X    istool,		/* argv[0] == "xxxxtool", ranges from 0 to 2 */
X    n_array[128],	/* array of message numbers in the header window */
X    screen,		/* number of headers window can handle */
X
X    quit(), cleanup(), catch(), do_alias(), respond(), cd(), sh(), stop(),
X    folder(), save_msg(), delete(), do_mail(), lpr(), alts(), set(), do_hdrs(),
X    rm_edfile(), pick(), save_opts(), preserve(), sort(), readmsg(),
X    do_pick(), print_help(), folders(), question_mark(), do_from(), my_stty(),
X    do_version(), disp_hist(), source(), do_echo(), sigchldcatcher(), ls(),
X    nopenfiles(), Setenv(), Unsetenv(), Printenv(), bus_n_seg(), msg_flags(),
X    toggle_debug(), stop_start(), interrupt();
X
long
X    still_more,		/* there is still more message to display */
X    spool_size,		/* size of sppol mail regardless of current folder */
X    last_size,		/* the lastsize of the mailfile since last check */
X    time();		/* satisfy lint */
X
void
X    xfree(), free_vec(), error(), getmail(), mail_status(),
X    file_to_fp(), init(), display_msg();
X    /* printf(), fclose(), fflush(), fputs(), fputc() */
X#ifdef TIOCGLTC
struct ltchars ltchars;			/* tty character settings */
X#endif /* TIOCGLTC */
X
X#ifdef CURSES
X
X#define STANDOUT(y,x,s) standout(), mvaddstr(y,x,s), standend()
X#define redraw()	clearok(curscr, TRUE), wrefresh(curscr)
X
int
X    curses_init(),	/* interpret commands via the curses interface */
X    bind_it();		/* bind chars or strings to functions */
X#endif /* CURSES */
X
X#ifdef SUNTOOL
void
X    lock_cursors(), unlock_cursors(), scroll_win(),
X    set_fkeys(), set_key(), toggle_opt(), help_opt();
X
char
X    *rite(),		/* rite a char to msg_win: return string if c == '\n' */
X    *find_key(),	/* pass x,y coords to find which function key assoc. */
X    *key_set_to(),	/* pass fkey string, return string describing func */
X    *panel_get(),      	/* returns what has been typed in a panel item */
X    *tool_help,		/* help for tool-related things (sometimes, overlap) */
X    blank[128];		/* use to clear to end of line */
X
int
X    time_out,		/* time out interval to wait for new mail */
X    rootfd,		/* the root window's fd */
X    parentfd,		/* the parent's window fd */
X    getting_opts,	/* true if getting/setting opts from msg_win */
X    curfont,		/* the current font to use for mail message window */
X    total_fonts,	/* total number of fonts available */
X    get_hdr_field,	/* bitmask of header fields to be gotten */
X
X    msg_io(), msgwin_handlesigwinch(), hdr_io(), hdrwin_handlesigwinch(),
X    sigchldcatcher(), sigtermcatcher(), sigwinchcatcher(), do_sort(),
X    do_compose(), do_edit(), read_mail(), delete_mail(), respond_mail(),
X    do_hdr(), display_hdrs(), print_sigwinch(), p_set_opts(),
X    tool_mgmt(), do_help(), text_done(), msg_num_done(), do_lpr(),
X    toolquit(), change_font(), do_clear(), do_update(),
X    file_dir(), do_file_dir(), do_send(), abort_mail(), check_new_mail(),
X    fkey_cmd(), fkey_settings();
X
struct tchars  tchars;			/* more tty character settings */
X
struct tool *tool;      /* main tool structure */
struct toolsw
X    *panel_sw,		/* main panel subwindow */
X    *hdr_sw, 		/* subwindow for message headers */
X    *hdr_panel_sw,	/* panel for headers */
X    *tty_sw, 		/* subwindow which forks a shell (usually editor) */
X    *print_sw, 		/* subwindow for print statements */
X    *msg_sw; 		/* main subwindow to display messages and more */
X
struct pixwin
X    *msg_win,		/* main pixwin for message display and more */
X    *hdr_win,		/* pixwin for message headers */
X    *print_win;		/* pixwin for printing messages ( print() ) */
X
struct pr_pos txt;   			/* current position of text written */
struct rect msg_rect, hdr_rect;         /* sizes of the main and hdr rects */
struct pixfont *fonts[MAX_FONTS];	/* array of fonts */
X
Panel
X    main_panel,		/* the main panel dealing with generic items */
X    hdr_panel;		/* panel which contains message header specific items */
X
Panel_item
X    abort_item,		/* abort mail in progress */
X    alias_item,		/* set/view/change current mail aliases */
X    cd_item,		/* changes file_item to cd (for cd-ing) */
X    comp_item,		/* compose a letter */
X    delete_item,	/* delete/undelete messages */
X    edit_item,		/* edit a message */
X    font_item,		/* choose which font to use */
X    folder_item,	/* change folders */
X    file_item, 		/* text item for files or directories (forlder/cd) */
X    hdr_display,	/* format message headers are displayed */
X    help_item,		/* choose this to get various help */
X    ignore_item,	/* set/view/change message headers to be ignored */
X    input_item,		/* text item to get values for set/unsetting values */
X    msg_num_item,	/* text item to explicity state which message to read */
X    next_scr,		/* display the next screenful of message headers */
X    option_item,	/* set/view/unset mail options */
X    prev_scr,		/* display the previous screen of messages */
X    print_item,		/* send current message to the printer */
X    quit_item,		/* quit tool/close to icon */
X    read_item,		/* read the current message */
X    respond_item,	/* respond to messages */
X    save_item,		/* saves messages; uses text item input_item */
X    send_item,		/* when composing letter, this will send it off */
X    sort_item,		/* sort routine... */
X    sub_hdr_item[6],	/* display items that just sit there and give help */
X    update_item;	/* commit changes to folder */
X
struct itimerval mail_timer;	/* frequency to check for new mail */
X
X			/* mouse symbols and data */
X/* left, middle and right mouse pixrects */
struct cursor
X    l_cursor, m_cursor, r_cursor, coffee, read_cursor, write_cursor,
X    main_cursor, checkmark;
X
struct pixrect *msg_pix; /* pixrect holding text of a message */
extern struct pixrect mouse_left, mouse_middle, mouse_right;
extern struct pixrect dn_arrow, up_arrow, cycle, shade_50;
X
extern struct icon mail_icon;
X#endif /* SUNTOOL */
X
END_OF_FILE
if test 20902 -ne `wc -c <'mush.h'`; then
    echo shar: \"'mush.h'\" unpacked with wrong size!
fi
# end of 'mush.h'
fi
echo shar: End of archive 8 \(of 14\).
cp /dev/null ark8isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 14 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
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.