[comp.sources.unix] v11i057: Mail user's shell, Part07/12

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

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

#! /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 7 (of 12)."
# Contents:  commands.c misc.c
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'\" \(19548 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
Xstruct 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
Xstruct cmd ucb_cmds[] = {
X    { "t",   readmsg   }, { "n",  readmsg  }, { "p", readmsg  },
X    { "+",   readmsg   }, { "-", readmsg   },
X    { "x",   quit      }, { "q",  quit     },
X    { ":a",  do_hdrs   }, { ":d", 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 },
X    { "pre", preserve  }, { "w",  save_msg },
X    { "R",   respond   }, { "r",   respond },
X    { "reply", respond }, { "respond", respond },
X    { NULL, quit }
X};
X
Xstruct 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
Xtoggle_debug(argc, argv)
Xchar **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
Xstatic
Xsorter(cmd1, cmd2)
Xregister struct cmd *cmd1, *cmd2;
X{
X    return strcmp(cmd1->command, cmd2->command);
X}
X
Xsort_commands()
X{
X    qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1,
X			sizeof(struct cmd), sorter);
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 */
Xreadmsg(x, argv, list)
Xregister char **argv, list[];
X{
X    register char *p = x? *argv : NULL;
X    register long flg = 0;
X
X    if (x && *++argv && !strcmp(*argv, "-?"))
X	return help(0, "readmsg", cmd_help);
X#ifdef NOT_NOW
X    if (ison(glob_flags, IS_GETTING)) {
X	print("Finish editing your letter first.\n");
X	return -1;
X    }
X#endif NOT_NOW
X    if (!msg_cnt) {
X	print("No messages.\n");
X	return -1;
X    }
X    if (x && !strcmp(p, "top"))
X	turnon(flg, TOP);
X    if (p && (*p == '+')) {
X	turnon(flg, NO_PAGE);
X	turnon(flg, NO_HEADER);
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.  Stop at the end (don't wrap). Not the greatest way to
X	     * do it, but people complain if it doesn't do it.
X	     */
X#ifdef NOT_ANYMORE
X	    if (current_msg == msg_cnt) /* wrap around */
X		current_msg = 0;
X#endif NOT_ANYMORE
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
Xpreserve(n, argv, list)
Xregister int n;		/* no use for argc, so use space for a local variable */
Xregister 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		turnoff(msg[n].m_flags, PRESERVE);
X	    else {
X		turnon(msg[n].m_flags, PRESERVE);
X		turnoff(msg[n].m_flags, DELETE);
X	    }
X    if (istool)
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    return 0;
X}
X
Xlpr(n, argv, list)
Xregister int n;  /* no use for argc, so use its address space for a variable */
Xregister 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] */
Xsave_msg(n, argv, list)   /* argc isn't used, so use space for variable 'n' */
Xregister 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, 0))
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 (is_spool(mailfile) && firstchar != 'c')
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 (is_spool(mailfile))
X	turnon(glob_flags, DO_UPDATE);
X#ifdef SUNTOOL
X    if (istool) {
X	unlock_cursors();
X	(void) do_hdrs(0, DUBL_NULL, NULL);
X    }
X#endif SUNTOOL
X    return 0;
X}
X
Xrespond(n, argv, list)
Xregister int n;  /* no use for argc, so use its address space for a variable */
Xregister 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, argv) == -1) /* do_mail doesn't look at argc */
X		return -1;
X	}
X    return 0;
X}
X
X/* cd to a particular directory specified by "p" */
Xcd(x, argv) /* argc, unused -- use space for a non-register variable */
Xregister char **argv;
X{
X    char *tmp, cwd[128], *p = argv[1];
X#ifdef SYSV
X    char *getcwd();
X#else
X    char *getwd();
X#endif SYSV
X    int err = 0;
X
X    if (!strcmp(*argv, "pwd")) {
X	p = do_set(set_options, "cwd");
X	if (p && *p) {
X	    print("%s\n", p);
X	    return -1;
X	}
X    }
X    if (!p || !*p)
X	p = (**argv == 'p')? "." : "~";
X    x = 0;
X    tmp = getpath(p, &x);
X    if (x == -1)
X        print("%s: %s.\n", p, tmp), err++;
X    else if (!x)
X        print("%s: not a directory.\n", tmp), err++;
X    else if (chdir(tmp))
X        error("can't chdir to %s", tmp), err++;
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, buf[256];
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
Xquit(argc, argv)
Xchar **argv;
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    }
X#endif CURSES
X    cleanup(0);
X#ifdef lint
X    return 0;
X#endif lint
X}
X
Xdelete(argc, argv, list)
Xregister int argc;
Xregister char **argv, list[];
X{
X    register int prnt_next, undel = argc && **argv == 'u';
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 (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(FALSE, DELETE) && prnt_next)
X	    prnt_next = 0;
X
X    if (prnt_next)
X	display_msg(current_msg, (long)0);
X    if (istool)
X	(void) do_hdrs(0, DUBL_NULL, NULL);
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 */
Xdo_from(n, argv, list)
Xchar **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 */
Xls(x, argv)
Xchar **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
Xsh(un_used, argv)
Xchar **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
Xquestion_mark(x, argv)
Xchar **argv;
X{
X    int n = 0;
X    char *Cmds[50], *p, *malloc(), buf[30];
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
Xstop(argc, argv)
Xchar **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
Xextern char **environ;
Xstatic int spaces = 0;
X
XSetenv(i, argv)
Xchar **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
XUnsetenv(n, argv)
Xchar **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
XPrintenv()
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 */
Xmy_stty(un_used, argv)
Xchar **argv;
X{
X    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 19548 -ne `wc -c <'commands.c'`; then
    echo shar: \"'commands.c'\" unpacked with wrong size!
fi
# end of 'commands.c'
fi
if test -f 'misc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'misc.c'\"
else
echo shar: Extracting \"'misc.c'\" \(21487 characters\)
sed "s/^X//" >'misc.c' <<'END_OF_FILE'
X/* @(#)misc.c	(c) copyright 10/18/86 (Dan Heller) */
X
X#include "mush.h"
X
X/* check to see if a string describes a message that is within the range of
X * all messages; if invalid, return 0 and print error. else return msg number
X */
Xchk_msg(s)
Xregister char *s;
X{
X    register int n;
X
X    if ((n = atoi(s)) > 0 && n <= msg_cnt)
X	return n;
X    else if (*s == '^' && msg_cnt)
X	return 1;
X    else if (*s == '$' && msg_cnt)
X	return msg_cnt;
X    else if (*s == '.' && msg_cnt)
X	return current_msg+1;
X    print("Invalid message number: %s\n", s);
X    return 0;
X}
X
X/*
X * loop thru all msgs starting with current_msg and find next message whose
X * m_flags has the "flags" bit being on
X */
Xnext_msg(on, flags)
X{
X    register int n = current_msg;
X    if (!msg_cnt)
X	return current_msg = 0;
X    for (n++; n != current_msg; n++)
X	if (n == msg_cnt)     /* hit the end, start back at the beginning */
X	    n = -1; /* increments to 0 in  loop  */
X	else if (isoff(msg[n].m_flags, DELETE) &&
X		((on && ison(msg[n].m_flags, flags)) ||
X		(!on && isoff(msg[n].m_flags, flags))))
X	    return current_msg = n;
X    return current_msg = 0;
X}
X
X/* takes string 'p' and address of int (isdir).  If p uses the ~ to reference
X * a home directory of somesort, then expand it.  find out what sort of
X * file final path is. set isidr to 1 if a directory, 0 if not, -1 on error
X * return final path. If an error occurrs, return string indicating error.
X * if isdir has a value of 1 when passed, it ignores "No such file or directory"
X */
X#include <pwd.h>
Xchar *
Xgetpath(p, isdir)
Xregister char *p;
Xint *isdir;
X{
X    static char buf[256];
X    struct stat stat_buf;
X
X    if (!p || !*p || !strcmp(p, "~")) {
X	char *home = do_set(set_options, "home");
X	if (!home || !*home)
X	    home = ALTERNATE_HOME;
X	(void) strcpy(buf, home);  /* no arg means home */
X    } else if (*p == '~') {
X	if (p[1] != '/') {
X	    /* not our home, but someone else's
X	     * look for ~user or ~user/subpath
X	     * if '/' exists, separate into tmp="user" p="subpath"
X	     */
X	    struct passwd *ent, *getpwnam();
X	    char *p2 = p+1;
X	    if (p = index(p2, '/'))
X		*p++ = 0;
X	    if (!(ent = getpwnam(p2))) {
X		*isdir = -1;
X		return sprintf(buf, "no such user: %s", p2);
X	    }
X	    /* append subpath to pathname */
X	    if (p && *p)
X		(void) sprintf(buf, "%s/%s", ent->pw_dir, p);
X	    /* if *p == NULL, pathname is done (buf), set isdir = 1 */
X	    else {
X		*isdir = 1;
X		return strcpy(buf, ent->pw_dir);
X	    }
X	} else {
X	    char *home = do_set(set_options, "home");
X	    if (!home || !*home)
X		home = ALTERNATE_HOME;
X	    (void) sprintf(buf, "%s/%s", home, p+2);
X	}
X    } else if (*p == '%') {
X	/* if %user, append user name... else, it's just us */
X	(void) sprintf(buf, "%s/", MAILDIR);
X	if (!*++p || *p == ' ' || *p == '\t')
X	    (void) strcat(buf, login);
X	else
X	    (void) strcat(buf, p);
X    } else if (*p == '+') {
X	register char *p2 = do_set(set_options, "folder");
X	if (p2 && *p2)
X	    (void) sprintf(buf, "%s/%s", p2, ++p);
X	else
X	    (void) sprintf(buf, "~/%s", p);
X	if (*buf == '~') {
X	    int t_isdir = *isdir;
X	    char *t, tmp[256];
X	    (void) strcpy(tmp, buf);
X	    t = getpath(tmp, &t_isdir);
X	    if (t_isdir == -1) {
X		*isdir = -1;
X		return t;
X	    }
X	    /* strcpy(buf, t); --buf already has info because it's static */
X	}
X    } else {  /* allow \ to escape the special chars, +, %, ~ */
X	if (*p == '\\')
X	    p++;
X	(void) strcpy(buf, p);
X    }
X    if (stat(buf, &stat_buf)) {
X	(void) access(buf, 0); /* set errno to the "real" reason */
X	if (errno == ENOENT && *isdir == 1) {
X	    *isdir = 0; /* say it's a regular file even tho it doesn't exist */
X	    return buf; /* it may be wanted for creating */
X	}
X	*isdir = -1;
X	return sys_errlist[errno];
X    }
X    *isdir = ((stat_buf.st_mode & S_IFDIR) != 0);
X    return buf;
X}
X
X/*
X * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
X * opens the file with the mode.
X * If the mode is "r" then we read the file into the file pointer at the
X * end (fseek(fp, 2, 0)).  If the file is opened for writing, then read
X * from the beginning of fp and write it into the file.
X * This is usually called to read .signatures into messages (thus,
X * opening .signture with "r" and writing to the end of fp which is probably
X * the sendmail process or the message file pointer) or to write fortunes into
X * the message buffer: reading fp (the popened fortune) and writing into file.
X */
Xvoid
Xfile_to_fp(p, fp, mode)
Xregister char *p;
Xregister FILE *fp;
Xchar *mode;
X{
X    int 	x = 1;
X    char 	*file, buf[BUFSIZ];
X    FILE 	*tmp_fp;
X
X    if (!p || !*p) {
X	print("specify filename");
X	return;
X    }
X    file = getpath(p, &x);
X    if (x == -1) { /* on error, file contains error message */
X	wprint(file);
X	return;
X    }
X    wprint("%s: ", file), fflush(stdout);
X    if (x)   /* if x == 1, then path is a directory */
X	wprint("directory.\n");
X    else if (!(tmp_fp = fopen(file, mode))) {
X	wprint("%s\n", sys_errlist[errno]);
X	return;
X    } else if (*mode != 'r') {
X	rewind(fp);
X	for(x = 0; fgets(buf, BUFSIZ, fp); x++)
X	    fputs(buf, tmp_fp);
X    } else
X	for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
X	    fputs(buf, fp);
X    wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
X				  x, (x == 1)? "": "s");
X    fflush(fp);
X    fclose(tmp_fp);
X}
X
X/*
X * lose the newline character, trailing whitespace, and return the end of p
X * test for '\n' separately since some _ctype_[] arrays may not have the
X * _S bit set for the newline character.  see <ctype.h> for more info.
X */
Xchar *
Xno_newln(p)
Xregister char *p;
X{
X    register char *p2 = p + strlen(p);	/* point it to the null terminator */
X
X    while (p2 > p && *--p2 == '\n' || isspace(*p2))
X	*p2 = 0;  /* get rid of newline and trailing spaces */
X    return p2;
X}
X
X/* find any character in string2 that's in string1 */
Xchar *
Xany(s1, s2)
Xregister char *s1, *s2;
X{
X    register char *p;
X    if (!s1 || !*s1 || !s2 || !*s2)
X	return NULL;
X    for( ; *s1; s1++) {
X	for(p = s2; *p; p++)
X	    if (*p == *s1)
X		return s1;
X    }
X    return NULL;
X}
X
X/* since print_help just prints help, always return help() */
Xprint_help(argc, argv)
Xregister char **argv;
X{
X#ifdef SUNTOOL
X    if (istool)
X	return help(tool->tl_windowfd, "general", tool_help);
X#endif SUNTOOL
X    if (!argc || !*++argv)
X	return help(0, "general", cmd_help);
X    return help(0, *argv, cmd_help);
X}
X
X/* since this function does not affect messages, return -1 */
Xhelp(fd, str, file)
X#ifdef SUNTOOL
Xcaddr_t *str;
X#else
Xchar *str;
X#endif /* SUNTOOL */
Xchar *file;
X{
X#ifdef SUNTOOL
X    if (istool > 1) {
X	int oldmask;
X	if (!fd)
X	    fd = print_sw->ts_windowfd;
X	oldmask = sigblock(1 << ((SIGALRM) - 1));
X	lock_cursors();
X	if (display_help(fd, str, file, fonts[LARGE]) && file)
X	    error("can't read %s", file);
X	unlock_cursors();
X	(void) sigsetmask(oldmask);
X    } else
X#endif SUNTOOL
X    if (find_help(str, file) && file)
X	error("can't read %s", file);
X    return -1; /* doesn't affect any messages */
X}
X
X#ifdef SUNTOOL
Xvoid
Xunlock_cursors()
X{
X    if (istool < 2)
X	return;
X    win_setcursor(print_sw->ts_windowfd, &main_cursor);
X    win_setcursor(panel_sw->ts_windowfd, &main_cursor);
X    if (getting_opts)
X	win_setcursor(msg_sw->ts_windowfd, &checkmark);
X    else if (ison(glob_flags, IS_GETTING))
X	win_setcursor(msg_sw->ts_windowfd, &write_cursor);
X    else
X	win_setcursor(msg_sw->ts_windowfd, &read_cursor);
X    win_setcursor(hdr_panel_sw->ts_windowfd, &main_cursor);
X    win_setcursor(hdr_sw->ts_windowfd, &l_cursor);
X}
X
Xvoid
Xlock_cursors()
X{
X    if (istool < 2)
X	return;
X    win_setcursor(hdr_sw->ts_windowfd, &coffee);
X    win_setcursor(print_sw->ts_windowfd, &coffee);
X    win_setcursor(panel_sw->ts_windowfd, &coffee);
X    win_setcursor(msg_sw->ts_windowfd, &coffee);
X    win_setcursor(hdr_panel_sw->ts_windowfd, &coffee);
X}
X
X#include <suntool/fullscreen.h>
X/* return the event-id that confirmed */
Xconfirm(fd)
X{
X    struct fullscreen *fs;
X
X    struct inputmask im;
X    struct inputevent event;
X
X    fs = fullscreen_init(fd);
X    input_imnull(&im);
X    im.im_flags |= IM_ASCII;
X    win_setinputcodebit(&im, MS_LEFT);
X    win_setinputcodebit(&im, MS_MIDDLE);
X    win_setinputcodebit(&im, MS_RIGHT);
X    win_setinputmask(fd, &im, &im, WIN_NULLLINK);
X    win_setcursor(fd, &l_cursor);
X    if (input_readevent(fd, &event) == -1)
X	error("confim failed");
X    fullscreen_destroy(fs);
X    return ID;
X}
X#endif SUNTOOL
X
X/* check two lists of strings each of which contain substrings.
X * Each substring is delimited by any char in "delimeters"
X * return true if any elements in list1 are on list2.
X * thus:
X * string1 = "foo, bar, baz"
X * string2 = "foobar, baz, etc"
X * delimeters = ", \t"
X * example returns 1 because "baz" exists in both lists
X * NOTE: case is ignored.
X */
Xchk_two_lists(list1, list2, delimeters)
Xregister char *list1, *list2, *delimeters;
X{
X    register char *p, c;
X    register int found = 0;
X
X    if (p = any(list1, delimeters)) {
X	for (p++; *p && index(delimeters, *p); p++)
X	    ;
X	if (chk_two_lists(p, list2, delimeters))
X	    return 1;
X    }
X    if (p = any(list2, delimeters)) {
X	for (p++; *p && index(delimeters, *p); p++)
X	    ;
X	if (chk_two_lists(list1, p, delimeters))
X	    return 1;
X    }
X    if (p) {
X	while (index(delimeters, *(p-1)))
X	    --p;
X	c = *p, *p = 0;
X    }
X    found = !lcase_strcmp(list1, list2);
X    if (p)
X	*p = c;
X    return found;
X}
X
Xbzero(addr, size)
Xregister char *addr;
Xregister int size;
X{
X    while (size-- > 0)
X	addr[size] = 0;
X}
X
X/* see if there are at least Max lines in this file. return lines less than Max
X * that actually *are* in the file
X */
Xlines_in(fp, Max)
Xregister FILE *fp;
Xregister int Max;
X{
X    char tmp[BUFSIZ];
X    long place_in_fp = ftell(fp);
X    rewind(fp);
X    while (Max > 0 && fgets(tmp, BUFSIZ, fp))
X	Max--;
X    (void) fseek(fp, place_in_fp, 0);
X    return Max;
X}
X
X/* clear all contents of the file.  Careful that the file is opened for
X * _writing_ --tempfile is opened for reading, so don't try to empty it
X * if you're using ftruncate.   Return -1 on error, 0 on success.
X */
Xemptyfile(fp, fname)
Xregister FILE **fp;
Xregister char *fname;
X{
X    Debug("Emptying \"%s\"\n", fname);
X#ifndef SYSV
X    return ftruncate(fileno(*fp), 0);
X#else
X    {
X	int omask = umask(077), ret;
X	fclose(*fp);
X	if (!(*fp = fopen(fname, "w")))
X	    ret = -1;
X	ret = 0;
X	(void) umask(omask);
X	return ret;
X    }
X#endif SYSV
X}
X
X/* do an atoi() on the string passed and return in "val" the decimal value.
X * the function returns a pointer to the location in the string that is not
X * a digit.
X */
Xchar *
Xmy_atoi(p, val)
Xregister char *p;
Xregister int *val;
X{
X    if (!p)
X	return NULL;
X    *val = 0;
X    while (isdigit(*p))
X	*val = (*val) * 10 + *p++ - '0';
X    return p;
X}
X
X/* strcmp ignoring case */
Xlcase_strcmp(str1, str2)
Xregister char *str1, *str2;
X{
X    while (*str1 && *str2)
X	if (lower(*str1) != lower(*str2))
X	    break;
X	else
X	    str1++, str2++;
X    return *str1 - *str2;
X}
X
X/* strcpy coverting everything to lower case (arbitrary) to ignore cases */
Xchar *
Xlcase_strcpy(dst, src)
Xregister char *dst, *src;
X{
X    register char *s = dst;
X
X    /* "lower" is a macro, don't incrment its argument! */
X    while (*dst++ = lower(*src))
X	src++;
X    return s;
X}
X
X/* this strcpy returns number of bytes copied */
XStrcpy(dst, src)
Xregister char *dst, *src;
X{
X    register int n = 0;
X    if (!dst || !src)
X	return 0;
X    while (*dst++ = *src++)
X	n++;
X    return n;
X}
X
Xvoid
Xxfree(cp)
Xchar *cp;
X{
X    extern char end[];
X
X    if (cp >= end && cp < (char *) &cp && debug < 2)
X	free(cp);
X}
X
Xchar *
Xsavestr(s)
Xregister char *s;
X{
X    register char *p;
X    char *malloc();
X    if (!s)
X	s = "";
X    if (!(p = malloc((unsigned) (strlen(s) + 1)))) {
X	error("out of memory saving %s", s);
X	return NULL;
X    }
X    return strcpy(p, s);
X}
X
Xvoid
Xfree_vec(argv)
Xchar **argv;
X{
X    register int n;
X    if (!argv)
X	return;
X    for (n = 0; argv[n]; n++)
X	xfree(argv[n]);
X    xfree((char *)argv);
X}
X
X/* copy a vector of stirngs into one string -- return the end of the string */
Xchar *
Xargv_to_string(p, argv)
Xregister char *p, **argv;
X{
X    register int i;
X    register char *ptr = p;
X
X    *p = 0;
X    if (!argv[0])
X	return "";
X    for (i = 0; argv[i]; i++)
X	ptr += strlen(sprintf(ptr, "%s ", argv[i]));
X    *--ptr = 0;   /* get rid of the last space */
X    return ptr;
X}
X
X/* echo the command line. return -1 cuz no messages are affected */
Xdo_echo(argc, argv)
Xregister char **argv;
X{
X    char buf[BUFSIZ];
X    int no_return;
X
X    if (argc > 1 && !strcmp(argv[1], "-?")) {
X	print("usage: %s [-n] ...\n", *argv);
X	return -1;
X    }
X    no_return = *++argv && !strcmp(*argv, "-n");
X    (void) argv_to_string(buf, argv+no_return);
X    print("%s%s", buf, (no_return)? "" : "\n");
X    return -1;
X}
X
X/* return -1 on error or number of arguments in argv that were parsed */
Xget_msg_list(argv, list)
Xregister char **argv;
Xchar list[];
X{
X    register char *p2, *p;
X    char buf[256];
X    register int n;
X
X    if (!msg_cnt) {
X	print("No messages.\n");
X	return -1;
X    }
X    if (!argv || !*argv) {
X	if (isoff(glob_flags, IS_PIPE))
X	    set_msg_bit(list, current_msg);
X	return 0;
X    }
X    /* first, stuff argv's args into a single char array buffer */
X    (void) argv_to_string(buf, argv);
X    p = buf;
X    Debug("get_msg_list: parsing: (%s): ", p);
X    /*
X     * if do_range returns NULL, an invalid message was specified
X     */
X    if (!(p2 = do_range(p, list)))
X	return -1;
X    /*
X     * if p2 == p (and p isn't $ or ^ or .), then no message list was
X     * specified.  set the current message in such cases if we're not piping
X     */
X    if (p2 == p) {
X	if (*p == '$')
X	    set_msg_bit(list, msg_cnt-1);
X	else if (*p == '^')
X	    set_msg_bit(list, 0);
X	else if (*p == '.' || isoff(glob_flags, IS_PIPE))
X	    set_msg_bit(list, current_msg);
X    } else if (ison(glob_flags, IS_PIPE)) {
X	print("You can't pipe to a command *and* specifiy a msg_list\n");
X	return -1;
X    }
X    for (n = 0; p2 > p && *argv; n++)
X	p2 -= (strlen(*argv++)+1);
X    Debug("parsed %d args\n", n);
X    return n;
X}
X
Xchar *
Xitoa(n)
X{
X    static char buf[10];
X    return sprintf(buf, "%d", n);
X}
X
X#ifdef NOT_NEEDED_NOW
X/* return whether or not this process is in the foreground or background */
Xforeground()
X{
X#ifdef TIOCGPGRP
X    int tpgrp;	/* short in 4.1, int in 4.2 */
X
X    if (ioctl(0, TIOCGPGRP, (char *)&tpgrp))
X	return 0;
X    return tpgrp == getpgrp(0);
X#else
X    return 1;
X#endif TIOCGPGRP
X}
X#endif NOT_NEEDED_NOW
X
X#ifdef SYSV
Xchar *
XSprintf(buf, fmt, args)
Xregister char *buf, *fmt;
X{
X    vsprintf(buf, fmt, &args);
X    return buf;
X}
X#endif /* SYSV */
X
X/*
X * Finds out how many file descriptors are opened.  Useful for making sure
X * no files got opened in subprocedures which were not subsequently closed.
X */
Xnopenfiles(argc)
X{
X    register int nfiles = 0;
X#ifdef MAXFILES
X    register int size = MAXFILES;
X#else
X    register int size = getdtablesize();
X#endif MAXFILES
X
X    if (argc < 2)
X	print("open file descriptors:");
X    while (--size >= 0)
X        if (fcntl(size, F_GETFL, 0) != -1) {
X	    if (argc < 2)
X		print_more(" %d", size);
X            ++nfiles;
X        }
X    if (argc < 2)
X	print("\n");
X    return nfiles;
X}
X
X/*
X * Open a path for writing or appending -- return a FILE pointer.
X * If program is TRUE, then use popen, not fopen and don't check 
X * to see if the file is writable.
X */
XFILE *
Xopen_file(p, program)
Xregister char *p;
X{
X    register FILE *newfile = NULL_FILE;
X    register char *tmp;
X    int x = 1;
X
X    tmp = getpath(p, &x);
X    if (x == 1)
X	print("%s is a directory.\n", tmp);
X    else if (x == -1)
X	print("%s: %s\n", p, tmp);
X    else {
X	register char *mode = NULL;
X	/* if it doesn't exist open for "w" */
X	if (program || access(tmp, 0))
X	    mode = "w";
X	/* if we can't write to it, forget it */
X	else if (access(tmp, 2))
X	    error(tmp);
X	else
X	    mode = "a";
X	if (mode)
X	    if (program) {
X		if (!(newfile = popen(tmp, mode))) {
X		    error("Can't execute %s\n", tmp);
X		    return newfile;
X		}
X	    } else
X		if (!(newfile = fopen(tmp, mode)))
X		    error("Can't write to %s", tmp);
X	    else
X		Debug("Successfully opened %s\n", tmp);
X    }
X    return newfile;
X}
X
X/*
X * find_files gets a string of space/comma delimeted words and an array of
X * file pointers and the maximum size that array can be.
X * The object is to find the files or programs listed in "p", attempt
X * to fopen/popen them and save their filepointers in the array. If the
X * size is 0, then just extract the file names and give error messages
X * for each one since they will not be opened. Return the number of
X * files opened and delete all files (opened or not) from the list in
X * "p".  Tokens beginning with a "/, ~, or + are files; tokens beginning
X * with a | are programs.
X */
Xfind_files(p, files, size)
Xregister char *p;
XFILE *files[];
X{
X    register int     total = 0;
X    char 	     file[BUFSIZ], *start = p;
X    register char    *p2, *s;
X
X    for (s = p; p = any(s, "~+/|"); s = p) {
X	int prog = 0;
X
X	/* If there is no space or comma before this address, then
X	 * it's not the beginning of an address, but part of another.
X	 * Ignore this addres and continue to the next in the list.
X	 */
X	if (p > start && *(p-1) != ',' && !isspace(*(p-1))) {
X	    p++; /* prevent inifinite loop -- resume starting at next char */
X	    continue;
X	}
X
X	/* get the whole filename, stick it in "file" */
X	if (p2 = any(p, ", \t"))
X	    *p2++ = '\0';
X	else
X	    p2 = p + strlen(p);
X	(void) strcpy(file, p);
X	/* overwrite the filename in the string with whatever proceeds it */
X	while (isspace(*p2)) /* move to the next address (or end of string) */
X	    p2++;
X	if (*p2)
X	    (void) strcpy(p, p2);
X	else
X	    do
X		*p = '\0';
X	    while (--p >= start && (isspace(*p) || *p == ','));
X
X	if (*file == '|')
X	    prog = 1; /* it's a program name */
X	if (size && total < size) {
X	    /* either open "file" or &file[1] */
X	    if (files[total] = open_file(&file[prog], prog))
X		total++;
X	} else
X	    print("No open space for %s\n", file);
X	skipspaces(0);
X    }
X    return total;
X}
X
X/*
X * execute a command from a string.  f'rinstance: "pick -f foobar"
X * The string is made into an argv and then run.  Errors are printed
X * if the command failed to make.
X *   NOTES:
X *     NEVER pass stright text: e.g. "pick -f foobar", ALWAYS strcpy(buf, "...")
X *     no history is expanded (ignore_bang).
X */
Xcmd_line(buf, list)
Xchar buf[], list[];
X{
X    register char **argv;
X    int argc, ret_val = -1;
X    long save_bang = ison(glob_flags, IGN_BANG);
X    long save_do_pipe = ison(glob_flags, DO_PIPE);
X    long save_is_pipe = ison(glob_flags, IS_PIPE);
X
X    turnon(glob_flags, IGN_BANG);
X    turnoff(glob_flags, DO_PIPE);
X    turnoff(glob_flags, IS_PIPE);
X    if (argv = make_command(buf, TRPL_NULL, &argc))
X	ret_val = do_command(argc, argv, list);
X    if (!save_bang)
X	turnoff(glob_flags, IGN_BANG);
X    if (save_do_pipe)
X	turnon(glob_flags, DO_PIPE);
X    if (save_is_pipe)
X	turnon(glob_flags, IS_PIPE);
X    return ret_val;
X}
X
Xglob_test(s)
Xchar *s;
X{
X    print("%s: glob_flags =", s);
X    if (ison(glob_flags, DO_UPDATE))
X	print_more(" DO_UPDATE");
X    if (ison(glob_flags, REV_VIDEO))
X	print_more(" REV_VIDEO");
X    if (ison(glob_flags, CONT_PRNT  ))
X	print_more(" CONT_PRNT");
X    if (ison(glob_flags, DO_SHELL    ))
X	print_more(" DO_SHELL");
X    if (ison(glob_flags, DO_PIPE))
X	print_more(" DO_PIPE");
X    if (ison(glob_flags, IS_PIPE))
X	print_more(" IS_PIPE");
X    if (ison(glob_flags, IGN_SIGS))
X	print_more(" IGN_SIGS");
X    if (ison(glob_flags, IGN_BANG))
X	print_more(" IGN_BANG");
X    if (ison(glob_flags, ECHO_FLAG))
X	print_more(" ECHO_FLAG");
X    if (ison(glob_flags, IS_GETTING))
X	print_more(" IS_GETTING");
X    if (ison(glob_flags, PRE_CURSES))
X	print_more(" PRE_CURSES");
X    if (ison(glob_flags, READ_ONLY  ))
X	print_more(" READ_ONLY");
X    if (ison(glob_flags, REDIRECT))
X	print_more(" REDIRECT");
X    if (ison(glob_flags, WAS_INTR ))
X	print_more(" WAS_INTR");
X    if (ison(glob_flags, WARNING   ))
X	print_more(" WARNING");
X    print_more("\n");
X}
X
Xis_spool(f)
Xregister char *f;
X{
X    return !strncmp(f, MAILDIR, strlen(MAILDIR));
X}
X
Xprint_argv(argv)
Xchar **argv;
X{
X    while (*argv)
X	if (debug)
X	    printf("(%s) ", *argv++);
X	else
X	    wprint("%s ", *argv++);
X    if (debug) {
X	putchar('\n');
X	fflush(stdout);
X    } else
X	wprint("\n");
X}
X
Xmsg_flags(c, v, list)
Xregister char **v, *list;
X{
X    register int	i;
X    register long	newflag = 0;
X
X    if (c && *++v && !strcmp(*v, "-?"))
X	return help(0, "msg_flags", cmd_help);
X    if (c && (c = get_msg_list(v, list)) == -1)
X	return -1;
X    if (v && *(v += (c-1))) {
X	turnon(glob_flags, DO_UPDATE);
X	while (*++v)
X	    for (c = 0; v[0][c]; c++)
X		switch (lower(v[0][c])) {
X		    case 'n' : turnon(newflag, UNREAD), turnoff(newflag, OLD);
X		    when 'o' : turnon(newflag, OLD);
X		    when 'r' : turnoff(newflag, UNREAD);
X		    when 'd' : turnon(newflag, DELETE);
X		    when 'p' : turnon(newflag, PRESERVE);
X		    when 'u' : turnon(newflag, UNREAD);
X		    otherwise: return help(0, "msg_flags", cmd_help);
X		}
X    }
X
X    for (i = 0; i < msg_cnt; i++) {
X	if (!msg_bit(list, i))
X	    continue;
X	else if (!newflag) {
X	    wprint("msg %d: offset: %d, lines: %d, bytes: %d, flags:", i+1,
X		msg[i].m_offset, msg[i].m_lines, msg[i].m_size);
X	    if (ison(msg[i].m_flags, UNREAD))
X		wprint(" UNREAD");
X	    if (ison(msg[i].m_flags, OLD))
X		wprint(" OLD");
X	    if (ison(msg[i].m_flags, DELETE))
X		wprint(" DELETE");
X	    if (ison(msg[i].m_flags, PRESERVE))
X		wprint(" PRESERVE");
X	    if (ison(msg[i].m_flags, UPDATE_STATUS))
X		wprint(" UPDATE_STATUS");
X	    wprint("\n");
X	} else
X	    msg[i].m_flags = newflag;
X    }
X    return 0;
X}
END_OF_FILE
if test 21487 -ne `wc -c <'misc.c'`; then
    echo shar: \"'misc.c'\" unpacked with wrong size!
fi
# end of 'misc.c'
fi
echo shar: End of archive 7 \(of 12\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 12 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exi/+}