Subject: v14i035: Mail User's Shell, version 6.0, Part03/14 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: island!argv@sun.com (Dan Heller) Posting-number: Volume 14, Issue 35 Archive-name: mush6.0/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 'curs_io.c' <<'END_OF_FILE' X/* @(#)curs_io.c (c) copyright 3/18/87 (Dan Heller) */ X X/* curs_io.c -- curses based I/O */ X#include "mush.h" X X#ifdef CURSES X#include "bindings.h" X#endif /* CURSES */ X char *_unctrl[] = { X "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "^I", "^J", "^K", X "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V", "^W", X "^X", "^Y", "^Z", "^[", "^\\", "^]", "^~", "^_", X " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", X ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", X "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", X "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", X "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", X "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", X "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "^?" X}; X X#ifdef Addch X#undef Addch X#endif /* Addch */ X X#ifndef CURSES X X#define Addch(c) if (isoff(glob_flags, ECHO_FLAG)) \ X fputc(c, stdout), fflush(stdout) X X#else X X/* see end of Getstr */ X#define Addch(c) \ X if (iscurses) \ X addch(c), refresh(); \ X else if (isoff(glob_flags, ECHO_FLAG)) \ X fputc(c, stdout), fflush(stdout) X#endif /* CURSES */ X X/* X * get a string of at most 'length' chars. X * allow backspace-space-backspace, kill word and kill line X * (options set by user in stty). X * length is the max length this string can get. offset is from beginning X * of string. X * input of ^D returns -1; otherwise, return the number of chars in string. X */ Getstr(String, length, offset) char String[]; register int length; X{ X register int c, literal_next = FALSE; X int count = offset; X X while ((c = getchar()) != '\n' && c != '\r' && c != EOF && X isoff(glob_flags, WAS_INTR)) { X /* echo isn't set, so whatever the character, enter it */ X if (ison(glob_flags, ECHO_FLAG)) X if (count < length) X String[count++] = c; X else { X print("Warning: string too long. Truncated at %d chars.\n", X length); X break; X } X /* ^D as the first char on a line or two ^D's in a row is EOF */ X else if (c == CTRL(D) && !count) X break; X else if (c == '\\') { X literal_next = TRUE; X Addch(String[count++] = '\\'); X } else if (literal_next) { X literal_next = FALSE; X if (iscntrl(c) || c == _tty.sg_kill || c == _tty.sg_erase X#ifdef TIOCGLTC X || c == ltchars.t_werasc X#endif /* TIOCGLTC */ X ) X backspace(String, &count); X String[count++] = c; X if (iscntrl(c) || c == _tty.sg_erase) { X if (iscntrl(c)) X Addch('^'); X Addch(_unctrl[c][1]); X } else X Addch(c); X } else if (c == _tty.sg_erase || c == CTRL(H) || c == 127 /*CTRL(?)*/) { X if (count) X backspace(String, &count); X /* if iscurses, then backspacing too far is cancelling a function */ X else if (!count && iscurses) { X String[0] = '\0'; X return -1; X } X } else if (c == _tty.sg_kill) { X if (count) { X do backspace(String, &count); X while (count); X } X } else X#ifndef TIOCGLTC X if (c == CTRL(R)) /* system doesn't have ltchars */ X#else X if (c == ltchars.t_rprntc) /* reprint line */ X#endif /* TIOCGLTC */ X String[count] = 0, printf("\n%s", String); X else X#ifndef TIOCGLTC X if (c == CTRL(W)) /* system doesn't have ltchars */ X#else X if (c == ltchars.t_werasc) /* word erase */ X#endif /* TIOCGLTC */ X while (count) { X backspace(String, &count); X if (!count || X isspace(String[count-1]) && !isspace(String[count]) || X !isalnum(String[count-1]) && isalnum(String[count])) X break; X } X else if (c == '\t') X do { X Addch(' '); X String[count] = ' '; X } while (++count % 8 && count < length); X else if (count == length) X bell(); X else { X String[count++] = c; X if (c != '\t' && iscntrl(c)) { X Addch('^'); X Addch(_unctrl[c][1]); X } else X Addch(c); X } X } X if (c == CTRL(D) || c == EOF || ison(glob_flags, WAS_INTR)) { X if (feof(stdin)) X clearerr(stdin); X return -1; X } X if (count && String[count-1] == '\\') { X int count2; X if (isoff(glob_flags, ECHO_FLAG)) X putchar('\n'); X if ((count2 = Getstr(&String[count-1], length - count + 1, 0)) == -1) X return -1; X return count + count2; X } X if (!iscurses && isoff(glob_flags, ECHO_FLAG)) X putchar('\n'); X while (count > 0 && isspace(String[count-1])) X --count; X String[count] = 0; X return count; X} X static backspace(str, n) register char *str; int *n; X{ X (*n)--; X Addch('\b'); Addch(' '); Addch('\b'); X if (iscntrl(str[*n])) { X Addch('\b'); Addch(' '); Addch('\b'); X } X} X X#undef Addch X X#ifdef CURSES X/* X * prompt for a carriage return, but return whatever user types unless X * it's a character which he might regret (like 'q' or 'x'). Ignore X * interrupts (kind of) because we have nowhere to longjmp to. When we X * return, we'll setjmp again (top of loop.c) X */ hit_return() X{ X int c; X X turnon(glob_flags, IGN_SIGS); X iscurses = FALSE; X (void) check_new_mail(); X iscurses = TRUE; X mail_status(1), addstr("...continue... "), refresh(); X c = getcmd(); X turnoff(glob_flags, IGN_SIGS); X X /* don't let the user type something he might regret */ X if (c == C_QUIT || c == C_EXIT) X return C_NULL; X return c; X} X curses_msg_list(str, list, m_list) register char *str, *list; char m_list[]; X{ X register char *p = NULL; X int c; X X print(str); X c = Getstr(list, COLS-13, 0); X move(LINES-1, 0), refresh(); X if (c <= 0 || !(p = do_range(list, m_list)) || X (p == list && *p && *p != '$' && *p != '^')) { X if (p) X print("Invalid message list: %s", p); X return 0; X } X return 1; X} X curs_vars(which) int which; /* really, a char */ X{ X char c, buf[128], buf2[128], *string; X struct options **list; X X switch(which) { X case C_OWN_HDR : string = "my_hdr", list = &own_hdrs; X when C_ALIAS : string = "alias", list = &aliases; X when C_IGNORE : string = "ignore", list = &ignore_hdr; X when C_VAR_SET : string = "set", list = &set_options; X otherwise : clr_bot_line(); return; X } X X print("%s [? Set Unset All]: ", string); X c = getchar(); X clr_bot_line(); X switch (Lower(c)) { X /* if help, print help -- if "all", show all settings. */ X case '?' : case 'a' : X if (c == '?') { X if (!strcmp(string, "set")) { X print("which variable? [all ]: "); X if ((c = Getstr(buf+1, COLS-40, 0)) < 0) X return; X clr_bot_line(); X buf[0] = '?'; X if (c > 0) { X char *argv[3]; X argv[0] = string; X argv[1] = buf; X argv[2] = NULL; X Lower(buf[1]); X if (!strcmp(buf+1, "a")) X (void) strcpy(buf+1, "all"); X if (!strcmp(buf+1, "all")) X turnon(glob_flags, CNTD_CMD); X (void) set(2, argv); X return; X } X } X /* help returns next command (hit_return) */ X help(0, string, cmd_help); X turnon(glob_flags, CNTD_CMD); X return; X } X turnon(glob_flags, CNTD_CMD); X (void) do_set(*list, NULL); X X /* if set, prompt for string and let user type */ X when 's' : X print("set: "); X c = Getstr(buf, COLS-18, 0); X clr_bot_line(); X if (c > 0) X (void) cmd_line(sprintf(buf2, "%s %s", string, buf), msg_list); X X /* if unset, just as easy as set! */ X when 'u' : X print("unset: ", string); X if (Getstr(buf, COLS-18, 0) > 0 && !un_set(list, buf)) X print("%s isn't set", buf); X } X if (ison(glob_flags, CNTD_CMD)) X putchar('\n'); X} X X#endif /* CURSES */ END_OF_FILE if test 7380 -ne `wc -c <'curs_io.c'`; then echo shar: \"'curs_io.c'\" unpacked with wrong size! fi # end of 'curs_io.c' fi if test -f 'dates.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dates.c'\" else echo shar: Extracting \"'dates.c'\" \(7499 characters\) sed "s/^X//" >'dates.c' <<'END_OF_FILE' X/* @(#)dates.c 1.1 (c) copyright 10/15/86 (Dan Heller) */ X X#include "mush.h" X char *day_names[] = { X "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat" X}; char *month_names[] = { /* imported in pick.c */ X "Jan", "Feb", "Mar", "Apr", "May", "Jun", X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" X}; X X/* Time() returns a string according to criteria: X * if "now" is 0, then the current time is gotten and used. X * else, use the time described by now X * opts points to a string of args which is parsed until an unknown X * arg is found and opts will point to that upon return. X * valid args are T (time of day), D (day of week), M (month), Y (year), X * N (number of day in month -- couldn't think of a better letter). X */ char * Time(opts, now) register char *opts; long now; X{ X static char time_buf[30]; X struct tm *T; X register char *p = time_buf; X long x; X X if (!opts) X return NULL; X if (now) X x = now; X else X (void) time(&x); X T = localtime(&x); X for (;; opts++) { X switch(*opts) { X case 'T': X if (ison(glob_flags, MIL_TIME)) X (void) sprintf(p, "%2d:%02d", T->tm_hour, T->tm_min); X else X (void) sprintf(p, "%d:%02d", (T->tm_hour) ? X ((T->tm_hour <= 12) ? T->tm_hour : T->tm_hour - 12) : X 12, T->tm_min); X when 'D': (void) strcpy(p, day_names[T->tm_wday]); X when 'M': (void) strcpy(p, month_names[T->tm_mon]); X when 'Y': (void) sprintf(p, "%d", T->tm_year); X when 'N': (void) sprintf(p, "%d", T->tm_mday); X otherwise: *--p = 0; return time_buf; X } X p += strlen(p); X *p++ = ' '; X } X} X X/* find the date of a message and return a string of the same form X * described by parse_date() below. X */ char * msg_date(n) register int n; X{ X register char *p, *p2 = NULL; X char line[BUFSIZ]; X X /* not in use */ X /* try the easy way out first -- This is potentially a serious kludge X * because not all message-id lines are right. -- most of the time, X * this is correct. it's not correct from messages from strange X * mailers (non-sendmail) they do a different format in message-id. X if ((p = header_field(n, "message-id")) && (p2 = index(p, '<'))) { X p = p2+1; X if (p2 = index(p, '.')) { X *p2 = 0; X return p; X } X } X */ X X /* else, get the "date" line, if that fails, get the date in "From" line */ X if ((p = header_field(n, "date")) && (p2 = parse_date(p))) X return p2; X X (void) fseek(tmpf, msg[n].m_offset, L_SET); X (void) fgets(line, BUFSIZ, tmpf); X if (!(p = index(line, ' ')) || !(p2 = index(p+1, ' '))) X return NULL; X p = p2; X X if (!(p2 = parse_date(p))) X print("Message %d has bad date: %s\n", n+1, p); X return p2; X} X X/* parse date and return a string that looks like X * "%2d%2d%2d%2d%2d", yr,mo,date,hrs,mins X */ char * parse_date(p) register char *p; X{ X /* If it's not a month, it can get _long_. this is also the static X * buffer whose address we return. X */ X static char month[64]; X int Month = 0, Day = 0, Year = 0, Hours = -1, Mins = -1; X X skipspaces(0); X X /* Possible combinations that we could have: X * day_number month_name year_number time timezone ... X * day_name month_name day_number time year_number X * day_name month_name day_number year_number time X * day_name day_number month_name year_number time X * day_number month_name year_number time X * day_number month_name year_number time-timezone (day) X * ^no colon separator X * day_name month_name day_number time timezone year_number X * day_number-month_name-year time X * day_name, day_number-month_name-year time X * day_number month_name year_number, time "-" X */ X /* programmer's note -- there are too many scanfs here for some compilers X * to put them all into one if statement. Use goto's :-( X */ X if (sscanf(p, "%*s %s %d %d %d:%d", month,&Day,&Year,&Hours,&Mins) == 5) X goto gotit; X if (sscanf(p, "%d %s %d %d:%d", &Day,month,&Year,&Hours,&Mins) == 5) X goto gotit; X if (sscanf(p, "%*s %s %d %d:%d:%*d %d", month,&Day,&Hours,&Mins,&Year) == 5) X goto gotit; X if (sscanf(p, "%*s %d %s %d %d:%d", &Day,month,&Year,&Hours,&Mins) == 5) X goto gotit; X if (sscanf(p, "%d %s %d %d:%d", &Day,month,&Year,&Hours,&Mins) == 5) X goto gotit; X if (sscanf(p, "%d %s %d %2d%2d", &Day,month,&Year,&Hours,&Mins) == 5) X goto gotit; X if (sscanf(p, "%*s %s %d %d:%d:%*d %*s %d", X month, &Day, &Hours, &Mins, &Year) == 5) X goto gotit; X if (sscanf(p, "%*s %s %d %d:%d %*s %d", X month, &Day, &Hours, &Mins, &Year) == 5) X goto gotit; X if (sscanf(p,"%d-%[^-]-%d %d:%d", &Day, month, &Year, &Hours, &Mins) == 5) X goto gotit; X if (sscanf(p,"%d %s %d, %d:%d:%*d -",&Day, month, &Year, &Hours, &Mins)== 5) X goto gotit; X if (sscanf(p,"%*s %d-%[^-]-%d %d:%d",&Day, month, &Year, &Hours, &Mins)== 5) X goto gotit; X goto didnt_getit; gotit: X if (Year > 1900) X Year -= 1900; X if ((Month = month_to_n(month)) == -1) { X print("bad month: %s\n", p); X return NULL; X } X return sprintf(month, "%02d%02d%02d%02d%02d", Year,Month,Day,Hours,Mins); didnt_getit: X if (ison(glob_flags, WARNING)) X print("Unknown date format: %s\n", p); X return NULL; X} X X/* pass a string in the form described above, put into string. X * return values in buffers provided they are not null. X */ char * date_to_string(Date, Yr, Mon, Day, Wkday, Tm, ret_buf) char *Date, *Yr, *Mon, *Day, *Wkday, *Tm, *ret_buf; X{ X X static int mtbl[]={0,31,59,90,120,151,181,212,243,273,304,334}; X unsigned int days_ctr; X int yr, mon, day, hr, mins; X char a_or_p, *p = ret_buf; X X (void) sscanf(Date, "%2d%2d%2d%2d%02d", &yr, &mon, &day, &hr, &mins); X a_or_p = (hr < 12)? 'a': 'p'; X X if (Wkday) { X days_ctr = ((yr * 365) + ((yr + 3) / 4) + mtbl[mon-1] + day + 6); X if (mon > 2 && (yr % 4 == 0)) X days_ctr++; X (void) (sprintf(Wkday, "%.3s", day_names[days_ctr % 7])); X } X if (Yr) X (void) sprintf(Yr, "19%d", yr); X if (Day) X (void) sprintf(Day, "%d", day); X if (Mon) X (void) strcpy(Mon, month_names[mon-1]); X p += strlen(sprintf(p, "%s %2.d, ", month_names[mon-1], day)); X if (ison(glob_flags, MIL_TIME)) X (void) sprintf(p, "%2d:%02d",hr,mins); X else X (void) sprintf(p, "%2.d:%02d%cm", X (hr)? (hr <= 12)? hr: hr - 12: 12, mins, a_or_p); X if (Tm) X (void) strcpy(Tm, p); X return ret_buf; X} X X#define JAN 1 X#define FEB 2 X#define MAR 3 X#define APR 4 X#define MAY 5 X#define JUN 6 X#define JUL 7 X#define AUG 8 X#define SEP 9 X#define OCT 10 X#define NOV 11 X#define DEC 12 X X/* stolen direct from ELM */ month_to_n(name) register char *name; X{ X /** return the month number given the month name... **/ X X register char ch; X X switch (lower(*name)) { X case 'a' : if ((ch = lower(name[1])) == 'p') X return(APR); X else if (ch == 'u') X return(AUG); X else return(-1); /* error! */ X case 'd' : return(DEC); X case 'f' : return(FEB); X case 'j' : if ((ch = lower(name[1])) == 'a') X return(JAN); X else if (ch == 'u') { X if ((ch = lower(name[2])) == 'n') X return(JUN); X else if (ch == 'l') X return(JUL); X else return(-1); /* error! */ X } X else return(-1); /* error */ X case 'm' : if ((ch = lower(name[2])) == 'r') X return(MAR); X else if (ch == 'y') X return(MAY); X else return(-1); /* error! */ X case 'n' : return(NOV); X case 'o' : return(OCT); X case 's' : return(SEP); X default : return(-1); X } X} END_OF_FILE if test 7499 -ne `wc -c <'dates.c'`; then echo shar: \"'dates.c'\" unpacked with wrong size! fi # end of 'dates.c' 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'\" \(5679 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 X#else X#ifndef SYSV X#include X#endif /* SYSV */ X#endif /* BSD */ X X#ifdef lint X#include X#endif /* lint */ X execute(argv) char **argv; X{ X#ifdef SYSV X int status; X#else X union wait status; X#endif /* SYSV */ X#ifdef SIGCONT X int (*oldstop)(), (*oldcont)(); X#endif /* SIGCONT */ X int pid, (*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 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 sigchldcatcher() 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 follwoing 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 struture! 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 sigtermcatcher() 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 5679 -ne `wc -c <'execute.c'`; then echo shar: \"'execute.c'\" unpacked with wrong size! fi # end of 'execute.c' fi if test -f 'file.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'file.c'\" else echo shar: Extracting \"'file.c'\" \(8484 characters\) sed "s/^X//" >'file.c' <<'END_OF_FILE' X/* file.c -- Copyright (1988) Dan Heller */ X X#include "mush.h" X#include X X/* takes string 'p' and address of int (isdir). If p uses the ~ to reference X * a home directory of somesort, then expand it. find out what sort of X * file final path is. set isidr to 1 if a directory, 0 if not, -1 on error X * return final path. If an error occurrs, return string indicating error. X * if isdir has a value of 1 when passed, it ignores "No such file or directory" X */ char * getpath(p, isdir) register char *p; int *isdir; X{ X static char buf[BUFSIZ]; X struct stat stat_buf; X X if (!p || !*p || !strcmp(p, "~")) { X char *home = do_set(set_options, "home"); X if (!home || !*home) X home = ALTERNATE_HOME; X (void) strcpy(buf, home); /* no arg means home */ X } else if (*p == '~') { X if (p[1] != '/') { X /* not our home, but someone else's X * look for ~user or ~user/subpath X * if '/' exists, separate into tmp="user" p="subpath" X */ X struct passwd *ent, *getpwnam(); X char *p2 = p+1; X if (p = index(p2, '/')) X *p++ = 0; X if (!(ent = getpwnam(p2))) { X *isdir = -1; X return sprintf(buf, "no such user: %s", p2); X } X /* append subpath to pathname */ X if (p && *p) X (void) sprintf(buf, "%s/%s", ent->pw_dir, p); X /* if *p == NULL, pathname is done (buf), set isdir = 1 */ X else { X *isdir = 1; X return strcpy(buf, ent->pw_dir); X } X } else { X char *home = do_set(set_options, "home"); X if (!home || !*home) X home = ALTERNATE_HOME; X (void) sprintf(buf, "%s/%s", home, p+2); X } X } else if (*p == '%') { X /* if %user, append user name... else, it's just us */ X (void) sprintf(buf, "%s/", MAILDIR); X if (!*++p || *p == ' ' || *p == '\t') X (void) strcat(buf, login); X else X (void) strcat(buf, p); X } else if (*p == '+') { X register char *p2 = do_set(set_options, "folder"); X if (!p2 || !*p2) X p2 = DEF_FOLDER; X (void) sprintf(buf, "%s/%s", p2, ++p); X if (*buf == '~') { X int t_isdir = *isdir; X char *t, tmp[256]; X (void) strcpy(tmp, buf); X t = getpath(tmp, &t_isdir); X if (t_isdir == -1) { X *isdir = -1; X return t; X } X /* strcpy(buf, t); --buf already has info because it's static */ X } X } else { /* allow \ to escape the special chars, +, %, ~ */ X if (*p == '\\') X p++; X (void) strcpy(buf, p); X } X if (stat(buf, &stat_buf)) { X (void) access(buf, F_OK); /* set errno to the "real" reason */ X if (errno == ENOENT && *isdir == 1) { X *isdir = 0; /* say it's a regular file even tho it doesn't exist */ X return buf; /* it may be wanted for creating */ X } X *isdir = -1; X return sys_errlist[errno]; X } X *isdir = ((stat_buf.st_mode & S_IFDIR) != 0); X return buf; X} X X/* X * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp X * opens the file with the mode. X * If the mode is "r" then we read the file into the file pointer at the X * end (fseek(fp, 2, 0)). If the file is opened for writing, then read X * from the beginning of fp and write it into the file. X * This is usually called to read .signatures into messages (thus, X * opening .signture with "r" and writing to the end of fp which is probably X * the sendmail process or the message file pointer) or to write fortunes into X * the message buffer: reading fp (the popened fortune) and writing into file. X */ void file_to_fp(p, fp, mode) register char *p; register FILE *fp; char *mode; X{ X int x = 1; X char *file, buf[BUFSIZ]; X FILE *tmp_fp; X X if (!p || !*p) { X print("specify filename"); X return; X } X file = getpath(p, &x); X if (x == -1) { /* on error, file contains error message */ X wprint(file); X return; X } X wprint("%s: ", file); X if (x) /* if x == 1, then path is a directory */ X wprint("directory.\n"); X else if (!(tmp_fp = fopen(file, mode))) { X wprint("%s\n", sys_errlist[errno]); X return; X } else if (*mode != 'r') { X rewind(fp); X for(x = 0; fgets(buf, BUFSIZ, fp); x++) X fputs(buf, tmp_fp); X } else X for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++) X fputs(buf, fp); X wprint("%s%d line%s\n", (*mode == 'a')? "added ": "", X x, (x == 1)? "": "s"); X fflush(fp); X fclose(tmp_fp); X} X X/* clear all contents of the file. Careful that the file is opened for X * _writing_ --tempfile is opened for reading, so don't try to empty it X * if you're using ftruncate. Return -1 on error, 0 on success. X */ emptyfile(fp, fname) register FILE **fp; register char *fname; X{ X Debug("Emptying \"%s\"\n", fname); X#ifndef SYSV X return ftruncate(fileno(*fp), 0L); X#else X { X int omask = umask(077), ret; X fclose(*fp); X if (!(*fp = fopen(fname, "w"))) X ret = -1; X ret = 0; X (void) umask(omask); X return ret; X } X#endif /* SYSV */ X} X X/* X * Finds out how many file descriptors are opened. Useful for making sure X * no files got opened in subprocedures which were not subsequently closed. X */ nopenfiles(argc) X{ X register int nfiles = 0; X#ifdef MAXFILES X register int size = MAXFILES; X#else X register int size = getdtablesize(); X#endif /* MAXFILES */ X X if (argc < 2) X print("open file descriptors:"); X while (--size >= 0) X if (fcntl(size, F_GETFL, 0) != -1) { X if (argc < 2) X print_more(" %d", size); X ++nfiles; X } X if (argc < 2) X print("\n"); X return nfiles; X} X X/* X * Open a path for writing or appending -- return a FILE pointer. X * If program is TRUE, then use popen, not fopen and don't check X * to see if the file is writable. X */ FILE * open_file(p, program) register char *p; X{ X register FILE *newfile = NULL_FILE; X register char *tmp; X int x = 1; X X if (program || *p == '/') X tmp = p, x = 0; X else X tmp = getpath(p, &x); X if (x == 1) X print("%s is a directory.\n", tmp); X else if (x == -1) X print("%s: %s\n", p, tmp); X else { X register char *mode = NULL; X /* if it doesn't exist open for "w" */ X if (program || Access(tmp, F_OK)) X mode = "w"; X /* if we can't write to it, forget it */ X else if (Access(tmp, W_OK)) X error(tmp); X else X mode = "a"; X if (mode) X if (program) { X if (!(newfile = popen(tmp, mode))) { X error("Can't execute %s\n", tmp); X return newfile; X } X } else X if (!(newfile = fopen(tmp, mode))) X error("Can't write to %s", tmp); X else X Debug("Successfully opened %s\n", tmp); X } X return newfile; X} X X/* X * find_files gets a set of addresses and an array of X * file pointers and the maximum size that array can be. X * The object is to find the files or programs listed in "s", attempt X * to fopen/popen them and save their filepointers in the array. If the X * size is 0, then just extract the file names and give error messages X * for each one since they will not be opened. Return the number of X * files opened and delete all files (opened or not) from the list in X * "s". Tokens beginning with a "/, ~, or + are files; tokens beginning X * with a | are programs. X * The string "s" is modified to be a list of address -- all names AND X * files are stripped out of the list. X */ find_files(s, files, size) register char *s; FILE *files[]; X{ X register int total = 0, prog; X char file[BUFSIZ], buf[BUFSIZ], *start = s, c; X register char *p, *b = buf; X X do { X if (!(p = get_name_n_addr(s, NULL, file))) X break; X c = *p, *p = 0; X /* It's a file -- try to open it. This doesn't get written back X * onto "buf" since it is supposed to be extracted anyway. X */ X if (*file == '+' || *file == '~' || *file == '|' || *file == '/') { X prog = (*file == '|'); X if (size && total < size) { X /* either open "file" or &file[1] */ X if (files[total] = open_file(&file[prog], prog)) X total++; X } else X print("No open space for %s\n", file); X } else { X b += Strcpy(b, s); X *b++ = ',', *b++ = ' '; X } X for (*p = c, s = p; *s == ',' || isspace(*s); s++) X ; X } while (*s); X for (*b-- = 0; b > buf && (*b == ',' || isspace(*b)); b--) X *b = 0; X (void) strcpy(start, buf); X return total; X} X X/* X * access(2) has an undocumented feature which ignores suid. If you are X * su'ed and try to read your mail, you will be unable to because access() X * will give the illusion that you cannot read/write to your mbox. Solve X * the problem by using stat() instead. X */ Access(file, mode) register char *file; X{ X struct stat buf; X X if (stat(file, &buf) == -1) X return -1; X if (mode == R_OK) X return (buf.st_mode & 0400)? 0 : -1; X if (mode == W_OK) X return (buf.st_mode & 0200)? 0 : -1; X return 0; X} END_OF_FILE if test 8484 -ne `wc -c <'file.c'`; then echo shar: \"'file.c'\" unpacked with wrong size! fi # end of 'file.c' fi if test -f 'main_panel.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'main_panel.c'\" else echo shar: Extracting \"'main_panel.c'\" \(9189 characters\) sed "s/^X//" >'main_panel.c' <<'END_OF_FILE' X/* "@(#)main_panel.c (c) copyright 10/18/86 (Dan Heller) */ X X#include "mush.h" X make_main_panel(choice_args, button_args) char **choice_args, **button_args; X{ X /* main panel stuff: */ X panel_sw = panel_create(tool, X PANEL_HEIGHT, 80, X 0); X main_panel = (Panel)panel_sw->ts_data; X X quit_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 4, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Done", 6, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Done", X PANEL_CHOICE_STRINGS, "Close to Icon", X "Quit Tool", X "Help", X 0, X PANEL_NOTIFY_PROC, toolquit, X 0); X X help_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 79, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Help", 4, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Available Help", X PANEL_CHOICE_STRINGS, "General", X "Help with \"help\"", X "The Mouse", X "Windows", X "Function Keys", X "Message headers", X "Message lists", X 0, X PANEL_NOTIFY_PROC, do_help, X 0); X X read_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 136, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Next", 4, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Next Message", X PANEL_CHOICE_STRINGS, "Read Next", "Help", 0, X PANEL_NOTIFY_PROC, read_mail, X 0); X X respond_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 193, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Reply", 5, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Respond to Current Message", X PANEL_CHOICE_STRINGS, "Sender Only", X "Sender Only (include msg)", X "All Recipients", X "All Recipients (include msg)", X "Help", 0, X PANEL_NOTIFY_PROC, respond_mail, X 0); X X delete_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 259, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Delete", 6, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Delete/Undelete Messages", X PANEL_CHOICE_STRINGS, "Delete", X "Undelete", X "Help", 0, X PANEL_NOTIFY_PROC, delete_mail, X 0); X X sort_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 334, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Sort", 4, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Sort Messages", X PANEL_CHOICE_STRINGS, "By Date", X "By Author", X "By Subject", X "By Subject (ignore Re:)", X "By Status", X "Help", 0, X PANEL_NOTIFY_PROC, do_sort, X 0); X X option_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 391, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Opts", 4, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Mail Options", X PANEL_CHOICE_STRINGS, "Set Options", "Function keys", X "Help", 0, X PANEL_NOTIFY_PROC, p_set_opts, X 0); X X alias_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 448, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Aliases", 7, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Mail Aliases", X PANEL_CHOICE_STRINGS, "Current Aliases", X "Add/Change alias", X "Unalias", "Help", 0, X PANEL_NOTIFY_PROC, p_set_opts, X 0); X X comp_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 532, X PANEL_ITEM_Y, 4, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Compose", 8, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Compose a letter", X PANEL_CHOICE_STRINGS, "Help", 0, X PANEL_NOTIFY_PROC, do_compose, X 0); X X file_item = panel_create_item(main_panel, PANEL_TEXT, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 4, X PANEL_ITEM_Y, 30, X PANEL_LABEL_FONT, fonts[DEFAULT], X PANEL_SHOW_MENU, TRUE, X PANEL_LABEL_STRING, "filename:", X PANEL_MENU_CHOICE_STRINGS, "Save message without message header",0, X PANEL_VALUE_DISPLAY_LENGTH, 35, X PANEL_NOTIFY_STRING, "\n\r", X PANEL_NOTIFY_PROC, file_dir, X 0); X X input_item = panel_create_item(main_panel, PANEL_TEXT, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 373, X PANEL_ITEM_Y, 30, X PANEL_SHOW_ITEM, FALSE, X PANEL_SHOW_MENU, TRUE, X PANEL_LABEL_FONT, fonts[DEFAULT], X PANEL_VALUE_DISPLAY_LENGTH, 20, X PANEL_NOTIFY_STRING, "\n\r", X PANEL_NOTIFY_PROC, text_done, X 0); X X print_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 4, X PANEL_ITEM_Y, 50, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Printer", 7, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Printing Messages", X PANEL_CHOICE_STRINGS, "Help", 0, X PANEL_NOTIFY_PROC, do_lpr, X 0); X X folder_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 88, X PANEL_ITEM_Y, 50, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "folder", 6, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Change folder", X PANEL_CHOICE_STRINGS, "System Mailbox", X "Main Mailbox", X "Last Accessed Folder", X 0, X PANEL_NOTIFY_PROC, do_file_dir, X 0); X X add_folder_to_menu(folder_item, 3); X X save_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 163, X PANEL_ITEM_Y, 50, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Save", 4, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Save messages", X PANEL_CHOICE_STRINGS, "~/mbox", 0, X PANEL_NOTIFY_PROC, do_file_dir, X 0); X X add_folder_to_menu(save_item, 1); X X cd_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 220, X PANEL_ITEM_Y, 50, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "chdir", 5, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Change Working Directory", X PANEL_CHOICE_STRINGS, "Print Current directory", X "HOME directory", X "Private Mail directory.", X "Help", 0, X PANEL_NOTIFY_PROC, do_file_dir, X 0); X X update_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 286, X PANEL_ITEM_Y, 50, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Update", 6, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Updating folders", X PANEL_CHOICE_STRINGS, "Help", 0, X PANEL_NOTIFY_PROC, do_update, X 0); X X send_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 361, X PANEL_ITEM_Y, 50, X PANEL_SHOW_ITEM, FALSE, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Send", 6, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Send Letter", X PANEL_CHOICE_STRINGS, "Help", 0, X PANEL_NOTIFY_PROC, do_send, X 0); X X edit_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 436, X PANEL_ITEM_Y, 50, X PANEL_SHOW_ITEM, FALSE, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Editor", 4, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Editing", X PANEL_CHOICE_STRINGS, "Help", 0, X PANEL_NOTIFY_PROC, do_edit, X 0); X X abort_item = panel_create_item(main_panel, PANEL_BUTTON, X PANEL_ATTRIBUTE_LIST, button_args, X PANEL_ITEM_X, 511, X PANEL_ITEM_Y, 50, X PANEL_SHOW_ITEM, FALSE, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Abort", 5, fonts[LARGE]), X PANEL_NOTIFY_PROC, abort_mail, X 0); X X font_item = panel_create_item(main_panel, PANEL_CHOICE, X PANEL_ATTRIBUTE_LIST, choice_args, X PANEL_ITEM_X, 577, X PANEL_ITEM_Y, 50, X PANEL_LABEL_IMAGE, X panel_button_image(main_panel, "Fonts", 5, fonts[LARGE]), X PANEL_MENU_TITLE_STRING, "Fonts", X PANEL_SHOW_MENU_MARK, TRUE, X PANEL_CHOICE_FONTS, fonts[0], fonts[1], fonts[2], 0, X PANEL_CHOICE_STRINGS, "Default", "Small", "Large", 0, X PANEL_NOTIFY_PROC, change_font, X 0); X} X X/* X * Open the user's mail folder (either user set or default path) and find all X * the files (assumed to be mail folders) and add them to the menu list of X * folders to use. X */ add_folder_to_menu(item, n) struct panel_item *item; register int n; X{ X register FILE *pp = NULL_FILE; X register char *p, *tmp = NULL; X int x = 0; X char buf[128], path[128]; X X if (!(p = do_set(set_options, "folder")) || !*p) X p = DEF_FOLDER; X if (p) { X tmp = getpath(p, &x); X if (x == -1) { X if (errno != ENOENT) X print("%s: %s\n", p, tmp); X tmp = NULL; X } X } X if (p = tmp) { X p = sprintf(buf, "%s %s", LS_COMMAND, p); X if (!(pp = popen(buf, "r"))) X error(buf); X else { X *path = '+'; X while (fgets(path+1, 128, pp)) { X struct stat s_buf; X if (p = index(path+1, '\n')) X *p = 0; X (void) sprintf(buf, "%s/%s", tmp, path+1); X if (stat(buf, &s_buf) || s_buf.st_mode & S_IFDIR) X continue; X panel_set(item, PANEL_CHOICE_STRING, n++, path, 0); X } X pclose(pp); X } X } X panel_set(item, PANEL_CHOICE_STRING, n, "Help", 0); X} END_OF_FILE if test 9189 -ne `wc -c <'main_panel.c'`; then echo shar: \"'main_panel.c'\" unpacked with wrong size! fi # end of 'main_panel.c' fi if test -f 'signals.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'signals.c'\" else echo shar: Extracting \"'signals.c'\" \(9615 characters\) sed "s/^X//" >'signals.c' <<'END_OF_FILE' X/* @(#)signals.c (c) copyright 10/18/86 (Dan Heller) */ X X#include "mush.h" X X#ifndef SYSV extern char *sys_siglist[]; X#else X/* sys-v doesn't have normal sys_siglist */ static char *sys_siglist[] = { X/* no error */ "no error", X/* SIGHUP */ "hangup", X/* SIGINT */ "interrupt (rubout)", X/* SIGQUIT */ "quit (ASCII FS)", X/* SIGILL */ "illegal instruction (not reset when caught)", X/* SIGTRAP */ "trace trap (not reset when caught)", X/* SIGIOT */ "IOT instruction", X/* SIGEMT */ "EMT instruction", X/* SIGFPE */ "floating point exception", X/* SIGKILL */ "kill (cannot be caught or ignored)", X/* SIGBUS */ "bus error", X/* SIGSEGV */ "segmentation violation", X/* SIGSYS */ "bad argument to system call", X/* SIGPIPE */ "write on a pipe with no one to read it", X/* SIGALRM */ "alarm clock", X/* SIGTERM */ "software termination signal from kill", X/* SIGUSR1 */ "user defined signal 1", X/* SIGUSR2 */ "user defined signal 2", X/* SIGCLD */ "death of a child", X/* SIGPWR */ "power-fail restart" X}; X#endif /* SYSV */ X X#ifdef SUNTOOL msgwin_handlesigwinch() X{ X register struct rect rect; X if (exec_pid) X return; X rect = msg_rect; X pw_damaged(msg_win); X /* this prevents old screen from being lost when editor finishes */ X if (isoff(glob_flags, IS_GETTING)) X gfxsw_interpretesigwinch(msg_sw->ts_data); X gfxsw_handlesigwinch(msg_sw->ts_data); X pw_repairretained(msg_win); X pw_donedamaged(msg_win); X win_getrect(msg_sw->ts_windowfd, &msg_rect); X crt = msg_rect.r_height / l_height(curfont); X if (rect.r_height != msg_rect.r_height || rect.r_width != rect.r_width) X if (getting_opts == 1) X display_opts(0); X else if (getting_opts == 2) X set_fkeys(); X else if (msg_pix) X scroll_win(0); X} X hdrwin_handlesigwinch() X{ X register struct rect rect; X rect = hdr_rect; X pw_damaged(hdr_win); X gfxsw_interpretesigwinch(hdr_sw->ts_data); X gfxsw_handlesigwinch(hdr_sw->ts_data); X pw_repairretained(hdr_win); X pw_donedamaged(hdr_win); X win_getrect(hdr_sw->ts_windowfd, &hdr_rect); X if (rect.r_width != hdr_rect.r_width || rect.r_height != hdr_rect.r_height){ X pw_writebackground(hdr_win, 0,0, X hdr_rect.r_width, hdr_rect.r_height, PIX_CLR); X screen = hdr_rect.r_height/l_height(DEFAULT); X (void) do_hdrs(0, DUBL_NULL, NULL); X } X} X print_sigwinch() X{ X pw_damaged(print_win); X gfxsw_handlesigwinch(print_sw->ts_data); X pw_writebackground(print_win, 0,0, X win_getwidth(print_sw->ts_windowfd), X win_getheight(print_sw->ts_windowfd), PIX_CLR); X pw_donedamaged(print_win); X print(NULL); /* reprint whatever was there before damage */ X} X sigwinchcatcher() X{ X tool_sigwinch(tool); X} X#endif /* SUNTOOL */ X interrupt(sig) X{ X Debug("interrupt() caught: %d\n", sig); X turnon(glob_flags, WAS_INTR); X} X X/* X * catch signals to reset state of the machine. Always print signal caught. X * If signals are ignored, return. If we're running the shell, longjmp back. X */ X/*ARGSUSED*/ catch(sig) X{ X Debug("Caught signal: %d\n", sig); X (void) signal(sig, catch); X if (ison(glob_flags, IGN_SIGS) && sig != SIGTERM && sig != SIGHUP) X return; X print("%s: %s\n", prog_name, sys_siglist[sig]); X turnoff(glob_flags, IS_PIPE); X if (istool || sig == SIGTERM || sig == SIGHUP) { X if (istool) /* istool is 2 if tool is complete */ X istool = 1; X (void) setjmp(jmpbuf); X if (ison(glob_flags, IS_GETTING)) X rm_edfile(-1); X cleanup(sig); X } X if (ison(glob_flags, DO_SHELL)) { X turnoff(glob_flags, IS_GETTING); X longjmp(jmpbuf, 1); X } else X puts("exiting"), cleanup(sig); X} X X#ifdef SIGCONT stop_start(sig) X{ X extern FILE *ed_fp; X X Debug("Caught signal: %d", sig); X if (sig == SIGCONT) { X (void) signal(SIGTSTP, stop_start); X (void) signal(SIGCONT, stop_start); X echo_off(); X if (istool || ison(glob_flags, IGN_SIGS) && !iscurses) X return; X /* we're not in an editor but we're editing a letter */ X if (ison(glob_flags, IS_GETTING)) { X if (ed_fp) X print("(Continue editing letter)\n"); X } X#ifdef CURSES X else if (iscurses) X if (ison(glob_flags, IGN_SIGS)) { X clr_bot_line(); X if (msg_list) X puts(compose_hdr(current_msg)); X mail_status(1), addstr("...continue... "); X refresh(); X } else { X int curlin = max(1, current_msg - n_array[0] + 1); X redraw(); X print("Continue"); X move(curlin, 0); X refresh(); X /* make sure we lose reverse video on continuation */ X if (ison(glob_flags, REV_VIDEO) && msg_cnt) { X char buf[256]; X (void) strncpy(buf, compose_hdr(current_msg), COLS-1); X buf[COLS-1] = 0; /* strncpy does not null terminate */ X mvaddstr(curlin, 0, buf); X } X } X#endif /* CURSES */ X else X mail_status(1), fflush(stdout); X } else { X#ifdef CURSES X if (iscurses) { X /* when user stops mush, the current header is not in reverse X * video -- note that a refresh() has not been called in curses.c! X * so, make sure that when a continue is called, the reverse video X * for the current message returns. X */ X turnon(glob_flags, WAS_INTR); X if (isoff(glob_flags, IGN_SIGS) && ison(glob_flags, REV_VIDEO) && X msg_cnt) { X int curlin = max(1, current_msg - n_array[0] + 1); X char buf[256]; X (void) strncpy(buf, stdscr->_y[curlin], COLS-1); X buf[COLS-1] = 0; /* strncpy does not null terminate */ X STANDOUT(curlin, 0, buf); X } X print("Stopping..."); X } X#endif /* CURSES */ X echo_on(); X (void) signal(SIGTSTP, SIG_DFL); X (void) signal(SIGCONT, stop_start); X (void) kill(getpid(), sig); X } X} X#endif /* SIGCONT */ X X/*ARGSUSED*/ cleanup(sig) X{ X char buf[128], c = ison(glob_flags, IGN_SIGS)? 'n' : 'y'; X X#ifdef CURSES X if (iscurses) X iscurses = FALSE, endwin(); X#endif /* CURSES */ X X echo_on(); X X if (ison(glob_flags, IS_GETTING)) X turnoff(glob_flags, IS_GETTING), dead_letter(); X if ((sig == SIGSEGV || sig == SIGBUS) && isoff(glob_flags, IGN_SIGS) X && *tempfile) { X fprintf(stderr, "remove %s [y]? ", tempfile), fflush(stderr); X if (fgets(buf, 128, stdin)) X c = lower(*buf); X } X if (c != 'n' && *tempfile && unlink(tempfile) && !sig && errno != ENOENT) X error(tempfile); X#ifdef SUNTOOL X if (istool && tool) X tool_destroy(tool); X#endif /* SUNTOOL */ X if (sig == SIGSEGV || sig == SIGBUS) { X if (isoff(glob_flags, IGN_SIGS)) { X fprintf(stderr, "coredump [n]? "), fflush(stderr); X if (fgets(buf, 128, stdin)) X c = lower(*buf); X } X if (c == 'y') X puts("dumping core for debugging"), abort(); X } X exit(sig); X} X X/* X * if new mail comes in, print who it's from. 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 statment. 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 */ check_new_mail() X{ X int ret_value; X char buf[BUFSIZ]; X register char *p = buf; X static long last_spool_size = -1; X X#ifdef SUNTOOL X static int is_iconic, was_iconic; X X if (istool) { X timerclear(&(mail_timer.it_interval)); X timerclear(&(mail_timer.it_value)); X mail_timer.it_value.tv_sec = time_out; X setitimer(ITIMER_REAL, &mail_timer, NULL); X } X#endif /* SUNTOOL */ X /* if fullscreen access in progress (help), don't do anything */ X if (ret_value = mail_size()) { X#ifdef CURSES X int new_hdrs = last_msg_cnt; X#endif /* CURSES */ X#ifdef SUNTOOL X /* if our status has changed from icon to toolform, 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 = (tool->tl_flags&TOOL_ICONIC)) && was_iconic) X last_msg_cnt = msg_cnt; X#endif /* SUNTOOL */ X turnon(glob_flags, NEW_MAIL); X getmail(); /* msg_cnt gets incremented here */ X if (istool) { X mail_status(0); X (void) do_hdrs(0, DUBL_NULL, NULL); X } 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 = tool->tl_flags & TOOL_ICONIC)) X#endif /* SUNTOOL */ X if (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) strcat(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 X#endif /* CURSES */ X print("%s", buf); /* buf might have %'s in them!!! */ X } else X#ifdef SUNTOOL X if (!istool || !is_iconic) X#endif /* SUNTOOL */ X turnoff(glob_flags, NEW_MAIL); X if (last_spool_size > -1 && /* handle first case */ X strcmp(mailfile, spoolfile) && last_spool_size < spool_size) X print("You have new mail in your system mailbox.\n"), ret_value = 1; X last_spool_size = spool_size; X return ret_value; X} X X/*ARGSUSED*/ /* we ignore the sigstack, cpu-usage, etc... */ bus_n_seg(sig) X{ X fprintf(stderr, "%s: %s\n", prog_name, X (sig == SIGSEGV)? "Segmentation violation": "Bus error"); X cleanup(sig); X} END_OF_FILE if test 9615 -ne `wc -c <'signals.c'`; then echo shar: \"'signals.c'\" unpacked with wrong size! fi # end of 'signals.c' fi echo shar: End of archive 3 \(of 14\). cp /dev/null ark3isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 14 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