syd@dsinc.UUCP (Syd Weinstein) (12/14/88)
---- Cut Here and unpack ---- #!/bin/sh # this is part 18 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/screen.c continued # CurArch=18 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file src/screen.c" sed 's/^X//' << 'SHAR_EOF' >> src/screen.c X return(FALSE); X X /** compute last header to display **/ X X this_msg = header_page * headers_per_page; X last = this_msg + (headers_per_page - 1); X } X X if (last >= message_count) last = message_count-1; X X /** Okay, now let's show the header page! **/ X X ClearLine(line); /* Clear the top line... */ X X MoveCursor(line, 0); /* and move back to the top of the page... */ X X while ((selected && displayed < last) || this_msg <= last) { X tail_of(header_table[this_msg].from, newfrom, TRUE); X X if (selected) { X if (this_msg == current-1) X build_header_line(buffer, &header_table[this_msg], ++displayed, X TRUE, newfrom); X else X build_header_line(buffer, &header_table[this_msg], X ++displayed, FALSE, newfrom); X } X else { X if (this_msg == current-1) X build_header_line(buffer, &header_table[this_msg], this_msg+1, X TRUE, newfrom); X else X build_header_line(buffer, &header_table[this_msg], X this_msg+1, FALSE, newfrom); X } X X if (this_msg == current-1 && has_highlighting && ! arrow_cursor) { X StartInverse(); X Write_to_screen("%s\r\n", 1, buffer); /* avoid '%' probs */ X EndInverse(); X } else X Write_to_screen("%s\r\n", 1, buffer); /* avoid '%' probs */ X CleartoEOLN(); X line++; /* for clearing up in a sec... */ X X if (selected) { X if ((this_msg = next_visible(this_msg+1)-1) < 0) X break; /* GET OUTTA HERE! */ X X /* the preceeding looks gross because we're using an INDEX X variable to pretend to be a "current" counter, and the X current counter is always 1 greater than the actual X index. Does that make sense?? X */ X } X else X this_msg++; /* even dumber... */ X } X X if (mini_menu) X last_line = LINES-8; X else X last_line = LINES-4; X X while (line < last_line) { X CleartoEOLN(); X Writechar('\r'); X Writechar('\n'); X line++; X } X X display_central_message(); X X last_current = current; X last_header_page = header_page; X X return(TRUE); X} X Xshow_current() X{ X /** Show the new header, with all the usual checks **/ X X register int first = 0, last = 0, last_line, new_line, i=0, j=0; X char newfrom[SLEN], old_buffer[SLEN], new_buffer[SLEN]; X X (void) fix_header_page(); /* Who cares what it does? ;-) */ X X /** compute last header to display **/ X X first = header_page * headers_per_page; X last = first + (headers_per_page - 1); X X if (last > message_count) X last = message_count; X X /** okay, now let's show the pointers... **/ X X /** have we changed??? **/ X X if (current == last_current) X return; X X if (selected) { X last_line = ((i=compute_visible(last_current-1)-1) % X headers_per_page)+4; X new_line = ((j=compute_visible(current-1)-1) % headers_per_page)+4; X } X else { X last_line = ((last_current-1) % headers_per_page)+4; X new_line = ((current-1) % headers_per_page)+4; X } X X if (has_highlighting && ! arrow_cursor) { X /** build the old and new header lines... **/ X X tail_of(header_table[current-1].from, newfrom, TRUE); X build_header_line(new_buffer, &header_table[current-1], X (selected? compute_visible(current-1) : current), X TRUE, newfrom); X X if (last_current > 0 && X (last_current-1 <= last && last_current >= first)) { X X dprint(5, (debugfile, X "\nlast_current = %d ... clearing [1] before we add [2]\n", X last_current)); X dprint(5, (debugfile, "first = %d, and last = %d\n\n", X first, last)); X X tail_of(header_table[last_current-1].from, newfrom, TRUE); X build_header_line(old_buffer, &header_table[last_current-1], X (selected? compute_visible(last_current-1) : last_current), X FALSE, newfrom); X X ClearLine(last_line); X PutLine0(last_line, 0, old_buffer); X } X MoveCursor(new_line, 0); X StartInverse(); X Write_to_screen("%s", 1, new_buffer); X EndInverse(); X } X else { X if (on_page(last_current)) X PutLine0(last_line,0," "); /* remove old pointer... */ X if (on_page(current)) X PutLine0(new_line, 0,"->"); X } X X last_current = current; X} X Xbuild_header_line(buffer, entry, message_number, highlight, from) Xchar *buffer; Xstruct header_rec *entry; Xint message_number, highlight; Xchar *from; X{ X /** Build in buffer the message header ... entry is the current X message entry, 'from' is a modified (displayable) from line, X 'highlight' is either TRUE or FALSE, and 'message_number' X is the number of the message. X **/ X X /** Note: using 'strncpy' allows us to output as much of the X subject line as possible given the dimensions of the screen. X The key is that 'strncpy' returns a 'char *' to the string X that it is handing to the dummy variable! Neat, eh? **/ X X char subj[LONG_SLEN]; /* to output subject */ X X strncpy(subj, entry->subject, COLUMNS-44); X X subj[COLUMNS-45] = '\0'; /* insurance, eh? */ X X /* now THIS is a frightening format statement!!! */ X X sprintf(buffer, "%s%s%c%-3d %3.3s %-2d %-18.18s (%d) %s%s", X (highlight && arrow_cursor)? "->" : " ", X show_status(entry->status), X (entry->status & TAGGED? '+' : ' '), X message_number, X entry->month, X atoi(entry->day), X from, X entry->lines, X (entry->lines / 1000 > 0? "" : /* spacing the */ X entry->lines / 100 > 0? " " : /* same for the */ X entry->lines / 10 > 0? " " : /* lines in () */ X " "), /* [wierd] */ X subj); X} X Xint Xfix_header_page() X{ X /** this routine will check and ensure that the current header X page being displayed contains messages! It will silently X fix 'header-page' if wrong. Returns TRUE if changed. **/ X X int last_page, old_header; X X old_header = header_page; X X last_page = (int) ((message_count-1) / headers_per_page); X X if (header_page > last_page) X header_page = last_page; X else if (header_page < 0) X header_page = 0; X X return(old_header != header_page); X} X Xint Xon_page(message) Xint message; X{ X /** Returns true iff the specified message is on the displayed page. **/ X X if (selected) message = compute_visible(message-1); X X if (message >= header_page * headers_per_page) X if (message <= ((header_page+1) * headers_per_page)) X return(TRUE); X X return(FALSE); X} X Xchar *show_status(status) Xint status; X{ X /** This routine returns a pair of characters indicative of X the status of this message. The first character represents X the interim status of the message (e.g. the status within X the mail system): X X E = Expired message X N = New message X D = Deleted message X _ = (space) default X X and the second represents the permanent attributes of the X message: X X C = Company Confidential message X U = Urgent (or Priority) message X P = Private message X A = Action associated with message X F = Form letter X _ = (space) default X **/ X X static char mybuffer[3]; X X /** the first character, please **/ X X if (status & DELETED) mybuffer[0] = 'D'; X else if (status & EXPIRED) mybuffer[0] = 'E'; X else if (status & NEW) mybuffer[0] = 'N'; X else mybuffer[0] = ' '; X X /** and the second... **/ X X if (status & CONFIDENTIAL) mybuffer[1] = 'C'; X else if (status & URGENT) mybuffer[1] = 'U'; X else if (status & PRIVATE) mybuffer[1] = 'P'; X else if (status & ACTION) mybuffer[1] = 'A'; X else if (status & FORM_LETTER) mybuffer[1] = 'F'; X else mybuffer[1] = ' '; X X mybuffer[2] = '\0'; X X return( (char *) mybuffer); X} SHAR_EOF echo "File src/screen.c is complete" chmod 0444 src/screen.c || echo "restore of src/screen.c fails" echo "x - extracting src/showmsg.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/showmsg.c && X Xstatic char rcsid[] = "@(#)$Id: showmsg.c,v 2.1.1.2 88/09/23 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: showmsg.c,v $ X * Revision 2.1 88/09/15 20:29:43 syd X * checked in with -k by syd at 88.09.15.20.29.43. X * X * 88/08/27 ssw X * add deluth patches X * X * Revision 2.1 88/07/21 09:59:34 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:36 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This file contains all the routines needed to display the specified X message. X X X Modified 6/86 to use pager variable!!! Hurrah!!!! X Modified 7/86 to have secure pipes.. *sigh* X and again 10/87 to do more interesting things with the screen w.r.t. X end of message prompting and so on... X**/ X X#include "headers.h" X#include <ctype.h> X#include <errno.h> X#include <signal.h> X X#ifdef BSD X# include <sys/wait.h> X# undef tolower X#endif X Xextern int errno; X Xchar *error_name(), *strcat(), *strcpy(); Xvoid _exit(); X Xint memory_lock = FALSE; /* is it available?? */ Xint pipe_abort = FALSE; /* did we receive a SIGNAL(SIGPIPE)? */ X Xextern int lines_displayed, /* defined in "builtin" */ X lines_put_on_screen; /* ditto too! */ X Xint Xshow_msg(number) Xint number; X{ X /*** display number'th message. Get starting and ending lines X of message from headers data structure, then fly through X the file, displaying only those lines that are between the X two! X Returns non-zero iff the screen was changed, or the X character pressed at the 'end-of-screen' prompt (to be X processed via process_showmsg_cmd()). X ***/ X X dprint(8, (debugfile, "show_msg called\n")); X X if (number > message_count) { X error1("Only %d messages!", message_count); X return(0); X } X else if (number < 1) { X error("you can't read THAT message!"); X return(0); X } X X clearit(header_table[number-1].status, NEW); /* it's been read now! */ X X memory_lock = FALSE; X X /* some explanation for that last one - We COULD use memory locking X to speed up the paging, but the action of "ClearScreen" on a screen X with memory lock turned on seems to vary considerably (amazingly so) X so it's safer to only allow memory lock to be a viable bit of X trickery when dumping text to the screen in scroll mode. X Philosophical arguments should be forwarded to Bruce at the X University of Walamazoo, Australia, via ACSNet *wry chuckle* */ X X return(show_message(header_table[number-1].lines, X header_table[number-1].offset,number)); X} X Xint Xshow_message(lines, file_loc, msgnumber) Xint lines, msgnumber; Xlong file_loc; X{ X /*** Show the indicated range of lines from mailfile X for message 'msgnumber' by using 'display' X Returns non-zero iff screen was altered, or the char X pressed (see previous routine header comment). X ***/ X int retval; X X dprint(9, (debugfile, "show_message(%d,%ld,%d)\n", X lines, file_loc, msgnumber)); X X if (fseek(mailfile, file_loc, 0) == -1) { X dprint(1, (debugfile, X "Error: seek %d bytes into file, errno %s (show_message)\n", X file_loc, error_name(errno))); X error2("ELM failed seeking %d bytes into file (%s)", X file_loc, error_name(errno)); X return(0); X } X X if (feof(mailfile)) X dprint(1, (debugfile, "\n*** seek put us at END OF FILE!!! ***\n")); X X X /* next read will get 'this' line so must be at end of previous */ X X if (first_word(pager,"builtin") || first_word(pager,"internal")) X retval = display(lines, msgnumber); X else X retval = secure_display(lines, msgnumber); X X if (memory_lock) EndMemlock(); /* turn it off!! */ X X return(retval == 0? 1 : retval); /* we did it boss! */ X} X X X/** This next one is the 'pipe' file descriptor for writing to the X pager process... **/ X XFILE *output_pipe, *popen(); X Xint Xdisplay(lines, msgnum) Xint lines, msgnum; X{ X /** Display specified number of lines from file mailfile. X Note: This routine MUST be placed at the first line X of the input file! X Returns the same as the routine above (namely zero or one) X **/ X X char title1[SLEN], title2[SLEN], *p; X char from_buffer[LONG_STRING], buffer[VERY_LONG_STRING]; X X int crypted = 0, gotten_key = 0; /* encryption */ X int weed_header, weeding_out = 0; /* weeding */ X int mail_sent, /* misc use */ X form_letter = FALSE, /* Form ltr? */ X form_letter_section = 0, /* section */ X padding = 0, /* counter */ X builtin = FALSE, /* our pager? */ X val = 0; /* return val */ X X dprint(4, (debugfile,"displaying %d lines from message %d using %s\n", X lines, msgnum, pager)); X X ClearScreen(); X X if (cursor_control) transmit_functions(OFF); X X pipe_abort = FALSE; X X builtin =(first_word(pager,"builtin") || first_word(pager,"internal")); X X if (form_letter = (header_table[msgnum-1].status&FORM_LETTER)) { X if (filter) X form_letter_section = 1; /* initialize to section 1 */ X } X X if (builtin) X start_builtin(lines); X else { X lines_displayed = 0; X Raw(OFF); X if ((output_pipe = popen(pager,"w")) == NULL) { X error2("Can't create pipe to %s [%s]", pager, X error_name(errno)); X dprint(1, (debugfile, X "\n*** Can't create pipe to %s - error %s ***\n\n", X pager, error_name(errno))); X Raw(ON); X return(0); X } X dprint(4, (debugfile, X "Opened a write-only pipe to pager %s \n", pager)); X } X X if (title_messages && filter) { X X mail_sent = (strncmp(header_table[msgnum-1].from, "To:", 3) == 0); X X tail_of(header_table[msgnum-1].from, from_buffer, FALSE); X X sprintf(title1, "%s %d/%d %s %s%s", X header_table[msgnum-1].status & DELETED ? "[deleted]" : X form_letter? "Form": "Message", X msgnum, message_count, X mail_sent? "to" : "from", from_buffer, X strlen(from_buffer) > 26? "\n": ""); X X sprintf(title2, " %s %s '%d at %s\n", X header_table[msgnum-1].month, X header_table[msgnum-1].day, X atoi(header_table[msgnum-1].year), X header_table[msgnum-1].time); X X /** and now let's add some spaces between the two parts, please **/ X X if (strlen(from_buffer) > 26) { X if (builtin) X display_line(title1); X else X fprintf(output_pipe, "%s", title1); X title1[0] = '\0'; X padding = COLUMNS - strlen(title2) - 1; X } X else X padding = COLUMNS - strlen(title1) - strlen(title2) - 1; X X p = title1 + strlen(title1); X while (padding-- > 0) X *p++ = ' '; X *p = '\0'; X strcat(title1, title2); X X if (builtin) X display_line(title1); X else X fprintf(output_pipe, "%s", title1); X X /** if there's a subject, let's next output it, centered. **/ X X if (strlen(header_table[current-1].subject) > 0 && X matches_weedlist("Subject:")) { X padding = (COLUMNS - strlen(header_table[current-1].subject)) / 2; X p = buffer; X while (padding-- > 0) X *p++ = ' '; X *p = '\0'; X strcat(buffer, header_table[current-1].subject); X strcat(buffer, "\n"); X } X else X strcpy(buffer, "\n"); X X if (builtin) X display_line(buffer); X else X fprintf(output_pipe, "%s", buffer); X X /** was this message address to us? if not, then to whom? **/ X X if (! mail_sent && matches_weedlist("To:") && filter && X strcmp(header_table[current-1].to,username) != 0 && X strlen(header_table[current-1].to) > 0) { X if (strlen(header_table[current-1].to) > 60) X sprintf(buffer, "%s(message addressed to %.60s)\n", X strlen(header_table[current-1].subject) > 0 ? "\n" : "", X header_table[current-1].to); X else X sprintf(buffer, "%s(message addressed to %s)\n", X strlen(header_table[current-1].subject) > 0 ? "\n" : "", X header_table[current-1].to); X if (builtin) X display_line(buffer); X else X fprintf(output_pipe, "%s", buffer); X } X X /** The test above is: if we didn't originally send the mail X (e.g. we're not reading "mail.sent") AND the user is currently X weeding out the "To:" line (otherwise they'll get it twice!) X AND the user is actually weeding out headers AND the message X wasn't addressed to the user AND the 'to' address is non-zero X (consider what happens when the message doesn't HAVE a "To:" X line...the value is NULL but it doesn't match the username X either. We don't want to display something ugly like X "(message addressed to )" which will just clutter up the X screen!). X X And you thought programming was EASY!!!! X **/ X X /** one more friendly thing - output a line indicating what sort X of status the message has (e.g. Urgent etc). Mostly added X for X.400 support, this is nonetheless generally useful to X include... X **/ X X buffer[0] = '\0'; X X /* we want to flag Urgent, Confidential, Private and Expired tags */ X X if (header_table[current-1].status & PRIVATE) X strcpy(buffer, "\n(** This message is tagged Private"); X else if (header_table[current-1].status & CONFIDENTIAL) X strcpy(buffer, "\n(** This message is tagged Company Confidential"); X X if (header_table[current-1].status & URGENT) { X if (buffer[0] == '\0') X strcpy(buffer, "\n(** This message is tagged Urgent"); X else if (header_table[current-1].status & EXPIRED) X strcat(buffer, ", Urgent"); X else X strcat(buffer, " and Urgent"); X } X X if (header_table[current-1].status & EXPIRED) { X if (buffer[0] == '\0') X strcpy(buffer, "\n(** This message has Expired"); X else X strcat(buffer, ", and has Expired"); X } X X if (buffer[0] != '\0') { X strcat(buffer, " **)\n"); X if (builtin) X display_line(buffer); X else X fprintf(output_pipe, buffer); X } X X if (builtin) /* this is for a one-line blank */ X display_line("\n"); /* separator between the title */ X else /* stuff and the actual message */ X fprintf(output_pipe, "\n"); /* we're trying to display */ X X } X X weed_header = filter; /* allow us to change it after header */ X X while (lines > 0 && pipe_abort == FALSE) { X X if (fgets(buffer, VERY_LONG_STRING, mailfile) == NULL) { X if (lines_displayed == 0) { X X /* AUGH! Why do we get this occasionally??? */ X X dprint(1, (debugfile, X "\n\n** Out of Sync!! EOF with nothing read (display) **\n")); X dprint(1, (debugfile, X "** closing and reopening mailfile... **\n\n")); X X if (!builtin) { X pclose(output_pipe); /* close pipe NOW! */ X Raw(ON); X } X X if (mailfile != NULL) X fclose(mailfile); /* huh? */ X X if ((mailfile = fopen(infile, "r")) == NULL) { X error("Sync error: can't re-open mailbox!!"); X show_mailfile_stats(); X emergency_exit(); X } X return(show_message(lines, X header_table[msgnum-1].offset, X msgnum)); X } X X if (!builtin) { X pclose(output_pipe); X Raw(ON); X } X X if (lines == 0 && pipe_abort == FALSE) { /* displayed it all */ X MoveCursor(LINES,0); X StartBold(); X Write_to_screen(" Please press <return> to return to Elm : ",0); X EndBold(); X fflush(stdout); X val = ReadCh(); X } X return(val); X } X X if (strlen(buffer) > 0) X no_ret(buffer); X X if (strlen(buffer) == 0) { X weed_header = 0; /* past header! */ X weeding_out = 0; X } X X if (form_letter && weed_header) X /* skip it. NEVER display random headers in forms! */; X else if (weed_header && matches_weedlist(buffer)) X weeding_out = 1; /* aha! We don't want to see this! */ X else if (buffer[0] == '[') { X if (strcmp(buffer, START_ENCODE)==0) X crypted++; X else if (strcmp(buffer, END_ENCODE)==0) X crypted--; X else if (crypted) { X encode(buffer); X val = show_line(buffer, builtin); X } X else X val = show_line(buffer, builtin); X } X else if (crypted) { X if (! gotten_key++) getkey(OFF); X encode(buffer); X val = show_line(buffer, builtin); X } X else if (weeding_out) { X weeding_out = (whitespace(buffer[0])); /* 'n' line weed */ X if (! weeding_out) /* just turned on! */ X val = show_line(buffer, builtin); X } X else if (form_letter && first_word(buffer,"***") && filter) { X strcpy(buffer, X"\n------------------------------------------------------------------------------\n"); X val = show_line(buffer, builtin); /* hide '***' */ X form_letter_section++; X } X else if (form_letter_section == 1 || form_letter_section == 3) X /** skip this stuff - we can't deal with it... **/; X else X val = show_line(buffer, builtin); X X if (val != 0) { /* let's get back to the top level ... */ X if (! builtin) { X pclose(output_pipe); X Raw(ON); X } X return(val); X } X X lines--; X lines_displayed++; X } X X if (cursor_control) transmit_functions(ON); X X if (! builtin) { X pclose(output_pipe); X Raw(ON); X } X X if (lines == 0 && pipe_abort == FALSE) { /* displayed it all! */ X MoveCursor(LINES,0); X StartBold(); X Write_to_screen(" Please press <return> to return to Elm : ", 0); X EndBold(); X fflush(stdout); X val = ReadCh(); X } X X return(val); X} X Xint Xshow_line(buffer, builtin) Xchar *buffer; Xint builtin; X{ X /** Hands the given line to the output pipe. 'builtin' is true if X we're using the builtin pager. We will return 'val' as the X intermediate value from the builtin pager if the user chooses X to do something else at the end-of-page prompt! **/ X X register int val; X X if (builtin) { X strcat(buffer, "\n"); X if ((val = display_line(buffer)) > 1) { X return(val); X } X else X pipe_abort = val; X X } X else { X errno = 0; X fprintf(output_pipe, "%s\n", buffer); X X if (errno != 0) X dprint(1, (debugfile, "\terror %s hit!\n", error_name(errno))); X } X X return(0); X} X Xint Xsecure_display(lines, msgnumber) Xint lines, msgnumber; X{ X /** This is the cheap way to implement secure pipes - spawn a X child process running under the old userid, then open the X pager and feed the message to it. When the subprocess ends X (the routine returns) simply return. Simple and effective. X (too bad it's this much of a hassle to implement secure X pipes, though - I can imagine it being a constant problem!) X **/ X X int pid, w; X#ifdef BSD X union wait status; X#else X int status; X#endif X register int (*istat)(), (*qstat)(); X X#ifdef NO_VM /* machine without virtual memory! */ X if ((pid = fork()) == 0) { X#else X# ifdef hp9000s500 /* done this way for portability */ X if ((pid = fork()) == 0) { X# else X if ((pid = vfork()) == 0) { X# endif X#endif X X setgid(groupid); /* and group id */ X setuid(userid); /* back to the normal user! */ X X _exit(display(lines, msgnumber)); X } X X istat = signal(SIGINT, SIG_IGN); X qstat = signal(SIGQUIT, SIG_IGN); X X while ((w = wait(&status)) != pid && w != -1) X ; X X signal(SIGINT, istat); X signal(SIGQUIT, qstat); X X /** used to return status, but who cares? Just get BACK! **/ X X return(0); X} SHAR_EOF chmod 0444 src/showmsg.c || echo "restore of src/showmsg.c fails" echo "x - extracting src/showmsg_c.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/showmsg_c.c && X Xstatic char rcsid[] = "@(#)$Id: showmsg_c.c,v 2.1 88/09/15 20:29:46 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: showmsg_c.c,v $ X * Revision 2.1 88/09/15 20:29:46 syd X * checked in with -k by syd at 88.09.15.20.29.46. X * X * 88/08/27 ssw X * add deluth patches X * X * 88/08/27 ssw X * split tolower and ReadCh due to macro calls X * X * Revision 2.1 88/07/21 09:59:37 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:38 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This is an interface for the showmsg command line. The possible X functions that could be invoked from the showmsg command line are X almost as numerous as those from the main command line and include X the following; X X | = pipe this message to command... X ! = call Unix command X < = scan message for calendar info X b = bounce (remail) message X d = mark message for deletion X f = forward message X g = group reply X h = redisplay this message from line #1, showing headers X i = move back to the index page (simply returns from function) X j,n = move to body of next message X k = move to body of previous message X m = mail a message out to someone X p = print this (all tagged) message X r = reply to this message X s = save this message to a maibox/folder X t = tag this message X u = undelete message X x = Exit Elm NOW X X all commands not explicitly listed here are beeped at. Use I)ndex X to get back to the main index page, please. X X This function returns when it is ready to go back to the index X page. X**/ X X#include "headers.h" X X#ifdef BSD X#undef tolower X#endif X Xint screen_mangled = 0; X Xint Xprocess_showmsg_cmd(command) Xint command; X{ X int i, intbuf; /* for dummy parameters...etc */ X int ch; /* for arrow keys */ X int key_offset; /* for arrow keys */ X char error_line[SLEN]; /* for stat line messsages */ X X Raw(ON); X X while (TRUE) { X clear_error(); X switch (command) { X case '|' : clear_bottom_of_screen(); X PutLine0(LINES-3,0,"Command: pipe"); X (void) do_pipe(); /* do pipe - ignore return val */ X break; X X case '!' : clear_bottom_of_screen(); X PutLine0(LINES-3,0,"Command: system call"); X (void) subshell(); /* do shell regardless */ X break; X X case '<' : X#ifdef ENABLE_CALENDAR X scan_calendar(); X#else X strcpy(error_line, "can't scan for calendar entries!"); X goto show_prompt_again; X#endif X break; X X case '%' : clear_bottom_of_screen(); X get_return(error_line); X error1("%s", error_line); X/* X PutLine1(LINES-3, (COLUMNS-strlen(error_line))/2, X "%78s", error_line); X*/ X goto show_prompt_again; X break; X X case 'b' : clear_bottom_of_screen(); X PutLine0(LINES-3,0,"Command: bounce message"); X remail(); X break; X X case 'd' : delete_msg(TRUE, FALSE); /* really delete it, silent */ X if (! resolve_mode) { X if (screen_mangled) X strcpy(error_line,"message marked for deletion"); X else { X ClearLine(LINES-1); X PutLine0(LINES-1, 0, X "Message marked for deletion. Command ? "); X CleartoEOLN(); X } X } else goto move_to_next_message; X break; X X case 'f' : clear_bottom_of_screen(); X PutLine0(LINES-3,0,"Command: forward message"); X (void) forward(); X break; X X case 'g' : clear_bottom_of_screen(); X PutLine0(LINES-3,0,"Command: group reply"); X (void) reply_to_everyone(); X break; X X case 'h' : screen_mangled = 0; X if (filter) { X filter = 0; X intbuf = show_msg(current); X filter = 1; X return(intbuf); X } X else X return(show_msg(current)); X Xmove_to_next_message : /* a target for resolve mode actions */ X X case 'j' : X case 'n' : if (current < message_count) { X screen_mangled = 0; X i = current; X while (++current <= message_count && X header_table[current-1].status & DELETED) X /* continue looking... */ ; X if (current > message_count) { X current = i; X return(0); /* no more! */ X } X else X return(show_msg(current)); X } X else X return(0); X X case 'J' : if (current < message_count) { X screen_mangled = 0; X return(show_msg(++current)); X } X else X return(0); X X case 'k' : if (current > 0) { X screen_mangled = 0; X i = current; X while (--current > 0 && X header_table[current-1].status & DELETED) X /* continue looking... */ ; X if (current <= 0) { X current = i; X return(0); /* no more! */ X } X else X return(show_msg(current)); X } X else X return(0); X X case 'K' : if (current > 0) { X screen_mangled = 0; X return(show_msg(--current)); X } X else X return(0); X X case 'm' : clear_bottom_of_screen(); X PutLine0(LINES-3,0,"Command: Mail message"); X (void) sendmsg("","","", TRUE, allow_forms, FALSE); X break; X X case 'p' : print_msg(); X if (screen_mangled) { X strcpy(error_line, "queued for printing"); X goto show_prompt_again; X } X else { X ClearLine(LINES-1); X PutLine0(LINES-1, 0, X "Queued for printing. Command ? "); X CleartoEOLN(); X } X break; X X case 'r' : clear_bottom_of_screen(); X PutLine0(LINES-3,0,"Command: reply to message"); X (void) reply(); X break; X X case 's' : clear_bottom_of_screen(); X PutLine0(LINES-3,0,"Command: save message"); X (void) save(&intbuf, TRUE); X if (resolve_mode) goto move_to_next_message; X break; X X case 't' : tag_message(); X if (screen_mangled) { X strcpy(error_line, "message tagged"); X goto show_prompt_again; X } X else { X ClearLine(LINES-1); X PutLine0(LINES-1, 0, X "Message tagged. Command ? "); X CleartoEOLN(); X } X break; X X case 'u' : undelete_msg(FALSE); /* undelete it, silently */ X if (! resolve_mode) { X if (screen_mangled) X strcpy(error_line, "message undeleted"); X else { X ClearLine(LINES-1); X PutLine0(LINES-1, 0, X "Message undeleted. Command ? "); X CleartoEOLN(); X } X } X else { X/****************************************************************************** X ** We're special casing the U)ndelete command here *not* to move to the next X ** undeleted message ; instead it'll blindly move to the next message in the X ** list. See 'elm.c' and the command by "case 'u'" for further information. X ** The old code was: X goto move_to_next_message; X*******************************************************************************/ X if (current == message_count) X return(0); /* we're at the last message! */ X else X return(show_msg(++current)); /* move forward 1 */ X } X break; X X case 'x' : fflush(stdout); leave(); X X case 'q' : X case 'i' : X case ' ' : X case '\n': X case '\r': (void) get_page(current); X clear_error(); /* zero out pending msg */ X if (cursor_control) X transmit_functions(ON); X return(0); /* avoid <return> looping */ X X case ctrl('L') : screen_mangled = 0; X return(show_msg(current)); X X case ESCAPE : if (cursor_control) { X X key_offset = 1; X X ch = ReadCh(); X X if (ch == ESCAPE) X ch = ReadCh(); X X if ( ch == '[' || ch == 'O') X { X ch = ReadCh(); X key_offset++; X } X X if (ch == up[key_offset]) { X if (current > 0) { X screen_mangled = 0; X return(show_msg(--current)); X } X else X return(0); X X } X else if (ch == down[key_offset]) { X if (current < message_count) { X screen_mangled = 0; X return(show_msg(++current)); X } X else X return(0); X X } X else X { X return(0); X } X } X else /* Eat 2 chars for escape codes */ X { X ch = ReadCh(); X ch = ReadCh(); X putchar((char) 007); X fflush(stdout); X return(0); X } X break; X X default : putchar((char) 007); /* BEEP! */ X fflush(stdout); X } X X if (screen_mangled) { X clear_bottom_of_screen(); Xshow_prompt_again: X PutLine0(LINES-3, 0, "Request (return to I)ndex page) ? "); X/** X if (error_line[0] != '\0') X error(error_line); X**/ X } X X command = GetPrompt(); X command = tolower(command); X } X} X Xclear_bottom_of_screen() X{ X /** clear the last 4 lines of the screen... **/ X X screen_mangled = 1; X X MoveCursor(LINES-4, 0); X CleartoEOS(); X PutLine0(LINES-4, 0, X"--------------------------------------------------------------------------\n"); X X show_last_error(); X} SHAR_EOF chmod 0444 src/showmsg_c.c || echo "restore of src/showmsg_c.c fails" echo "x - extracting src/signals.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/signals.c && X Xstatic char rcsid[] = "@(#)$Id: signals.c,v 2.1 88/07/21 09:59:39 edc Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: signals.c,v $ X * Revision 2.1 88/07/21 09:59:39 edc X * checked in with -k by syd at 88.09.15.20.29.49. X * X * Revision 2.1 88/07/21 09:59:39 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:39 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This set of routines traps various signals and informs the X user of the error, leaving the program in a nice, graceful X manner. X X**/ X X#include "headers.h" X#include <signal.h> X Xextern int pipe_abort; /* set to TRUE if receive SIGPIPE */ X Xquit_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGQUIT **\n\n\n\n")); X leave(); X} X Xhup_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGHUP **\n\n\n\n")); X leave(); X} X Xterm_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGTERM **\n\n\n\n")); X leave(); X} X Xill_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGILL **\n\n\n\n")); X PutLine0(LINES, 0, "\n\nIllegal Instruction signal!\n\n"); X emergency_exit(); X} X Xfpe_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGFPE **\n\n\n\n")); X PutLine0(LINES, 0,"\n\nFloating Point Exception signal!\n\n"); X emergency_exit(); X} X Xbus_signal() X{ X dprint(1, (debugfile, "\n\n** Received SIGBUS **\n\n\n\n")); X PutLine0(LINES, 0,"\n\nBus Error signal!\n\n"); X emergency_exit(); X} X Xsegv_signal() X{ X dprint(1, (debugfile,"\n\n** Received SIGSEGV **\n\n\n\n")); X PutLine0(LINES, 0,"\n\nSegment Violation signal!\n\n"); X emergency_exit(); X} X Xalarm_signal() X{ X /** silently process alarm signal for timeouts... **/ X X int alarm_signal(); X X signal(SIGALRM, alarm_signal); X} X Xpipe_signal() X{ X /** silently process pipe signal... **/ X X int pipe_signal(); X X dprint(2, (debugfile, "*** received SIGPIPE ***\n\n")); X X pipe_abort = TRUE; /* internal signal ... wheeee! */ X X signal(SIGPIPE, pipe_signal); X} X X#ifdef SIGTSTP Xint was_in_raw_state; X Xsig_user_stop() X{ X /* This is called when the user presses a ^Z to stop the X process within BSD X */ X if (signal(SIGTSTP, SIG_DFL) != SIG_DFL) { X signal(SIGTSTP, SIG_DFL); X was_in_raw_state = RawState(); X } X X Raw(OFF); /* turn it off regardless */ X X printf("\n\nStopped. Use \"fg\" to return to Elm\n\n"); X X kill(0, SIGSTOP); X} X Xsig_return_from_user_stop() X{ X /** this is called when returning from a ^Z stop **/ X X int sig_user_stop(); X X if (signal(SIGTSTP, sig_user_stop) == SIG_DFL) X signal(SIGTSTP, sig_user_stop); X X printf( X "\nBack in Elm. (you might need to explicitly request a redraw)\n\n"); X X if (was_in_raw_state) X Raw(ON); X} X#endif SHAR_EOF chmod 0444 src/signals.c || echo "restore of src/signals.c fails" echo "x - extracting src/softkeys.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/softkeys.c && X Xstatic char rcsid[] = "@(#)$Id: softkeys.c,v 2.1 88/07/21 09:59:40 edc Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: softkeys.c,v $ X * Revision 2.1 88/07/21 09:59:40 edc X * checked in with -k by syd at 88.09.15.20.29.51. X * X * Revision 2.1 88/07/21 09:59:40 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:40 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X X#include <stdio.h> X#include "headers.h" X Xdefine_softkeys(level) Xint level; X{ X if (! hp_softkeys) return; X X if (level == MAIN) { X X define_key(f1, " Read Msg", "\r"); X define_key(f2, " Mail Msg", "m"); X define_key(f3, " Reply to Msg", "r"); X X if (user_level == 0) { X define_key(f4, " Save Msg", "s"); X define_key(f5, " Delete Msg", "d"); X define_key(f6, "Undelete Msg", "u"); X } X else { X define_key(f4, " Change Mailbox", "c"); X define_key(f5, " Save Msg", "s"); X define_key(f6, " Delete/Undelete", "^"); X } X X define_key(f7, " Print Msg", "p"); X define_key(f8, " Quit Elm", "q"); X } X else if (level == ALIAS) { X define_key(f1, " Alias Current", "a"); X define_key(f2, " Check Person", "p"); X define_key(f3, " Check System", "s"); X define_key(f4, " Make Alias", "m"); X clear_key(f5); X clear_key(f6); X clear_key(f7); X define_key(f8, " Return to Elm", "r"); X } X else if (level == YESNO) { X define_key(f1, " Yes", "y"); X clear_key(f2); X clear_key(f3); X clear_key(f4); X clear_key(f5); X clear_key(f6); X clear_key(f7); X define_key(f8, " No", "n"); X } X else if (level == READ) { X define_key(f1, " Next Page ", " "); X clear_key(f2); X define_key(f3, " Next Msg ", "j"); X define_key(f4, " Prev Msg ", "k"); X define_key(f5, " Reply to Msg ", "r"); X define_key(f6, " Delete Msg ", "d"); X define_key(f7, " Send Msg ", "m"); X define_key(f8, " Return to Elm ", "q"); X } X else if (level == CHANGE) { X define_key(f1, " Mail Directry", "=/"); X define_key(f2, " Home Directry", "~/"); X clear_key(f3); X define_key(f4, "Incoming Mailbox", "!\n"); X clear_key(f5); X clear_key(f6); X clear_key(f7); X define_key(f8, " Cancel", "\n"); X } X X softkeys_on(); X} X Xdefine_key(key, display, send) Xint key; Xchar *display, *send; X{ X X char buffer[30]; X X sprintf(buffer,"%s%s", display, send); X X fprintf(stderr, "%c&f%dk%dd%dL%s", ESCAPE, key, X strlen(display), strlen(send), buffer); X fflush(stdout); X} X Xsoftkeys_on() X{ X /* enable (esc&s1A) turn on softkeys (esc&jB) and turn on MENU X and USER/SYSTEM options. */ X X if (hp_softkeys) { X fprintf(stderr, "%c&s1A%c&jB%c&jR", ESCAPE, ESCAPE, ESCAPE); X fflush(stdout); X } X X} X Xsoftkeys_off() X{ X /* turn off softkeys (esc&j@) */ X X if (hp_softkeys) { X fprintf(stderr, "%c&s0A%c&j@", ESCAPE, ESCAPE); X fflush(stdout); X } X} X Xclear_key(key) X{ X /** set a key to nothing... **/ X X if (hp_softkeys) X define_key(key, " ", ""); X} SHAR_EOF chmod 0444 src/softkeys.c || echo "restore of src/softkeys.c fails" echo "x - extracting src/sort.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/sort.c && X Xstatic char rcsid[] = "@(#)$Id: sort.c,v 2.1 88/09/15 20:29:53 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: sort.c,v $ X * Revision 2.1 88/09/15 20:29:53 syd X * checked in with -k by syd at 88.09.15.20.29.53. X * X * 88/09/01 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob> X * fix mismatch between the displayed sort criteria and the X * actual criteria used and listed X * X * Revision 2.1 88/07/21 09:59:41 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:25:41 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** Sort mailbox header table by the field specified in the global X variable "sortby"...if we're sorting by something other than X the default SENT_DATE, also put some sort of indicator on the X screen. X X**/ X X#include "headers.h" X Xchar *sort_name(), *skip_re(); Xvoid qsort(); X Xsort_mailbox(entries, visible) Xint entries, visible; X{ X /** Sort the header_table definitions... If 'visible', then X put the status lines etc **/ X X int last_index = -1; X int compare_headers(); /* for sorting */ X X dprint(2, (debugfile, "\n** sorting mailbox by %s **\n\n", X sort_name(FULL))); X X if (entries > 0) X last_index = header_table[current-1].index_number; X X if (entries > 30 && visible) X error1("sorting messages by %s", sort_name(FULL)); X X qsort(header_table, (unsigned) entries, sizeof (struct header_rec), X compare_headers); X X if (last_index > -1) X find_old_current(last_index); X X clear_error(); X} X Xint Xcompare_headers(first, second) Xstruct header_rec *first, *second; X{ X /** compare two headers according to the sortby value. X X Sent Date uses a routine to compare two dates, X Received date is keyed on the file offsets (think about it) X Sender uses the truncated from line, same as "build headers", X and size and subject are trivially obvious!! X (actually, subject has been modified to ignore any leading X patterns [rR][eE]*:[ \t] so that replies to messages are X sorted with the message (though a reply will always sort to X be 'greater' than the basenote) X **/ X X char from1[SLEN], from2[SLEN]; /* sorting buffers... */ X int sign = 1; X X if (sortby < 0) X sign = -1; X X switch (abs(sortby)) { X X case SENT_DATE : return( sign*compare_dates(first, second)); X X case RECEIVED_DATE: return( sign* X compare_parsed_dates(first->received, X second->received)); X X case SENDER : tail_of(first->from, from1, TRUE); X tail_of(second->from, from2, TRUE); X return( sign*strcmp(from1, from2)); X X case SIZE : return( sign*(first->lines - second->lines)); X X case MAILBOX_ORDER : return( sign* X (first->index_number - second->index_number)); X X case SUBJECT : /* need some extra work 'cause of STATIC buffers */ X strcpy(from1, skip_re(shift_lower(first->subject))); X return( sign* X strcmp(from1, X skip_re(shift_lower(second->subject)))); X X case STATUS : return( sign*(first->status - second->status)); X } X X return(0); /* never get this! */ X} X Xchar *sort_name(type) Xint type; X{ X /** return the name of the current sort option... X type can be "FULL", "SHORT" or "PAD" X **/ X int pad, abr; X X pad = (type == PAD); X abr = (type == SHORT); X X if (sortby < 0) { X switch (- sortby) { X case SENT_DATE : return( X pad? "Reverse Date Mail Sent " : X abr? "Reverse-Sent" : X "Reverse Date Mail Sent"); X case RECEIVED_DATE: return( X abr? "Reverse-Received": X "Reverse Date Mail Rec'vd" ); X X case MAILBOX_ORDER: return( X pad? "Reverse Mailbox Order " : X abr? "Reverse-Mailbox": X "Reverse Mailbox Order"); X X case SENDER : return( X pad? "Reverse Message Sender " : X abr? "Reverse-From": X "Reverse Message Sender"); X case SIZE : return( X abr? "Reverse-Lines" : X "Reverse Lines in Message"); X case SUBJECT : return( X pad? "Reverse Message Subject " : X abr? "Reverse-Subject" : X "Reverse Message Subject"); X case STATUS : return( X pad? "Reverse Message Status " : X abr? "Reverse-Status": X "Reverse Message Status"); X } X } X else { X switch (sortby) { X case SENT_DATE : return( X pad? "Date Mail Sent " : X abr? "Sent" : X "Date Mail Sent"); X case RECEIVED_DATE: return( X pad? "Date Mail Rec'vd " : X abr? "Received" : X "Date Mail Rec'vd"); X case MAILBOX_ORDER: return( X pad? "Mailbox Order " : X abr? "Mailbox" : X "Mailbox Order"); X case SENDER : return( X pad? "Message Sender " : X abr? "From" : X "Message Sender"); X case SIZE : return( X pad? "Lines in Message " : X abr? "Lines" : X "Lines in Message"); X case SUBJECT : return( X pad? "Message Subject " : X abr? "Subject" : X "Message Subject"); X case STATUS : return( X pad? "Message Status " : X abr? "Status" : X "Message Status"); X } X } X X return("*UNKNOWN-SORT-PARAMETER*"); X} X Xfind_old_current(index) Xint index; X{ X /** Set current to the message that has "index" as it's X index number. This is to track the current message X when we resync... **/ X X register int i; X X dprint(4, (debugfile, "find-old-current(%d)\n", index)); X X for (i = 0; i < message_count; i++) X if (header_table[i].index_number == index) { X current = i+1; X dprint(4, (debugfile, "\tset current to %d!\n", current)); X return; X } X X dprint(4, (debugfile, X "\tcouldn't find current index. Current left as %d\n", X current)); X return; /* can't be found. Leave it alone, then */ X} X Xchar *skip_re(string) Xchar *string; X{ X /** this routine returns the given string minus any sort of SHAR_EOF echo "End of part 18" echo "File src/sort.c is continued in part 19" echo "19" > s2_seq_.tmp exit 0 -- ===================================================================== Sydney S. Weinstein, CDP, CCP Elm Coordinator Datacomp Systems, Inc. Voice: (215) 947-9900 {allegra,bellcore,bpa,vu-vlsi}!dsinc!syd FAX: (215) 938-0235