rsalz@bbn.com (Rich Salz) (03/16/89)
Submitted-by: Dan Heller <island!argv@sun.com> Posting-number: Volume 18, Issue 25 Archive-name: mush6.4/part03 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 3 (of 19)." # Contents: advanced.mushrc execute.c expr.c hdr_procs.c print.c # rite.c sample.mushrc sort.c tool.c # Wrapped by rsalz@papaya.bbn.com on Mon Mar 13 19:25:08 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'advanced.mushrc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'advanced.mushrc'\" else echo shar: Extracting \"'advanced.mushrc'\" \(4980 characters\) sed "s/^X//" >'advanced.mushrc' <<'END_OF_FILE' X# advanced.mushrc X# by Bart Schaefer X# with special thanks to Phil Lapsley <phil@east.Berkeley.EDU>, who X# provided the original files on which this example is based. Most of X# Phil's stuff is still here -- just reorganized and updated to use X# mush 6.4 features that were unavailable when Phil did the originals. X# X# This file is intended to demonstrate helpful ways to use the X# .mushrc, not advanced mush commands. X X# The variable $thisfolder is always set EXCEPT when the .mushrc file X# is read the first time. A test for non-existance of $thisfolder X# allows the same .mushrc file to be sourced repeatedly without X# redundant execution of the initialization commands. X# Xif ! $?thisfolder X # Ignore the usual stuff X ignore received message-id status X # Hide folders in ~/.mail and save read mail in spool X set folder=~/.mail hold X # Remember a few commands, set up editors, act like a shell X set history=20 editor=ex visual=vi unix X # Prompt has folder name, message number, history number X set prompt="%f %m (!) & " X # Header summaries show name, date, and subject X set hdr_format="%25n %-15d %27s" X # Initialize the cmds below (see later comments) X set first_time=1 X X # These two commands are used for automated "bursting" of the spool X # mailbox. This means that the messages are reorganized into new X # folders to be read in a prearranged order. See comments below. X # X # n brings up the next folder, not the next message X cmd n 'source ~/.mushrc' X # N gets the next folder without "bursting" X cmd N 'set first_time=0; source ~/.mushrc' X X # Delete messages by pattern-matching. Examples: X # del f mailer-daemon Delete mail from mailer-daemon X # del t mush-users Delete mail to mush-users X cmd del 'pick -i -\!* | delete' X # Forwarding X cmd for 'mail -f' X # Quick folder change X cmd F 'folder' X X # Some useful aliases X alias dheller 'The Mush God <island\!argv@cad.berkeley.edu>' X alias barts 'Archangel Mushael <schaefer@cse.ogc.edu>' X X # On init, don't source beyond this point X exit Xendif # End of init section -- read on startup only X X# This part of the file handles "bursting". A burst is done when the X# n cmd is used the first time. This is most useful if you habitually X# have lots of mail when you first log in each morning; unwanted mail X# can be deleted, and other mail organized for you. X# X# The folders in this example bursting scheme are: X# mush-users anything to or cc'ed to mush-users X# stats daily stats X# root root mail other than daily stats X# Mail not falling into one of these categories is left in the system X# mailbox to be dealt with first. X# Xif $first_time X # Kill off some uucp garbage X pick -i -s "file c.* delete" | delete X pick -i -s "file .* can.t access" | delete X pick -i -s "remote access to path/file denied" | delete X # Nuke the boring usenet stuff X pick -i -f usenet | pick -i -s "uucp map for" | delete X pick -i -t usenet | pick -i -s "returned mail" | delete X pick -i -t usenet | pick -i -s "automatic test echo" | delete X pick -i -t "owner-post" | pick -i -s "unknown mailer" | delete X pick -i -s "usenet disk space report" | delete X pick -i -s "very old news articles" | delete X pick -i -s "uucp map for" | delete X # Wipe out some uninteresting daily stats X pick -i -s "the maid was here." | delete X pick -i -s "daily accounting" | delete X pick -i -t netsurvey | delete X # Get rid of these things for good. This isn't essential, but X # avoids complexity in the later "pick" commands. X update X # Save anything "to" or "cc" to mush-users in that folder. X pick -i -t mush-users | save +mush-users X pick -i -h cc mush-users | save +mush-users X # Also save interesting daily stat mail and generic root mail X pick -i -f root | pick -i -s stats | save +stats X pick -i -f root | pick -i -s report | save +stats X pick -i -f uucp | pick -i -s report | save +stats X pick -i -f root | pick -i -s summary | save +stats X pick -i -f root | pick -i -s munge | save +stats X pick -i -t root | save +root X # Again, make the changes permanent. Saved mail gets deleted. X # This won't work if you have $keepsave set. X update X X # Make sure we don't burst again needlessly. X set first_time=0 X X # Stop sourcing here. Otherwise, we'd change folders without X # handling the mail left in the system mailbox. X exit Xendif X X# Finally, handle stepping through the folders one by one. This has been X# set up for sendmail, where the system mailbox is /usr/spool/mail/$USER, X# but could easily be modified for other mailers. X# X# $thisfolder:t returns the tail only of the folder name. X Xif $thisfolder:t == $USER X folder +stats X exit Xendif X Xif $thisfolder:t == stats X folder +mush-users X exit Xendif X Xif $thisfolder:t == mush-users X folder +root X exit Xendif X X# Default back to the system mailbox Xfolder % X X# End of advanced.mushrc END_OF_FILE if test 4980 -ne `wc -c <'advanced.mushrc'`; then echo shar: \"'advanced.mushrc'\" unpacked with wrong size! fi # end of 'advanced.mushrc' fi if test -f 'execute.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'execute.c'\" else echo shar: Extracting \"'execute.c'\" \(5802 characters\) sed "s/^X//" >'execute.c' <<'END_OF_FILE' X/* execute.c (c) copyright 10/28/86 (Dan Heller) */ X X#include "mush.h" X#ifdef BSD X#include <sys/wait.h> X#else X#ifndef SYSV X#include <wait.h> X#endif /* SYSV */ X#endif /* BSD */ X X#ifdef lint X#include <sys/resource.h> X#endif /* lint */ X Xexecute(argv) Xchar **argv; X{ X#ifdef SYSV X int status; X#else X union wait status; X#endif /* SYSV */ X#ifdef SIGCONT X SIGRET (*oldstop)(), (*oldcont)(); X#endif /* SIGCONT */ X int pid; X SIGRET (*oldint)(), (*oldquit)(); X X#ifdef SUNTOOL X if (istool) { X print("Editing letter..."); X X panel_set(abort_item, PANEL_SHOW_ITEM, FALSE, 0); X panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0); X panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0); X win_setrect(tty_sw->ts_windowfd, &msg_rect); X msg_rect.r_height = 0; X win_setrect(msg_sw->ts_windowfd, &msg_rect); X if ((exec_pid = ttysw_fork(tty_sw->ts_data, argv, X &tty_sw->ts_io.tio_inputmask, X &tty_sw->ts_io.tio_outputmask, X &tty_sw->ts_io.tio_exceptmask)) == -1) X error("%s failed", *argv), sigchldcatcher(); X Debug("tty pid = %d\n", exec_pid); X return; X } X#endif /* SUNTOOL */ X oldint = signal(SIGINT, SIG_IGN); X oldquit = signal(SIGQUIT, SIG_IGN); X#ifdef SIGCONT X oldstop = signal(SIGTSTP, SIG_DFL); X oldcont = signal(SIGCONT, SIG_DFL); X#endif /* SIGCONT */ X turnon(glob_flags, IGN_SIGS); X X echo_on(); X if ((exec_pid = vfork()) == 0) { X (void) signal(SIGINT, SIG_DFL); X (void) signal(SIGQUIT, SIG_DFL); X (void) signal(SIGPIPE, SIG_DFL); X (void) closefileds(3); /* close all descriptors above 2 */ X execvp(*argv, argv); X if (errno == ENOENT) X print("%s: command not found.\n", *argv); X else X error(*argv); X _exit(-1); X } X /* parent's got to do something; sigchldcatcher will do waiting X * if other forks die (sendmail), then this wait will catch them, X * This loop will really get -1, cuz sigchldcatcher will catch all else. X */ X while ((pid = wait(&status)) != -1 && pid != exec_pid) X Debug("The exec loop caught a signal? (pid = %d)\n", pid); X /* reset our ttymodes */ X echo_off(); X (void) signal(SIGINT, oldint); X (void) signal(SIGQUIT, oldquit); X#ifdef SIGCONT X (void) signal(SIGTSTP, oldstop); X (void) signal(SIGCONT, oldcont); X#endif /* SIGCONT */ X turnoff(glob_flags, IGN_SIGS); X} X XSIGRET Xsigchldcatcher() X{ X#ifdef SUNTOOL X struct rect rect; X extern FILE *ed_fp; X#endif /* SUNTOOL */ X#ifdef SYSV X int status; X#else X union wait status; X#endif /* SYSV */ X int pid; X X#ifdef BSD X /* The following SHOULDN'T be necessary, but it is!!! ttysw_fork() X * returns the pid of the thing that it executes, but that's not the X * pid that dies! There are many procs that might die from ttysw_fork X * one of them is the process, another is the tty, etc... other X * procs that might die are sendmail, fortune, etc... tool_sigchld() X * handles these, but we can't let it have control unless we KNOW the X * editor is done. X * so if what we catch is not the exec_pid from ttysw_fork(), then X * send ourselves a sigchld to go thru this routine again. mush -d X */ X while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) { X Debug("%d died...\n", pid); X if (pid == exec_pid) X break; X } X#else X#ifndef SYSV X while ((pid = wait2(&status, WNOHANG)) > 0 && pid != exec_pid) X Debug("%d died...\n", pid); X#else /* SYSV */ X while ((pid = wait((int *)0)) > 0 && pid != exec_pid) X Debug("%d died...\n", pid); X#endif /* SYSV */ X#endif /* BSD */ X#ifndef SUNTOOL X } X#else /* SUNTOOL */ X if (pid != exec_pid || exec_pid <= 0) /* if the editor didn't die, return */ X return; X /* editor died -- reset exec_pid so no one thinks we're running */ X exec_pid = 0; X /* only the tool needs to continue from here. Reset the win */ X if (istool < 1) X return; X tool_sigchld(tool); X print("Editor done."); X win_getrect(tty_sw->ts_windowfd, &msg_rect); X if (msg_rect.r_height < 2 * l_height(curfont)) { X print_more(" (well, something just happened)"); X return; X } X { X extern char *edfile; X if (!(ed_fp = fopen(edfile, "r+"))) X error("can't reopen %s", edfile); X (void) fseek(ed_fp, 0L, 2); X } X /* I'd like to be able to just pw_rop the tty window onto the window X * we're going to use now, but I can't access the data structure! X * X * pw_rop(msg_win, 0, 0, msg_rect.r_width, msg_rect.r_height, PIX_SRC, X * ((struct ??? *)(tty_sw->ts_data))->pr_pixrect, 0, 0); X * So, instead, just clear the window and write the last N lines from the X * end of the file into the window. X */ X rect.r_top = rect.r_left = rect.r_height = 0; X rect.r_width = msg_rect.r_width; X win_setrect(tty_sw->ts_windowfd, &rect); X win_setrect(msg_sw->ts_windowfd, &msg_rect); X do_clear(); X /* read the last 2K bytes in the file -- search backwards for enough X * carriage returns that will fill the window with the end of the letter X * written so far and display the text. X */ X { X register long where = ftell(ed_fp); X register int cr = 0, lines = msg_rect.r_height * l_height(curfont) - 3; X char buf[2*BUFSIZ], *p; X where = max(0, where-2*BUFSIZ); X (void) fseek(ed_fp, where, L_SET); X p = buf + read(fileno(ed_fp), buf, 2*BUFSIZ); X *p = 0; X while (cr < lines && p > buf) X if (*--p == '\n') X cr++; X if (p > buf) X while (*p != '\n') X p++; X Addstr(p); X } X panel_set(comp_item, PANEL_SHOW_ITEM, FALSE, 0); X panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0); X panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0); X panel_set(abort_item, PANEL_SHOW_ITEM, TRUE, 0); X wprint("(continue editing letter.)\n"); X type_cursor(PIX_SRC); X} X XSIGRET Xsigtermcatcher() X{ X ttysw_done(tty_sw->ts_data); X if (ison(glob_flags, IS_GETTING)) X rm_edfile(-1); X cleanup(SIGTERM); X} X#endif /* SUNTOOL */ END_OF_FILE if test 5802 -ne `wc -c <'execute.c'`; then echo shar: \"'execute.c'\" unpacked with wrong size! fi # end of 'execute.c' fi if test -f 'expr.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'expr.c'\" else echo shar: Extracting \"'expr.c'\" \(4682 characters\) sed "s/^X//" >'expr.c' <<'END_OF_FILE' X/* @(#)expr.c 2.3 (c) copyright 10/15/86 (Dan Heller) */ X X#include "mush.h" X Xchar *eval_expr(); X X/* Parse a string (p) to interpret numbers and ranges of numbers (n-m) X * delimited by whitespace or comma's. Set msg_list bitfields using X * macros in mush.h. X * Return the address of the end of whatever we parsed (in case there's X * more that the calling routine cares to deal with). X * Finally, remember that user specifies one more than actual message number X */ Xchar * Xdo_range(p, list1) Xregister char *p, *list1; X{ X register int num1 = -1, num2 = -1, except = 0; X register char *p2; X char list2[MAXMSGS_BITS]; X X if (!p) X return ""; X while (*p) { X if (isdigit(*p) || *p == '$' || *p == '.' || *p == '^') { X if (isdigit(*p)) { X char c; X p2 = p; X skipdigits(0); /* find the end of the digits */ X c = *p, *p = 0; /* temporarily plug a null */ X if (!(num2 = chk_msg(p2))) { X clear_msg_list(list1); X return NULL; X } X *p = c; X } else if (*p == '$') X p++, num2 = msg_cnt; X else if (*p == '.') X p++, num2 = current_msg+1; X else if (*p == '^') X p++, num2 = 1; X if (except) X unset_msg_bit(list1, num2-1); X else X set_msg_bit(list1, num2-1); X if (num1 >= 0) { X if (num1 > num2) { X print("syntax error: range sequence order reversed.\n"); X clear_msg_list(list1); X return NULL; X } X while (++num1 < num2) X if (except) X unset_msg_bit(list1, num1-1); X else X set_msg_bit(list1, num1-1); X num1 = num2 = -1; X } X } X /* expressions to evaluate start with a ` X * p2 points to first char passed the last char parsed. X */ X if (*p == '`') { X clear_msg_list(list2); X if (!(p = eval_expr(p, list2))) { X clear_msg_list(list1); X return NULL; X } else { X if (except) X bitput(list2, list1, msg_cnt, &=~) /* MACRO */ X else X bitput(list2, list1, msg_cnt, |=) /* MACRO */ X } X } X /* NOT operator: `* {5}' (everything except for 5) X * `4-16 {8-10}' (4 thru 16 except for 8,9,10) X */ X if (*p == '{' || *p == '}') { X if (*p == '{' && (except || num1 >= 0)) X break; X if (*p == '}' && !except) { X print("syntax error: missing {\n"); /* } */ X break; X } X except = !except; X } else if (*p == '-') X if (num1 >= 0 || num2 < 0 X || !index(" \t{},.*`$", *(p+1)) && !isdigit(*(p+1))) X break; X else X num1 = num2; X else if (*p == ',' || *p == '*') { X if (num1 >= 0) X break; X else if (*p == '*') { X if (except) X clear_msg_list(list1); X else X for (num1 = 0; num1 < msg_cnt; num1++) X set_msg_bit(list1, num1); X num1 = -1; X } X } else if (!index(" \t`", *p)) X break; X if (*p) X skipspaces(1); /* don't make user type stuff squished together */ X } X if (num1 >= 0 || except) { X if (except) X /* { */ print("syntax error: unmatched }\n"); X else X print("syntax error: unfinished range\n"); X clear_msg_list(list1); X return NULL; X } X return p; X} X X/* X * convert a message list to an ascii string. X */ Xvoid Xlist_to_str(list, str) Xchar list[], *str; X{ X int n, m = -1; X X for (n = 0; n < msg_cnt; n++) { X if (msg_bit(list, n)) { X if (m == -1) X str += strlen(sprintf(str, "%d", (m = n) + 1 )); X continue; X } X if (m == -1) X continue; X if (n - m > 2) X str += strlen(sprintf(str, "-%d", n)); X else if (n - m == 2) X str += strlen(sprintf(str, " %d", n)); X *str++ = ' '; X m = -1; X } X if (m > -1 && m != n - 1) { X if (n - m > 2) X *str++ = '-'; X else X *str++ = ' '; X str += Strcpy(str, itoa(msg_cnt)); X } X *str = 0; X} X X/* evaluate expressions: X * mail> delete `pick -f root` deletes all messages from root. X * mail> save * {`pick -s "Re:"`} save all message that don't have "Re:" X * in the subject header. X * mail> save `pick -x -s "Re:"` same X * args as follows: X * p should point to the first ` -- check for it. X * on tells whether to turn bits on or off if messages match. X */ Xchar * Xeval_expr(p, new_list) Xregister char *p, new_list[]; X{ X register char *p2, **argv; X int argc; X u_long save_flags = glob_flags; X X if (!(p2 = index(++p, '`'))) { X print("unmatched backquote (`)\n"); X return NULL; X } X *p2 = 0; X X skipspaces(0); X if (!*p) { X print("Invalid null command\n"); X return NULL; X } X turnon(glob_flags, DO_PIPE); X /* ignore sigs only because if user interrupts the do_command, X * the longjmp will corrupt the stack and the program is hosed. X * fix is to have layers of jmp_bufs to return to different levels. X */ X turnon(glob_flags, IGN_SIGS); X if (*p && (argv = make_command(p, TRPL_NULL, &argc))) X (void) do_command(argc, argv, new_list); X glob_flags = save_flags; X *p2 = '`'; X return p2+1; X} END_OF_FILE if test 4682 -ne `wc -c <'expr.c'`; then echo shar: \"'expr.c'\" unpacked with wrong size! fi # end of 'expr.c' fi if test -f 'hdr_procs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hdr_procs.c'\" else echo shar: Extracting \"'hdr_procs.c'\" \(4239 characters\) sed "s/^X//" >'hdr_procs.c' <<'END_OF_FILE' X/* @(#)hdr_procs.c (c) copyright 10/18/86 (Dan Heller) */ X X/* hdr_procs.c -- panel item procedures for the message hdrs */ X#include "mush.h" X X/* which message headers are to be displayed */ Xdo_hdr(foo, value, event) XPanel_item foo; Xint value; Xstruct inputevent *event; X{ X register char *argv[3]; X argv[2] = NULL; X argv[0] = "headers"; X X if (!msg_cnt) { X print("No Mail."); X return; X } X if (!value || event->ie_code == MS_LEFT) X argv[1] = (foo == next_scr)? "+": "-"; X else X argv[1] = (foo == next_scr)? "-": "+"; X X panel_set(foo, PANEL_VALUE, 0, 0); X (void) do_hdrs(2, argv, NULL); X} X X/* alters display of the message headers */ Xdisplay_hdrs(foo, value, event) XPanel_item foo; Xint value; Xstruct inputevent *event; X{ X int show_deleted = !!do_set(set_options, "show_deleted"); X X if (event->ie_code != MS_LEFT) { X switch(value) { X case 0 : case 1: { X char buf[25]; X show_deleted = !value; X (void) cmd_line(sprintf(buf, "%sset show_deleted", X (value == 0)? "" : "un"), msg_list); X } X when 2 : X turnoff(glob_flags, REV_VIDEO); X when 3 : X turnon(glob_flags, REV_VIDEO); X when 4: X return help(hdr_panel_sw->ts_windowfd, "headers", tool_help); X } X (void) do_hdrs(0, DUBL_NULL, NULL); X } X print("%sShow Deleted headers, \"Current Message\" header in %s", X (show_deleted)? NO_STRING: "Don't ", X (ison(glob_flags, REV_VIDEO))? "reverse": "boldface"); X} X Xp_set_opts(item, value, event) XPanel_item item; Xint value; Xstruct inputevent *event; X{ X static char *p, *oldp; X static char buf[8]; X u_long bang = ison(glob_flags, IGN_BANG); X X if (event->ie_code == MS_LEFT) X value = 0; X if (value && (value != 3 || value != 2) X && panel_get(input_item, PANEL_SHOW_ITEM)) { X print("Need value for %s first!", oldp); X return; X } else if (!value && ison(glob_flags, IS_GETTING)) { X print("Finish editing letter first"); X return; X } else if (item == option_item) { X if (!value) /* first menu item */ X view_options(); X else if (value == 1) X set_fkeys(); X else X (void) help(panel_sw->ts_windowfd, "opts", tool_help); X return; X } else if (item == ignore_item) X if (value == 3) X return help(hdr_panel_sw->ts_windowfd, "ignore", tool_help); X else X oldp = p = strcpy(buf, "ignore"); X else if (item == alias_item) X if (value == 3) X return help(panel_sw->ts_windowfd, "aliases", tool_help); X else X oldp = p = strcpy(buf, "alias"); X if (value) { X char tmp[30]; X (void) sprintf(tmp, "%set %s:", (value == 1)? "S": "Uns", p); X panel_set(input_item, X PANEL_LABEL_STRING, tmp, X PANEL_MENU_CHOICE_STRINGS, "Abort", 0, X PANEL_SHOW_ITEM, TRUE, X 0); X oldp = p; X return; X } X panel_set(item, PANEL_VALUE, 0, 0); X do_clear(); X pw_text(msg_win, l_width(DEFAULT), 15, PIX_SRC, fonts[LARGE], p); X if (item != ignore_item) X pw_text(msg_win, 30*l_width(DEFAULT),15,PIX_SRC,fonts[LARGE],"Values"); X turnon(glob_flags, IGN_BANG); X (void) cmd_line(p, msg_list); X if (!bang) X turnoff(glob_flags, IGN_BANG); X} X Xmsg_num_done(item, event) XPanel_item item; Xstruct inputevent *event; X{ X char buf[82]; X u_long bang = ison(glob_flags, IGN_BANG); X register char *p; X int n; X X if (event->ie_code != '\n' && event->ie_code != '\r') X return help(hdr_panel_sw->ts_windowfd, "message range", tool_help); X (void) sprintf(buf, "headers %s", (p = (char *)panel_get_value(item))); X panel_set(item, PANEL_VALUE, NO_STRING, 0); X if (!(n = chk_msg(p))) X return; X current_msg = --n; X turnon(glob_flags, IGN_BANG); X (void) cmd_line(buf, msg_list); X if (!bang) X turnoff(glob_flags, IGN_BANG); X display_msg(n, (long)0); X} X Xdo_sort(item, value, event) XPanel_item item; Xint value; Xstruct inputevent *event; X{ X register char *argv[3]; X argv[0] = "sort"; X argv[2] = NULL; X if (event->ie_code == MS_LEFT) X argv[1] = do_set(set_options, "sort"); X else switch(value) { X case 0: argv[1] = "d"; X when 1: argv[1] = "a"; X when 2: argv[1] = "s"; X when 3: argv[1] = "S"; X when 4: argv[1] = "R"; X when 5: help(hdr_panel_sw->ts_windowfd, "sort", tool_help); X } X if (value != 5) { X (void) sort(2, argv, NULL); X (void) do_hdrs(0, DUBL_NULL, NULL); X } X panel_set(item, PANEL_VALUE, 0, 0); X} END_OF_FILE if test 4239 -ne `wc -c <'hdr_procs.c'`; then echo shar: \"'hdr_procs.c'\" unpacked with wrong size! fi # end of 'hdr_procs.c' fi if test -f 'print.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'print.c'\" else echo shar: Extracting \"'print.c'\" \(5250 characters\) sed "s/^X//" >'print.c' <<'END_OF_FILE' X/* @(#)print.c 2.4 (c) copyright 10/15/86 (Dan Heller) */ X X#include "mush.h" X#include <varargs.h> X X/*ARGSUSED*/ X/*VARARGS1*/ Xvoid Xerror(fmt, arg1, arg2, arg3, arg4) Xregister char *fmt; Xchar *arg1, *arg2, *arg3, *arg4; X{ X print(fmt, arg1, arg2, arg3, arg4); X print_more(": %s\n", sys_errlist[errno]); X} X X#if defined(SUNTOOL) || defined(CURSES) X/* 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 * Also note same casting in wprint(). X */ X/*VARARGS*/ Xvoid Xprint(va_alist) Xva_dcl X{ X static char msgbuf[BUFSIZ]; X char *fmt; X va_list args; X#ifndef VPRINTF X FILE foo; X#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 X#ifdef CURSES X if (iscurses) { X if (isoff(glob_flags, CONT_PRNT)) X move(LINES-1, x = 0), refresh(); X } else X#endif /* CURSES */ X if (istool < 2) { X va_start(args); X fmt = va_arg(args, char *); X#ifdef VPRINTF X vprintf(fmt, args); X#else /* VPRINTF */ X _doprnt(fmt, args, stdout); X#endif /* VPRINTF */ X va_end(args); X fflush(stdout); X return; X } X va_start(args); X fmt = va_arg(args, char *); X if (fmt) { X#ifdef VPRINTF X vsprintf(msgbuf, fmt, args); /* NULL in fmt reprints last msg */ X#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 */ X#endif /* VPRINTF */ X } X va_end(args); X p = msgbuf; X if (iscurses || istool) X while (p = index(p, '\n')) X *p = ' '; X#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 fflush(stdout); /* some sys-v's aren't fflushing \n's */ X return; X } X#endif /* CURSES */ X#ifdef SUNTOOL X if (isoff(glob_flags, CONT_PRNT)) X x = 5; X turnoff(glob_flags, CONT_PRNT); X pw_text(print_win, x, l_height(LARGE), PIX_SRC, fonts[LARGE], msgbuf); X pw_text(print_win, x+1, l_height(LARGE), PIX_SRC|PIX_DST, X fonts[LARGE], msgbuf); X x += strlen(msgbuf) * l_width(LARGE); X Clrtoeol(print_win, x, l_height(LARGE), LARGE); X#endif /* SUNTOOL */ X} X#endif /* SUNTOOL || CURSES */ X X#ifdef SUNTOOL X/*VARARGS*/ Xvoid Xwprint(va_alist) Xva_dcl X{ X#ifndef VPRINTF X FILE foo; X#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 *); X#ifdef VPRINTF X vprintf(fmt, args); X#else /* VPRINTF */ X _doprnt(fmt, args, stdout); X#endif /* VPRINTF */ X va_end(args); X fflush(stdout); X return; X } X va_start(args); X fmt = va_arg(args, char *); X if (fmt) { X#ifdef VPRINTF X vsprintf(msgbuf, fmt, args); /* NULL in fmt reprints last msg */ X#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 */ X#endif /* VPRINTF */ X Addstr(msgbuf); /* addstr() will scroll if necessary */ X } X va_end(args); X} X X/* X * scroll the msg_win "lines" X * if `lines' is negative (backwards scroll) msg_pix can't be NULL X */ Xvoid Xscroll_win(lines) Xregister int lines; X{ X register int y = lines * l_height(curfont); X /* if the user attempts to scroll back to before the beginning of the X * message [either with the middle mouse button or the keyboard command X * keys ('k', 'K', '-')], scroll back only to the beginning of the message. X */ X if (txt.y + y < msg_rect.r_height) X y = - (txt.y - msg_rect.r_height); X txt.x = 5; X X if (msg_pix) { X if (txt.y + y >= msg_pix->pr_size.y - 5) X y = msg_pix->pr_size.y - txt.y; X still_more += y; /* let scrolling know where we are */ X txt.y += y; X pw_rop(msg_win, 0, 5, X msg_rect.r_width, crt * l_height(curfont), X PIX_SRC, msg_pix, 0, txt.y - msg_rect.r_height + 3); X tool_more(NULL); X return; X } X /* y must be positive (forward scrolling) so we're scrolling typed X * text or something like that (~p, ~?, etc...) X */ X pw_copy(msg_win, 0, 0, X msg_rect.r_width, msg_rect.r_height - y, X PIX_SRC, msg_win, 0, y); X pw_writebackground(msg_win, 0, msg_rect.r_height - y, X msg_rect.r_width, y, PIX_CLR); X txt.y -= y; X} X#endif /* SUNTOOL */ X Xclr_bot_line() X{ X print(""); X} END_OF_FILE if test 5250 -ne `wc -c <'print.c'`; then echo shar: \"'print.c'\" unpacked with wrong size! fi # end of 'print.c' fi if test -f 'rite.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rite.c'\" else echo shar: Extracting \"'rite.c'\" \(4181 characters\) sed "s/^X//" >'rite.c' <<'END_OF_FILE' X/* rite.c (c) copyright 1986 (Dan Heller) */ X X#include "mush.h" X X#define LASTLINE (msg_rect.r_height - l_height(LARGE)-5) X Xstatic char String[BUFSIZ]; Xstatic int count, overflow, save_orig_x; X Xchar * Xrite(c) Xregister char c; X{ X static int literal_next; X X if (c == ltchars.t_lnextc || literal_next) { X if (literal_next) X Addch(c); X else /* don't call Addch to prevent cursor from advancing */ X pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], '^'); X literal_next = !literal_next; X return NULL; X } X literal_next = 0; X if (c == _tty.sg_erase || c == CTRL(127) || c == CTRL(H)) { X if (count) X backspace(); X } else if (c == _tty.sg_kill) { X if (count) { X Clrtoeol(msg_win, txt.x = save_orig_x, txt.y,curfont); X overflow = count = String[0] = 0; X } X } else if (c == ltchars.t_werasc) X while (count) { X char c = String[count-1]; X backspace(); X if (!count || X isspace(String[count-1]) && !isspace(c) || X !isalnum(String[count-1]) && isalnum(c)) X break; X } X else if (c == '\n' || c == '\r' || c == 13) { X String[count] = 0; X if ((txt.y += l_height(curfont)) >= LASTLINE && !getting_opts) X scroll_win(1); X /* else Clrtoeol(msg_win, txt.x, txt.y, curfont); */ X overflow = count = 0, txt.x = 5; X return String; X } else if (c == 12) X if (ison(glob_flags, IS_GETTING)) X Addch(c); X else X do_clear(); X else if (count == BUFSIZ-1) X print("Text too long for String!"), count--; X else if (c == '\t') X do Addch(' '); X while (count % 8 && count < BUFSIZ); X else X Addch(c); X return NULL; X} X Xstatic Xbackspace() X{ X if (overflow) { X pw_text(msg_win, save_orig_x, txt.y, PIX_SRC, fonts[curfont], X &String[--overflow]); X Clrtoeol(msg_win, msg_rect.r_width-10-l_width(curfont), txt.y, curfont); X String[--count] = 0; X } else if ((txt.x -= l_width(curfont)) >= 5) { X if (iscntrl(String[count-1])) { X pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], ' '); X txt.x -= l_width(curfont); X } X pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], ' '); X String[--count] = 0; X } else X txt.x = 5; X} X Xstatic XAddch(c) Xregister char c; X{ X extern char *_unctrl[]; X X if (!count) X save_orig_x = txt.x, bzero(String, BUFSIZ); X if (c > 31 && c != 127) X String[count++] = c; X else { X Addch('^'), count--; X Addch(_unctrl[c][1]); X String[count-1] = c; X return; X } X pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], c); X if ((txt.x += l_width(curfont)) <= msg_rect.r_width-5-l_width(curfont)) X return; X if (getting_opts) { X pw_text(msg_win, save_orig_x, txt.y, PIX_SRC, fonts[curfont], X &String[++overflow]); X txt.x -= l_width(curfont); X pw_char(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], ' '); X } else { X txt.x = 5; X if ((txt.y += l_height(curfont)) >= LASTLINE) X scroll_win(1); X } X} X XAddstr(s) Xregister char *s; X{ X char buf[BUFSIZ]; X register int cnt = 0, max_len; X register char *p = buf, newline = 0; X X max_len = (msg_rect.r_width - 10) / l_width(curfont) + 1; X X while ((*p = *s++) && *p != '\n' && cnt < max_len) X if (*p == '\t') X do *p++ = ' '; X while (++cnt % 8); X else p++, cnt++; X *p = 0; X X if (*--s) X newline = *s, *s = 0; /* newline may or may not be a '\n' */ X else X s = 0; X X if (*buf) { X if (msg_pix) { X struct pr_prpos pixr; X pixr.pr = msg_pix; X pixr.pos = txt; X pf_text(pixr, PIX_SRC, fonts[curfont], buf); X } else X pw_text(msg_win, txt.x, txt.y, PIX_SRC, fonts[curfont], buf); X txt.x += cnt * l_width(curfont); X } X if (newline) { X if (newline != '\n') X *s = newline; X if ((txt.y += l_height(curfont)) >= LASTLINE && !msg_pix) X scroll_win(1); X txt.x = 5; X if (newline == '\n' && !*++s) X return; X Addstr(s); X } X} X Xtool_more(p) Xregister char *p; X{ X int percent; X /* we are typing -- scrool the window */ X if (!msg_pix) { X scroll_win(1); X return; X } X if (p) X print(p); X else { X if ((percent = (still_more * 100) / msg_pix->pr_size.y) >= 100) X print( "--End of Message %d--", current_msg+1); X else X print("--Message %d--(%d%%)", current_msg+1, percent); X if (ison(glob_flags, IS_GETTING)) X print_more(" ('q' returns to type-in mode)"); X } X} END_OF_FILE if test 4181 -ne `wc -c <'rite.c'`; then echo shar: \"'rite.c'\" unpacked with wrong size! fi # end of 'rite.c' fi if test -f 'sample.mushrc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sample.mushrc'\" else echo shar: Extracting \"'sample.mushrc'\" \(7468 characters\) sed "s/^X//" >'sample.mushrc' <<'END_OF_FILE' X# sample.mushrc X# By Bart Schaefer and Dan Heller X# X# Change mush's temp file directory, to avoid quota collisions. X# /usr/tmp so tmpfiles won't be rm'd before they can be recovered. Xset tmpdir=/usr/tmp X X# Set the folder and mbox locations; the + expands to value of "folder". Xset folder=$HOME/Mail mbox=+mbox X X# Set up the display early to allow quick exit in headers-only mode. X# The hdrs_only flag is true if the command line was: "mush -H". X# The variable hdr_format is set to change the format of the header X# summaries that are displayed. Xif hdrs_only X set hdr_format='%28a %M %-2N %.33s' X exit # Quits reading this file Xelse X set hdr_format='%28a %M %-2N (%3.5l li) %.25s' Xendif X X# Set the prompt to show current time, name of the current folder, X# current message number, and count of total messages. Xset prompt="(%T) %f: #%m of %t> " X X# Hitting <CR> should do nothing (helps make mush more shell-like). If X# newline is not set, hitting <CR> prints the next message (like Mail). X# This variable could be set to any mush command. Xset newline X X# These variables are helpful for new users: X# ask -- always prompt for Subject: of mail X# ignoreeof -- ignore end-of-file from keyboard X# verify -- query that all is well before sending mail X# warning -- report miscellaneous possible problems Xset ask verify warning Xset ignoreeof="echo 'Use "'"'quit'"'" to quit.'" X X# When reading messages, don't bother looking at lengthy, boring headers. Xignore message-id received X X# Since mush has csh-like history, you might find it annoying to type X# things like "mail host\!host1\!host2\!user" from within the mush shell. X# Setting nonobang will prevent the "unknown event" and allow the !'s to X# be typed without having to be preceded by backslashes. Xset nonobang X X# By default, mush's history is set to the last command only. Set it to X# remember the last 100 commands. Xset history = 100 X X# If the variable "unix" is set, then any command that isn't a mush command X# will execute the command as if you typed it from the shell. Note, such X# commands will not go through another shell -- this is it. Xset unix X X# Mush tries to read ~/.mushrc first, then it tries ~/.mailrc. Assuming X# you use *this* file as your .mushrc, source the contents of .mailrc as X# well in case there are Mail aliases that are set there. Xsource $HOME/.mailrc X X# Use a real pager. Xset pager=less X X# When typing in a letter, it is sometimes convenient to have lines wrap X# automatically similar to editors like vi and emacs. In this example, if X# the user types past column 74, a newline will automatically be inserted. Xset wrapcolumn=74 X X# If "autosign" is set, then a file can be read in automatically whenever X# mail is sent. This file is normally your "signature," that is, your X# name and other information you want included in every message. Xset autosign = ~/.signature X X# When you use the -i option to reply, or use the ~i tilde escape in a letter X# when in compose mode, the current message will be included in your text. X# Put a nice wrapper around those included messages. Here, show the author's X# name and the subject of his letter, label the end, and add a trailing blank X# to separate each inclusion and make finding the end easier. Xset pre_indent_str='On %M %N, %T, %.50n wrote:\n} Subject: %.65s' Xset indent_str='} ' # actual message text is preceded by a "}" Xset post_indent_str='}-- End of excerpt from %.50n\n' X X# Label replies with a header showing the who, what, and when of the X# message being replied-to. Xset in_reply_to='%f\n\t"%s" (%d)' X X# Mail routing and address-fixing conveniences. If auto_route is set, then X# replies to messages take a closer look at the addresses of the recipients. X# If any redundant paths are present, they are pruned. Also, the path that X# precedes any hosts listed in the "known_hosts" list is truncated. This is X# useful for uucp sites only, and is therefore commented out in this sample. X# set auto_route known_hosts="sun ucbcad well unicom" X X# The "alts" command specifies alternate addresses that I have. Here, X# "*" expands to any "path" whose recipient ends with the user's current X# login name. If another login name is desired, the login and/or path X# to that login must be preceded by a !. Otherwise, standard paths are used. Xalts "*" X X# The "map" command can rebind certain key sequences in tty-mode only. X# Here, if the user types two R's in a row at the prompt, then the string X# "reply -ei " will be echoed as if the user typed it. Xmap RR "reply -ei " X# "rr" will do a reply and do the newline for you so you don't have to. Xmap rr "reply\n" X X# The "map!" command is similar to "map" in that you can do keyboard X# acceleration, but map! occurs during letter composition mode only. Xmap! '\CT' ' ' # ^T generates 4 spaces in composition mode. X# Here, hitting * twice will append a pre-signature. Xmap! ** "\n Later,\n" X X# Be careful with map and map! -- you can cause an infinite loop. X# Your interrupt key (usually ^C) will stop such loops. X X# The curses mode allows the screen to be set up like a full screen editor. X# There are basic "curses commands" which are bound to keyboard key-sequences X# (usually one character). The user can rebind these keys to suit his tastes. X# Note that the binding for R below removes the binding of reply-all. X# Xset curses_help # Unset this to remove help message in curses. Xbind \n display # Hit return to display the next message. Xbind t top # Make it easier to see the top few lines. Xbind e macro "[line-mode]edit\n" # Quick edit from curses. Xbind P macro "[line-mode]Print\n" # Show me all the headers. Xbind R macro "[line-mode]reply -ei " # Reply with inclusion and edit. Xbind A macro "R[getline]~t\n\CUargv\n" # R to Dan w/auto address fix. X X# "cmd" is used to set command line aliases similar to the way "csh" X# does it. The only difference is that "alias" is a reserved word in X# Mush and Mail, so cmd is used. X# Xcmd dq 'd \!*; q' # Delete a message list, then quit. Xcmd unread 'flags \!* U O' # Mark messages unread. Xcmd : curses # Colon now "toggles" curses mode. X X# Find messages from mailer-daemon (ignore upper/lower case). Xcmd md 'pick -i -f mailer-daemon' X# Because mush can pipe commands to one another, including "cmd"'s, this X# example will delete all messages from mailer-daemon Xcmd dmd 'md | delete' X X# aliases -- just like Mail's, but you can specify "names" Xalias argv Dan Heller <island!argv@sun.com> Xalias bart Bart Schaefer <schaefer@ogccse.ogc.edu> Xalias mush-users Mush Users <mush-users-request@garp.mit.edu> X X# The rest of this file demonstrates how sysadmins with novice users X# might want to set things up. The following "exit" should be removed. Xexit X Xif -e $HOME/.mushexpert X set quiet X exit Xendif Xif ! -e $HOME/.mushuser X echo "I see you've never used the Mush program before." X echo "I'll set some special flags to help you out." X echo "After you've used Mush a few times, you can type the command:" X echo -p "${prompt} expert\n" X echo "and the flags will no longer be set unless you put them" X echo "in your $HOME/.mushrc file." X sh touch $HOME/.mushuser # Use sh in case $unix is not set. X if $?quiet X unset quiet # Show the help message on startup. X endif Xendif X# At this point some helpful variables should be set. See the list above, X# marked as "helpful for new users", for suggestions. X# X# Create the "expert" command mentioned in the message above. Xcmd expert 'sh touch $HOME/.mushexpert' END_OF_FILE if test 7468 -ne `wc -c <'sample.mushrc'`; then echo shar: \"'sample.mushrc'\" unpacked with wrong size! fi # end of 'sample.mushrc' fi if test -f 'sort.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sort.c'\" else echo shar: Extracting \"'sort.c'\" \(5803 characters\) sed "s/^X//" >'sort.c' <<'END_OF_FILE' X/* sort.c 2.0 (c) copyright 1986 (Dan Heller) */ X X#include "mush.h" X/* #define MYQSORT */ X Xstatic int order, ignore_case; Xstatic jmp_buf sortbuf; X Xsort(argc, argv, list) Xregister int argc; Xregister char *argv[], list[]; X{ X int status_cmp(), author_cmp(), date_cmp(), subject_cmp(), subj_with_re(); X SIGRET (*oldint)(), (*oldquit)(); X int (*how)() = status_cmp; X int n, offset = -1, range = 0; X X order = 1, ignore_case = FALSE; X X while (argc && *++argv) { X n = 0; X while (argv[0][n]) X switch(argv[0][n++]) { X case '-': order = -1; X when 'd': how = date_cmp; X when 'a': how = author_cmp; X when 's': how = subject_cmp; X when 'R': how = subj_with_re; X when 'S': how = status_cmp; X when 'i': ignore_case = TRUE; X otherwise: return help(0, "sort", cmd_help); X } X } X if (msg_cnt <= 1) { X print("Not enough messages to sort.\n"); X return -1; X } X turnon(glob_flags, IGN_SIGS); X on_intr(); X X if (list && ison(glob_flags, IS_PIPE)) { X for (n = 0; n < msg_cnt; n++) X if (msg_bit(list, n)) { X if (offset < 0) X offset = n; X range++; X } else if (offset >= 0) X break; X } else X offset = 0, range = msg_cnt; X X if (range < 2) X print("Range not broad enough to sort anything\n"); X else { X Debug("Sorting %d messages starting at message %d\n", range, offset+1); X X if (setjmp(sortbuf) == 0) X qsort((char *)&msg[offset], range, sizeof (struct msg), how); X else X print("WARNING: Sorting interrupted: unpredictable order.\n"); X turnon(glob_flags, DO_UPDATE); X } X turnoff(glob_flags, IGN_SIGS); X off_intr(); X /* Break pipes because message lists are invalid */ X return 0 - in_pipe(); X} X X#ifdef MYQSORT Xqsort(base, len, siz, compar) Xregister struct msg *base; Xint (*compar)(); X{ X register int i, swapping; X struct msg temp; X X do { X swapping = 0; X for (i = 0; i < len-1; ++i) { X if (compar(base+i, base+i+1) > 0) { X temp = base[i]; X base[i] = base[i+1]; X base[i+1] = temp; X swapping = 1; X } X } X } while (swapping); X} X#endif /* MYSORT */ X Xstatus_cmp(msg1, msg2) Xregister struct msg *msg1, *msg2; X{ X if (ison(glob_flags, WAS_INTR)) X longjmp(sortbuf, 1); X if (msg1 < msg || msg2 < msg) { X wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg); X return 0; X } X if (msg1->m_flags == msg2->m_flags) X return 0; X if (ison(msg1->m_flags, DELETE) && isoff(msg2->m_flags, DELETE)) X return order; X if (isoff(msg1->m_flags, DELETE) && ison(msg2->m_flags, DELETE)) X return -order; X if (isoff(msg1->m_flags, OLD) && ison(msg2->m_flags, OLD)) X return -order; X if (ison(msg1->m_flags, OLD) && isoff(msg2->m_flags, OLD)) X return order; X if (ison(msg1->m_flags, UNREAD) && isoff(msg2->m_flags, UNREAD)) X return -order; X if (isoff(msg1->m_flags, UNREAD) && ison(msg2->m_flags, UNREAD)) X return order; X if (ison(msg1->m_flags,PRESERVE) && isoff(msg2->m_flags,PRESERVE)) X return -order; X if (isoff(msg1->m_flags,PRESERVE) && ison(msg2->m_flags,PRESERVE)) X return order; X if (ison(msg1->m_flags,REPLIED) && isoff(msg2->m_flags,REPLIED)) X return -order; X if (isoff(msg1->m_flags,REPLIED) && ison(msg2->m_flags,REPLIED)) X return order; X if (ison(msg1->m_flags,SAVED) && isoff(msg2->m_flags,SAVED)) X return -order; X if (isoff(msg1->m_flags,SAVED) && ison(msg2->m_flags,SAVED)) X return order; X X return order; X} X Xauthor_cmp(msg1, msg2) Xregister struct msg *msg1, *msg2; X{ X char buf1[HDRSIZ], buf2[HDRSIZ]; X X if (ison(glob_flags, WAS_INTR)) X longjmp(sortbuf, 1); X if (msg1 < msg || msg2 < msg) { X wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg); X return 0; X } X (void) reply_to(msg1 - msg, 0, buf1); /* "0" for "author only" */ X (void) reply_to(msg2 - msg, 0, buf2); X Debug("author: msg %d: %s, msg %d: %s\n", msg1-msg, buf1, msg2-msg, buf2); X if (ignore_case) X return lcase_strncmp(buf1, buf2, -1) * order; X return strcmp(buf1, buf2) * order; X} X X/* X * Subject comparison ignoring Re: subject_to() appends an Re: if there is X * any subject whatsoever. X */ Xsubject_cmp(msg1, msg2) Xregister struct msg *msg1, *msg2; X{ X char buf1[HDRSIZ], buf2[HDRSIZ]; X X if (ison(glob_flags, WAS_INTR)) X longjmp(sortbuf, 1); X if (msg1 < msg || msg2 < msg) { X wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg); X return 0; X } X (void) subject_to(msg1 - msg, buf1); X (void) subject_to(msg2 - msg, buf2); X Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n", msg1-msg,buf1,msg2-msg,buf2); X if (ignore_case) X return lcase_strncmp(buf1, buf2, -1) * order; X return strcmp(buf1, buf2) * order; X} X X/* X * compare subject strings from two messages. X * If Re is appended, so be it -- if user wants to ignore Re: use 'R' flag. X */ Xsubj_with_re(msg1, msg2) Xregister struct msg *msg1, *msg2; X{ X char buf1[HDRSIZ], buf2[HDRSIZ], *p; X X if (ison(glob_flags, WAS_INTR)) X longjmp(sortbuf, 1); X if (msg1 < msg || msg2 < msg) { X wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg); X return 0; X } X if (!(p = header_field(msg1 - msg, "subject"))) X p = ""; X (void) strcpy(buf1, p); X if (!(p = header_field(msg2 - msg, "subject"))) X p = ""; X (void) strcpy(buf2, p); X Debug("subjects: (%d): \"%s\" (%d): \"%s\"\n", X msg1-msg, buf1, msg2-msg, buf2); X if (ignore_case) X return lcase_strncmp(buf1, buf2, -1) * order; X return strcmp(buf1, buf2) * order; X} X Xdate_cmp(msg1, msg2) Xregister struct msg *msg1, *msg2; X{ X if (ison(glob_flags, WAS_INTR)) X longjmp(sortbuf, 1); X if (msg1 < msg || msg2 < msg) { X wprint("sort botch trying to sort %d and %d\n", msg1-msg, msg2-msg); X return 0; X } X if (ison(glob_flags, DATE_RECV)) X return strcmp(msg1->m_date_recv, msg2->m_date_recv) * order; X else X return strcmp(msg1->m_date_sent, msg2->m_date_sent) * order; X} END_OF_FILE if test 5803 -ne `wc -c <'sort.c'`; then echo shar: \"'sort.c'\" unpacked with wrong size! fi # end of 'sort.c' fi if test -f 'tool.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tool.c'\" else echo shar: Extracting \"'tool.c'\" \(4177 characters\) sed "s/^X//" >'tool.c' <<'END_OF_FILE' X/* @(#)tool.c (c) copyright 10/15/86 (Dan Heller) */ X X/* tool.c --make the mailtool windows, panels, etc... */ X#include "mush.h" X Xmake_tool(args) Xchar **args; X{ X struct stat rootbuf, tmpbuf; X struct inputmask im; X register unsigned i; X char **choice_args, **button_args, *p; X char buf1[WIN_NAMESIZE], buf2[WIN_NAMESIZE]; X X getfonts(); X mail_icon.ic_font = fonts[DEFAULT]; X X if (p = do_set(set_options, "screen_win")) X screen = atoi(p); X else X screen = 6; X X /* where to place text on mail icon -- how many messages there are */ X rect_construct(&mail_icon.ic_textrect, X l_width(DEFAULT), 58-l_height(DEFAULT), X 3*l_width(DEFAULT), l_height(DEFAULT)); X X if (!(tool = tool_make( X WIN_ICON, &mail_icon, X WIN_HEIGHT, 700, X WIN_WIDTH, 650, X WIN_BOUNDARY_MGR, 1, X WIN_ATTR_LIST, args, X NULL))) X perror(prog_name), cleanup(0); X tool_free_attribute_list(args); X X choice_args = panel_make_list( X PANEL_MENU_TITLE_FONT, fonts[LARGE], X PANEL_DISPLAY_LEVEL, PANEL_NONE, X PANEL_SHOW_MENU, TRUE, X PANEL_SHOW_MENU_MARK, FALSE, X 0); X X button_args = panel_make_list( X PANEL_FEEDBACK, PANEL_INVERTED, X PANEL_SHOW_MENU, FALSE, X 0); X X make_hdr_panel(choice_args, button_args); X X if (!(hdr_sw = gfxsw_createtoolsubwindow(tool, "hdr_sw", X TOOL_SWEXTENDTOEDGE, 10+ screen*l_height(DEFAULT), (char **)0))) X perror("hdr_sw"), cleanup(0); X gfxsw_getretained((struct gfxsubwindow *)hdr_sw->ts_data); X hdr_win = ((struct gfxsubwindow *)(hdr_sw->ts_data))->gfx_pixwin; X X input_imnull(&im); X win_setinputcodebit(&im, LOC_STILL); X win_setinputcodebit(&im, LOC_MOVE); X win_setinputcodebit(&im, LOC_WINENTER); X for (i = VKEY_FIRSTFUNC; i <= VKEY_LASTFUNC; i++) X win_setinputcodebit(&im, i); X win_setinputmask(hdr_sw->ts_windowfd, &im, &im, X win_fdtonumber(hdr_panel_sw->ts_windowfd)); X hdr_sw->ts_io.tio_selected = hdr_io; X hdr_sw->ts_io.tio_handlesigwinch = hdrwin_handlesigwinch; X X make_main_panel(choice_args, button_args); X xfree(choice_args), xfree(button_args); X X if (!(print_sw = gfxsw_createtoolsubwindow(tool, "print_sw", X TOOL_SWEXTENDTOEDGE, l_height(LARGE) + 10, (char **)0))) X perror("print_sw"), cleanup(0); X print_win = ((struct gfxsubwindow *)(print_sw->ts_data))->gfx_pixwin; X print_sw->ts_io.tio_handlesigwinch = print_sigwinch; X X /* text subwindow */ X if (!(msg_sw = gfxsw_createtoolsubwindow(tool, "msg_sw", X TOOL_SWEXTENDTOEDGE, TOOL_SWEXTENDTOEDGE, (char **)0))) X perror("msg_sw"), cleanup(0); X gfxsw_getretained((struct gfxsubwindow *)msg_sw->ts_data); X msg_win = ((struct gfxsubwindow *)(msg_sw->ts_data))->gfx_pixwin; X X /* everything we want the text window to pay attention to */ X input_imnull(&im); X im.im_flags = IM_ASCII; X im.im_flags &= ~IM_ANSI; X for (i = VKEY_FIRSTFUNC; i <= VKEY_LASTFUNC; i++) X win_setinputcodebit(&im, i); X win_setinputmask(msg_sw->ts_windowfd, &im, &im, WIN_NULLLINK); X msg_sw->ts_io.tio_selected = msg_io; X msg_sw->ts_io.tio_handlesigwinch = msgwin_handlesigwinch; X X /* tty subwindow */ X if (!(tty_sw = ttytlsw_createtoolsubwindow(tool, "tty_sw", X TOOL_SWEXTENDTOEDGE, 0, (char **)0))) X perror("tty_sw"), cleanup(0); X ttysw_handlesigwinch(tty_sw); X win_setcursor(tty_sw->ts_windowfd, &write_cursor); X X (void) sprintf(blank, "%128c", ' '); X (void) signal(SIGWINCH, sigwinchcatcher); X (void) signal(SIGTERM, sigtermcatcher); X (void) signal(SIGCHLD, sigchldcatcher); X pw_writebackground(hdr_win, 0,0, hdr_rect.r_width, hdr_rect.r_height, X PIX_CLR); X if (ioctl(0, TIOCGETC, &tchars)) X perror("gtty failed"), cleanup(0); X win_numbertoname (0, buf1); X if ((rootfd = open(buf1, 0)) == -1) X error("can't open %s", buf1), cleanup(0); X if (fstat(rootfd, &rootbuf)) X error("can't stat %s", buf1), cleanup(0); X for (parentfd = 3; parentfd < rootfd; parentfd++) X if (fstat(parentfd, &tmpbuf)) X error("Can't stat fd-%d", parentfd); X else if (tmpbuf.st_ino == rootbuf.st_ino) { X (void) close(rootfd); X rootfd = parentfd; X break; X } X istool = 2; X (void) do_version(); X lock_cursors(); X tool_install(tool); X tool_display(tool); X do_clear(); X} END_OF_FILE if test 4177 -ne `wc -c <'tool.c'`; then echo shar: \"'tool.c'\" unpacked with wrong size! fi # end of 'tool.c' fi echo shar: End of archive 3 \(of 19\). cp /dev/null ark3isdone 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 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.