sources-request@mirror.TMC.COM (03/10/87)
Submitted by: Dave Taylor <hplabs!taylor> Mod.sources: Volume 9, Issue 12 Archive-name: elm2/Part12 #! /bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # If this archive is complete, you will see the message: # "End of archive 12 (of 19)." # Contents: src/curses.q src/editmsg.c src/leavembox.c utils/readmsg.c PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo shar: Extracting \"src/curses.q\" \(11832 characters\) if test -f src/curses.q ; then echo shar: Will not over-write existing file \"src/curses.q\" else sed "s/^X//" >src/curses.q <<'END_OF_src/curses.q' X/** curses.c **/ X X/** This library gives programs the ability to easily access the X termcap information and write screen oriented and raw input X programs. The routines can be called as needed, except that X to use the cursor / screen routines there must be a call to X InitScreen() first. The 'Raw' input routine can be used X independently, however. X X Modified 2/86 to work (hopefully) on Berkeley systems. If X there are any problems with BSD Unix, please report them to X the author at hpcnoe!dat@HPLABS (fixed, if possible!) X X (C) Copyright 1985 Dave Taylor, HP Colorado Networks X**/ X X#include "headers.h" X X#ifdef RAWMODE X# ifdef BSD X# include <sgtty.h> X# else X# include <termio.h> X# endif X#endif X X#include <ctype.h> X X#ifdef BSD X#undef tolower X#endif X#include "curses.h" X X#ifdef BSD X# include "/usr/include/curses.h" /* don't ask! */ X#endif X X#ifdef RAWMODE X# define TTYIN 0 X#endif X Xextern int debug; X X#ifdef RAWMODE X# ifndef BSD X struct termio _raw_tty, X _original_tty; X# endif X Xstatic int _inraw = 0; /* are we IN rawmode? */ Xstatic int _line = -1, /* initialize to "trash" */ X _col = -1; X X#ifdef UTS Xstatic int _clear_screen = 0; /* Next i/o clear screen? */ Xstatic char _null_string[SLEN]; /* a string of nulls... */ X#endif X X#endif X Xstatic int _intransmit; /* are we transmitting keys? */ X Xstatic Xchar *_clearscreen, *_moveto, *_up, *_down, *_right, *_left, X *_setbold, *_clearbold, *_setunderline, *_clearunderline, X *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse, X *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off; Xstatic Xint X _lines, _columns; X Xstatic char _terminal[1024]; /* Storage for terminal entry */ Xstatic char _capabilities[256]; /* String for cursor motion */ X Xstatic char *ptr = _capabilities; /* for buffering */ X Xint outchar(); /* char output for tputs */ X XInitScreen() X{ X /* Set up all this fun stuff: returns zero if all okay, or; X -1 indicating no terminal name associated with this shell, X -2..-n No termcap for this terminal type known X */ X X int tgetent(), /* get termcap entry */ X error; X char *tgetstr(), /* Get termcap capability */ X termname[40]; X X#ifdef SUN X if (getenv("TERM") == NULL) X return(-1); X#endif X X#ifdef UTS X X /* use _line for lack of a better variable, what the heck! */ X X for (_line = 0; _line < SLEN; _line++) X _null_string[_line] = '\0'; X#endif X X if (strcpy(termname, getenv("TERM")) == NULL) X return(-1); X X if ((error = tgetent(_terminal, termname)) != 1) X return(error-2); X X _line = 1; /* where are we right now?? */ X _col = 1; /* assume zero, zero... */ X X /* load in all those pesky values */ X _clearscreen = tgetstr("cl", &ptr); X _moveto = tgetstr("cm", &ptr); X _up = tgetstr("up", &ptr); X _down = tgetstr("do", &ptr); X _right = tgetstr("nd", &ptr); X _left = tgetstr("bs", &ptr); X _setbold = tgetstr("so", &ptr); X _clearbold = tgetstr("se", &ptr); X _setunderline = tgetstr("us", &ptr); X _clearunderline = tgetstr("ue", &ptr); X _setinverse = tgetstr("so", &ptr); X _clearinverse = tgetstr("se", &ptr); X _sethalfbright = tgetstr("hs", &ptr); X _clearhalfbright = tgetstr("he", &ptr); X _cleartoeoln = tgetstr("ce", &ptr); X _cleartoeos = tgetstr("cd", &ptr); X _lines = tgetnum("li"); X _columns = tgetnum("co"); X _transmit_on = tgetstr("ks", &ptr); X _transmit_off = tgetstr("ke", &ptr); X X X if (!_left) { X _left = ptr; X *ptr++ = '\b'; X *ptr++ = '\0'; X } X X#ifdef BSD X initscr(); /* initalize curses too! */ X#endif X X return(0); X} X Xchar *return_value_of(termcap_label) Xchar *termcap_label; X{ X /** This will return the string kept by termcap for the X specified capability. Modified to ensure that if X tgetstr returns a pointer to a transient address X that we won't bomb out with a later segmentation X fault (thanks to Dave@Infopro for this one!) **/ X X static char escape_sequence[20]; X X char *tgetstr(); /* Get termcap capability */ X X strcpy(escape_sequence, tgetstr(termcap_label, &ptr)); X return( (char *) escape_sequence); X} X Xtransmit_functions(newstate) Xint newstate; X{ X /** turn function key transmission to ON | OFF **/ X X if (newstate != _intransmit) { X _intransmit = ! _intransmit; X if (newstate == ON) X tputs(_transmit_on, 1, outchar); X else X tputs(_transmit_off, 1, outchar); X X fflush(stdout); /* clear the output buffer */ X } X} X X/****** now into the 'meat' of the routines...the cursor stuff ******/ X XScreenSize(lines, columns) Xint *lines, *columns; X{ X /** returns the number of lines and columns on the display. **/ X X *lines = _lines - 1; /* assume index from zero */ X *columns = _columns; X} X XClearScreen() X{ X /* clear the screen: returns -1 if not capable */ X X#ifdef UTS X if (isatube) { X _clear_screen++; /* queue up for clearing... */ X return(0); X } X#endif X X if (!_clearscreen) X return(-1); X X tputs(_clearscreen, 1, outchar); X fflush(stdout); /* clear the output buffer */ X return(0); X} X XMoveCursor(row, col) Xint row, col; X{ X /** move cursor to the specified row column on the screen. X 0,0 is the top left! **/ X X char *tgoto(); X char *stuff; X X _line = row; /* update current location... */ X _col = col; X X#ifdef UTS X if (isatube) { X at row, col; X return(0); X } X#endif X if (!_moveto) X return(-1); X X stuff = (char *) tgoto(_moveto, col, row); X tputs(stuff, 1, outchar); X fflush(stdout); X return(0); X} X X XCursorUp() X{ X /** move the cursor up one line **/ X X _line = (_line> 0? _line - 1: _line); /* up one line... */ X X#ifdef UTS X if (isatube) { X at _line, _col; X return(0); X } X#endif X if (!_up) X return(-1); X X tputs(_up, 1, outchar); X fflush(stdout); X return(0); X} X X XCursorDown() X{ X /** move the cursor down one line **/ X X _line = (_line< LINES? _line + 1: _line); /* up one line... */ X X#ifdef UTS X if (isatube) { X at _line, _col ; X return(0); X } X#endif X X if (!_down) X return(-1); X X tputs(_down, 1, outchar); X fflush(stdout); X return(0); X} X X XCursorLeft() X{ X /** move the cursor one character to the left **/ X X _col = (_col > 0? _col - 1: _col); /* up one line... */ X X#ifdef UTS X if (isatube) { X at _line, _col; X return(0); X } X#endif X X if (!_left) X return(-1); X X tputs(_left, 1, outchar); X fflush(stdout); X return(0); X} X X XCursorRight() X{ X /** move the cursor one character to the right (nondestructive) **/ X X _col = (_col < COLUMNS? _col + 1: _col); /* up one line... */ X X#ifdef UTS X if (isatube) { X at _line, _col; X return(0); X } X#endif X X if (!_right) X return(-1); X X tputs(_right, 1, outchar); X fflush(stdout); X return(0); X} X X XStartBold() X{ X /** start boldface/standout mode **/ X X if (!_setbold) X return(-1); X X tputs(_setbold, 1, outchar); X fflush(stdout); X return(0); X} X X XEndBold() X{ X /** compliment of startbold **/ X X if (!_clearbold) X return(-1); X X tputs(_clearbold, 1, outchar); X fflush(stdout); X return(0); X} X X XStartUnderline() X{ X /** start underline mode **/ X X if (!_setunderline) X return(-1); X X tputs(_setunderline, 1, outchar); X fflush(stdout); X return(0); X} X X XEndUnderline() X{ X /** the compliment of start underline mode **/ X X if (!_clearunderline) X return(-1); X X tputs(_clearunderline, 1, outchar); X fflush(stdout); X return(0); X} X X XStartHalfbright() X{ X /** start half intensity mode **/ X X if (!_sethalfbright) X return(-1); X X tputs(_sethalfbright, 1, outchar); X fflush(stdout); X return(0); X} X XEndHalfbright() X{ X /** compliment of starthalfbright **/ X X if (!_clearhalfbright) X return(-1); X X tputs(_clearhalfbright, 1, outchar); X fflush(stdout); X return(0); X} X XStartInverse() X{ X /** set inverse video mode **/ X X if (!_setinverse) X return(-1); X X tputs(_setinverse, 1, outchar); X fflush(stdout); X return(0); X} X X XEndInverse() X{ X /** compliment of startinverse **/ X X if (!_clearinverse) X return(-1); X X tputs(_clearinverse, 1, outchar); X fflush(stdout); X return(0); X} X XPutLine0(x, y, line) Xint x,y; Xchar *line; X{ X /** Write a zero argument line at location x,y **/ X X _line = x; X _col = y; X X#ifdef UTS X if (isatube) { X panel (erase=_clear_screen, cursor=_line, _col) { X #ON, line, strlen(line)-1# X } X _clear_screen = 0; X _col += (printable_chars(line) - 1); X return(0); X } X#endif X MoveCursor(x,y); X printf("%s", line); /* to avoid '%' problems */ X fflush(stdout); X _col += (printable_chars(line) - 1); X} X XPutLine1(x,y, line, arg1) Xint x,y; Xchar *line; Xchar *arg1; X{ X /** write line at location x,y - one argument... **/ X X char buffer[SLEN]; X X sprintf(buffer, line, arg1); X X PutLine0(x, y, buffer); X} X XPutLine2(x,y, line, arg1, arg2) Xint x,y; Xchar *line; Xchar *arg1, *arg2; X{ X /** write line at location x,y - one argument... **/ X X char buffer[SLEN]; X X sprintf(buffer, line, arg1, arg2); X X PutLine0(x, y, buffer); X} X XPutLine3(x,y, line, arg1, arg2, arg3) Xint x,y; Xchar *line; Xchar *arg1, *arg2, *arg3; X{ X /** write line at location x,y - one argument... **/ X X char buffer[SLEN]; X X sprintf(buffer, line, arg1, arg2, arg3); X X PutLine0(x, y, buffer); X} X XCleartoEOLN() X{ X /** clear to end of line **/ X#ifdef UTS X char buffer[SLEN]; X register int cols, i = 0; X X if (isatube) { X X for (cols = _col; cols < COLUMNS; cols++) X buffer[i++] = ' '; X X buffer[i] = '\0'; X X panel (noerase, cursor=_line, _col) { X #ON, buffer, strlen(buffer)-1# X } X } X#endif X X if (!_cleartoeoln) X return(-1); X X tputs(_cleartoeoln, 1, outchar); X fflush(stdout); /* clear the output buffer */ X return(0); X} X XCleartoEOS() X{ X /** clear to end of screen **/ X X#ifdef UTS X register int line_at; X X for (line_at = _line; line_at < LINES-1; line_at++) { X panel (noerase) { X #ON, _null_string, COLUMNS# X } X } X return(0); X X#endif X X if (!_cleartoeos) X return(-1); X X tputs(_cleartoeos, 1, outchar); X fflush(stdout); /* clear the output buffer */ X return(0); X} X X#ifdef RAWMODE X XRaw(state) Xint state; X{ X /** state is either ON or OFF, as indicated by call **/ X X if (state == OFF && _inraw) { X#ifdef BSD X echo(); X nocrmode(); X#else X (void) ioctl(TTYIN, TCSETAW, &_original_tty); X#endif X _inraw = 0; X } X else if (state == ON && ! _inraw) { X#ifdef BSD X noecho(); X crmode(); X#else X (void) ioctl(TTYIN, TCGETA, &_original_tty); /** current setting **/ X X (void) ioctl(TTYIN, TCGETA, &_raw_tty); /** again! **/ X _raw_tty.c_iflag &= ~(INLCR | ICRNL |BRKINT); X _raw_tty.c_iflag |= IXON; X _raw_tty.c_oflag |= OPOST; X _raw_tty.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET); X _raw_tty.c_lflag &= ~(ICANON | ECHO); X _raw_tty.c_cc[VMIN] = '\01'; X _raw_tty.c_cc[VTIME] = '\0'; X (void) ioctl(TTYIN, TCSETAW, &_raw_tty); X#endif X X _inraw = 1; X } X} X Xint XReadCh() X{ X /** read a character with Raw mode set! **/ X X register int result; X char ch; X X result = read(0, &ch, 1); X X return(result == 0? EOF : ch); X} X X#endif X Xoutchar(c) Xchar c; X{ X /** output the given character. From tputs... **/ X /** Note: this CANNOT be a macro! **/ X X putc(c, stdout); X} END_OF_src/curses.q if test 11832 -ne `wc -c <src/curses.q`; then echo shar: \"src/curses.q\" unpacked with wrong size!? fi # end of overwriting check fi echo shar: Extracting \"src/editmsg.c\" \(12220 characters\) if test -f src/editmsg.c ; then echo shar: Will not over-write existing file \"src/editmsg.c\" else sed "s/^X//" >src/editmsg.c <<'END_OF_src/editmsg.c' X/** editmsg.c **/ X X/** This contains routines to do with starting up and using an editor (or two) X from within Elm. This stuff used to be in mailmsg2.c... X X (C) Copyright 1986, Dave Taylor X**/ X X#include "headers.h" X#include <errno.h> X#include <setjmp.h> X#include <signal.h> X Xextern int errno; X Xchar *error_name(), *error_description(), *strcpy(); Xunsigned long sleep(); X Xint Xedit_the_message(filename, already_has_text) Xchar *filename; Xint already_has_text; X{ X /** Invoke the users editor on the filename. Return when done. X If 'already has text' then we can't use the no-editor option X and must use 'alternative editor' (e.g. $EDITOR or default_editor) X instead... **/ X X char buffer[SLEN]; X register int stat, return_value = 0; X X buffer[0] = '\0'; X X if (strcmp(editor, "builtin") == 0 || strcmp(editor, "none") == 0) { X if (already_has_text) X sprintf(buffer, "%s %s", alternative_editor, filename); X else X return(no_editor_edit_the_message(filename)); X } X X PutLine0(LINES, 0, "invoking editor..."); fflush(stdout); X if (strlen(buffer) == 0) X sprintf(buffer,"%s %s", editor, filename); X X Raw(OFF); X X chown(filename, userid, groupid); /* file was owned by root! */ X X if (cursor_control) X transmit_functions(OFF); /* function keys are local */ X X if ((stat = system_call(buffer, SH)) != 0) { X dprint1(1,"System call failed with stat %d (edit_the_message)\n", X stat); X error1("Can't invoke editor '%s' for composition", editor); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X ClearLine(LINES-1); X sleep(2); X return_value = 1; X } X X if (cursor_control) X transmit_functions(ON); /* function keys are local */ X X Raw(ON); X X return(return_value); X} X Xextern char to[VERY_LONG_STRING], cc[VERY_LONG_STRING], X expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING], X subject[SLEN]; X Xint interrupts_while_editing; /* keep track 'o dis stuff */ Xjmp_buf edit_location; /* for getting back from interrupt */ X X#ifdef ALLOW_BCC Xextern char bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING]; X#endif X Xchar *strip_commas(); X Xint Xno_editor_edit_the_message(filename) Xchar *filename; X{ X /** If the current editor is set to either "builtin" or "none", then X invoke this program instead. As it turns out, this and the X routine above have a pretty incestuous relationship (!)... X **/ X X FILE *edit_fd; X char buffer[SLEN], editor_name[SLEN]; X int edit_interrupt(), (*oldint)(), (*oldquit)(); X X Raw(OFF); X X if ((edit_fd = fopen(filename, "a")) == NULL) { X error2("Couldn't open %s for appending [%s]", filename, X error_name(errno)); X sleep (2); X dprint1(1,"Error encountered trying to open file %s;\n", filename); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X Raw(ON); X return(1); X } X X /** file open...let's start accepting input! **/ X X printf( X "\nPlease enter message, ^D to end, or ~? <RETURN> for help;\n\n"); X X oldint = signal(SIGINT, edit_interrupt); X oldquit = signal(SIGQUIT, edit_interrupt); X X interrupts_while_editing = 0; X Xmore_input: X X while (gets(buffer) != NULL) { X X if (setjmp(edit_location) != 0) { X if (interrupts_while_editing > 1) { X Raw(ON); X X (void) signal(SIGINT, oldint); X (void) signal(SIGQUIT, oldquit); X X if (edit_fd != NULL) /* insurance... */ X fclose(edit_fd); X return(1); X } X goto more_input; /* read input again, please! */ X } X X interrupts_while_editing = 0; /* reset to zero... */ X X if (strcmp(buffer, ".") == 0) X break; /* '.' is as good as a ^D to us dumb programs :-) */ X if (buffer[0] == TILDE) X switch (tolower(buffer[1])) { X case '?' : tilde_help(); printf("(continue)\n"); goto more_input; X case '~' : move_left(buffer, 1); goto tilde_input; /*!!*/ X X case 't' : get_with_expansion("To: ", to, expanded_to); break; X#ifdef ALLOW_BCC X case 'b' : get_with_expansion("Bcc: ", bcc,expanded_bcc); break; X#endif X case 'c' : get_with_expansion("Cc: ", cc, expanded_cc); break; X case 's' : get_with_expansion("Subject: ", subject,NULL); break; X X case 'h' : get_with_expansion("To: ", to, expanded_to); X get_with_expansion("Cc: ", cc, expanded_cc); X#ifdef ALLOW_BCC X get_with_expansion("Bcc: ", bcc,expanded_bcc); X#endif X get_with_expansion("Subject: ", subject,NULL); break; X X case 'r' : read_in_file(edit_fd, (char *) buffer + 2); X goto more_input; X case 'e' : if (strlen(emacs_editor) > 0) X if (access(emacs_editor, ACCESS_EXISTS) == 0) { X strcpy(buffer, editor); X strcpy(editor, emacs_editor); X fclose(edit_fd); X (void) edit_the_message(filename,0); X Raw(OFF); X strcpy(editor, buffer); X edit_fd = fopen(filename, "a"); X printf("(continue entering message, ^D to end)\n"); X goto more_input; X } X else X printf( X "(Can't find Emacs on this system! continue)\n"); X else X printf( X "(Don't know where Emacs would be...continue)\n"); X goto more_input; X X case 'v' : strcpy(buffer, editor); X strcpy(editor, default_editor); X fclose(edit_fd); X (void) edit_the_message(filename,0); X Raw(OFF); X strcpy(editor, buffer); X edit_fd = fopen(filename, "a"); X printf("(continue entering message, ^D to end)\n"); X goto more_input; X X case 'o' : printf("Please enter the name of the editor : "); X gets(editor_name); X if (strlen(editor_name) > 0) { X strcpy(buffer, editor); X strcpy(editor, editor_name); X fclose(edit_fd); X (void) edit_the_message(filename,0); X Raw(OFF); X strcpy(editor, buffer); X edit_fd = fopen(filename, "a"); X printf("(continue entering message, ^D to end)\n"); X goto more_input; X } X printf("(continue)\n"); X goto more_input; X case '!' : if (strlen(buffer) < 3) X (void) system_call(shell, USER_SHELL); X else X (void) system_call((char *) buffer+2, USER_SHELL); X printf("(continue)\n"); X goto more_input; X case 'm' : /* same as 'f' but with leading prefix added */ X case 'f' : /* this can be directly translated into a X 'readmsg' call with the same params! */ X read_in_messages(edit_fd, (char *) buffer + 1); X goto more_input; X case 'p' : /* print out message so far. Soooo simple! */ X print_message_so_far(edit_fd, filename); X goto more_input; X default : printf( X "(don't know what ~%c is. Try ~? for help)\n", X buffer[1]); X } X else Xtilde_input: X fprintf(edit_fd, "%s\n", buffer); X }; X X printf("<end-of-message>\n\n"); X X Raw(ON); X X (void) signal(SIGINT, oldint); X (void) signal(SIGQUIT, oldquit); X X if (edit_fd != NULL) /* insurance... */ X fclose(edit_fd); X X return(0); X} X Xtilde_help() X{ X /* a simple routine to print out what is available at this level */ X X printf( X"(Available 'tilde' commands at this point are;\n\ X\n\ X\t~?\tPrint this help menu\n\ X\t~~\tAdd line prefixed by a single '~' character\n"); X X#ifdef ALLOW_BCC X printf("\ X\t~b\tChange the addresses in the Blind-carbon-copy list\n"); X#endif X X printf("\ X\t~c\tChange the addresses in the Carbon-copy list\n\ X\t~e\tInvoke the Emacs editor on the message, if possible\n\ X\t~f\tadd the specified list of messages, or current\n"); X#ifdef ALLOW_BCC X printf("\t~h\tchange all available headers (to,cc,bcc,subject)\n"); X#endif X printf("\ X\t~m\tsame as '~f', but with the current 'prefix'\n\ X\t~o\tInvoke a user specified editor on the message\n\ X\t~p\tprint out message as typed in so far\n\ X\t~r\tRead in the specified file\n\ X\t~s\tChange the subject of the message\n\ X\t~t\tChange the addresses in the To list\n\ X\t~v\tInvoke the Vi visual editor on the message\n\ X\t~!\texecute a unix command (or give a shell if no command)\n\ X\n"); X X} X Xread_in_file(fd, filename) XFILE *fd; Xchar *filename; X{ X /** Open the specified file and stream it in to the already opened X file descriptor given to us. When we're done output the number X of lines we added, if any... **/ X X FILE *myfd; X char myfname[SLEN], buffer[LONG_SLEN]; X register int lines = 0; X X while (whitespace(filename[lines])) lines++; X X strcpy(myfname, (char *) filename + lines); X X if (strlen(myfname) == 0) { X printf("(no filename specified for file read! Continue...)\n"); X return; X } X X if ((myfd = fopen(myfname,"r")) == NULL) { X printf("(Couldn't open file '%s' for reading! Continue...)\n", X myfname); X return; X } X X lines = 0; X X while (fgets(buffer, LONG_SLEN, myfd) != NULL) { X lines++; X fputs(buffer, fd); X fflush(stdout); X } X X fclose(myfd); X X printf("(added %d line%s from file %s. Please continue...)\n", X lines, plural(lines), myfname); X return; X} X Xprint_message_so_far(edit_fd, filename) XFILE *edit_fd; Xchar *filename; X{ X /** This prints out the message typed in so far. We accomplish X this in a cheap manner - close the file, reopen it for reading, X stream it to the screen, then close the file, and reopen it X for appending. Simple, but effective! X X A nice enhancement would be for this to -> page <- the message X if it's sufficiently long. Too much work for now, though. X **/ X X char buffer[LONG_SLEN]; X X fclose(edit_fd); X X if ((edit_fd = fopen(filename, "r")) == NULL) { X printf("\nMayday! Mayday! Mayday!\n"); X printf("\nPanic: Can't open file for reading! Bail!\n"); X emergency_exit(); X } X X printf("To: %s\n", format_long(to, 4)); X printf("Cc: %s\n", format_long(cc, 4)); X#ifdef ALLOW_BCC X printf("Bcc: %s\n", format_long(bcc, 5)); X#endif X printf("Subject: %s\n\n", subject); X X while (fgets(buffer, LONG_SLEN, edit_fd) != NULL) X printf("%s", buffer); X X fclose(edit_fd); X X if ((edit_fd = fopen(filename, "a")) == NULL) { X printf("Mayday! Mayday! Abandon Ship! Aiiieeeeee\n"); X printf("\nPanic: Can't reopen file for appending!\n"); X emergency_exit(); X } X X printf("(continue entering message, please)\n\n"); X} X Xread_in_messages(fd, buffer) XFILE *fd; Xchar *buffer; X{ X /** Read the specified messages into the open file. If the X first character of "buffer" is 'm' then prefix it, other- X wise just stream it in straight... X **/ X X FILE *myfd, *popen(); X char local_buffer[LONG_SLEN]; X register int lines = 0, add_prefix=0; X X add_prefix = (tolower(buffer[0]) == 'm'); X X sprintf(local_buffer, "%s %s", readmsg, ++buffer); X X if ((myfd = popen(local_buffer, "r")) == NULL) { X printf("(can't get to 'readmsg' command. Sorry...)\n"); X return; X } X X while (fgets(local_buffer, LONG_SLEN, myfd) != NULL) { X lines++; X if (add_prefix) X fprintf(fd, "%s%s", prefixchars, local_buffer); X else X fputs(local_buffer, fd); X } X X pclose(myfd); X X if (lines == 0) X printf("(Couldn't add the requested message. Continue)\n"); X else X printf("(added %d line%s to message... Please continue)\n", X lines, plural(lines)); X X return; X} X Xget_with_expansion(prompt, buffer, expanded_buffer) Xchar *prompt, *buffer, *expanded_buffer; X{ X /** This is used to prompt for a new value of the specified field. X If expanded_buffer == NULL then we won't bother trying to expand X this puppy out! X **/ X X char mybuffer[VERY_LONG_STRING]; X X printf(prompt); fflush(stdout); /* output! */ X X strcpy(mybuffer, buffer); X X Raw(ON); X optionally_enter(buffer, -1, -1, TRUE); /* already data! */ X Raw(OFF); X putchar('\n'); X X if (strcmp(buffer, mybuffer) != 0 && expanded_buffer != NULL) X build_address(strip_commas(buffer), expanded_buffer); X X return; X} X Xedit_interrupt() X{ X /** This routine is called when the user hits an interrupt key X while in the builtin editor...it increments the number of X times an interrupt is hit and returns it. X **/ X X signal(SIGINT, edit_interrupt); X signal(SIGQUIT, edit_interrupt); X X if (! interrupts_while_editing++) X printf("(Interrupt. One more to cancel this letter...)\n\r"); X X longjmp(edit_location); /* get back */ X} END_OF_src/editmsg.c if test 12220 -ne `wc -c <src/editmsg.c`; then echo shar: \"src/editmsg.c\" unpacked with wrong size!? fi # end of overwriting check fi echo shar: Extracting \"src/leavembox.c\" \(12961 characters\) if test -f src/leavembox.c ; then echo shar: Will not over-write existing file \"src/leavembox.c\" else sed "s/^X//" >src/leavembox.c <<'END_OF_src/leavembox.c' X/** leavembox.c **/ X X/** leave current mailbox, updating etc. as needed... X X (C) Copyright 1985, Dave Taylor X**/ X X#include "headers.h" X#include <sys/types.h> X#include <sys/stat.h> X#include <errno.h> X X#define ECHOIT 1 /* echo on for prompting! */ X X/** added due to a bug in the 2.1 OS **/ X Xstruct utimbuf { X time_t actime; /** access time **/ X time_t modtime; /** modification */ X }; X Xextern int errno; X Xchar *error_name(), *error_description(), *strcpy(); Xunsigned short getegid(); Xunsigned long sleep(); X Xint Xleave_mbox(quitting) Xint quitting; X{ X /** Exit, saving files into mbox and deleting specified, or simply X delete specified mail... If "quitting" is true, then output status X regardless of what happens. Returns 1 iff mailfile was X changed (ie messages deleted from file), 0 if not, and -1 if new X mail has arrived in the meantime... X **/ X X FILE *temp; X char outfile[SLEN], buffer[SLEN]; X struct stat buf; /* stat command */ X struct utimbuf times; /* utime command */ X register int to_delete = 0, to_save = 0, i, mode = 00644, X pending = 0, number_saved = 0, last_sortby; X char dflt; X long bytes(); X X dprint0(1,"\n\n-- leaving_mailbox --\n\n"); X X if (message_count == 0) X return(FALSE); /* nothing changed */ X X for (i = 0; i < message_count; i++) X if (ison(header_table[i].status, DELETED)) to_delete++; X else to_save++; X X dprint2(2,"Count: %d to delete and %d to save\n", to_delete, to_save); X X if (mbox_specified == 0) X update_mailtime(); X X if (hp_softkeys && question_me) { X define_softkeys(YESNO); /* YES or NO on softkeys */ X softkeys_on(); X } X X if (always_del) /* set up the default answer... */ X dflt = 'y'; X else X dflt = 'n'; X X if (question_me && to_delete) X if (to_save) { X fflush(stdin); X sprintf(buffer, "Delete message%s? (y/n) ", plural(to_delete)); X if (want_to(buffer, dflt, ECHOIT) != 'y') { X if (mbox_specified == 0) unlock(); /* remove lock! */ X dprint1(3,"\tDelete message%s? - answer was NO\n", X plural(to_delete)); X error("Nothing deleted"); X return(FALSE); /* nothing was deleted! */ X } X } X else if (! to_save) { /* nothing to save!! */ X fflush(stdin); X if (want_to("Delete all mail? (y/n) ", dflt, ECHOIT)!='y') { X if (mbox_specified == 0) unlock(); /* remove lock! */ X dprint0(3,"Delete all mail? - answer was NO\n"); X error("Nothing deleted"); X return(FALSE); /* nothing was deleted */ X } X } X X if (always_leave) X dflt = 'y'; X else X dflt = 'n'; X X /** we have to check to see what the sorting order was...so that X the order of saved messages is the same as the order of the X messages originally (a subtle point...) **/ X X if (sortby != RECEIVED_DATE) { /* what we want anyway! */ X last_sortby = sortby; X sortby = RECEIVED_DATE; X sort_mailbox(message_count, FALSE); X sortby = last_sortby; X } X X if (question_me && to_save && mbox_specified == 0) { X fflush(stdin); X if (want_to("Keep mail in incoming mailbox? (y/n) ",dflt, ECHOIT) X == 'y') X if (to_delete) /* okay - keep undeleted as pending! */ X pending++; X else { /* gag! nothing to delete, don't save! */ X unlock(); /* remove mailfile lock! */ X dprint0(3,"Keep mail in incoming mailbox? -- answer was YES\n"); X error("Mailbox unchanged"); X return(FALSE); /* nothing changed! */ X } X } X X /** okay...now lets do it! **/ X X if (to_save > 0) { X if (to_delete > 0) X sprintf(buffer ,"[%s %d message%s, and deleting %d]", X pending? "keeping" : "storing", X to_save, plural(to_save), to_delete); X else if (quitting) X sprintf(buffer,"[%s %s]", X pending? "keeping" : "storing", X to_save > 1? "all messages" : "message"); X else X buffer[0] = '\0'; /* no string! */ X } X else { X if (to_delete > 0) X sprintf(buffer, "[deleting all messages]"); X else if (quitting) X sprintf(buffer, "[no messages to %s, and none to delete]", X pending? "keep" : "save"); X else X buffer[0] = '\0'; X } X X dprint1(2,"Action: %s\n", buffer); X X error(buffer); X X if (! mbox_specified) { X if (pending) { /* keep some messages pending! */ X sprintf(outfile,"%s%d", temp_mbox, getpid()); X unlink(outfile); X } X else if (mailbox_defined) /* save to specified mailbox */ X strcpy(outfile, mailbox); X else /* save to $home/mbox */ X sprintf(outfile,"%s/mbox", home); X } X else { X if (! to_delete) return(FALSE); /* no work to do! */ X sprintf(outfile, "%s%d", temp_file, getpid()); X unlink(outfile); /* ensure it's empty! */ X } X X if (to_save) { X if ((errno = can_open(outfile, "a"))) { X error1( X "Permission to append to %s denied! Leaving mailbox intact\n", X outfile); X dprint2(1, X "Error: Permission to append to outfile %s denied!! (%s)\n", X outfile, "leavembox"); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X unlock(); X return(0); X } X if ((temp = fopen(outfile,"a")) == NULL) { X if (mbox_specified == 0) X unlock(); /* remove mailfile lock! */ X dprint1(1,"Error: could not append to file %s\n", X outfile); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X sprintf(buffer, " Could not append to file %s! ", X outfile); X Centerline(LINES-1, buffer); X emergency_exit(); X } X X for (i = 0; i < message_count; i++) X if (! (header_table[i].status & DELETED)) { X current = i+1; X if (! number_saved++) { X dprint2(2,"Saving message%s #%d, ", plural(to_save), current); X } X else { X dprint1(2,"#%d, ", current); X } X copy_message("", temp, FALSE, FALSE); X } X fclose(temp); X dprint0(2,"\n\n"); X } X X /* remove source file...either default mailbox or original copy of X specified one! */ X X /** let's grab the original mode and date/time of the mailfile X before removing it **/ X X if (stat(infile, &buf) == 0) X mode = buf.st_mode & 00777; X else { X dprint2(1,"Error: errno %s attempting to stat file %s\n", X error_name(errno), infile); X error3("Error %s (%s) on stat(%s)", error_name(errno), X error_description(errno), infile); X } X X fclose(mailfile); /* close the baby... */ X X if (mailfile_size != bytes(infile)) { X sort_mailbox(message_count, FALSE); /* display sorting order! */ X unlock(); X error("New mail has just arrived - resyncing..."); X return(-1); X } X unlink(infile); /* and BLAMO! */ X X if (to_save && (mbox_specified || pending)) { X if (link(outfile, infile) != 0) X if (errno == EXDEV) { /** different file devices! Use copy! **/ X if (copy(outfile, infile) != 0) { X dprint2(1,"leavembox: copy(%s, %s) failed;", X outfile, infile); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X error("couldn't modify mail file!"); X sleep(1); X sprintf(infile,"%s/%s", home, unedited_mail); X if (copy(outfile, infile) != 0) { X dprint1(1,"leavembox: couldn't copy to %s either!! Help;", X infile); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X error("something godawful is happening to me!!!"); X emergency_exit(); X } X else { X dprint1(1,"\nWoah! Confused - Saved mail in %s (leavembox)\n", X infile); X error1("saved mail in %s", infile); X } X } X } X else { X dprint2(1,"link(%s, %s) failed (leavembox)\n", outfile, infile); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X error2("link failed! %s - %s", error_name(errno), X error_description(errno)); X emergency_exit(); X } X unlink(outfile); X } X else if (keep_empty_files) { X sleep(1); X error1("..keeping empty mail file '%s'..", infile); X temp = fopen(infile, "w"); X fclose(temp); X chmod(infile, mode); X chown(infile, userid, groupid); X } X X if (mbox_specified == 0) { X if (mode != 00644) { /* if not the default mail access mode... */ X if (! pending) { /* if none still being saved */ X temp = fopen(infile, "w"); X fclose(temp); X } X chmod(infile,mode); X X /* let's set the access times of the new mail file to be X the same as the OLD one (still sitting in 'buf') ! */ X X times.actime = buf.st_atime; X times.modtime= buf.st_mtime; X X if (utime(infile, ×) != 0) { X dprint0(1,"Error: encountered error doing utime (leavmbox)\n"); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X error2("Error %s trying to change file %s access time", X error_name(errno), infile); X } X } X unlock(); /* remove the lock on the file ASAP! */ X X /** finally, let's change the ownership of the default X outgoing mailbox, if needed **/ X X if (to_save) X chown(outfile, userid, groupid); X } X X#ifdef SAVE_GROUP_MAILBOX_ID X chown(infile, userid, getegid()); /** see the Config Guide **/ X#else X chown(infile, userid, groupid); /** file owned by user **/ X#endif X X return(to_delete); X} X Xchar lock_name[SLEN]; X Xlock(direction) Xint direction; X{ X /** Create lock file to ensure that we don't get any mail X while altering the mailbox contents! X If it already exists sit and spin until X either the lock file is removed...indicating new mail X or X we have iterated MAX_ATTEMPTS times, in which case we X either fail or remove it and make our own (determined X by if REMOVE_AT_LAST is defined in header file X X If direction == INCOMING then DON'T remove the lock file X on the way out! (It'd mess up whatever created it!). X **/ X X register int iteration = 0, access_val, lock_fd; X X sprintf(lock_name,"%s%s.lock", mailhome, username); X X access_val = access(lock_name, ACCESS_EXISTS); X X while (access_val != -1 && iteration++ < MAX_ATTEMPTS) { X dprint1(2,"File '%s' currently exists! Waiting...(lock)\n", X lock_name); X if (direction == INCOMING) X PutLine0(LINES, 0, "\nMail being received!\twaiting..."); X else X error1("Attempt %d: Mail being received...waiting", X iteration); X sleep(5); X access_val = access(lock_name, ACCESS_EXISTS); X } X X if (access_val != -1) { X X#ifdef REMOVE_AT_LAST X X /** time to waste the lock file! Must be there in error! **/ X X dprint0(2, X "Warning: I'm giving up waiting - removing lock file(lock)\n"); X if (direction == INCOMING) X PutLine0(LINES, 0,"\nTimed out - removing current lock file..."); X else X error("Throwing away the current lock file!"); X X if (unlink(lock_name) != 0) { X dprint3(1,"Error %s (%s)\n\ttrying to unlink file %s (%s)\n", X error_name(errno), error_description(errno), lock_name); X PutLine1(LINES, 0, X "\n\rI couldn't remove the current lock file %s\n\r", X lock_name); X PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno), X error_description(errno)); X if (direction == INCOMING) X leave(); X else X emergency_exit(); X } X X /* everything is okay, so lets act as if nothing had happened... */ X X#else X X /* okay...we die and leave, not updating the mailfile mbox or X any of those! */ X if (direction == INCOMING) { X PutLine1(LINES, 0, "\nGiving up after %d iterations...", iteration); X PutLine0(LINES, 0, X "Please try to read your mail again in a few minutes.\n"); X dprint1(2,"Warning:bailing out after %d iterations...(lock)\n", X iteration); X leave_locked(0); X } X else { X dprint1(2,"Warning: after %d iterations, timed out! (lock)\n", X iteration); X leave(error("Timed out on lock file reads. Leaving program")); X } X X#endif X } X X /* if we get here we can create the lock file, so lets do it! */ X X if ((lock_fd = creat(lock_name, 0)) == -1) { X dprint2(1,"Can't create lock file: creat(%s) raises error %s (lock)\n", X lock_name, error_name(errno)); X if (errno == EACCES) X leave(error1( X "Can't create lock file! I need write permission in %s!\n\r", X mailhome)); X else { X dprint1(1,"Error encountered attempting to create lock %s\n", X lock_name); X dprint2(1,"** %s - %s **\n", error_name(errno), X error_description(errno)); X PutLine1(LINES, 0, X "\n\rError encountered while attempting to create lock file %s;\n\r", X lock_name); X PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno), X error_description(errno)); X leave(); X } X } X close(lock_fd); /* close it. We don't want to KEEP the thing! */ X} X Xunlock() X{ X /** Remove the lock file! This must be part of the interrupt X processing routine to ensure that the lock file is NEVER X left sitting in the mailhome directory! **/ X X (void) unlink(lock_name); X} END_OF_src/leavembox.c if test 12961 -ne `wc -c <src/leavembox.c`; then echo shar: \"src/leavembox.c\" unpacked with wrong size!? fi # end of overwriting check fi echo shar: Extracting \"utils/readmsg.c\" \(13084 characters\) if test -f utils/readmsg.c ; then echo shar: Will not over-write existing file \"utils/readmsg.c\" else sed "s/^X//" >utils/readmsg.c <<'END_OF_utils/readmsg.c' X/** readmsg.c **/ X X/** This routine adds the functionality of the "~r" command to the Elm mail X system while still allowing the user to use the editor of their choice. X X The program, without any arguments, tries to read a file in the users home X directory called ".readmsg" (actually defined in the sysdefs.h system X defines file) and if it finds it reads the current message. If it doesn't X find it, it will return a usage error. X X The program can also be called with an explicit message number, list of X message numbers, or a string to match in the message (including the header). X NOTE that when you use the string matching option it will match the first X message containing that EXACT (case sensitive) string and then exit. X X Changed 5/86 to SORT the input list of message numbers to ensure that X they're in first-to-last order... X X Added the "weed" option as the default. This is inspired by the mail X system used at NASA RIACS. If THEY can do it, so can we!! X X Also added '*' as a flag - indicating ALL messages in the mailbox. X X (C) Copyright 1985, Dave Taylor X X**/ X X#include <stdio.h> X#include <ctype.h> X X#include "defs.h" X X/** three defines for what level of headers to display **/ X X#define ALL 1 X#define WEED 2 X#define NONE 3 X X#define metachar(c) (c == '=' || c == '+' || c == '%') X Xstatic char ident[] = { WHAT_STRING }; X X#define MAX_LIST 25 /* largest single list of arguments */ X X#define LAST_MESSAGE 9999 /* last message in list ('$' char) */ X#define LAST_CHAR '$' /* char to delimit last message.. */ X#define STAR '*' /* char to delimit all messages... */ X Xint read_message[MAX_LIST]; /* list of messages to read */ Xint messages = 0; /* index into list of messages */ X Xint numcmp(); /* strcmp, but for numbers */ Xchar *words(), /* function defined below... */ X *expand_define(); /* ditto... */ X X#define DONE 0 /* for use with the getopt */ X#define ERROR -1 /* library call... */ X Xextern char *optional_arg; /* for parsing the ... */ Xextern int opt_index; /* .. starting arguments */ X Xchar *getenv(); /* keep lint happy */ X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X FILE *file; /* generic file descriptor! */ X char filename[SLEN], /* filename buffer */ X infile[SLEN], /* input filename */ X buffer[SLEN], /* file reading buffer */ X string[SLEN]; /* string match buffer */ X X int current_in_queue = 0, /* these are used for... */ X current = 0, /* ...going through msgs */ X list_all_messages = 0, /* just list 'em all?? */ X num, /* for argument parsing */ X page_breaks = 0, /* use "^L" breaks?? */ X total, /* number of msgs current */ X include_headers = WEED, /* flag: include msg header? */ X last_message = 0, /* flag: read last message? */ X not_in_header = 0, /* flag: in msg header? */ X string_match = 0; /* flag: using string match? */ X X /**** start of the actual program ****/ X X while ((num = get_options(argc, argv, "nhf:p")) > 0) { X switch (num) { X case 'n' : include_headers = NONE; break; X case 'h' : include_headers = ALL; break; X case 'f' : strcpy(infile, optional_arg); X if (metachar(infile[0])) X if (expand(infile) == 0) X printf("%s: couldn't expand filename %s!\n", X argv[0], infile); X break; X case 'p' : page_breaks++; break; X } X } X X if (num == ERROR) { X printf("Usage: %s [-n|-h] [-f filename] [-p] <message list>\n", X argv[0]); X exit(1); X } X X /** whip past the starting arguments so that we're pointing X to the right stuff... **/ X X *argv++; /* past the program name... */ X X while (opt_index-- > 1) { X *argv++; X argc--; X } X X /** now let's figure out the parameters to the program... **/ X X if (argc == 1) { /* no arguments... called from 'Elm'? */ X sprintf(filename, "%s/%s", getenv("HOME"), readmsg_file); X if ((file = fopen(filename, "r")) != NULL) { X fscanf(file, "%d", &(read_message[messages++])); X fclose(file); X } X else { /* no arguments AND no .readmsg file!! */ X fprintf(stderr, X "Usage: readmsg [-n|-h] [-f filename] [-p] <message list>\n"); X exit(1); X } X } X else if (! isdigit(*argv[0]) && *argv[0] != LAST_CHAR && X *argv[0] != STAR) { X string_match++; X X while (*argv) X sprintf(string, "%s%s%s", string, string[0] == '\0'? "" : " ", X *argv++); X } X else if (*argv[0] == STAR) /* all messages.... */ X list_all_messages++; X else { /* list of nums */ X X while (--argc > 0) { X num = -1; X X sscanf(*argv,"%d", &num); X X if (num < 0) { X if (*argv[0] == LAST_CHAR) { X last_message++; X num = LAST_MESSAGE; X } X else { X fprintf(stderr,"I don't understand what '%s' means...\n", X *argv); X exit(1); X } X } X else if (num == 0) { /* another way to say "last" */ X last_message++; X num = LAST_MESSAGE; X } X X *argv++; X X read_message[messages++] = num; X } X X /** and now sort 'em to ensure they're in a reasonable order... **/ X X qsort(read_message, messages, sizeof(int), numcmp); X } X X /** Now let's get to the mail file... **/ X X if (strlen(infile) == 0) X sprintf(infile, "%s/%s", mailhome, getenv("LOGNAME")); X X if ((file = fopen(infile, "r")) == NULL) { X printf("But you have no mail! [ file = %d ]\n", infile); X exit(0); X } X X /** Now it's open, let's display some 'ole messages!! **/ X X if (string_match || last_message) { /* pass through it once */ X X if (last_message) { X total = count_messages(file); /* instantiate count */ X for (num=0; num < messages; num++) X if (read_message[num] == LAST_MESSAGE) X read_message[num] = total; X } X else if (string_match) X match_string(file, string); /* stick msg# in list */ X X if (total == 0 && ! string_match) { X printf("There aren't any messages to read!\n"); X exit(0); X } X } X X /** now let's have some fun! **/ X X while (fgets(buffer, SLEN, file) != NULL) { X if (strncmp(buffer, "From ", 5) == 0) { X if (! list_all_messages) { X if (current == read_message[current_in_queue]) X current_in_queue++; X if (current_in_queue >= messages) X exit(0); X } X current++; X not_in_header = 0; /* we're in the header! */ X } X if (current == read_message[current_in_queue] || list_all_messages) X if (include_headers==ALL || not_in_header) X printf("%s", buffer); X else if (strlen(buffer) < 2) { X not_in_header++; X if (include_headers==WEED) X list_saved_headers(page_breaks); X } X else if (include_headers==WEED) X possibly_save(buffer); /* check to see if we want this */ X } X X exit(0); X} X Xint Xcount_messages(file) XFILE *file; X{ X /** Returns the number of messages in the file **/ X X char buffer[SLEN]; X int count = 0; X X while (fgets(buffer, SLEN, file) != NULL) X if (strncmp(buffer, "From ", 5) == 0) X count++; X X rewind( file ); X return( count ); X} X Xmatch_string(mailfile, string) XFILE *mailfile; Xchar *string; X{ X /** Increment "messages" and put the number of the message X in the message_count[] buffer until we match the specified X string... **/ X X char buffer[SLEN]; X int message_count; X X while (fgets(buffer, SLEN, mailfile) != NULL) { X if (strncmp(buffer, "From ", 5) == 0) X message_count++; X X if (in_string(buffer, string)) { X read_message[messages++] = message_count; X rewind(mailfile); X return; X } X } X X fprintf(stderr,"Couldn't find message containing '%s'\n", string); X exit(1); X} X Xint Xnumcmp(a, b) Xint *a, *b; X{ X /** compare 'a' to 'b' returning less than, equal, or greater X than, accordingly. X **/ X X return(*a - *b); X} X Xstatic char from[SLEN], subject[SLEN], date[SLEN], to[SLEN]; X Xpossibly_save(buffer) Xchar *buffer; X{ X /** Check to see what "buffer" is...save it if it looks X interesting... We'll always try to get SOMETHING X by tearing apart the "From " line... **/ X X if (strncmp(buffer, "Date:", 5) == 0) X strcpy(date, buffer); X else if (strncmp(buffer, "Subject:", 8) == 0) X strcpy(subject,buffer); X else if (strncmp(buffer,"From:", 5) == 0) X strcpy(from, buffer); X else if (strncmp(buffer,"To: ", 3) == 0) X strncpy(to, buffer, SLEN); X else if (strncmp(buffer,"From ", 5) == 0) { X sprintf(from, "From: %s\n", words(2,1, buffer)); X sprintf(date,"Date: %s", words(3,7, buffer)); X to[0] = '\0'; X } X} X Xlist_saved_headers(page_break) Xint page_break; X{ X /** This routine will display the information saved from the X message being listed...If it displays anything it'll end X with a blank line... **/ X X register int displayed_line = FALSE; X static int messages_listed = 0; X X if (page_break && messages_listed++) putchar(FORMFEED); X X if (strlen(from) > 0) { printf("%s", from); displayed_line++;} X if (strlen(subject) > 0) { printf("%s", subject); displayed_line++;} X if (strlen(to) > 0) { printf("%s", to); displayed_line++;} X if (strlen(date) > 0) { printf("%s", date); displayed_line++;} X X if (displayed_line) X putchar('\n'); X} X Xchar *words(word, num_words, buffer) Xint word, num_words; Xchar *buffer; X{ X /** Return a buffer starting at 'word' and containing 'num_words' X words from buffer. Assume white space will delimit each word. X **/ X X static char internal_buffer[SLEN]; X char *wordptr, *bufptr, mybuffer[SLEN], *strtok(); X int wordnumber = 0, copying_words = 0; X X internal_buffer[0] = '\0'; /* initialize */ X X strcpy(mybuffer, buffer); X bufptr = (char *) mybuffer; /* and setup */ X X while ((wordptr = strtok(bufptr, " \t")) != NULL) { X if (++wordnumber == word) { X strcpy(internal_buffer, wordptr); X copying_words++; X num_words--; X } X else if (copying_words) { X strcat(internal_buffer, " "); X strcat(internal_buffer, wordptr); X num_words--; X } X X if (num_words < 1) X return((char *) internal_buffer); X X bufptr = NULL; X } X X return( (char *) internal_buffer); X} X Xint Xexpand(infile) Xchar *infile; X{ X /** Expand the filename since the first character is a meta- X character that should expand to the "maildir" variable X in the users ".elmrc" file... X X Note: this is a brute force way of getting the entry out X of the .elmrc file, and isn't recommended for the faint X of heart! X **/ X X FILE *rcfile; X char buffer[SLEN], *expanded_dir, *home, *getenv(), *bufptr; X int foundit = 0; X X bufptr = (char *) buffer; /* same address */ X X if ((home = getenv("HOME")) == NULL) { X printf( X "Can't expand environment variable $HOME to find .elmrc file!\n"); X exit(1); X } X X sprintf(buffer, "%s/%s", home, elmrcfile); X X if ((rcfile = fopen(buffer, "r")) == NULL) { X printf("Can't open your \".elmrc\" file (%s) for reading!\n", X buffer); X exit(1); X } X X while (fgets(buffer, SLEN, rcfile) != NULL && ! foundit) { X if (strncmp(buffer, "maildir", 7) == 0 || X strncmp(buffer, "folders", 7) == 0) { X while (*bufptr != '=' && *bufptr) X bufptr++; X bufptr++; /* skip the equals sign */ X while (whitespace(*bufptr) && *bufptr) X bufptr++; X home = bufptr; /* remember this address */ X X while (! whitespace(*bufptr) && *bufptr != '\n') X bufptr++; X X *bufptr = '\0'; /* remove trailing space */ X foundit++; X } X } X X fclose(rcfile); /* be nice... */ X X if (! foundit) { X printf("Couldn't find \"maildir\" in your .elmrc file!\n"); X exit(1); X } X X /** Home now points to the string containing your maildir, with X no leading or trailing white space... X **/ X X expanded_dir = expand_define(home); X X sprintf(buffer, "%s%s%s", expanded_dir, X (expanded_dir[strlen(expanded_dir)-1] == '/' || X infile[0] == '/') ? "" : "/", (char *) infile+1); X X strcpy(infile, buffer); X} X Xchar *expand_define(maildir) Xchar *maildir; X{ X /** This routine expands any occurances of "~" or "$var" in X the users definition of their maildir directory out of X their .elmrc file. X X Again, another routine not for the weak of heart or staunch X of will! X **/ X X static char buffer[SLEN]; /* static buffer AIEE!! */ X char name[SLEN], /* dynamic buffer!! (?) */ X *nameptr, /* pointer to name?? */ X *value; /* char pointer for munging */ X X if (*maildir == '~') X sprintf(buffer, "%s%s", getenv("HOME"), ++maildir); X else if (*maildir == '$') { /* shell variable */ X X /** break it into a single word - the variable name **/ X X strcpy(name, (char *) maildir + 1); /* hurl the '$' */ X nameptr = (char *) name; X while (*nameptr != '/' && *nameptr) nameptr++; X *nameptr = '\0'; /* null terminate */ X X /** got word "name" for expansion **/ X X if ((value = getenv(name)) == NULL) { X printf("Couldn't expand shell variable $%s in .elmrc!\n", name); X exit(1); X } X sprintf(buffer, "%s%s", value, maildir + strlen(name) + 1); X } X else X strcpy(buffer, maildir); X X return( ( char *) buffer); X} X END_OF_utils/readmsg.c if test 13084 -ne `wc -c <utils/readmsg.c`; then echo shar: \"utils/readmsg.c\" unpacked with wrong size!? fi # end of overwriting check fi echo shar: End of archive 12 \(of 19\). cp /dev/null ark12isdone DONE=true for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do if test ! -f ark${I}isdone ; then echo shar: You still need to run archive ${I}. DONE=false fi done if test "$DONE" = "true" ; then echo You have unpacked all 19 archives. echo "See the Instructions file" rm -f ark[1-9]isdone ark[1-9][0-9]isdone fi ## End of shell archive. exit 0