home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-05-06 | 53.7 KB | 1,805 lines |
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # If this archive is complete, you will see the following message at the end:
- # "End of archive 14 (of 19)."
- # Contents: mush/bind.c mush/folders.c mush/signals.c
- # Wrapped by argv@turnpike on Wed May 2 13:59:44 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'mush/bind.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/bind.c'\"
- else
- echo shar: Extracting \"'mush/bind.c'\" \(20570 characters\)
- sed "s/^X//" >'mush/bind.c' <<'END_OF_FILE'
- X/* bind.c */
- X
- X#include "bindings.h"
- X#include "mush.h"
- X
- Xextern char *c_macro();
- Xstatic un_bind();
- X
- Xstruct cmd_map *cmd_map, *line_map, *bang_map;
- X
- X/*
- X * Bindings are added here in REVERSE of the order that
- X * they will be displayed! Display order is based on a
- X * guess about the frequency of use and (to a lesser
- X * extent) how hard they are to remember.
- X *
- X * The user's own new bindings, if any, will be displayed
- X * before any of these default bindings.
- X */
- Xinit_bindings()
- X{
- X#ifdef CURSES
- X /* Help gets displayed last */
- X add_bind("?", C_HELP, NULL, &cmd_map);
- X add_bind("V", C_VERSION, NULL, &cmd_map);
- X
- X /* Miscellaneous shell commands */
- X add_bind("%", C_CHDIR, NULL, &cmd_map);
- X add_bind("|", C_PRINT_MSG, NULL, &cmd_map);
- X add_bind("!", C_SHELL_ESC, NULL, &cmd_map);
- X add_bind(":", C_CURSES_ESC, NULL, &cmd_map);
- X
- X /* Mush customization commands */
- X /* NOTE: No default C_MACRO bindings */
- X add_bind(")", C_SAVEOPTS, NULL, &cmd_map);
- X add_bind("(", C_SOURCE, NULL, &cmd_map);
- X add_bind("&!", C_MAP_BANG, NULL, &cmd_map);
- X add_bind("&:", C_MAP, NULL, &cmd_map);
- X add_bind("&&", C_BIND_MACRO, NULL, &cmd_map);
- X add_bind("v", C_VAR_SET, NULL, &cmd_map);
- X add_bind("i", C_IGNORE, NULL, &cmd_map);
- X add_bind("h", C_OWN_HDR, NULL, &cmd_map);
- X add_bind("B", C_UNBIND, NULL, &cmd_map);
- X add_bind("b", C_BIND, NULL, &cmd_map);
- X add_bind("a", C_ALIAS, NULL, &cmd_map);
- X
- X /* Display modification commands */
- X add_bind("\022", C_REVERSE, NULL, &cmd_map); /* ^R */
- X add_bind("\014", C_REDRAW, NULL, &cmd_map); /* ^L */
- X add_bind("Z", C_PREV_SCREEN, NULL, &cmd_map);
- X add_bind("z", C_NEXT_SCREEN, NULL, &cmd_map);
- X
- X /* Searching and sorting commands */
- X add_bind("\016", C_CONT_SEARCH, NULL, &cmd_map); /* ^N */
- X add_bind("\037", C_PREV_SEARCH, NULL, &cmd_map); /* ^/ */
- X add_bind("/", C_NEXT_SEARCH, NULL, &cmd_map);
- X add_bind("O", C_REV_SORT, NULL, &cmd_map);
- X add_bind("o", C_SORT, NULL, &cmd_map);
- X
- X /* Ways to get out */
- X add_bind("X", C_EXIT_HARD, NULL, &cmd_map);
- X add_bind("x", C_EXIT, NULL, &cmd_map);
- X add_bind("Q", C_QUIT_HARD, NULL, &cmd_map);
- X add_bind("q", C_QUIT, NULL, &cmd_map);
- X
- X /* Folder modification commands */
- X add_bind("\025", C_UPDATE, NULL, &cmd_map); /* ^U */
- X add_bind("\020", C_PRESERVE, NULL, &cmd_map); /* ^P */
- X add_bind("W", C_WRITE_LIST, NULL, &cmd_map);
- X add_bind("w", C_WRITE_MSG, NULL, &cmd_map);
- X add_bind("U", C_UNDEL_LIST, NULL, &cmd_map);
- X add_bind("u", C_UNDEL_MSG, NULL, &cmd_map);
- X add_bind("S", C_SAVE_LIST, NULL, &cmd_map);
- X add_bind("s", C_SAVE_MSG, NULL, &cmd_map);
- X add_bind("f", C_FOLDER, NULL, &cmd_map);
- X add_bind("D", C_DELETE_LIST, NULL, &cmd_map);
- X add_bind("d", C_DELETE_MSG, NULL, &cmd_map);
- X add_bind("C", C_COPY_LIST, NULL, &cmd_map);
- X add_bind("c", C_COPY_MSG, NULL, &cmd_map);
- X
- X /* Cursor movement and message selection */
- X add_bind("g", C_GOTO_MSG, NULL, &cmd_map);
- X add_bind("}", C_BOTTOM_PAGE, NULL, &cmd_map);
- X add_bind("{", C_TOP_PAGE, NULL, &cmd_map);
- X add_bind("$", C_LAST_MSG, NULL, &cmd_map);
- X add_bind("^", C_FIRST_MSG, NULL, &cmd_map);
- X add_bind("\013",C_PREV_MSG, NULL, &cmd_map); /* ^K */
- X add_bind("\012", C_NEXT_MSG, NULL, &cmd_map); /* ^J */
- X add_bind("-",C_PREV_MSG, NULL, &cmd_map);
- X add_bind("+",C_NEXT_MSG, NULL, &cmd_map);
- X add_bind("K", C_PREV_MSG, NULL, &cmd_map);
- X add_bind("k", C_PREV_MSG, NULL, &cmd_map);
- X add_bind("J", C_NEXT_MSG, NULL, &cmd_map);
- X add_bind("j", C_NEXT_MSG, NULL, &cmd_map);
- X
- X /* Mail-sending commands */
- X add_bind("R", C_REPLY_ALL, NULL, &cmd_map);
- X add_bind("r", C_REPLY_SENDER, NULL, &cmd_map);
- X add_bind("M", C_MAIL_FLAGS, NULL, &cmd_map);
- X add_bind("m", C_MAIL, NULL, &cmd_map);
- X
- X /* Mail-reading commands */
- X add_bind(".", C_DISPLAY_MSG, NULL, &cmd_map);
- X add_bind("T", C_TOP_MSG, NULL, &cmd_map);
- X add_bind("t", C_DISPLAY_MSG, NULL, &cmd_map);
- X add_bind("p", C_DISPLAY_MSG, NULL, &cmd_map);
- X add_bind("n", C_DISPLAY_NEXT, NULL, &cmd_map);
- X
- X#endif /* CURSES */
- X}
- X
- X/* Bindable function names.
- X * Most of these can't be used if CURSES is not defined,
- X * but help and lookups get confused if they aren't all here.
- X */
- Xstruct cmd_map map_func_names[] = {
- X /* These MUST be in numerical order; see bindings.h */
- X { C_NULL, "no-op", NULL, NULL_MAP },
- X { C_GOTO_MSG, "goto-msg", NULL, NULL_MAP },
- X { C_WRITE_LIST, "write-list", NULL, NULL_MAP },
- X { C_WRITE_MSG, "write", NULL, NULL_MAP },
- X { C_SAVE_LIST, "save-list", NULL, NULL_MAP },
- X { C_SAVE_MSG, "save", NULL, NULL_MAP },
- X { C_COPY_LIST, "copy-list", NULL, NULL_MAP },
- X { C_COPY_MSG, "copy", NULL, NULL_MAP },
- X { C_DELETE_LIST, "delete-list", NULL, NULL_MAP },
- X { C_DELETE_MSG, "delete", NULL, NULL_MAP },
- X { C_UNDEL_LIST, "undelete-list", NULL, NULL_MAP },
- X { C_UNDEL_MSG, "undelete", NULL, NULL_MAP },
- X { C_REDRAW, "redraw", NULL, NULL_MAP },
- X { C_REVERSE, "reverse-video", NULL, NULL_MAP },
- X { C_NEXT_MSG, "next-msg", NULL, NULL_MAP },
- X { C_PREV_MSG, "back-msg", NULL, NULL_MAP },
- X { C_FIRST_MSG, "first-msg", NULL, NULL_MAP },
- X { C_LAST_MSG, "last-msg", NULL, NULL_MAP },
- X { C_TOP_PAGE, "top-page", NULL, NULL_MAP },
- X { C_BOTTOM_PAGE, "bottom-page", NULL, NULL_MAP },
- X { C_NEXT_SCREEN, "screen-next", NULL, NULL_MAP },
- X { C_PREV_SCREEN, "screen-back", NULL, NULL_MAP },
- X { C_SOURCE, "source", NULL, NULL_MAP },
- X { C_SAVEOPTS, "saveopts", NULL, NULL_MAP },
- X { C_NEXT_SEARCH, "search-next", NULL, NULL_MAP },
- X { C_PREV_SEARCH, "search-back", NULL, NULL_MAP },
- X { C_CONT_SEARCH, "search-again", NULL, NULL_MAP },
- X { C_PRESERVE, "preserve", NULL, NULL_MAP },
- X { C_REV_SORT, "sort-reverse", NULL, NULL_MAP },
- X { C_SORT, "sort", NULL, NULL_MAP },
- X { C_QUIT_HARD, "quit!", NULL, NULL_MAP },
- X { C_QUIT, "quit", NULL, NULL_MAP },
- X { C_EXIT_HARD, "exit!", NULL, NULL_MAP },
- X { C_EXIT, "exit", NULL, NULL_MAP },
- X { C_UPDATE, "update", NULL, NULL_MAP },
- X { C_FOLDER, "folder", NULL, NULL_MAP },
- X { C_SHELL_ESC, "shell-escape", NULL, NULL_MAP },
- X { C_CURSES_ESC, "line-mode", NULL, NULL_MAP },
- X { C_PRINT_MSG, "lpr", NULL, NULL_MAP },
- X { C_CHDIR, "chdir", NULL, NULL_MAP },
- X { C_VAR_SET, "variable", NULL, NULL_MAP },
- X { C_IGNORE, "ignore", NULL, NULL_MAP },
- X { C_ALIAS, "alias", NULL, NULL_MAP },
- X { C_OWN_HDR, "my-hdrs", NULL, NULL_MAP },
- X { C_VERSION, "version", NULL, NULL_MAP },
- X { C_MAIL_FLAGS, "mail-flags", NULL, NULL_MAP },
- X { C_MAIL, "mail", NULL, NULL_MAP },
- X { C_REPLY_ALL, "reply-all", NULL, NULL_MAP },
- X { C_REPLY_SENDER, "reply", NULL, NULL_MAP },
- X { C_DISPLAY_NEXT, "display-next", NULL, NULL_MAP },
- X { C_DISPLAY_MSG, "display", NULL, NULL_MAP },
- X { C_TOP_MSG, "top", NULL, NULL_MAP },
- X { C_BIND_MACRO, "bind-macro", NULL, NULL_MAP },
- X { C_BIND, "bind", NULL, NULL_MAP },
- X { C_UNBIND, "unbind", NULL, NULL_MAP },
- X { C_MAP_BANG, "map!", NULL, NULL_MAP },
- X { C_MAP, "map", NULL, NULL_MAP },
- X { C_MACRO, "macro", NULL, NULL_MAP },
- X /* C_HELP Must be the last one! */
- X { C_HELP, "help", NULL, NULL_MAP }
- X};
- X
- X#ifdef CURSES
- X
- X/*
- X * getcmd() is called from curses mode only. It waits for char input from
- X * the user via m_getchar() (which means that a macro could provide input)
- X * and then compares the chars input against the "bind"ings set up by the
- X * user (or the defaults). For example, 'j' could bind to "next msg" which
- X * is interpreted by the big switch statement in curses_command() (curses.c).
- X * getcmd() returns the int-value of the curses command the input is "bound"
- X * to. If the input is unrecognized, C_NULL is returned (curses_command()
- X * might require some cleanup, so this is valid, too).
- X *
- X * Since the input could originate from a macro rather than the terminal,
- X * check to see if this is the case and search for a '[' char which indicates
- X * that there is a curses command or other "long" command to be executed.
- X */
- Xgetcmd()
- X{
- X char buf[MAX_BIND_LEN * 3];
- 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 active_cmd = NULL_MAP;
- X c = m_getchar();
- X /* If user did job control (^Z), then the interrupt flag will be
- X * set. Be sure it's unset before continuing.
- X */
- X turnoff(glob_flags, WAS_INTR);
- X if (isdigit(c)) {
- X buf[0] = c;
- X buf[1] = '\0';
- X Ungetstr(buf); /* So mac_flush can clear on error */
- X return C_GOTO_MSG;
- X }
- X for (;;) {
- X if (ison(glob_flags, IN_MACRO) && c == MAC_LONG_CMD)
- X return long_mac_cmd(c, TRUE);
- 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\" ",
- X ctrl_strcpy(buf,
- X map_func_names[list->m_cmd].m_str,
- X TRUE));
- X if (list->m_cmd == C_MACRO) {
- X curs_macro(list->x_str);
- X return getcmd();
- X }
- X active_cmd = list;
- X return (int)list->m_cmd;
- X } else if (match != NO_MATCH)
- X m++;
- X }
- X if (m == 0) {
- X if (debug) {
- X char tmp[sizeof buf];
- X print("No binding for \"%s\" found.",
- X ctrl_strcpy(tmp, buf, TRUE));
- X }
- X return C_NULL;
- X }
- X c = m_getchar();
- X }
- X}
- X
- X#endif /* CURSES */
- X
- X/*
- X * bind_it() is used to set or unset bind, map and map! settings.
- X * bind is used to accelerate curses commands by mapping key sequences
- X * to curses commands. map is used to accelerate command mode keysequences
- X * by simulating stdin. map! is the same, but used when in compose mode.
- X *
- X * bind_it() doesn't touch messages; return -1 for curses mode.
- X * return -2 to have curses command set CNTD_CMD to prevent screen refresh
- X * to allow user to read output in case of multiple lines.
- X *
- X * Since this routine deals with a lot of binding and unbinding of things
- X * like line-mode "map"s and is interactive (calls Getstr()), be very careful
- X * not to allow expansions during interaction.
- X */
- Xbind_it(len, argv)
- Xchar **argv;
- X{
- X char string[MAX_BIND_LEN], buf[256], *name = NULL;
- X char *rawstr; /* raw format of string (ptr to string if no argv avail) */
- X char ascii[MAX_BIND_LEN*2]; /* printable ascii version of string */
- X register int x;
- X SIGRET (*oldint)(), (*oldquit)();
- X struct cmd_map **map_list;
- X int unbind = (argv && **argv == 'u');
- X int map = 0, is_bind_macro = 0;
- X int ret = 0 - iscurses; /* return value */
- X
- X if (argv && !strcmp(name = *argv, "bind-macro"))
- X is_bind_macro++;
- X
- X if (map = (argv && (!strcmp(name, "map!") || !strcmp(name, "unmap!"))))
- X map_list = &bang_map;
- X else if (map = (argv && (!strcmp(name, "map") || !strcmp(name, "unmap"))))
- X map_list = &line_map;
- X else
- X map_list = &cmd_map;
- X
- X if (argv && *++argv && !strcmp(*argv, "-?"))
- X /* Subtract ret and iscurses to signal output */
- X return help(0, unbind? name+2 : name, cmd_help) - ret - iscurses;
- X
- X if (iscurses)
- X on_intr();
- X
- X if (unbind) {
- X if (!*argv) {
- X char savec = complete;
- X complete = 0;
- X print("%s what? ", name);
- X len = Getstr(buf, sizeof buf, 0);
- X complete = savec;
- X if (len <= 0) {
- X if (iscurses)
- X off_intr();
- X return -1;
- X }
- X rawstr = m_xlate(buf);
- X } else
- X rawstr = m_xlate(*argv);
- X if (!un_bind(rawstr, map_list)) {
- X (void) ctrl_strcpy(ascii, rawstr, TRUE);
- X print("\"%s\" isn't bound to a command.\n", ascii);
- X }
- X if (iscurses)
- X off_intr();
- X return ret;
- X }
- X if (argv && *argv) {
- X rawstr = m_xlate(*argv);
- X (void) ctrl_strcpy(ascii, rawstr, TRUE);
- X if (!*++argv) {
- X /*
- X * determine whether "argv" references a "map" or a "bind"
- X */
- X int binding = c_bind(rawstr, *map_list);
- X if (binding == C_MACRO) {
- X char *mapping = c_macro(NULL, rawstr, *map_list);
- X if (mapping) {
- X print("\"%s\" is mapped to ", ascii);
- X print_more("\"%s\".\n",
- X ctrl_strcpy(buf, mapping, FALSE));
- X } else
- X print("\"%s\" isn't mapped.\n", ascii);
- X } else if (binding)
- X print("\"%s\" is %s to \"%s\".\n", ascii,
- X map? "mapped" : "bound", map_func_names[binding].m_str);
- X else if (map)
- X print("\"%s\" isn't mapped.\n", ascii);
- X else
- X print("\"%s\" isn't bound to a command.\n", ascii);
- X if (iscurses)
- X off_intr();
- X return ret;
- X }
- X } else {
- X char savec = complete;
- X complete = 0;
- X print("%s [<CR>=all, -?=help]: ", name);
- X len = Getstr(string, MAX_BIND_LEN-1, 0);
- X complete = savec;
- X if (len == 0) {
- X int add_to_ret = iscurses;
- X#ifdef CURSES
- X if (iscurses)
- X move(LINES-1, 0), refresh();
- X#endif
- X if (map || is_bind_macro)
- X add_to_ret = !c_macro(name, NULL, *map_list);
- X else
- X add_to_ret = !c_bind(NULL, *map_list);
- X if (iscurses)
- X off_intr();
- X /* signal CTND_CMD if there was output */
- X return ret - add_to_ret;
- X }
- X if (len < 0) {
- X if (iscurses)
- X off_intr();
- X return ret;
- X }
- X rawstr = m_xlate(string);
- X (void) ctrl_strcpy(ascii, rawstr, TRUE);
- X }
- X /* if a binding was given on the command line */
- X if (argv && *argv && !map)
- X if (is_bind_macro)
- X (void) strcpy(buf, "macro");
- X else
- X (void) strcpy(buf, *argv++);
- X else {
- X /* at this point, "rawstr" and "ascii" should both be set */
- X int binding;
- X
- X if (!strcmp(ascii, "-?")) {
- X if (iscurses)
- X clr_bot_line();
- X ret -= help(0, name, cmd_help);
- X if (iscurses)
- X off_intr();
- X /* Subtract iscurses to signal CNTD_CMD */
- X return ret - iscurses;
- X }
- X
- X if (!map && !is_bind_macro) {
- X binding = c_bind(rawstr, *map_list);
- X
- X for (len = 0; len == 0; ) {
- X print("\"%s\" = <%s>: New binding [<CR> for list]: ",
- X ascii, (binding? map_func_names[binding].m_str : "unset"));
- X len = Getstr(buf, sizeof buf, 0);
- X if (iscurses)
- X clr_bot_line();
- X /* strip any trailing whitespace */
- X if (len > 0)
- X len = no_newln(buf) - buf;
- X if (len == 0) {
- X (void) do_pager(NULL, TRUE);
- X if (iscurses)
- X putchar('\n');
- X for (x = 1; x <= C_HELP; x++) {
- X if (!(x % 4))
- X if (do_pager("\n", FALSE) == EOF)
- X break;
- X (void) do_pager(sprintf(buf, "%-15.15s ",
- X map_func_names[x].m_str), FALSE);
- X }
- X (void) do_pager("\n", FALSE);
- X (void) do_pager(NULL, FALSE);
- X ret -= iscurses;
- X }
- X }
- X } else /* map */
- X (void) strcpy(buf, "macro"), len = 5;
- 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 if (iscurses)
- X off_intr();
- X return ret;
- X }
- X }
- X for (x = 1; x <= C_HELP; x++) {
- X if (prefix(buf, map_func_names[x].m_str) == MATCH) {
- X int add_to_ret;
- X if (debug)
- X print("\"%s\" will execute \"%s\".\n", ascii, buf);
- X if (map_func_names[x].m_cmd == C_MACRO) {
- X if (argv && *argv) {
- X (void) argv_to_string(buf, argv);
- X (void) m_xlate(buf); /* Convert buf to raw chars */
- X add_to_ret =
- X do_bind(rawstr, map_func_names[x].m_cmd, buf, map_list);
- X } else {
- X char exp[MAX_MACRO_LEN*2]; /* printable expansion */
- X char *mapping = c_macro(NULL, rawstr, *map_list);
- X
- X if (mapping)
- X (void) ctrl_strcpy(exp, mapping, TRUE);
- X print("\"%s\" = <%s>", ascii, mapping ? exp : "unset");
- X putchar('\n'), print("New macro: ");
- X ret -= iscurses; /* To signal screen messed up */
- X /* we are done with buf, so we can trash over it */
- X len = Getstr(buf, MAX_MACRO_LEN, 0);
- X if (len > 0) {
- X if (iscurses)
- X clr_bot_line();
- X (void) m_xlate(buf); /* Convert buf to raw chars */
- X add_to_ret =
- X do_bind(rawstr, C_MACRO, buf, map_list);
- X if (debug) {
- X (void) ctrl_strcpy(exp, buf, TRUE);
- X print("\"%s\" will execute \"%s\".\n", ascii, exp);
- X }
- X } else if (len < 0) {
- X if (iscurses)
- X off_intr();
- X return ret;
- X } else
- X print("Can't bind to null macro"), putchar('\n');
- X }
- X } else /* not a macro */ {
- X (void) argv_to_string(buf, argv);
- X add_to_ret =
- X do_bind(rawstr, map_func_names[x].m_cmd, buf, map_list);
- X }
- X /* if do_bind had 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 if (iscurses)
- X off_intr();
- X return min(add_to_ret, ret);
- X }
- X }
- X print("\"%s\": Unknown function.\n", buf);
- X if (iscurses)
- 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, opts)
- Xregister char *str;
- Xregister struct cmd_map *opts;
- X{
- X register int incurses = iscurses;
- X
- X if (!str) {
- X if (!opts) {
- X print("No command bindings.\n");
- X return C_ERROR;
- X }
- X if (incurses)
- X clr_bot_line(), iscurses = FALSE;
- X (void) do_pager(NULL, TRUE);
- X (void) do_pager("Current key to command bindings:\n", FALSE);
- X (void) do_pager("\n", FALSE);
- X }
- X
- X for (; opts; opts = opts->m_next) {
- X char buf[BUFSIZ], buf2[MAX_BIND_LEN], exp[MAX_MACRO_LEN*2], *xp;
- X if (!str) {
- X (void) ctrl_strcpy(buf2, opts->m_str, FALSE);
- X if ((xp = opts->x_str) && opts->m_cmd == C_MACRO)
- X xp = ctrl_strcpy(exp, opts->x_str, TRUE);
- X if (do_pager(sprintf(buf, "%s\t%-15.15s %s\n",
- X buf2, map_func_names[opts->m_cmd].m_str,
- X xp? xp : ""),
- X FALSE) == EOF)
- X break;
- X } else
- X if (strcmp(str, opts->m_str))
- X continue;
- X else
- X return opts->m_cmd;
- X }
- X
- X iscurses = incurses;
- X if (!str)
- X (void) do_pager(NULL, FALSE);
- X return C_NULL;
- X}
- X
- X/*
- X * Doesn't touch messages, but changes macros: return -1.
- X * Error output causes return < -1.
- X * args is currently the execute string of a macro mapping, but may be
- X * used in the future as an argument string for any curses command.
- X */
- Xdo_bind(str, func, args, map_list)
- Xregister char *str, *args;
- Xstruct cmd_map **map_list;
- Xlong func;
- X{
- X register int ret = -1;
- X register struct cmd_map *list;
- X int match;
- X
- X if (func == C_MACRO && !check_mac_bindings(args))
- X --ret;
- X (void) un_bind(str, map_list);
- X for (list = *map_list; list; list = list->m_next)
- X if ((match = prefix(str, list->m_str)) != NO_MATCH) {
- X ret--;
- X switch (match) {
- X case MATCH:
- X puts("Something impossible just happened.");
- X when A_PREFIX_B:
- X wprint("Warning: \"%s\" prefixes \"%s\" (%s)\n", str,
- X list->m_str, map_func_names[list->m_cmd].m_str);
- X when B_PREFIX_A:
- X wprint("Warning: \"%s\" (%s) prefixes: \"%s\"\n",
- X list->m_str, map_func_names[list->m_cmd].m_str, str);
- X }
- X }
- X add_bind(str, func, args, map_list);
- 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
- X/*
- X * add a binding to a list. This may include "map"s or other mappings since
- X * the map_list argument can control that. The "func" is an int defined in
- X * bindings.h ... the "str" passed is the string the user would have to type
- X * to get the macro/map/binding expanded. This must in in raw format: no
- X * \n's to mean \015. Convert first using m_xlate().
- X */
- Xadd_bind(str, func, args, map_list)
- Xregister char *str, *args;
- Xstruct cmd_map **map_list;
- Xlong func;
- X{
- X register struct cmd_map *tmp;
- X
- X if (!str || !*str)
- X return;
- X
- X /* now make a new option struct and set fields */
- X if (!(tmp = (struct cmd_map *)calloc((unsigned)1,sizeof(struct cmd_map)))) {
- X error("calloc");
- X return;
- X }
- X tmp->m_next = *map_list;
- X *map_list = tmp;
- X
- X tmp->m_str = savestr(str);
- X tmp->m_cmd = func; /* strdup handles the NULL case */
- X if (args && *args)
- X tmp->x_str = savestr(args);
- X else
- X tmp->x_str = NULL;
- X}
- X
- Xstatic
- Xun_bind(p, map_list)
- Xregister char *p;
- Xstruct cmd_map **map_list;
- X{
- X register struct cmd_map *list = *map_list, *tmp;
- X
- X if (!list || !*list->m_str || !p || !*p)
- X return 0;
- X
- X if (!strcmp(p, (*map_list)->m_str)) {
- X *map_list = (*map_list)->m_next;
- X xfree (list->m_str);
- X if (list->x_str)
- X xfree (list->x_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 if (tmp->x_str)
- X xfree (tmp->x_str);
- X xfree ((char *)tmp);
- X return 1;
- X }
- X return 0;
- X}
- X
- Xprefix(a, b)
- Xregister char *a, *b;
- X{
- X if (!a || !b)
- X return NO_MATCH;
- 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}
- END_OF_FILE
- if test 20570 -ne `wc -c <'mush/bind.c'`; then
- echo shar: \"'mush/bind.c'\" unpacked with wrong size!
- fi
- # end of 'mush/bind.c'
- fi
- if test -f 'mush/folders.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/folders.c'\"
- else
- echo shar: Extracting \"'mush/folders.c'\" \(19662 characters\)
- sed "s/^X//" >'mush/folders.c' <<'END_OF_FILE'
- X/* @(#)folders.c (c) copyright 10/18/86 (Dan Heller) */
- X
- X#include "mush.h"
- X
- Xstatic char oldfolder[MAXPATHLEN];
- X
- X/* folder %[user] --new mailfile is the spool/mail/login file [user].
- X * folder # --new mailfile is the folder previous to the current folder
- X * folder & --new mailfile is ~/mbox (or whatever "mbox" is set to)
- X * folder +file --new mailfile is in the directory "folder"; name is 'file'
- X * folder "path" --full path name or the one in current working directory.
- X *
- X * in all cases, changes are updated unless a '!' is specified after the
- X * folder command (e.g. "f!", "folder !" "fo!" .. all permutations)
- X * as usual, if new mail has arrived before the file is copied back, then
- X * user will be notified beforehand.
- X *
- X * RETURN -1 on error -- else return 0. All bits in msg_list are set to true.
- X */
- Xfolder(argc, argv, list)
- Xregister char **argv;
- Xchar list[];
- X{
- X int n, updating = !strcmp(*argv, "update"), do_read_only = 0, no_hdrs = 0;
- X char *tmp, *newfolder = NULL, buf[MAXPATHLEN];
- X struct stat statbuf;
- X extern long last_spool_size;
- X
- X if (ison(glob_flags, IS_PIPE)) {
- X print("You can't pipe to the %s command.\n", *argv);
- X return -1;
- X } else if (ison(glob_flags, IS_SENDING)) {
- X print("You can't use the %s command when sending.\n", *argv);
- X return -1;
- X } else if (!tempfile || !*tempfile) {
- X print("You can't use the %s command in init files.\n", *argv);
- X return -1;
- X }
- X while (*++argv && (**argv == '-' || **argv == '!'))
- X if (!strcmp(*argv, "-N"))
- X no_hdrs = !(iscurses || ison(glob_flags, PRE_CURSES));
- X else if (!updating && !strcmp(*argv, "-n"))
- X turnoff(glob_flags, DO_UPDATE);
- X else if (!strcmp(*argv, "-r"))
- X do_read_only = 1;
- X else if (!strcmp(*argv, "!")) {
- X if (updating)
- X turnon(glob_flags, DO_UPDATE); /* useful? */
- X else
- X turnoff(glob_flags, DO_UPDATE);
- X } else
- X return help(0, "folder", cmd_help);
- X
- X if (updating) {
- X (void) strcpy(buf, mailfile);
- X if (ison(glob_flags, READ_ONLY))
- X do_read_only = 1;
- X } else {
- X if (!*argv) {
- X mail_status(0);
- X return 0;
- X }
- X if (!strcmp(*argv, "#"))
- X if (!*oldfolder) {
- X print("No previous folder\n");
- X return -1;
- X } else
- X newfolder = oldfolder;
- X else if (!strcmp(*argv, "&")) {
- X if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
- X newfolder = DEF_MBOX;
- X } else
- X newfolder = *argv;
- X n = 0;
- X tmp = getpath(newfolder, &n);
- X if (n == -1) {
- X print("%s: %s\n", newfolder, tmp);
- X return -1;
- X } else if (n == 1) {
- X print("%s: is a directory\n", tmp);
- X return -1;
- X }
- X /* strcpy so copyback() below (which calls getpath) doesn't change
- X * the data that tmp intended to point to. Get the cwd if necessary.
- X */
- X n = 0;
- X if (*tmp != '/') {
- X#ifdef SYSV
- X extern char *getcwd();
- X if (!getcwd(buf, MAXPATHLEN))
- X#else /* SYSV */
- X extern char *getwd();
- X if (!getwd(buf))
- X#endif /* SYSV */
- X {
- X error("getcwd: %s",buf);
- X return -1;
- X }
- X n = strlen(buf);
- X buf[n++] = '/';
- X }
- X (void) strcpy(&buf[n], tmp);
- X }
- X#ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(TRUE);
- X#endif /* SUNTOOL */
- X if (stat(buf, &statbuf) == -1 || !(statbuf.st_mode & 0400)) {
- X error("Unable to read %s", buf);
- X#ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(FALSE);
- X#endif /* SUNTOOL */
- X return -1;
- X }
- X /* If the file can't be opened for writing, autoset READ_ONLY */
- X if (!(statbuf.st_mode & 0200))
- X do_read_only = 1;
- X
- X if (!(n = copyback(updating ? "Update folder?" : "Change anyway?"))) {
- X#ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(FALSE);
- X#endif /* SUNTOOL */
- X /* an error occured updating the folder */
- X return -1;
- X }
- X /* Assure that both oldfolder and mailfile are full paths */
- X if (strcmp(mailfile, buf) || !*oldfolder) {
- X n = 1; /* force load of new folder */
- X if (!updating)
- X (void) strcpy(oldfolder, *oldfolder? mailfile : buf);
- X strdup(mailfile, buf);
- X }
- X do_read_only? turnon(glob_flags,READ_ONLY) : turnoff(glob_flags,READ_ONLY);
- X last_size = spool_size = 0L;
- X while (msg_cnt--) {
- X xfree(msg[msg_cnt].m_date_recv);
- X xfree(msg[msg_cnt].m_date_sent);
- X msg[msg_cnt].m_date_recv = msg[msg_cnt].m_date_sent = NO_STRING;
- X }
- X msg_cnt = 0, msg[0].m_offset = 0L;
- X turnoff(glob_flags, CONT_PRNT);
- X
- X turnon(glob_flags, IGN_SIGS);
- X /* clear the tempfile */
- X if (tmpf)
- X (void) fclose(tmpf);
- X if (!do_read_only) {
- X if (!(tmpf = mask_fopen(tempfile, "w"))) {
- X error("error truncating %s", tempfile);
- X turnoff(glob_flags, IGN_SIGS);
- X return -1;
- X }
- X }
- X /* Don't reload the folder if it was removed */
- X if (n > 0) {
- X if (load_folder(mailfile, TRUE, NULL) < 1) {
- X last_msg_cnt = 0;
- X last_size = statbuf.st_size; /* Disable check_new_mail() */
- X turnoff(glob_flags, IGN_SIGS);
- X return -1;
- X }
- X if (do_read_only && !(tmpf = fopen(mailfile, "r"))) {
- X error(mailfile);
- X turnoff(glob_flags, IGN_SIGS);
- X return -1;
- X }
- X }
- X last_msg_cnt = msg_cnt; /* for check_new_mail */
- X /* Prevent both bogus "new mail" messages and missed new mail */
- X last_size = msg[msg_cnt].m_offset;
- X if (!strcmp(mailfile, spoolfile))
- X spool_size = last_spool_size = last_size;
- X#ifdef SUNTOOL
- X if (istool) {
- X extern Panel_item folder_text_item;
- X Rect *rect = (Rect *)window_get(hdr_sw, WIN_RECT);
- X (void) pw_rop(hdr_win, 0,0, rect->r_width, rect->r_height, PIX_CLR,
- X (struct pixrect *) 0,0,0);
- X panel_set_value(folder_text_item, mailfile);
- X }
- X#endif /* SUNTOOL */
- X
- X if (!updating || current_msg >= msg_cnt)
- X current_msg = (msg_cnt? 0 : -1);
- X turnoff(glob_flags, IGN_SIGS);
- X
- X /* now sort messages according a user-defined default */
- X if (!updating && msg_cnt > 1 && !strcmp(mailfile, spoolfile) &&
- X (tmp = do_set(set_options, "sort"))) {
- X (void) sprintf(buf, "sort %s", tmp);
- X if ((argv = mk_argv(buf, &argc, TRUE)) && argc > 0) {
- X /* msg_list can't be null for do_command and since we're not
- X * interested in the result, call sort directly
- X */
- X (void) sort(argc, argv, NULL);
- X free_vec(argv);
- X if (!updating)
- X current_msg = 0; /* Sort may move the current message */
- X }
- X }
- X turnoff(glob_flags, DO_UPDATE);
- X
- X /* go to first NEW message */
- X for (n = 0; n < msg_cnt && ison(msg[n].m_flags, OLD); n++)
- X ;
- X if (n == msg_cnt) {
- X turnoff(glob_flags, NEW_MAIL);
- X if (!updating) {
- X /* no new message found -- try first unread message */
- X for (n = 0; n < msg_cnt && isoff(msg[n].m_flags, UNREAD); n++)
- X ;
- X }
- X } else {
- X turnon(glob_flags, NEW_MAIL);
- X /* default for toolmode is true */
- X if (istool && !chk_option("quiet", "tool"))
- X bell();
- X }
- X if (msg_cnt && (!updating || current_msg < 0))
- X current_msg = (n == msg_cnt ? 0 : n);
- X
- X if ((!istool || istool && !msg_cnt) && !iscurses)
- X mail_status(0);
- X /* be quiet if we're piping */
- X if (!istool && !updating && !no_hdrs && msg_cnt
- X && isoff(glob_flags, DO_PIPE))
- X (void) cmd_line(sprintf(buf, "headers %d", current_msg+1), msg_list);
- X#ifdef SUNTOOL
- X if (istool > 1) {
- X if (!msg_cnt)
- X print("No Mail in %s\n", mailfile);
- X if (msg_cnt) {
- X display_msg(current_msg, (long)0);
- X do_hdrs(0, DUBL_NULL, NULL);
- X }
- X timeout_cursors(FALSE);
- X }
- X#endif /* SUNTOOL */
- X if (list) {
- X clear_msg_list(list);
- X bitput(list, list, msg_cnt, =~); /* macro */
- X }
- X return 0;
- X}
- X
- Xfolders(argc, argv)
- Xregister char **argv;
- X{
- X register char *p;
- X char buf[128], unused[MAXMSGS_BITS];
- X
- X if (argv && argv[1] && !strcmp(argv[1], "-?"))
- X return help(0, "folders", cmd_help);
- X
- X if (!(p = do_set(set_options, "folder")) || !*p)
- X p = DEF_FOLDER;
- X (void) sprintf(buf, "ls -FR %s", p);
- X if (argv = make_command(buf, TRPL_NULL, &argc))
- X return do_command(argc, argv, unused);
- X return -1;
- X}
- X
- X/*
- X * Determine whether a file could be a folder. If prompt is non-NULL,
- X * ask the user whether we should treat the file as a folder anyway.
- X */
- Xtest_folder(name, prompt)
- Xchar *name, *prompt;
- X{
- X char line[BUFSIZ], *p;
- X FILE *fp = fopen(name, "r");
- X int retval = FALSE;
- X
- X if (!fp)
- X return 0;
- X if (fgets(line, sizeof line - 1, fp)) {
- X#ifndef MSG_SEPARATOR
- X if (p = any(line, " \t")) {
- X skipspaces(1);
- X p = any(p, " \t");
- X }
- X if (p && !strncmp(line, "From ", 5) && (p = parse_date(p + 1)))
- X#else /* MSG_SEPARATOR */
- X if (!strncmp(line, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
- X#endif /* MSG_SEPARATOR */
- X retval = TRUE;
- X } else
- X retval = TRUE; /* Empty files are legitimate folders */
- X (void) fclose(fp);
- X if (prompt && !retval) {
- X char buf[BUFSIZ];
- X#ifdef SUNTOOL
- X if (istool) {
- X (void) sprintf(buf, "\"%s\": %s", name, prompt);
- X return ask(buf);
- X }
- X#endif /* SUNTOOL */
- X print("\"%s\": %s [n] ", name, prompt);
- X buf[0] = 0;
- X retval = (Getstr(buf, sizeof (buf), 0) && lower(*buf) == 'y');
- X }
- X return retval;
- X}
- X
- X/* merge_folders filename -- concatenate the folder specified by filename
- X * to the current folder.
- X *
- X * RETURN -1 on error -- else return 0. A bit in msg_list is set to true
- X * for each of the "new" messages read in to the current folder.
- X */
- Xmerge_folders(n, argv, list)
- Xregister char **argv, list[];
- X{
- X int no_hdrs = 0, newest_msg;
- X long orig_offset;
- X char *tmp, *newfolder = NULL, buf[MAXPATHLEN];
- X
- X if (ison(glob_flags, IS_PIPE)) {
- X print("You can't pipe to the %s command.\n", *argv);
- X return -1;
- X } else if (ison(glob_flags, IS_SENDING)) {
- X print("You can't use the %s command while sending.\n", *argv);
- X return -1;
- X }
- X
- X while (*++argv && **argv == '-')
- X if (!strcmp(*argv, "-?"))
- X return help(0, "merge", cmd_help);
- X else if (!strcmp(*argv, "-N"))
- X no_hdrs = !(iscurses || ison(glob_flags, PRE_CURSES));
- X
- X if (!*argv)
- X return 0;
- X
- X if (ison(glob_flags, READ_ONLY)) {
- X print("Folder is read-only.\n");
- X return -1;
- X }
- X
- X if (!strcmp(*argv, "#"))
- X if (!*oldfolder) {
- X print("No previous folder\n");
- X return -1;
- X } else
- X newfolder = oldfolder;
- X else if (!strcmp(*argv, "&")) {
- X if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
- X newfolder = DEF_MBOX;
- X } else
- X newfolder = *argv;
- X n = 0;
- X tmp = getpath(newfolder, &n);
- X if (n == -1) {
- X print("%s: %s\n", newfolder, tmp);
- X return -1;
- X } else if (n == 1) {
- X print("%s: is a directory\n", tmp);
- X return -1;
- X }
- X
- X turnon(glob_flags, IGN_SIGS);
- X orig_offset = msg[msg_cnt].m_offset;
- X (void) load_folder(tmp, 2, list);
- X msg[msg_cnt].m_offset = orig_offset;
- X newest_msg = last_msg_cnt;
- X Debug("newest_msg = %d\n", newest_msg);
- X last_msg_cnt = msg_cnt; /* for check_new_mail */
- X Debug("msg_cnt = %d\n", msg_cnt);
- X (void) mail_size();
- X turnoff(glob_flags, IGN_SIGS);
- X
- X if ((!istool || istool && !msg_cnt)
- X && !iscurses && !ison(glob_flags, PRE_CURSES))
- X mail_status(0);
- X /* be quiet if we're piping or if told not to show headers */
- X if ((istool || !no_hdrs) && isoff(glob_flags, DO_PIPE)
- X && newest_msg < msg_cnt)
- X (void) cmd_line(sprintf(buf, "headers %d", newest_msg + 1), NULL);
- X return 0;
- X}
- X
- X/*
- X * Default digest article separator
- X */
- X#define ARTICLE_SEP "--------"
- X
- X/*
- X * Undigestify messages. If a message is in digest-format, there are many
- X * messages within this message which are to be extracted. Kinda like a
- X * folder within a folder. By default, this routine will create a new
- X * folder that contains the new messages. -m option will merge the new
- X * messages into the current folder.
- X */
- Xdo_undigest(n, argv, list)
- Xchar *argv[], list[];
- X{
- X int r, articles = 0, merge = 0, appending = 0;
- X char buf[MAXPATHLEN], cmdbuf[MAXPATHLEN], newlist[MAXMSGS_BITS], *dir;
- X char *art_sep = ARTICLE_SEP, *mktemp();
- X FILE *fp;
- X
- X while (argv && *++argv && **argv == '-') {
- X switch(argv[0][1]) {
- X case 'm':
- X if (ison(glob_flags, READ_ONLY)) {
- X print("Folder is read only.\n");
- X return -1;
- X }
- X merge++;
- X when 'p':
- X if (*++argv)
- X art_sep = *argv;
- X else {
- X print("Specify separator pattern with -p.\n");
- X return -1;
- X }
- X otherwise: return help(0, "undigest", cmd_help);
- X }
- X }
- X
- X if ((n = get_msg_list(argv, list)) == -1)
- X return -1;
- X
- X argv += n;
- X
- X if (*argv) {
- X int isdir = 1; /* Ignore file nonexistance errors */
- X (void) strcpy(buf, getpath(*argv, &isdir));
- X if (isdir < 0) {
- X print("%s: %s\n", *argv, buf);
- X return -1;
- X } else if (isdir == 1) {
- X print("%s: is a directory\n", buf);
- X return -1;
- X }
- X } else {
- X register char *p, *p2;
- X if (Access(dir = ".", W_OK) == 0 ||
- X (dir = do_set(set_options, "folder")) ||
- X (dir = do_set(set_options, "tmpdir")))
- X dir = getdir(dir); /* expand metachars */
- X if (!dir)
- Xalted:
- X dir = ALTERNATE_HOME;
- X for (n = 0; n < msg_cnt; n++)
- X if (msg_bit(list, n))
- X break;
- X
- X if (!(p = header_field(n, "subject")))
- X (void) mktemp(sprintf(buf, "%s/digestXXXXX", dir));
- X else {
- X if (!lcase_strncmp(p, "re: ", 4))
- X p += 4;
- X for (p2 = p; *p2; p2++)
- X if (!isalnum(*p2) && *p2 != '-' && *p2 != '.') {
- X *p2 = 0;
- X break;
- X }
- X p2 = buf + Strcpy(buf, dir);
- X *p2++ = '/';
- X (void) strcpy(p2, p);
- X }
- X }
- X
- X if (!Access(buf, W_OK))
- X appending = ((fp = mask_fopen(buf, "a")) != NULL_FILE);
- X else
- X fp = mask_fopen(buf, "w");
- X if (!fp) {
- X if (!*argv && strcmp(dir, ALTERNATE_HOME))
- X goto alted;
- X error("can't create %s", buf);
- X return -1;
- X }
- X
- X for (n = 0; n < msg_cnt; n++) {
- X if (!msg_bit(list, n))
- X continue;
- X
- X print("undigesting message %d\n", n+1);
- X /* copy message into file making sure all headers exist. */
- X r = undigest(n, fp, art_sep);
- X if (r <= 0)
- X break;
- X articles += r;
- X }
- X (void) fclose(fp);
- X if (r <= 0) {
- X if (!appending)
- X (void) unlink(buf);
- X return -1;
- X }
- X if (merge) {
- X (void) cmd_line(sprintf(cmdbuf, "\\merge -N %s", buf), newlist);
- X (void) unlink(buf);
- X print("Merged in %d messages.\n", articles);
- X } else
- X print("Added %d messages to \"%s\".\n", articles, buf);
- X clear_msg_list(list);
- X for (n = 0; n < msg_cnt; n++)
- X if (msg_bit(newlist, n))
- X set_msg_bit(list, n);
- X return 0;
- X}
- X
- X/*
- X * split digest-message 'n' to file "fp" using article separator "sep".
- X * return number of articles copied or -1 if system error on fputs.
- X * A digest is a folder-in-a-message in a special, semi-standard form.
- X */
- Xundigest(n, fp, sep)
- Xint n;
- XFILE *fp;
- Xchar *sep;
- X{
- X int art_cnt = 0, on_hdr = -1; /* on_hdr is -1 if hdr not yet found */
- X int sep_len = (sep ? strlen(sep) : strlen(sep = ARTICLE_SEP));
- X long get_hdr = 0L;
- X char from[HDRSIZ], line[HDRSIZ], last_sep[HDRSIZ];
- X char from_hdr[256], afrom[256], adate[64];
- X char *fdate = "Xxx Xxx 00 00:00:00 0000"; /* Dummy date in ctime form */
- X SIGRET (*oldint)(), (*oldquit)();
- X
- X if (!msg_get(n, from, sizeof from)) {
- X error("Unable to find msg %d", n+1);
- X return -1;
- X }
- X#ifndef MSG_SEPARATOR
- X else {
- X char *p = from + 5;
- X skipspaces(0);
- X p = index(p, ' ');
- X if (p) {
- X skipspaces(0);
- X fdate = p;
- X }
- X if (fputs(from, fp) == EOF)
- X return -1;
- X }
- X#endif /* !MSG_SEPARATOR */
- X
- X on_intr();
- X *afrom = *adate = *last_sep = '\0';
- X while (ftell(tmpf) < msg[n].m_offset + msg[n].m_size &&
- X fgets(line, sizeof (line), tmpf)) {
- X if (ison(glob_flags, WAS_INTR))
- X goto handle_error;
- X if (*line == '\n' && on_hdr > 0) /* blank line -- end of header */
- X on_hdr = 0;
- X
- X /* Check for the beginning of a digest article */
- X if (!strncmp(line, sep, sep_len)) {
- X if (get_hdr) {
- X if (do_set(set_options, "warning"))
- X print("Article with no header? (added to article #%d)\n",
- X art_cnt);
- X /* Don't start a new message for whatever this is,
- X * just fseek back and keep appending to the last one.
- X */
- X if (fseek(tmpf, get_hdr, L_SET) < 0 ||
- X fputs(last_sep, fp) == EOF) {
- X art_cnt = -1;
- X goto handle_error;
- X }
- X get_hdr = 0L;
- X on_hdr = 0;
- X } else {
- X (void) strcpy(last_sep, line);
- X get_hdr = ftell(tmpf);
- X *afrom = *adate = '\0';
- X on_hdr = -1; /* Haven't found the new header yet */
- X }
- X continue;
- X }
- X
- X if (get_hdr) {
- X char *p = *line == '>' ? line + 1 : line;
- X if (*line == '\n') {
- X if (*afrom || *adate) {
- X (void) fseek(tmpf, get_hdr, L_SET);
- X /* Terminate the previous article */
- X art_cnt++;
- X#ifdef MSG_SEPARATOR
- X#ifdef END_MSG_SEP
- X if (fputs(END_MSG_SEP, fp) == EOF) {
- X art_cnt = -1;
- X goto handle_error;
- X }
- X#endif /* END_MSG_SEP */
- X#ifdef MMDF
- X /* MMDF has a newline in MSG_SEPARATOR */
- X if (fputs(MSG_SEPARATOR, fp) == EOF)
- X#else /* !MMDF */
- X /* Other MSG_SEPARATORs need a newline */
- X if (fputs(MSG_SEPARATOR, fp) == EOF ||
- X fputc('\n', fp) == EOF)
- X#endif /* MMDF */
- X#else /* !MSG_SEPARATOR */
- X /* Everybody else needs a From_ line */
- X if (fprintf(fp, "From %s %s", *afrom ? afrom : "unknown",
- X *adate ? date_to_ctime(adate) : fdate) == EOF)
- X#endif /* MSG_SEPARATOR */
- X {
- X art_cnt = -1;
- X goto handle_error;
- X }
- X /* Make sure there is a From: without a leading > */
- X if (*afrom && *from_hdr && fputs(from_hdr, fp) == EOF) {
- X art_cnt = -1;
- X goto handle_error;
- X }
- X get_hdr = 0L;
- X } else if (on_hdr < 0)
- X /* Skip blanks between "--------" and the hdr */
- X get_hdr = ftell(tmpf);
- X } else if (on_hdr < 0)
- X on_hdr = 1;
- X if (on_hdr > 0 && !strncmp(p, "From: ", 6)) {
- X (void) get_name_n_addr(p + 6, NULL, afrom);
- X (void) no_newln(afrom);
- X /* Get the From: minus the leading > */
- X if (p != line)
- X (void) strcpy(from_hdr, p);
- X else /* We don't need From: twice! */
- X *from_hdr = '\0';
- X } else if (on_hdr > 0 && !strncmp(line, "Date: ", 6)) {
- X if (p = parse_date(line+6))
- X (void) strcpy(adate, p);
- X } else if (on_hdr > 0 && !lcase_strncmp(line, "end", 3)) {
- X if (!*afrom && !*adate)
- X break;
- X }
- X } else if (fputs(line, fp) == EOF) {
- X /* Pipe broken, out of file space, etc */
- X art_cnt = -1;
- X goto handle_error;
- X }
- X }
- X ++art_cnt;
- X#ifdef END_MSG_SEP
- X if (art_cnt > 0 && fputs(END_MSG_SEP, fp) == EOF) {
- X art_cnt = -1;
- X goto handle_error;
- X }
- X#endif /* END_MSG_SEP */
- X /* If we're still looking for a header, there is some stuff left
- X * at the end of the digest. Create an extra article for it.
- X */
- X if (get_hdr) {
- X char *p;
- X (void) fseek(tmpf, get_hdr, L_SET);
- X if (ftell(tmpf) >= msg[n].m_offset + msg[n].m_size)
- X goto handle_error;
- X#ifdef MSG_SEPARATOR
- X#ifdef MMDF
- X if (fputs(MSG_SEPARATOR, fp) == EOF)
- X#else /* !MMDF */
- X if (fputs(MSG_SEPARATOR, fp) == EOF ||
- X fputc('\n', fp) == EOF)
- X#endif /* MMDF */
- X#else /* !MSG_SEPARATOR */
- X if (fputs(from, fp) == EOF)
- X#endif /* MSG_SEPARATOR */
- X art_cnt = -1;
- X if (!(p = header_field(n, "from")))
- X p = "Mush-Undigest (Real author unknown)";
- X if (fprintf(fp, "From: %s\n", p) == EOF)
- X art_cnt = -1;
- X if (!(p = header_field(n, "date")))
- X p = fdate, (void) no_newln(p);
- X if (fprintf(fp, "Date: %s\n", p) == EOF)
- X art_cnt = -1;
- X if (!(p = header_field(n, "subject")))
- X p = "Digest";
- X if (fprintf(fp, "Subject: Trailing part of %s\n\n", p) == EOF)
- X art_cnt = -1;
- X /* header_field() moves the pointer, so seek again */
- X (void) fseek(tmpf, get_hdr, L_SET);
- X while (art_cnt > 0 && ftell(tmpf) < msg[n].m_offset + msg[n].m_size
- X && fgets(line, sizeof (line), tmpf)) {
- X if (fputs(line, fp) == EOF)
- X art_cnt = -1;
- X#ifdef END_MSG_SEP
- X if (!strncmp(line, END_MSG_SEP, strlen(END_MSG_SEP)))
- X break;
- X#endif /* END_MSG_SEP */
- X }
- X /* The END_MSG_SEP, if any, of the digest will have been output
- X * by the while loop above, so we don't need to add one here.
- X */
- X ++art_cnt;
- X }
- Xhandle_error:
- X if (art_cnt == -1)
- X error("cannot completely undigest");
- X else if (ison(glob_flags, WAS_INTR))
- X art_cnt = -1;
- X off_intr();
- X return art_cnt;
- X}
- END_OF_FILE
- if test 19662 -ne `wc -c <'mush/folders.c'`; then
- echo shar: \"'mush/folders.c'\" unpacked with wrong size!
- fi
- # end of 'mush/folders.c'
- fi
- if test -f 'mush/signals.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/signals.c'\"
- else
- echo shar: Extracting \"'mush/signals.c'\" \(10857 characters\)
- sed "s/^X//" >'mush/signals.c' <<'END_OF_FILE'
- X/* @(#)signals.c (c) copyright 10/18/86 (Dan Heller) */
- X
- X#include "mush.h"
- X
- X#ifndef SYSV
- Xextern char *sys_siglist[];
- X#else
- X/* sys-v doesn't have normal sys_siglist */
- Xstatic char *sys_siglist[] = {
- X/* no error */ "no error",
- X/* SIGHUP */ "hangup",
- X/* SIGINT */ "interrupt (rubout)",
- X/* SIGQUIT */ "quit (ASCII FS)",
- X/* SIGILL */ "illegal instruction (not reset when caught)",
- X/* SIGTRAP */ "trace trap (not reset when caught)",
- X/* SIGIOT */ "IOT instruction",
- X/* SIGEMT */ "EMT instruction",
- X/* SIGFPE */ "floating point exception",
- X/* SIGKILL */ "kill (cannot be caught or ignored)",
- X/* SIGBUS */ "bus error",
- X/* SIGSEGV */ "segmentation violation",
- X/* SIGSYS */ "bad argument to system call",
- X/* SIGPIPE */ "write on a pipe with no one to read it",
- X/* SIGALRM */ "alarm clock",
- X/* SIGTERM */ "software termination signal from kill",
- X/* SIGUSR1 */ "user defined signal 1",
- X/* SIGUSR2 */ "user defined signal 2",
- X/* SIGCLD */ "death of a child",
- X/* SIGPWR */ "power-fail restart"
- X};
- X#endif /* SYSV */
- X
- XSIGRET
- Xintrpt(sig)
- X{
- X Debug("interrupt() caught: %d\n", sig);
- X mac_flush();
- X turnon(glob_flags, WAS_INTR);
- X}
- X
- X/*
- X * catch signals to reset state of the machine. Always print signal caught.
- X * If signals are ignored, return. If we're running the shell, longjmp back.
- X */
- X/*ARGSUSED*/
- XSIGRET
- Xcatch(sig)
- X{
- X Debug("Caught signal: %d\n", sig);
- X (void) signal(sig, catch);
- X if (ison(glob_flags, IGN_SIGS) && sig != SIGTERM && sig != SIGHUP)
- X return;
- X mac_flush();
- X print("%s: %s\n", prog_name, sys_siglist[sig]);
- X turnoff(glob_flags, IS_PIPE);
- X if (istool || sig == SIGTERM || sig == SIGHUP) {
- X if (istool) { /* istool is 2 if tool is complete */
- X#if defined(SUNTOOL) && !defined(SUN_4_0)
- X if (sig == SIGHUP && window_get(tool, WIN_SHOW))
- X return;
- X#endif /* SUNTOOL && !SUN_4_0 */
- X istool = 1;
- X }
- X (void) setjmp(jmpbuf);
- X if (ison(glob_flags, IS_GETTING))
- X rm_edfile(-1);
- X cleanup(sig);
- X }
- X if (ison(glob_flags, DO_SHELL)) {
- X /* wrapcolumn may have been trashed -- restore it */
- X if (ison(glob_flags, IS_GETTING)) {
- X char *fix = do_set(set_options, "wrapcolumn");
- X if (fix && *fix)
- X wrapcolumn = atoi(fix);
- X }
- X turnoff(glob_flags, IS_GETTING);
- X longjmp(jmpbuf, 1);
- X } else
- X puts("exiting"), cleanup(sig);
- X}
- X
- X#ifdef SIGCONT
- XSIGRET
- Xstop_start(sig)
- X{
- X extern FILE *ed_fp;
- X
- X Debug("Caught signal: %d", sig);
- X if (sig == SIGCONT) {
- X (void) signal(SIGTSTP, stop_start);
- X (void) signal(SIGCONT, stop_start);
- X echo_off();
- X if (istool || ison(glob_flags, IGN_SIGS) && !iscurses)
- X return;
- X /* we're not in an editor but we're editing a letter */
- X if (ison(glob_flags, IS_GETTING)) {
- X if (ed_fp)
- X print("(Continue editing letter)\n");
- X }
- X#ifdef CURSES
- X else if (iscurses)
- X if (ison(glob_flags, IGN_SIGS)) {
- X clr_bot_line();
- X if (msg_cnt)
- X puts(compose_hdr(current_msg));
- X mail_status(1), addstr("...continue... ");
- X refresh();
- X } else {
- X int curlin = max(1, current_msg - n_array[0] + 1);
- X redraw();
- X print("Continue");
- X move(curlin, 0);
- X refresh();
- X /* make sure we lose reverse video on continuation */
- X if (ison(glob_flags, REV_VIDEO) && msg_cnt) {
- X char buf[256];
- X (void) strncpy(buf, compose_hdr(current_msg), COLS-1);
- X buf[COLS-1] = 0; /* strncpy does not null terminate */
- X mvaddstr(curlin, 0, buf);
- X }
- X }
- X#endif /* CURSES */
- X else
- X mail_status(1), (void) fflush(stdout);
- X } else {
- X#ifdef CURSES
- X if (iscurses) {
- X /* when user stops mush, the current header is not in reverse
- X * video -- note that a refresh() has not been called in curses.c!
- X * so, make sure that when a continue is called, the reverse video
- X * for the current message returns.
- X */
- X turnon(glob_flags, WAS_INTR);
- X if (isoff(glob_flags, IGN_SIGS) && ison(glob_flags, REV_VIDEO) &&
- X msg_cnt) {
- X int curlin = max(1, current_msg - n_array[0] + 1);
- X char buf[256];
- X scrn_line(curlin, buf);
- X STANDOUT(curlin, 0, buf);
- X }
- X print("Stopping...");
- X }
- X#endif /* CURSES */
- X echo_on();
- X (void) signal(SIGTSTP, SIG_DFL);
- X (void) signal(SIGCONT, stop_start);
- X (void) kill(getpid(), sig);
- X }
- X}
- X#endif /* SIGCONT */
- X
- X/*ARGSUSED*/
- Xvoid
- Xcleanup(sig)
- X{
- X char buf[128], c;
- X
- X if (sig != SIGTERM && sig != SIGHUP && ison(glob_flags, IGN_SIGS))
- X c = 'n';
- X else
- X c = 'y';
- X
- X#ifdef CURSES
- X if (iscurses && sig != SIGHUP)
- X iscurses = FALSE, endwin();
- X#endif /* CURSES */
- X
- X echo_on();
- X
- X if (ison(glob_flags, IS_GETTING))
- X turnoff(glob_flags, IS_GETTING), dead_letter(sig);
- X if ((sig == SIGSEGV || sig == SIGBUS) && isoff(glob_flags, IGN_SIGS)
- X && *tempfile && !istool) {
- X (void) fprintf(stderr, "remove %s [y]? ", tempfile), (void) fflush(stderr);
- X if (fgets(buf, sizeof(buf), stdin))
- X c = lower(*buf);
- X }
- X if (c != 'n' && *tempfile) {
- X if (sig == SIGHUP && do_set(set_options, "hangup") && copyback(NULL))
- X (void) unlink(tempfile);
- X else if (unlink(tempfile) && !sig && errno != ENOENT)
- X error(tempfile);
- X }
- X if (sig == SIGSEGV || sig == SIGBUS) {
- X if (isoff(glob_flags, IGN_SIGS) && !istool) {
- X (void) fprintf(stderr, "coredump [n]? "), (void) fflush(stderr);
- X if (fgets(buf, sizeof(buf), stdin))
- X c = lower(*buf);
- X }
- X if (c == 'y') {
- X if (!istool)
- X puts("dumping core for debugging");
- X abort();
- X }
- X }
- X exit(sig);
- X}
- X
- Xlong last_spool_size = -1; /* declared here cuz it's initialized here */
- X
- X#ifdef SUNTOOL
- XNotify_value
- Xdo_check()
- X{
- X if (isoff(glob_flags, IGN_SIGS))
- X (void) check_new_mail();
- X return (NOTIFY_DONE) ;
- X}
- X#endif /* SUNTOOL */
- X
- X/*
- X * Get any new mail that has arrived. This function assumes that a
- X * call to mail_size() has already been done, so that last_spool_size
- X * can be compared to spool_size to decide what should be done.
- X *
- X * The value for last_spool_size is updated to the new spool_size only
- X * if update_size is TRUE. check_new_mail() depends on the -1 initial
- X * value of last_spool_size for correct "New mail" messages, so it
- X * uses FALSE and updates last_spool_size itself.
- X */
- Xget_new_mail(update_size)
- Xint update_size;
- X{
- X if (last_spool_size > spool_size && !strcmp(mailfile, spoolfile)) {
- X print("Someone changed \"%s\"! ", mailfile);
- X if (update_size)
- X return 1; /* Don't reinit if called from copyback() */
- X print_more("Reinitializing...\n");
- X if (isoff(glob_flags, READ_ONLY))
- X (void) emptyfile(&tmpf, tempfile);
- X current_msg = msg_cnt = 0;
- X }
- X if (load_folder(mailfile, 1, NULL) < 1) {
- X print("Can't load new mail: \"%s\" may be corrupted!\n", mailfile);
- X turnon(glob_flags, DO_UPDATE); /* Don't reload without rewrite */
- X return update_size;
- X /* NOTE: The above is used to stop check_new_mail() from calling
- X * show_new_mail(), while still allowing copyback() to detect the
- X * possible error and to query about updating the folder. There
- X * should be a better-defined way to handle this.
- X */
- X }
- X if (last_spool_size != spool_size) {
- X if (update_size)
- X last_spool_size = spool_size;
- X if (msg_cnt < last_msg_cnt)
- X turnoff(glob_flags, NEW_MAIL);
- X else {
- X turnon(glob_flags, NEW_MAIL);
- X if (current_msg < 0)
- X current_msg = 0;
- X }
- X return 1;
- X }
- X return 0;
- X}
- X
- X#ifdef SUNTOOL
- Xint is_iconic, was_iconic;
- X#endif /* SUNTOOL */
- X
- X/*
- X * Display a summary when new mail has come in. sprintf it all into one
- X * buffer and print that instead of separate print statements to allow
- X * the tool mode to make one print statement. The reason for this is that
- X * when the tool is refreshed (caused by a resize, reopen, move, top, etc)
- X * the last thing printed is displayed -- display the entire line.
- X */
- Xshow_new_mail()
- X{
- X char buf[BUFSIZ];
- X register char *p = buf;
- X int noisy = !chk_option("quiet", "newmail");
- X#ifdef CURSES
- X int new_hdrs = last_msg_cnt;
- X#endif /* CURSES */
- X
- X if (msg_cnt == last_msg_cnt)
- X return 1; /* Nothing to print */
- X#ifdef SUNTOOL
- X if (istool) {
- X mail_status(0);
- X (void) do_hdrs(0, DUBL_NULL, NULL);
- X if (noisy && !chk_option("quiet", "tool"))
- X bell();
- X }
- X#endif /* SUNTOOL */
- X if (msg_cnt < last_msg_cnt) {
- X last_msg_cnt = msg_cnt;
- X if (!istool)
- X mail_status(0);
- X if (iscurses && isoff(glob_flags, CNTD_CMD))
- X (void) do_hdrs(0, DUBL_NULL, NULL);
- X return 0;
- X }
- X if (noisy) {
- X p += Strcpy(p, "New mail ");
- X if (msg_cnt - last_msg_cnt <= 1)
- X p += strlen(sprintf(p, "(#%d) ", msg_cnt));
- X else
- X p += strlen(sprintf(p, "(#%d thru #%d)\n", last_msg_cnt+1,msg_cnt));
- X }
- X#ifdef SUNTOOL
- X /*
- X * If mush is in tool mode and in icon form, don't update
- X * last_msg_cnt so that when the tool is opened, print() will
- X * print the correct number of "new" messages.
- X */
- X if (istool && (was_iconic = (int) window_get(tool, FRAME_CLOSED)))
- X (void) strcpy(p, "\n");
- X else
- X#endif /* SUNTOOL */
- X {
- X if (!noisy || iscurses && isoff(glob_flags, CNTD_CMD))
- X last_msg_cnt = msg_cnt;
- X else while (last_msg_cnt < msg_cnt) {
- X char *p2 = compose_hdr(last_msg_cnt++) + 9;
- X if (strlen(p2) + (p - buf) >= BUFSIZ-5) {
- X (void) strcpy(p, "...\n");
- X /* force a break by setting last_msg_cnt correctly */
- X last_msg_cnt = msg_cnt;
- X } else
- X p += strlen(sprintf(p, " %s\n", p2));
- X }
- X }
- X#ifdef CURSES
- X if (iscurses && isoff(glob_flags, CNTD_CMD)) {
- X if (new_hdrs - n_array[screen-1] < screen)
- X (void) do_hdrs(0, DUBL_NULL, NULL);
- X print("%s ...", buf);
- X } else
- X#endif /* CURSES */
- X if (noisy)
- X print("%s", buf); /* buf might have %'s in them!!! */
- X return 1;
- X}
- X
- X/*
- X * Look for new mail and read it in if any has arrived.
- X * return 0 if no new mail, 1 if new mail and -1 if new mail is in system
- X * folder, but current mbox is not system mbox.
- X */
- Xcheck_new_mail()
- X{
- X int ret_value;
- X
- X /* if fullscreen access in progress (help), don't do anything */
- X if (ret_value = mail_size()) {
- X#ifdef SUNTOOL
- X /* if our status has changed from icon to open window, then
- X * there will already be a message stating number of new
- X * messages. reset `n' to msg_cnt so we don't restate
- X * the same # of new messages upon receipt of yet another new message.
- X */
- X if (istool && !(is_iconic = ((int) window_get(tool, FRAME_CLOSED))) &&
- X was_iconic)
- X last_msg_cnt = msg_cnt;
- X#endif /* SUNTOOL */
- X if (get_new_mail(0) && !show_new_mail())
- X return 0;
- X } else
- X#ifdef SUNTOOL
- X if (!istool || !is_iconic)
- X#endif /* SUNTOOL */
- X turnoff(glob_flags, NEW_MAIL);
- X if (last_spool_size > -1 && /* handle first case */
- X strcmp(mailfile, spoolfile) && last_spool_size < spool_size)
- X print("You have new mail in your system mailbox.\n"), ret_value = -1;
- X last_spool_size = spool_size;
- X return ret_value;
- X}
- X
- X/*ARGSUSED*/ /* we ignore the sigstack, cpu-usage, etc... */
- XSIGRET
- Xbus_n_seg(sig)
- X{
- X (void) signal(sig, SIG_DFL);
- X (void) fprintf(stderr, "%s: %s\n", prog_name,
- X (sig == SIGSEGV)? "Segmentation violation": "Bus error");
- X cleanup(sig);
- X}
- END_OF_FILE
- if test 10857 -ne `wc -c <'mush/signals.c'`; then
- echo shar: \"'mush/signals.c'\" unpacked with wrong size!
- fi
- # end of 'mush/signals.c'
- fi
- echo shar: End of archive 14 \(of 19\).
- cp /dev/null ark14isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 19 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-
-