schaefer@ogicse.ogc.edu (Barton E. Schaefer) (12/20/89)
@OFF This is Official Patch #2 for Mush 7.0. It'll be the last one before the new year; Dan Heller is out of the country until Jan. 5 and I will be out in the cold (er, visiting family in Iowa, I mean) from Dec. 24 to Jan. 6. As usual, fully up-to-date versions are available for anonymous ftp from: ucbvax.berkeley.edu: pub/mailers/mush-7.0.tar.Z cse.ogi.edu: pub/mush/mush-7.0.tar.Z If you missed Official Patch #1, you can obtain it via E-mail by sending a message to me: <schaefer@cse.ogi.edu> or {harvard,rutgers,garp,decwrl,ucsd,unmvax}!ogicse!schaefer Include in your message a line of the form @PATCH patch-number path-from-ogicse-to-you To recieve a complete set of mush sources, use @MUSH path-from-ogicse-to-you The mush sources are mailed as a compressed tarfile, encoded for shipping with the "btoa" utility and "split" into 9 parts. Note that ogicse is still having some sendmail.cf troubles, so the path-from-ogicse-to-you must either be an Internet address (no mixing of !-paths and @-domains) or a uucp path that begins with a well-known (and preferably connected-to-ogicse) host. The mail server is now able to do some uucp hostname lookups on its own, so hopefully there will be few difficulties. Changes/fixes in this patch: Special-cased file listing (completion) so that only file names (not paths) are shown when no metacharacters are used in the string to be completed. Note that relative paths are (and have always been) used except when ~ or + appear in the string to be completed. Made changes to glob.c to support the above. Also fixed some pointer initialization problems that caused odd behavior on Suns. If you plan to make local changes to the glob routines, take care, because they are now used to construct menus of filenames in tool mode. Fixed problem with signal handler resets when mailing with $verbose. Added dependencies to the makefile.* to recompile proper .o's when version.h changes (as always happens when you apply a patch). Shortened some long lines in the man page and corrected some out-of- date passages. Fixed line-mode command calls from tool-mode items that could have incorrectly activated a user-defined cmd. The right-button menus of folders in tool mode Folder and Save are now sorted again, at least until new folders are added. The first choice on the Save menu is always your $mbox, which means that if your $mbox is in your $folder directory, it'll appear twice on the Save menu. New folders appear near the beginning of the menus as they are added, following the fixed choices. Problems that remain: A reported seg fault under SunOS 3.5 using Respond right-button Help in the Compose frame still has not been resolved. It seems likely that this is related to SunView running out of file descriptors at a spot where mush can't catch it, but we continue to investigate and would appreciate any additional reports (and stack traces) relating to this problem. *** /tmp/,RCSt1012127 Tue Dec 19 12:58:12 1989 --- curs_io.c Mon Dec 18 16:42:16 1989 *************** *** 521,527 **** expandall = 0; overstrike = (*buf == '+' || *buf == '~'); trim = (overstrike && len > 1); ! if (!overstrike || len > 1) *b++ = '*', *b = 0; f = filexp(buf, &exp); if (*--b == '*') --- 521,527 ---- expandall = 0; overstrike = (*buf == '+' || *buf == '~'); trim = (overstrike && len > 1); ! if (*buf != '~' || len > 1) *b++ = '*', *b = 0; f = filexp(buf, &exp); if (*--b == '*') *************** *** 550,558 **** return errbell(-1); } else if (f > 0) { Debug("result is: "), print_argv(exp); if (showlist) { putchar('\n'); ! if (columnate(f, exp) < 0) (void) errbell(-1); /* Reprint the line */ if (iscurses) { --- 550,565 ---- return errbell(-1); } else if (f > 0) { Debug("result is: "), print_argv(exp); + if (!expandall && f > 1) + prefix = lcprefix(exp, overstrike ? 0 : len); + else + prefix = 0; if (showlist) { + if (!expandall && f > 1) + while (prefix && exp[0][prefix - 1] != '/') + --prefix; putchar('\n'); ! if (columnate(f, exp, prefix) < 0) (void) errbell(-1); /* Reprint the line */ if (iscurses) { *************** *** 564,573 **** wprint("%s", string); } } else if (expandall || strlen(exp[0]) > len) { - if (!expandall && f > 1) - prefix = lcprefix(exp, overstrike ? 0 : len); - else - prefix = 0; Debug("%s", string); if (overstrike && (prefix || expandall || f == 1)) { char *tmpv[3]; --- 571,576 ---- *************** *** 612,618 **** Ungetstr(&exp[0][len]); } else Debug("\nno longer prefix\n%s", string); ! (void) errbell(0); } } else { Debug("no longer prefix\n%s", string); --- 615,626 ---- Ungetstr(&exp[0][len]); } else Debug("\nno longer prefix\n%s", string); ! /* Special case because "+" always tries to expand "+*" ! * to get listings and avoid getpath()'s trailing '/'. ! * No error bell is needed in those cases. ! */ ! if (strcmp(buf, "+") != 0) ! (void) errbell(0); } } else { Debug("no longer prefix\n%s", string); *** /tmp/,RCSt1012127 Tue Dec 19 12:58:15 1989 --- execute.c Fri Dec 15 12:42:48 1989 *************** *** 66,72 **** --- 66,76 ---- { print("Starting \"%s\"...\n", *argv); msg_rect = *(Rect *)window_get(msg_sw, WIN_RECT); + #ifdef ALERT_ATTR /* SunOS 4.0+ */ window_set(msg_sw, WIN_SHOW, FALSE, NULL); + #else /* ALERT_ATTR */ + textsw_set(msg_sw, WIN_SHOW, FALSE, NULL); + #endif /* ALERT_ATTR */ (void) window_set(tty_sw, WIN_RECT, &msg_rect, TTY_ARGV, argv, *** /tmp/,RCSt1012127 Tue Dec 19 12:58:16 1989 --- file.c Mon Dec 18 16:07:56 1989 *************** *** 104,110 **** *isdir = -1; return sys_errlist[errno]; } ! *isdir = ((stat_buf.st_mode & S_IFDIR) != 0); return buf; } --- 104,110 ---- *isdir = -1; return sys_errlist[errno]; } ! *isdir = ((stat_buf.st_mode & S_IFMT) == S_IFDIR); return buf; } *** /tmp/,RCSt1012127 Tue Dec 19 12:58:18 1989 --- glob.c Tue Dec 19 12:57:25 1989 *************** *** 42,48 **** while (*++argv) { (void) printf("%s -->\n", *argv); if (f = filexp(*argv, &e)) { ! columnate(f, e); } } #ifdef TEST2 /* Define TEST2 to automatically run these test cases */ --- 42,48 ---- while (*++argv) { (void) printf("%s -->\n", *argv); if (f = filexp(*argv, &e)) { ! columnate(f, e, 0); } } #ifdef TEST2 /* Define TEST2 to automatically run these test cases */ *************** *** 190,197 **** /* Two sort passes to eliminate duplicates -- see uniqcmp() */ qsort((char *)*exp, cnt, sizeof(char *), uniqcmp); qsort((char *)*exp, cnt, sizeof(char *), uniqcmp); ! while (!(*exp)[cnt - 1][0]) xfree((*exp)[--cnt]); } return cnt; } --- 190,199 ---- /* Two sort passes to eliminate duplicates -- see uniqcmp() */ qsort((char *)*exp, cnt, sizeof(char *), uniqcmp); qsort((char *)*exp, cnt, sizeof(char *), uniqcmp); ! while (!(*exp)[cnt - 1][0]) { xfree((*exp)[--cnt]); + (*exp)[cnt] = NULL; + } } return cnt; } *************** *** 527,532 **** --- 529,535 ---- *exp = t1; return n; } + *exp = DUBL_NULL; while (n-- && cnt >= 0) { new = sxp(t1[n], &t2); cnt = catv(cnt, exp, new, t2); *************** *** 620,630 **** #endif /* CURSES */ /* ! * Print a vector in columns. */ ! columnate(argc, argv) int argc; char **argv; { int colstep, colwidth[MAXCOLS + 1]; int maxcols = min(argc, MAXCOLS); --- 623,638 ---- #endif /* CURSES */ /* ! * Print a vector in columns ! * ! * If "skip" is nonzero, that many chars are assumed to be in common ! * and are not printed. WARNING: skip must be <= than the length of ! * the shortest string in the vector! Safest to call with skip = 0. */ ! columnate(argc, argv, skip) int argc; char **argv; + int skip; { int colstep, colwidth[MAXCOLS + 1]; int maxcols = min(argc, MAXCOLS); *************** *** 642,648 **** * Also remember the minimum width. */ for (minwidth = MAXWIDTH, maxwidth = n = 0; n < argc; n++) { ! widths[n] = max(strlen(argv[n]) + 2, MINWIDTH); if (widths[n] > MAXWIDTH - MINWIDTH) break; if (widths[n] > maxwidth) { --- 650,656 ---- * Also remember the minimum width. */ for (minwidth = MAXWIDTH, maxwidth = n = 0; n < argc; n++) { ! widths[n] = max(strlen(argv[n] + skip) + 2, MINWIDTH); if (widths[n] > MAXWIDTH - MINWIDTH) break; if (widths[n] > maxwidth) { *************** *** 675,692 **** * The maxword fills too much screen, so redo everything * above it, print maxword, then do everything below it. */ ! if (maxword > 0 && columnate(maxword, argv) < 0) return -1; ! wprint("%s\n", argv[maxword]); if (argc - maxword < 2) return 0; ! return columnate(argc - maxword - 1, &argv[maxword + 1]); } for (n = 0; n < colstep; n++) { for (c = 0; c < maxcols && n + c * colstep < argc - colstep; c++) ! wprint("%-*.*s", colwidth[c], colwidth[c], argv[n + c * colstep]); ! wprint("%s\n", argv[n + c * colstep]); } return 0; --- 683,701 ---- * The maxword fills too much screen, so redo everything * above it, print maxword, then do everything below it. */ ! if (maxword > 0 && columnate(maxword, argv, skip) < 0) return -1; ! wprint("%s\n", argv[maxword] + skip); if (argc - maxword < 2) return 0; ! return columnate(argc - maxword - 1, &argv[maxword + 1], skip); } for (n = 0; n < colstep; n++) { for (c = 0; c < maxcols && n + c * colstep < argc - colstep; c++) ! wprint("%-*.*s", colwidth[c], colwidth[c], ! argv[n + c * colstep] + skip); ! wprint("%s\n", argv[n + c * colstep] + skip); } return 0; *** /tmp/,RCSt1012127 Tue Dec 19 12:58:24 1989 --- mail.c Tue Dec 19 12:06:59 1989 *************** *** 1,7 **** /* @(#)mail.c (c) copyright 1986 (Dan Heller) */ #include "mush.h" - #include "version.h" /* * mail.c -- --- 1,6 ---- *************** *** 688,694 **** return 1; for (n = 0; n < msg_cnt; n++) if (msg_bit(list, n)) { - (void) fputc('\n', ed_fp); if (line[1] == 'f') { (void) reply_to(n, FALSE, buf); (void) fprintf(ed_fp, --- 687,692 ---- *************** *** 700,705 **** --- 698,705 ---- if (line[1] == 'f') (void) fprintf(ed_fp, "\n--- End of forwarded message from %s\n\n", buf); + else + (void) fputc('\n', ed_fp); } } /* To: Cc: and Bcc: headers */ *************** *** 1411,1419 **** #endif /* VERBOSE_ARG */ #endif /* SUNTOOL */ ! if ((ison(flags, VERBOSE) || debug > 2) && isoff(glob_flags, REDIRECT)) ! wprint("sent.\n"); ! else exit(0); /* not a user exit -- a child exit */ return 0; } --- 1411,1425 ---- #endif /* VERBOSE_ARG */ #endif /* SUNTOOL */ ! if (ison(flags, VERBOSE) || debug > 2) { ! if (isoff(glob_flags, REDIRECT)) ! wprint("sent.\n"); ! if (!istool) { ! (void) signal(SIGINT, oldint); ! (void) signal(SIGQUIT, oldquit); ! (void) signal(SIGTERM, oldterm); ! } ! } else exit(0); /* not a user exit -- a child exit */ return 0; } *** /tmp/,RCSt1012127 Tue Dec 19 12:58:28 1989 --- makefile.bsd Tue Dec 19 12:13:48 1989 *************** *** 31,37 **** @echo loading... @cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush ! $(OBJS): config.h tape: @tar cv $(MAKES) $(HDRS) $(SRCS) $(HELP_FILES) --- 31,38 ---- @echo loading... @cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush ! $(OBJS): config.h mush.h ! loop.o: version.h tape: @tar cv $(MAKES) $(HDRS) $(SRCS) $(HELP_FILES) *** /tmp/,RCSt1012127 Tue Dec 19 12:58:28 1989 --- makefile.hpux Tue Dec 19 12:10:37 1989 *************** *** 2,8 **** # HDRS1= mush.h config.h HDRS2= strings.h options.h ! HDRS3= bindings.h version.h glob.h SRCS1= commands.c dates.c execute.c expr.c folders.c \ hdrs.c init.c loop.c mail.c main.c misc.c msgs.c pick.c \ print.c setopts.c signals.c sort.c viewopts.c options.c lock.c --- 2,9 ---- # HDRS1= mush.h config.h HDRS2= strings.h options.h ! HDRS3= bindings.h glob.h ! HDRS4= version.h SRCS1= commands.c dates.c execute.c expr.c folders.c \ hdrs.c init.c loop.c mail.c main.c misc.c msgs.c pick.c \ print.c setopts.c signals.c sort.c viewopts.c options.c lock.c *************** *** 32,37 **** --- 33,39 ---- $(OBJS1): $(HDRS1) $(HDRS2) $(OBJS2): $(HDRS1) $(HDRS2) $(HDRS3) + loop.o: version.h BINDIR= /usr/local/bin LIBDIR= /usr/local/lib *** /tmp/,RCSt1012127 Tue Dec 19 12:58:29 1989 --- makefile.sys.v Tue Dec 19 12:13:16 1989 *************** *** 3,9 **** # HDRS1= mush.h config.h HDRS2= strings.h options.h ! HDRS3= bindings.h version.h glob.h SRCS1= commands.c dates.c execute.c expr.c folders.c \ hdrs.c init.c loop.c mail.c main.c misc.c msgs.c pick.c \ print.c setopts.c signals.c sort.c viewopts.c options.c lock.c --- 3,10 ---- # HDRS1= mush.h config.h HDRS2= strings.h options.h ! HDRS3= bindings.h glob.h ! HDRS4= version.h SRCS1= commands.c dates.c execute.c expr.c folders.c \ hdrs.c init.c loop.c mail.c main.c misc.c msgs.c pick.c \ print.c setopts.c signals.c sort.c viewopts.c options.c lock.c *************** *** 37,42 **** --- 38,44 ---- $(OBJS1): $(HDRS1) $(HDRS2) $(OBJS2): $(HDRS1) $(HDRS2) $(HDRS3) + loop.o: version.h BINDIR= /usr/local/bin LIBDIR= /usr/local/lib *** /tmp/,RCSt1012127 Tue Dec 19 12:58:29 1989 --- makefile.xenix Tue Dec 19 12:13:34 1989 *************** *** 42,48 **** @echo loading... @cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush ! $(OBJS): config.h # For 80286 machines, use these two lines... # misc.o: misc.c --- 42,49 ---- @echo loading... @cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush ! $(OBJS): config.h mush.h ! loop.o: version.h # For 80286 machines, use these two lines... # misc.o: misc.c *** /tmp/,RCSt1012127 Tue Dec 19 12:58:34 1989 --- mush.1 Sat Dec 16 13:31:44 1989 *************** *** 3486,3499 **** .sp .nf .ti +2 ! set autosign2 = \*Q!island @berkeley.edu @mit.edu *schaefer root: \--dan\*U .fi .sp This means that any mail sent to 1) anyone at island, 2) anyone within ! the berkeley domain, 3) anyone within the mit domain, 4) Bart Schaefer (at any host anywhere -- even locally), and 4) root on the local machine only (or, root@local-machine-name) ! will be signed by my \*Qalternate\*U signature. If any address on the recipient list fails to satisfy these four matches, the mail will be signed by my regular signature. .sp --- 3486,3500 ---- .sp .nf .ti +2 ! set autosign2 = \*Q!island @sun.com @mit.edu *schaefer root: \--dan\*U .fi .sp This means that any mail sent to 1) anyone at island, 2) anyone within ! the sun domain, 3) anyone within the mit domain, 4) Bart Schaefer (at any host anywhere -- even locally), and 4) root on the local machine only (or, root@local-machine-name) ! will be signed with the \*Qalternate\*U signature. ! If any address on the recipient list fails to satisfy these four matches, the mail will be signed by my regular signature. .sp *************** *** 3720,3728 **** A valid Cc: header does not remove this restriction. You may have as many To: and Cc: headers as you like. .sp ! The From: header must not be altered. ! Altering this header will result in a warning and it will be replaced by a ! correct one. .sp The Date: header will always be replaced by one with a more accurate time and date stamp. --- 3721,3729 ---- A valid Cc: header does not remove this restriction. You may have as many To: and Cc: headers as you like. .sp ! The From: header normally should not be changed. ! If you change this header to an address that mush is unable to identify as ! authentic, mush will silently put back the original From: header. .sp The Date: header will always be replaced by one with a more accurate time and date stamp. *** /tmp/,RCSt1012127 Tue Dec 19 12:58:47 1989 --- version.h Mon Dec 18 10:45:57 1989 *************** *** 1,8 **** /* @(#)version.h (c) Copyright 1989 (Dan Heller) */ #define MUSHNAME "Mail User's Shell" ! #define RELEASE_DATE "12/13/89" #define RELEASE 7 #define REVISION "0" ! #define PATCHLEVEL 1 #define ORIGINAL_DATE "12/10/89" --- 1,8 ---- /* @(#)version.h (c) Copyright 1989 (Dan Heller) */ #define MUSHNAME "Mail User's Shell" ! #define RELEASE_DATE "12/18/89" #define RELEASE 7 #define REVISION "0" ! #define PATCHLEVEL 2 #define ORIGINAL_DATE "12/10/89" *** /tmp/,RCSt1012282 Tue Dec 19 12:58:50 1989 --- doproc.c Mon Dec 18 15:59:00 1989 *************** *** 41,47 **** return; } /* delete current message */ ! print(sprintf(buf, "%sdelete %s", ((event_id(event) == MS_LEFT || val == 0)? "" : "un"), panel_get_value(msg_num_item))); turnon(glob_flags, IGN_BANG); --- 41,47 ---- return; } /* delete current message */ ! print(sprintf(buf, "\\%sdelete %s", ((event_id(event) == MS_LEFT || val == 0)? "" : "un"), panel_get_value(msg_num_item))); turnon(glob_flags, IGN_BANG); *************** *** 474,483 **** current_msg = value, value = 0; wprint("Responding to message %d\n", current_msg+1); (void) sprintf(buf, "%s %s %d", ! (value == 2 || value == 3)? "replyall" : "replysender", (value == 1 || value == 3)? "-i": NO_STRING, current_msg+1); current_msg = tmp; ! if (cmd_line(buf, msg_list) != -1) start_textsw_edit(FALSE); } --- 474,483 ---- current_msg = value, value = 0; wprint("Responding to message %d\n", current_msg+1); (void) sprintf(buf, "%s %s %d", ! (value == 2 || value == 3)? "\\replyall" : "\\replysender", (value == 1 || value == 3)? "-i": NO_STRING, current_msg+1); current_msg = tmp; ! if (cmd_line(buf, NULL) != -1) start_textsw_edit(FALSE); } *** /tmp/,RCSt1012282 Tue Dec 19 12:58:52 1989 --- makefile.sun Tue Dec 19 12:10:57 1989 *************** *** 35,41 **** @echo loading... @cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush ! $(OBJS): config.h lint: lint $(LINTFLAGS) $(SRCS) -DSUNTOOL -DCURSES -DBSD --- 35,42 ---- @echo loading... @cc $(LDFLAGS) $(OBJS) $(LIBES) $(OTHERLIBS) -o mush ! $(OBJS): config.h mush.h ! loop.o: version.h lint: lint $(LINTFLAGS) $(SRCS) -DSUNTOOL -DCURSES -DBSD *** /tmp/,RCSt1012282 Tue Dec 19 12:58:55 1989 --- panels.c Fri Dec 15 19:13:06 1989 *************** *** 428,434 **** /* don't add a folder to the list if user can't read it */ if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) return NULL; ! if (s_buf.st_mode & S_IFDIR) { int cnt = 0; if (!(dirp = opendir(path))) return NULL; /* don't bother adding to list if we can't scan it */ --- 428,434 ---- /* don't add a folder to the list if user can't read it */ if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) return NULL; ! if ((s_buf.st_mode & S_IFMT) == S_IFDIR) { int cnt = 0; if (!(dirp = opendir(path))) return NULL; /* don't bother adding to list if we can't scan it */ *************** *** 460,467 **** char *path; int *n; { ! DIR *dirp; ! struct dirent *dp; struct stat s_buf; char buf[MAXPATHLEN]; --- 460,466 ---- char *path; int *n; { ! char **names, **np; struct stat s_buf; char buf[MAXPATHLEN]; *************** *** 468,479 **** /* don't add a folder to the list if user can't read it */ if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) return; ! if (s_buf.st_mode & S_IFDIR) { ! for (dirp = opendir(path); dp = readdir(dirp); ) ! if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) ! add_path_to_menu(item, ! sprintf(buf, "%s/%s", path, dp->d_name), n); ! closedir(dirp); } else panel_set(item, PANEL_CHOICE_STRING, (*n)++, savestr(trim_filename(path)), --- 467,481 ---- /* don't add a folder to the list if user can't read it */ if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) return; ! if ((s_buf.st_mode & S_IFMT) == S_IFDIR) { ! sprintf(buf, "%s/{.*,*}", path); ! if (filexp(buf, &names) > 0) { ! for (np = names; np && *np; np++) { ! if (!glob(*np, "*/{.,..}")) ! add_path_to_menu(item, *np, n); ! } ! free_vec(names); ! } } else panel_set(item, PANEL_CHOICE_STRING, (*n)++, savestr(trim_filename(path)), -- Bart Schaefer "Miserable miscreant! Question MY integrity, will you?" "I have to see some *evidence* of it before I can question it." -- Calvin & Hobbes schaefer@cse.ogi.edu (used to be cse.ogc.edu)