argv@zipcode.com (Dan Heller) (04/22/91)
Submitted-by: Dan Heller <argv@zipcode.com> Posting-number: Volume 18, Issue 77 Archive-name: mush/part20 Supersedes: mush: Volume 12, Issue 28-47 #!/bin/sh # do not concatenate these parts, unpack them in order with /bin/sh # file pick.c continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 20; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 if test ! -f _shar_wnt_.tmp; then echo 'x - still skipping pick.c' else echo 'x - continuing file pick.c' sed 's/^X//' << 'SHAR_EOF' >> 'pick.c' && X * 1d 1Y X * X * Return number of args parsed; -1 on error. X */ ago_date(argv) char **argv; { #define SECS_PER_DAY (60 * 60 * 24) #define SECS_PER_WEEK (SECS_PER_DAY * 7) #define SECS_PER_MONTH ((int)(SECS_PER_DAY * 30.5)) #define SECS_PER_YEAR (SECS_PER_DAY * 365) X register char *p; X char buf[256]; X int n = 0, value; X long t; X struct tm *today; X X (void) argv_to_string(buf, argv); X p = buf; X (void) time (&t); /* get current time in seconds and subtract new values */ X if (*p == '-') X before = TRUE; X else if (*p == '+') X after = TRUE; X skipspaces(before || after); X while (*p) { X if (!isdigit(*p)) { X p -= 2; X break; /* really a syntax error, but it could be other pick args */ X } X p = my_atoi(p, &value); /* get 1 or more digits */ X skipspaces(0); /* 0 or more spaces */ X switch (lower(*p)) { /* d, m, or y */ X case 'd' : t -= value * SECS_PER_DAY; X when 'w' : t -= value * SECS_PER_WEEK; X when 'm' : t -= value * SECS_PER_MONTH; X when 'y' : t -= value * SECS_PER_YEAR; X otherwise: return -1; X } X for (p++; Lower(*p) >= 'a' && *p <= 'z'; p++) X ; /* skip the rest of this token */ X while (*p == ',' || isspace(*p)) X ++p; /* 0 or more whitespaces or commas */ X } X today = localtime(&t); X mdy[0] = today->tm_mon; X mdy[1] = today->tm_mday; X mdy[2] = today->tm_year; X X /* Count the number of args parsed */ X for (n = 0; p > buf && *argv; n++) X p -= (strlen(*argv++)+1); X Debug("parsed %d args\n", n); X return n; } SHAR_EOF echo 'File pick.c is complete' && chmod 0644 pick.c || echo 'restore of pick.c failed' Wc_c="`wc -c < 'pick.c'`" test 17697 -eq "$Wc_c" || echo 'pick.c: original size 17697, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= print.c ============== if test -f 'print.c' -a X"$1" != X"-c"; then echo 'x - skipping print.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting print.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'print.c' && /* @(#)print.c 2.4 (c) copyright 10/15/86 (Dan Heller) */ X #include "mush.h" #include <varargs.h> X /*ARGSUSED*/ /*VARARGS1*/ void error(fmt, arg1, arg2, arg3, arg4) register char *fmt; char *arg1, *arg2, *arg3, *arg4; { X char buf[BUFSIZ]; X X (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4); X sprintf(buf+strlen(buf), ": %s\n", sys_errlist[errno]); #ifdef SUNTOOL X if (istool > 1) X ok_box(buf); X else #endif /* SUNTOOL */ X print(buf); } X #if defined(SUNTOOL) || defined(CURSES) /* X * print just like printf -- to a window, to curses, or to stdout. Use vprintf X * if available. msgbuf is the buffer used to print into if necessary. X * If you're running SUN3.2 or higher, the typecast (unsigned char *)msgbuf X * (where indicated) otherwise, msgbuf is not typecast at all. X */ /*VARARGS*/ void print(va_alist) va_dcl { X static char msgbuf[BUFSIZ]; X char *fmt; X va_list args; #ifndef VPRINTF X FILE foo; #endif /* VPRINTF */ X static int x; /* position on line saved for continued prints */ X char *p; /* same type as struct file _ptr,_buf in stdio.h */ X #ifdef CURSES X if (iscurses) { X if (isoff(glob_flags, CONT_PRNT)) X move(LINES-1, x = 0), refresh(); X } else #endif /* CURSES */ X if (istool < 2) { X va_start(args); X fmt = va_arg(args, char *); #ifdef VPRINTF X (void) vprintf(fmt, args); #else /* VPRINTF */ X _doprnt(fmt, args, stdout); #endif /* VPRINTF */ X va_end(args); X (void) fflush(stdout); X return; X } X va_start(args); X fmt = va_arg(args, char *); X if (fmt) { #ifdef VPRINTF X (void) vsprintf(msgbuf, fmt, args); /* NULL in fmt reprints last msg */ #else /* VPRINTF */ X foo._cnt = BUFSIZ; X foo._base = foo._ptr = msgbuf; /* may have to cast(unsigned char *) */ X foo._flag = _IOWRT+_IOSTRG; X (void) _doprnt(fmt, args, &foo); X *foo._ptr = '\0'; /* plant terminating null character */ #endif /* VPRINTF */ X } X va_end(args); X if (istool) { X wprint("%s", msgbuf); X return; X } X p = msgbuf; X if (iscurses) X while (p = index(p, '\n')) X *p = ' '; #ifdef CURSES X if (iscurses) { X p = msgbuf; X for (;;) { X int len = COLS-1-x; /* space remaining at till the eol */ X /* don't wrap the line! Just print it and refresh() */ X printw("%-.*s", len, p), clrtoeol(), refresh(); X /* if length(p) (remainder of msgbuf) doesn't wrap, break loop */ X if ((x += strlen(p)) < COLS-1) X break; X /* the next print will overwrite bottom line, so \n first */ X putchar('\n'), move(LINES-1, x = 0); /* reset x */ X /* move p forward the number of chars we were able to display */ X p += len; X turnon(glob_flags, CNTD_CMD); /* display ...continue... prompt */ X } X turnoff(glob_flags, CONT_PRNT); X (void) fflush(stdout); /* some sys-v's aren't fflushing \n's */ X return; X } #endif /* CURSES */ } X #endif /* SUNTOOL || CURSES */ X /* for curses mode */ clr_bot_line() { X print(""); } X #ifdef SUNTOOL X /* X * wprint prints stuff to a scrollable textsw. This is intended for X * print statements that need to be recalled since print() overwrites X * its last message. X * For non-suntool mode, wprint() is just like printf(). For curses mode, X * wprint() does -not- act like print() -- lines length is not counted X * and newlines are not stripped. X */ /*VARARGS*/ void wprint(va_alist) va_dcl { #ifndef VPRINTF X FILE foo; #endif /* VPRINTF */ X char msgbuf[BUFSIZ]; /* we're not getting huge strings */ X char *fmt; X va_list args; X X if (istool < 2) { X va_start(args); X fmt = va_arg(args, char *); #ifdef VPRINTF X (void) vprintf(fmt, args); #else /* VPRINTF */ X _doprnt(fmt, args, stdout); #endif /* VPRINTF */ X va_end(args); X (void) fflush(stdout); X return; X } X X if (!mfprint_sw) X return; X va_start(args); X fmt = va_arg(args, char *); X if (fmt) { #ifdef VPRINTF X (void) vsprintf(msgbuf, fmt, args); /* NULL in fmt reprints last msg */ #else /* VPRINTF */ X foo._cnt = BUFSIZ; X foo._base = foo._ptr = msgbuf; /* may have to cast (unsigned char *) */ X foo._flag = _IOWRT+_IOSTRG; X _doprnt(fmt, args, &foo); /* format like printf into msgbuf via foo */ X *foo._ptr = '\0'; /* plant terminating null character */ #endif /* VPRINTF */ X textsw_insert(mfprint_sw, msgbuf, strlen(msgbuf)); X } X va_end(args); } X #include <sundev/kbio.h> #include <sundev/kbd.h> X bell() { #ifdef KIOCCMD X if (istool) { X int kbd = open("/dev/kbd", O_WRONLY, 0); X struct timeval timer; X timer.tv_sec = 0; X timer.tv_usec = 100000; X if (kbd != -1) { X int cmd = KBD_CMD_BELL; X (void) ioctl(kbd, KIOCCMD, &cmd); X (void) select(32, (fd_set *) 0,(fd_set *) 0,(fd_set *) 0, &timer); X cmd = KBD_CMD_NOBELL; X (void) ioctl(kbd, KIOCCMD, &cmd); X (void) close(kbd); X } X } else #endif /* KIOCCMD */ X (void) fputc('\007', stderr), (void) fflush(stderr); X return 0; } X #endif /* SUNTOOL */ X #ifdef BSD #undef fputs X /* X * The standard 4.x BSD fputs() does not return any useful value. X * For compatibility with Sun and SysV fputs(), we use this wrapper. X */ X Fputs(line, fp) char *line; FILE *fp; { X clearerr(fp); X (void) fputs(line, fp); X if (ferror(fp)) X return EOF; X return 0; } X #endif /* BSD */ SHAR_EOF chmod 0644 print.c || echo 'restore of print.c failed' Wc_c="`wc -c < 'print.c'`" test 5154 -eq "$Wc_c" || echo 'print.c: original size 5154, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= sample.mushrc ============== if test -f 'sample.mushrc' -a X"$1" != X"-c"; then echo 'x - skipping sample.mushrc (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting sample.mushrc (Text)' sed 's/^X//' << 'SHAR_EOF' > 'sample.mushrc' && # sample.mushrc # By Bart Schaefer and Dan Heller # # Change mush's temp file directory, to avoid quota collisions. # /usr/tmp so tmpfiles won't be rm'd before they can be recovered. set tmpdir=/usr/tmp X # Set the folder and mbox locations; the + expands to value of "folder". set folder=$HOME/Mail mbox=+mbox X # Set up the display early to allow quick exit in headers-only mode. # The hdrs_only flag is true if the command line was: "mush -H". # The variable hdr_format is set to change the format of the header # summaries that are displayed. if hdrs_only X set hdr_format='%28a %M %-2N %.33s' X exit # Quits reading this file else X set hdr_format='%28a %M %-2N (%3.5l li) %.25s' endif X # Set the prompt to show current time, name of the current folder, # current message number, and count of total messages. set prompt="(%T) %f: #%m of %t> " X # Hitting <CR> should do nothing (helps make mush more shell-like). If # newline is not set, hitting <CR> prints the next message (like Mail). # This variable could be set to any mush command. set newline X # These variables are helpful for new users: # ask -- always prompt for Subject: of mail # ignoreeof -- ignore end-of-file from keyboard # verify -- query that all is well before sending mail # warning -- report miscellaneous possible problems set ask verify warning set ignoreeof="echo 'Use "'"'quit'"'" to quit.'" X # When reading messages, don't bother looking at lengthy, boring headers. ignore message-id received via status X # Since mush has csh-like history, you might find it annoying to type # things like "mail host\!host1\!host2\!user" from within the mush shell. # Setting nonobang will prevent the "unknown event" and allow the !'s to # be typed without having to be preceded by backslashes. set nonobang X # By default, mush's history is set to the last command only. Set it to # remember the last 100 commands. set history = 100 X # If the variable "unix" is set, then any command that isn't a mush command # will execute the command as if you typed it from the shell. Note, such # commands will not go through another shell -- this is it. set unix X # Mush tries to read ~/.mushrc first, then it tries ~/.mailrc. Assuming # you use *this* file as your .mushrc, source the contents of .mailrc as # well in case there are Mail aliases that are set there. source $HOME/.mailrc X # Use a real pager. set pager=less X # When typing in a letter, it is sometimes convenient to have lines wrap # automatically similar to editors like vi and emacs. In this example, if # the user types past column 74, a newline will automatically be inserted. set wrapcolumn=74 X # If "autosign" is set, then a file can be read in automatically whenever # mail is sent. This file is normally your "signature," that is, your # name and other information you want included in every message. set autosign = ~/.signature X # When you use the -i option to reply, or use the ~i tilde escape in a letter # when in compose mode, the current message will be included in your text. # Put a nice wrapper around those included messages. Here, show the author's # name and the subject of his letter, label the end, and add a trailing blank # to separate each inclusion and make finding the end easier. set pre_indent_str='On %M %N, %T, %.50n wrote:\n} Subject: %.65s' set indent_str='} ' # actual message text is preceded by a "}" set post_indent_str='}-- End of excerpt from %.50n\n' X # Label replies with a header showing the who, what, and when of the # message being replied-to. set in_reply_to='%f\n\t"%s" (%d)' X # Mail routing and address-fixing conveniences. If auto_route is set, then # replies to messages take a closer look at the addresses of the recipients. # If any redundant paths are present, they are pruned. Also, the path that # precedes any hosts listed in the "known_hosts" list is truncated. This is # useful for uucp sites only, and is therefore commented out in this sample. # set auto_route known_hosts="sun ucbcad well unicom" X # The "alts" command specifies alternate addresses that I have. Here, # "*" expands to any "path" whose recipient ends with the user's current # login name. If another login name is desired, the login and/or path # to that login must be preceded by a !. Otherwise, standard paths are used. alts "*" X # The "map" command can rebind certain key sequences in tty-mode only. # Here, if the user types two R's in a row at the prompt, then the string # "reply -ei " will be echoed as if the user typed it. map RR "reply -ei " # "rr" will do a reply and do the newline for you so you don't have to. map rr "reply\n" X # The "map!" command is similar to "map" in that you can do keyboard # acceleration, but map! occurs during letter composition mode only. map! '\CT' ' ' # ^T generates 4 spaces in composition mode. # Here, hitting * twice will append a pre-signature. map! ** "\n Later,\n" X # Be careful with map and map! -- you can cause an infinite loop. # Your interrupt key (usually ^C) will stop such loops. X # The curses mode allows the screen to be set up like a full screen editor. # There are basic "curses commands" which are bound to keyboard key-sequences # (usually one character). The user can rebind these keys to suit his tastes. # Note that the binding for R below removes the binding of reply-all. # set curses_help # Unset this to remove help message in curses. bind \n display # Hit return to display the next message. bind t top # Make it easier to see the top few lines. bind e macro "[line-mode]edit\n" # Quick edit from curses. bind P macro "[line-mode]Print\n" # Show me all the headers. bind R macro "[line-mode]reply -ei " # Reply with inclusion and edit. bind A macro "R[getline]~t\n\CUargv\n" # R to Dan w/auto address fix. X # "cmd" is used to set command line aliases similar to the way "csh" # does it. The only difference is that "alias" is a reserved word in # Mush and Mail, so cmd is used. # cmd dq 'd \!*; q' # Delete a message list, then quit. cmd unread 'flags \!* U O' # Mark messages unread. cmd : curses # Colon now "toggles" curses mode. X # Find messages from mailer-daemon (ignore upper/lower case). cmd md 'pick -i -f mailer-daemon' # Because mush can pipe commands to one another, including "cmd"'s, this # example will delete all messages from mailer-daemon cmd dmd 'md | delete' X # aliases -- just like Mail's, but you can specify "names" alias argv Dan Heller <argv@sun.com> alias bart Bart Schaefer <schaefer@cse.ogi.edu> alias mush-users Mush Users <mush-users-request@apple.com> SHAR_EOF chmod 0644 sample.mushrc || echo 'restore of sample.mushrc failed' Wc_c="`wc -c < 'sample.mushrc'`" test 6535 -eq "$Wc_c" || echo 'sample.mushrc: original size 6535, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= setopts.c ============== if test -f 'setopts.c' -a X"$1" != X"-c"; then echo 'x - skipping setopts.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting setopts.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'setopts.c' && /* setopts.c (c) copyright 1986 (Dan Heller) */ X #include "mush.h" #include "bindings.h" X static void insert_option(list, opt, order) struct options **list, *opt; int order; /* Insert in sorted order? */ { X while (*list && (!order || (strcmp((*list)->option, opt->option) < 1))) X list = &((*list)->next); X opt->next = *list; X *list = opt; } X /* add an option indicated by "set option[=value]" or by "alias name alias" X * function is recursive, so multilists get appended accordingly X */ add_option(list, argv) register struct options **list; register char **argv; { X register struct options *tmp; X register char *option, *value = NULL; X X if (!(option = *argv)) X return 1; X /* check for one of three forms: X * option=value option= value option = value X */ X if (value = index(option, '=')) { X if (value == option) { X print("No variable specified\n"); X return 0; X } X /* "option=value" strip into option="option" value="value" */ X *value++ = 0; /* option is now a null terminated `option' */ X if (*value || (value = *++argv)) { /* "option= value" */ X ++argv; X } X } else if (*++argv && !strcmp(*argv, "=")) { X if (value = *++argv) /* "option = value" */ X ++argv; X } X X /* check for internal vars that can't be set this way */ X if (*list == set_options && check_internal(option)) { X print("You can't change %s with \"set\".\n", option); X return 0; X } X X /* check to see if option is already set by attempting to unset it */ X if (un_set(list, option) == -1) X return 0; X X /* now make a new option struct and set fields */ X if (!(tmp = (struct options *)calloc((unsigned)1,sizeof(struct options)))) { X error("calloc"); X return -1; X } X tmp->option = savestr(option); X tmp->value = savestr(value); /* strdup handles the NULL case */ X X insert_option(list, tmp, (list != &own_hdrs)); X X /* check for options which must have values or are used frequently */ X if (*list == set_options) { #if defined(CURSES) || defined(SUNTOOL) X if (!strcmp(tmp->option, "no_reverse")) X turnoff(glob_flags, REV_VIDEO); X else #endif /* CURSES || SUNTOOL */ #ifdef SUNTOOL X if (!strcmp(tmp->option, "tool_help")) X if (tmp->value && *(tmp->value)) X strdup(tool_help, tmp->value); X else { X int n = 0; X char *p = getpath(TOOL_HELP, &n); X if (n) X strdup(tool_help, "tool_help"); X else X strdup(tool_help, p); X strdup(tmp->value, tool_help); X } X else #endif /* SUNTOOL */ X if (!strcmp(tmp->option, "cmd_help")) X if (tmp->value && *(tmp->value)) X strdup(cmd_help, tmp->value); X else { X int n = 0; /* don't ignore no such file or directory */ X char *p = getpath(COMMAND_HELP, &n); X if (n) X strdup(cmd_help, "cmd_help"); X else X strdup(cmd_help, p); X strdup(tmp->value, cmd_help); X } X else if (!strcmp(tmp->option, "prompt")) X prompt = (tmp->value)? tmp->value : DEF_PROMPT; X else if (!strcmp(tmp->option, "warning")) X turnon(glob_flags, WARNING); X else if (!strcmp(tmp->option, "mil_time")) X turnon(glob_flags, MIL_TIME); #ifndef MSG_SEPARATOR X else if (!strcmp(tmp->option, "date_received")) X turnon(glob_flags, DATE_RECV); #endif /* MSG_SEPARATOR */ X else if (!strcmp(tmp->option, "escape")) { X escape = (tmp->value)? tmp->value : DEF_ESCAPE; X escape[1] = 0; /* only one character, please */ X } else if (!strcmp(tmp->option, "hdr_format")) X hdr_format = (tmp->value)? tmp->value : DEF_HDR_FMT; X else if (!strcmp(tmp->option, "crt")) { X if (!istool) X crt = (tmp->value)? max(atoi(tmp->value), 2): 18; X } X else if (!strcmp(tmp->option, "screen")) { X screen = (tmp->value)? max(atoi(tmp->value), 1): 18; #ifdef CURSES X if (iscurses && screen > LINES-2) X screen = LINES-2; #endif /* CURSES */ X } else if (!strcmp(tmp->option, "wrapcolumn")) { X char wval[16]; X wrapcolumn = X (tmp->value && *(tmp->value))? max(atoi(tmp->value), 0): 78; #ifdef CURSES X /* Use COLS-2 because of silly terminals like vt100 */ X if (iscurses && wrapcolumn > COLS - 2) X wrapcolumn = COLS - 2; #endif /* CURSES */ X xfree(tmp->value); X tmp->value = savestr(sprintf(wval, "%d", wrapcolumn)); X } else if (!strcmp(tmp->option, "history")) X init_history((value && *value)? atoi(value) : 1); X else if (!strcmp(tmp->option, "realname")) { X char *new[4]; X new[1] = "NAME"; X new[2] = tmp->value; X new[3] = NULL; X (void) Setenv(3, new); /* new[0] is ignored */ X } else if (!strcmp(tmp->option, "known_hosts")) { X register char *p; X int n; X /* in case user separated with commas */ X for (p = index(tmp->value, ','); p; p = index(p+1, ',')) X *p = ' '; X free_vec(known_hosts); X known_hosts = mk_argv(tmp->value, &n, FALSE); X } else if (!strcmp(tmp->option, "hostname")) { X register char *p; X int n; X /* in case user separated with commas */ X for (p = index(tmp->value, ','); p; p = index(p+1, ',')) X *p = ' '; X free_vec(ourname); X ourname = mk_argv(tmp->value, &n, FALSE); X } else if (!strcmp(tmp->option, "complete")) { X if (value && *value) { X m_xlate(value); /* use the original, don't change tmp->value */ X complete = value[0]; X complist = value[1]; X } else { X tmp->value = savestr("\\E\\CD"); X complete = '\033'; X complist = '\004'; X } X } X } X X if (*argv) X return add_option(list, argv); X return 1; } X /* X * If str is NULL, just print options and their values. Note that numerical X * values are not converted to int upon return. If str is not NULL X * return the string that matched, else return NULL; X */ char * do_set(list, str) register struct options *list; register char *str; { X register struct options *opts; X X if (!str) X (void) do_pager(NULL, TRUE); /* page using internal pager */ X X for (opts = list; opts; opts = opts->next) X if (!str) { X (void) do_pager(opts->option, FALSE); X if (opts->value && *opts->value) { X (void) do_pager(" \t", FALSE); X (void) do_pager(opts->value, FALSE); X } X if (do_pager("\n", FALSE) == EOF) X break; X } else { X if (strcmp(str, opts->option)) X continue; X if (opts->value) X return opts->value; X else X return ""; X } X X if (!str) X (void) do_pager(NULL, FALSE); /* terminate internal pager */ X X /* if we still haven't matched, check for environment vars */ X if (str && list == set_options) { X register int N, n; X for (N = 0; environ[N]; N++) { X char *p = index(environ[N], '='); X if (p) X *p = 0; X n = lcase_strncmp(str, environ[N], -1); X if (p) X *p = '='; X if (!n) X return p+1; X } X } X return NULL; } X /* X * unset the variable described by p in the list "list". X * if the variable isn't set, then return 0, else return 1. X */ un_set(list, p) register struct options **list; register char *p; { X register struct options *opts = *list, *tmp; X X if (!list || !*list || !p || !*p) X return 0; X if (*list == set_options) { #if defined(CURSES) || defined(SUNTOOL) X if (!strcmp(p, "no_reverse")) X turnon(glob_flags, REV_VIDEO); X else #endif /* CURSES || SUNTOOL */ X if (!strcmp(p, "prompt")) X prompt = DEF_PROMPT; X else if (!strcmp(p, "warning")) X turnoff(glob_flags, WARNING); X else if (!strcmp(p, "mil_time")) X turnoff(glob_flags, MIL_TIME); #ifndef MSG_SEPARATOR X else if (!strcmp(p, "date_received")) X turnoff(glob_flags, DATE_RECV); #endif /* MSG_SEPARATOR */ X else if (!strcmp(p, "escape")) X escape = DEF_ESCAPE; X else if (!strcmp(p, "hdr_format")) X hdr_format = DEF_HDR_FMT; X else if (!strcmp(p, "crt")) X crt = 18; X else if (!strcmp(p, "screen")) { X screen = 18; #ifdef CURSES X if (iscurses && screen > LINES-2) X screen = LINES-2; #endif /* CURSES */ X } else #ifdef SUNTOOL X if (!strcmp(p, "tool_help")) { X int n = 0; X char *p2 = getpath(TOOL_HELP, &n); X if (n) X strdup(tool_help, "tool_help"); X else X strdup(tool_help, p2); X } else #endif /* SUNTOOL */ X if (!strcmp(p, "cmd_help")) { X int n = 0; /* don't ignore no such file or directory */ X char *p2 = getpath(COMMAND_HELP, &n); X if (n) X strdup(cmd_help, "cmd_help"); X else X strdup(cmd_help, p2); X } else if (!strcmp(p, "wrapcolumn")) X wrapcolumn = 0; X else if (!strcmp(p, "history")) X init_history(1); X else if (!strcmp(p, "known_hosts")) { X free_vec(known_hosts); X known_hosts = DUBL_NULL; X } else if (!strcmp(p, "hostname")) { X free_vec(ourname); X ourname = DUBL_NULL; X } else if (ison(glob_flags, IS_GETTING) && !strcmp(p, "edit_hdrs")) { X wprint("You must finish this letter first.\n"); X return -1; X } else if (!strcmp(p, "complete")) X complete = complist = 0; #ifdef SUNTOOL X else if (!strcmp(p, "compose_icon")) { X if (ison(glob_flags, IS_GETTING)) { X wprint("You must finish this letter first.\n"); X return -1; X } else X /* destroy compose frame so that it is recreated X * later as the proper type (base frame or subframe). X */ X if (compose_frame) X destroy_compose(); X } #endif X } X X if (!strcmp(p, opts->option)) { X *list = (*list)->next; X xfree (opts->option); X if (opts->value) X xfree(opts->value); X xfree((char *)opts); X return 1; X } X for ( ; opts->next; opts = opts->next) X if (!strcmp(p, opts->next->option)) { X tmp = opts->next; X opts->next = opts->next->next; X xfree (tmp->option); X if (tmp->value) X xfree(tmp->value); X xfree ((char *)tmp); X return 1; X } X return 0; } X /* The functions below return 0 since they don't affect X * messages. X */ set(n, argv, list) register int n; register char **argv; char *list; { X void list_to_str(); X char firstchar = **argv; X register char *cmd = *argv; X register struct options **optlist; X char buf[BUFSIZ]; X X if (*cmd == 'u') X cmd += 2; X if (*++argv && !strcmp(*argv, "-?")) X return help(0, (*cmd == 'i')? "ignore": "set", cmd_help); X X if (*argv && **argv == '?') { X int incurses; X if (!strcmp(*argv, "?all")) { X if (incurses = iscurses) /* assign and compare to TRUE */ X clr_bot_line(), iscurses = FALSE; X (void) do_pager(NULL, TRUE); /* start internal pager */ X for (n = 0; variable_stuff(n, NULL, buf); n++) X if (do_pager(strcat(buf, "\n"), FALSE) == EOF) X break; X (void) do_pager(NULL, FALSE); /* terminate pager */ X iscurses = incurses; X } else { X /* May return null if variable not set. */ X (void) variable_stuff(0, (*argv)+1, buf); X print("%s\n", buf); X } X return 0; X } X X if (firstchar == 'u') { X if (!*argv) { X print("%s what?\n", cmd); X return -1; X } else { X optlist = (*cmd == 'i')? &ignore_hdr : &set_options; X do if (!strcmp(*argv, "*")) { X while (*optlist) X (void) un_set(optlist, (*optlist)->option); #ifdef SUNTOOL X if (*cmd != 'i') X opts_panel_item(NULL); #endif /* SUNTOOL */ X } else if (!un_set(optlist, *argv) && X do_set(set_options, "warning")) X print("un%s: %s not set\n", X (*cmd == 'i')? "ignore" : "set", *argv); #ifdef SUNTOOL X else if (*cmd != 'i') X opts_panel_item(*argv); #endif /* SUNTOOL */ X while (*++argv); #ifdef SUNTOOL X if (*cmd == 'i' && istool > 1) X update_list_textsw(&ignore_hdr); #endif /* SUNTOOL */ X } X return 0; X } X X if (!*argv) { X (void) do_set((*cmd == 'i')? ignore_hdr: set_options, NULL); X return 0; X } X X /* X * Check for input redirection. If so, set the variable to the ascii X * value of the current msg_list. X */ X if (ison(glob_flags, IS_PIPE)) { X char *newargv[4]; X X if (*cmd == 'i') { X print("You can't pipe to the \"%s\" command.\n", cmd); X return -1; X } X if (newargv[0] = index(argv[0], '=')) X *newargv[0] = 0; X list_to_str(list, buf); X if (!buf[0] && !do_set(set_options, argv[0])) { X return 0; X } X newargv[0] = argv[0]; X newargv[1] = "="; X newargv[2] = buf; X newargv[3] = NULL; X (void) add_option(&set_options, newargv); X return 0; X } X X /* X * finally, just set the variable the user requested. X */ X (void) add_option((*cmd == 'i')? &ignore_hdr: &set_options, argv); #ifdef SUNTOOL X if (istool > 1) X if (*cmd == 'i') X update_list_textsw(&ignore_hdr); X else X opts_panel_item(argv[0]); #endif /* SUNTOOL */ X return 0; } X /* X * The alts list is a list of hostnames or pathnames where the user X * has an account. If he doesn't specify "metoo", then when replying X * to mail, if his address is listed, it will be removed. The syntax X * is compatible with ucb Mail in that just hostnames can be used. X * However, there is an added feature that mush provides which another X * login name or path to another login can be specified by preceding the X * path or login with a ! X * "argv" may be a file pointer to write the data into by use of save_opts() X */ alts(argc, argv) register char **argv; { X char buf[BUFSIZ], *p; X X /* check here first because a 0 argc means to write it to a file */ X if (argc <= 1) { X int n; X if (!alternates) X return 0; X if (argc == 0) X (void) fprintf((FILE *)argv, "alts "); X for (n = 0; alternates[n]; n++) { X p = 0; X buf[0] = 0; X (void) strcpy(&buf[1], alternates[n]); X if (buf[1] != '*') X (void) reverse(&buf[1]); X if ((p = rindex(&buf[1], '!')) && !lcase_strncmp(p+1, login, -1)) X *p = 0; X else if (buf[1] != '*') X buf[0] = '!'; X if (argc == 0) X (void) fprintf((FILE *)argv, "%s ", *buf? buf : &buf[1]); X else X wprint("%s ", *buf? buf : &buf[1]); X if (p) X *p = '!'; X } X if (argc == 0) X (void) fputc('\n', (FILE *)argv); X else X wprint("\n"); X return 0; X } X X if (argc-- && *++argv && !strcmp(*argv, "-?")) X return help(0, "alts", cmd_help); X X free_vec(alternates); X if (alternates = (char **)calloc((unsigned)argc+1, sizeof(char *))) X while (argc-- > 0) { X if (argv[argc][0] == '!') X alternates[argc] = savestr(reverse(&argv[argc][1])); X else if (argv[argc][0] == '*') { X alternates[argc] = savestr(argv[argc]); X } else { X if (index(argv[argc], '@')) X bang_form(buf, argv[argc]); X else { X p = buf + Strcpy(buf, argv[argc]); X *p++ = '!', p += Strcpy(p, login); X } X alternates[argc] = savestr(reverse(buf)); X } X } X return 0; } X save_opts(cnt, argv) char **argv; { X char file[MAXPATHLEN], *tmp; X register FILE *fp; X X if (cnt && *++argv && !strcmp(*argv, "-?")) X return help(0, "source", cmd_help); X if (cnt && *argv) X (void) strcpy(file, *argv); X else if ((tmp = getenv("MUSHRC")) || (tmp = getenv("MAILRC"))) X (void) strcpy(file, tmp); X else { X char *home = do_set(set_options, "home"); X if (!home || !*home) X home = ALTERNATE_HOME; X /* if .mushrc doesn't exist, check .mailrc. If neither, force .mushrc */ X if (Access(sprintf(file, "%s/%s", home, MAILRC), F_OK) && X Access(sprintf(file, "%s/%s", home, ALTERNATE_RC), F_OK)) X (void) sprintf(file, "%s/%s", home, MAILRC); X } X X cnt = 1; X tmp = getpath(file, &cnt); X if (cnt) { X if (cnt == -1) { X print("%s: %s\n", file, tmp); X return -1; X } else { X print("%s is a directory.\n", tmp); X return -2; X } X } X /* See if the file exists and confirm overwrite */ X if (!Access(tmp, F_OK)) { X int overwrite = TRUE; X char buf[BUFSIZ]; X if (!istool) { X print("\"%s\" exists. Overwrite? ", trim_filename(tmp)); X if (Getstr(buf, 3, 0) <= 0 || lower(*buf) != 'y') X overwrite = FALSE; X } #ifdef SUNTOOL X else { X sprintf(buf, "\"%s\" exists. Overwrite? ", trim_filename(tmp)); X overwrite = ask(buf); X } #endif /* SUNTOOL */ X if (!overwrite) { X print("\"%s\" unchanged.\n", tmp); X return -3; X } X } X if (!(fp = fopen(tmp, "w"))) { X error("Can't open %s", file); X return -1; X } X X save_list("basic variable settings", set_options, "set", '=', fp); X X save_list("mail headers for outgoing mail", own_hdrs, "my_hdr", 0, fp); X X save_list("aliases", aliases, "alias", 0, fp); X X (void) alts(0, (char **)fp); X X save_list("headers to ignore", ignore_hdr, "ignore", ' ', fp); X X save_list("command abbreviations", functions, "cmd", ' ', fp); X X save_list("command macros for function keys", fkeys, "fkey", ' ', fp); X #ifdef CURSES X save_cmd("curses mode key bindings", cmd_map, "bind", 1, fp); #endif /* CURSES */ X X save_cmd("line mode mappings", line_map, "map", 0, fp); X X save_cmd("composition mode mappings", bang_map, "map!", 0, fp); X X (void) fclose(fp); X print("All variables and options saved in %s\n", trim_filename(tmp)); X return 0; } X save_list(title, list, command, equals, fp) struct options *list; register char *command, *title, equals; register FILE *fp; { X register struct options *opts; X register char *p; X X if (!list) X return; X (void) fprintf(fp, "#\n# %s\n#\n", title); X for (opts = list; opts; opts = opts->next) { X if (list == set_options && !strcmp(opts->option, "cwd")) X continue; /* don't print $cwd */ X (void) fprintf(fp, "%s %s", command, opts->option); X if (opts->value && *opts->value) { X register char *quote; X if (!equals) X quote = NO_STRING; X else if (p = any(opts->value, "\"'")) X if (*p == '\'') X quote = "\""; X else X quote = "'"; X else X if (!any(opts->value, " \t;|")) X quote = NO_STRING; X else X quote = "'"; X (void) fputc(equals? equals: ' ', fp); X (void) fprintf(fp, "%s%s%s", quote, opts->value, quote); X } X (void) fputc('\n', fp); X } } X extern struct cmd_map map_func_names[]; X save_cmd(title, list, command, equals, fp) struct cmd_map *list; register char *command, *title; register int equals; register FILE *fp; { X register struct cmd_map *opts; X register char *p; X char buf[MAX_MACRO_LEN * 2]; X X if (!list) X return; X (void) fprintf(fp, "#\n# %s\n#\n", title); X for (opts = list; opts; opts = opts->m_next) { X register char *quote; X if ((p = any(opts->m_str, "\"'")) && *p == '\'') X quote = "\""; X else X quote = "'"; X (void) fprintf(fp, "%s %s%s%s", command, quote, X ctrl_strcpy(buf, opts->m_str, TRUE), quote); X if (equals && map_func_names[opts->m_cmd].m_str) X (void) fprintf(fp, " %s", map_func_names[opts->m_cmd].m_str); X if (opts->x_str && *opts->x_str) { X if ((p = any(opts->x_str, "\"'")) && *p == '\'') X quote = "\""; X else X quote = "'"; X (void) fprintf(fp, " %s%s%s", quote, X ctrl_strcpy(buf, opts->x_str, TRUE), quote); X } X (void) fputc('\n', fp); X } } X /* X * do_alias handles aliases, header settings, functions, and fkeys. X * since they're all handled in the same manner, the same routine is X * used. argv[0] determines which to use. X * alias is given here as an example X * X * alias identify all aliases X * alias name identify alias X * alias name arg1 arg2 arg3... -> name="arg1 arg2 arg3"; call add_option X * unalias arg1 [arg2 arg3 ... ] unalias args X * X * same is true for dealing with your own headers. X * (also the expand command) X */ do_alias(argc, argv) register char **argv; { X register char *cmd = *argv, *p; X struct options **list; X char firstchar = *cmd, buf[BUFSIZ]; X X if (argc == 0) X return 0 - in_pipe(); X if (firstchar == 'u') X firstchar = cmd[2]; X if (*++argv && !strcmp(*argv, "-?")) { /* doesn't apply for fkeys */ X register char *help_str; X if (firstchar == 'a' || firstchar == 'e') X help_str = "alias"; X else if (firstchar == 'c') X help_str = "cmd"; X else if (firstchar == 'f') X help_str = "fkey"; X else X help_str = "my_hdr"; X return help(0, help_str, cmd_help); X } X X if (firstchar == 'a') X list = &aliases; X else if (firstchar == 'c') X list = &functions; X else if (firstchar == 'f') X list = &fkeys; X else X list = &own_hdrs; X X if (*cmd == 'u') { X if (!*argv) { X print("%s what?\n", cmd); X return -1; X /* unset a list separated by spaces or ',' */ X } else while (*argv) { X if (!strcmp(*argv, "*")) /* unset everything */ X while (*list) X (void) un_set(list, (*list)->option); X else if (!un_set(list, *argv)) X print("\"%s\" isn't set\n", *argv); X argv++; X } #ifdef SUNTOOL X if (istool > 1) X update_list_textsw(list); #endif /* SUNTOOL */ X return 0; X } X X if (!*argv && *cmd != 'e') { X /* just type out all the aliases or own_hdrs */ X (void) do_set(*list, NULL); X return 0; X } X X if (*cmd == 'e') { /* command was "expand" (aliases only) */ X if (!*argv) { X print("expand which alias?\n"); X return -1; X } else X do { X print("%s: ", *argv); X if (p = alias_to_address(*argv)) X print("%s\n", p); X } while (*++argv); X return 0; X } X X /* at this point, *argv now points to a variable name ... X * check for hdr -- if so, *argv better end with a ':' (check *p) X */ X if (list == &own_hdrs && !(p = index(*argv, ':'))) { X print("header labels must end with a ':' (%s)\n", *argv); X return -1; X } X if (!argv[1] && !index(*argv, '=')) X if (p = do_set(*list, *argv)) X print("%s\n", p); X else X print("%s is not set\n", *argv); X else { X char *tmpargv[2]; X (void) argv_to_string(buf, argv); X if ((p = any(buf, " \t=")) && *p != '=') X *p = '='; X /* if we're setting an alias, enforce the insertion of commas X * between each well-formed address. X */ X if (list == &aliases) X fix_up_addr(p+1); X tmpargv[0] = buf; X tmpargv[1] = NULL; X (void) add_option(list, tmpargv); #ifdef SUNTOOL X if (istool > 1) X update_list_textsw(list); #endif /* SUNTOOL */ X } X return 0; } SHAR_EOF chmod 0644 setopts.c || echo 'restore of setopts.c failed' Wc_c="`wc -c < 'setopts.c'`" test 21221 -eq "$Wc_c" || echo 'setopts.c: original size 21221, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= signals.c ============== if test -f 'signals.c' -a X"$1" != X"-c"; then echo 'x - skipping signals.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting signals.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'signals.c' && /* @(#)signals.c (c) copyright 10/18/86 (Dan Heller) */ X #include "mush.h" X #ifdef SUNTOOL extern int compose_destroy; #endif X static int was_stopped; X #ifndef SYSV extern char *sys_siglist[]; #else /* sys-v doesn't have normal sys_siglist */ static char *sys_siglist[] = { /* no error */ "no error", /* SIGHUP */ "hangup", /* SIGINT */ "interrupt (rubout)", /* SIGQUIT */ "quit (ASCII FS)", /* SIGILL */ "illegal instruction (not reset when caught)", /* SIGTRAP */ "trace trap (not reset when caught)", /* SIGIOT */ "IOT instruction", /* SIGEMT */ "EMT instruction", /* SIGFPE */ "floating point exception", /* SIGKILL */ "kill (cannot be caught or ignored)", /* SIGBUS */ "bus error", /* SIGSEGV */ "segmentation violation", /* SIGSYS */ "bad argument to system call", /* SIGPIPE */ "write on a pipe with no one to read it", /* SIGALRM */ "alarm clock", /* SIGTERM */ "software termination signal from kill", /* SIGUSR1 */ "user defined signal 1", /* SIGUSR2 */ "user defined signal 2", /* SIGCLD */ "death of a child", /* SIGPWR */ "power-fail restart" }; #endif /* SYSV */ X SIGRET intrpt(sig) { X if (!was_stopped) X Debug("interrupt() caught: %d\n", sig); X mac_flush(); X turnon(glob_flags, WAS_INTR); } 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 */ /*ARGSUSED*/ SIGRET catch(sig) { X if (!was_stopped) 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 turnoff(glob_flags, IS_PIPE); X if (istool || sig == SIGTERM || sig == SIGHUP) { #ifdef SUNTOOL X if (istool > 1) { /* istool is 2 if tool is complete */ X if (compose_destroy) { X if (sig == SIGTERM) /* tty_sw is dying */ X return; X if (sig == SIGHUP) { /* compose frame went away */ X compose_destroy = 0; X compose_frame = 0; X return; X } X } #ifndef SUN_4_0 X /* spurious SIGHUPs in 3.5 */ X if (sig == SIGHUP && window_get(tool, WIN_SHOW)) X return; #endif /* SUN_4_0 */ X istool = 1; X } #endif /* SUNTOOL */ X if (!was_stopped) X print("%s: %s\n", prog_name, sys_siglist[sig]); X (void) setjmp(jmpbuf); X if (ison(glob_flags, IS_GETTING)) X rm_edfile(-1); X cleanup(sig); X } X if (!was_stopped) X print("%s: %s\n", prog_name, sys_siglist[sig]); 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); #ifdef SYSV X /* Interrupting "await" leaves an alarm timer running, which X * some SysV systems mishandle. Clean up. X */ X if (!istool) X (void) signal(SIGALRM, SIG_IGN); #endif /* SYSV */ X longjmp(jmpbuf, 1); X } else { X if (!was_stopped) X puts("exiting"); X cleanup(sig); X } } X #ifdef SIGCONT #ifdef SIGTTOU jmp_buf ttoubuf; X SIGRET tostop(sig) { X (void) signal(SIGTTOU, SIG_DFL); X if (was_stopped) X longjmp(ttoubuf, 1); } #endif /* SIGTTOU */ X SIGRET stop_start(sig) { 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); #ifdef SIGTTOU X /* Restoring echo mode may cause a SIGTTOU if mush was killed X * while in the background. Jump around the echo_off() call if X * we get a TTOU when attempting it. Leave was_stopped on in X * this case, and don't do all the associated prompting. X */ X (void) signal(SIGTTOU, tostop); X if (setjmp(ttoubuf) == 0) { X echo_off(); X was_stopped = 0; X } #ifdef CURSES X else X iscurses = 0; #endif /* CURSES */ #endif /* SIGTTOU */ X if (istool || was_stopped || 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 } #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 } #endif /* CURSES */ X else X mail_status(1), (void) fflush(stdout); X } else { #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 } #endif /* CURSES */ X echo_on(); X (void) signal(SIGTSTP, SIG_DFL); X (void) signal(SIGCONT, stop_start); X was_stopped = 1; X (void) kill(getpid(), sig); X } } #endif /* SIGCONT */ X /*ARGSUSED*/ void cleanup(sig) { 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 #ifdef CURSES X if (iscurses && sig != SIGHUP) X iscurses = FALSE, endwin(); #endif /* CURSES */ X X if (!was_stopped) 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") && X copyback(NULL, TRUE) && isoff(glob_flags, CORRUPTED)) 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 long last_spool_size = -1; /* declared here cuz it's initialized here */ X #ifdef SUNTOOL Notify_value do_check() { X if (isoff(glob_flags, IGN_SIGS)) X (void) check_new_mail(); X return (NOTIFY_DONE) ; } #endif /* SUNTOOL */ 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 */ get_new_mail(update_size) int update_size; { 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 turnoff(glob_flags, CORRUPTED); X } X if (ison(glob_flags, CORRUPTED)) X return 0; 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, CORRUPTED); 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 /* 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_size; X if (last_spool_size != spool_size) X turnon(glob_flags, NEW_MAIL); X } else if (last_spool_size < spool_size) X turnon(glob_flags, NEW_MAIL); X if (msg_cnt && current_msg < 0) X current_msg = 0; X if (last_spool_size != spool_size) { X if (update_size) X last_spool_size = spool_size; X return 1; X } X return 0; } X #ifdef SUNTOOL int is_iconic, was_iconic; #endif /* SUNTOOL */ 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 */ show_new_mail() { X char buf[BUFSIZ]; X register char *p = buf; X int noisy = !chk_option("quiet", "newmail"); #ifdef CURSES X int new_hdrs = last_msg_cnt; #endif /* CURSES */ X X if (msg_cnt == last_msg_cnt) X return 1; /* Nothing to print */ #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 } #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 } #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 #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 } #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 #endif /* CURSES */ X if (noisy) X print("%s", buf); /* buf might have %'s in them!!! */ X return 1; } 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 */ check_new_mail() { X int ret_value; X X if (ret_value = mail_size()) { #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; #endif /* SUNTOOL */ X if (get_new_mail(0) && !show_new_mail()) X return 0; X } else #ifdef SUNTOOL X if (!istool || !is_iconic) #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 /*ARGSUSED*/ /* we ignore the sigstack, cpu-usage, etc... */ SIGRET bus_n_seg(sig) { X (void) signal(sig, SIG_DFL); SHAR_EOF true || echo 'restore of signals.c failed' fi echo 'End of part 20' echo 'File signals.c is continued in part 21' echo 21 > _shar_seq_.tmp exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.