rsalz@uunet.uu.net (Rich Salz) (06/05/90)
Submitted-by: Syd Weinstein <syd@dsinc.dsi.com> Posting-number: Volume 22, Issue 75 Archive-name: elm2.3/part16 ---- Cut Here and unpack ---- #!/bin/sh # this is part 16 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/hdrconfg.c continued # CurArch=16 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/hdrconfg.c" sed 's/^X//' << 'SHAR_EOF' >> src/hdrconfg.c X (void) build_address(strip_commas(cc), expanded_cc); X put_cc(); X break; X X case 'r' : PutLine0(INPUT_LINE, 0, "Reply-To: "); CleartoEOLN(); X if(optionally_enter(reply_to, X INPUT_LINE, 10, FALSE, FALSE) == -1) X return(0); X put_replyto(); X break; X X case 'a' : PutLine0(INPUT_LINE, 0, "Action: "); CleartoEOLN(); X if (optionally_enter(action, X INPUT_LINE, 8, FALSE, FALSE) == -1) X return(0); X put_action(); X break; X X case 'p' : PutLine0(INPUT_LINE, 0, "Priority: "); CleartoEOLN(); X if (optionally_enter(priority, X INPUT_LINE, 10, FALSE, FALSE)==-1) X return(0); X put_priority(); X break; X X case 'e' : enter_date(expires); X put_expires(); X break; X X case 'u' : PutLine0(EXTRA_PROMPT_LINE, 0, "User defined header: "); X CleartoEOLN(); X if (optionally_enter(user_defined_header, X INPUT_LINE, 0, FALSE, FALSE)==-1) X return(0); X check_user_header(user_defined_header); X put_userdefined(); X ClearLine(EXTRA_PROMPT_LINE); X break; X X case 'i' : if (strlen(in_reply_to) > 0) { X PutLine0(INPUT_LINE, 0, "In-Reply-To: "); CleartoEOLN(); X if (optionally_enter(in_reply_to, X INPUT_LINE, 13, FALSE, FALSE) == -1) X return(0); X put_inreplyto(); X break; X } X X#ifdef ALLOW_SUBSHELL X case '!': if (subshell()) X display_headers(); X continue; X#endif X X default : Centerline(ERROR_LINE, "No such header!"); X displayed_error = YES; X } X } X} X Xdisplay_headers() X{ X char buffer[SLEN]; X X ClearScreen(); X X Centerline(0,"Message Header Edit Screen"); X X put_to(); X put_cc(); X put_bcc(); X put_subject(); X put_replyto(); X put_action(); X put_expires(); X put_priority(); X if (in_reply_to[0]) X put_inreplyto(); X if (user_defined_header[0]) X put_userdefined(); X X strcpy(buffer, "Choose first letter of header, u)ser defined header, "); X#ifdef ALLOW_SUBSHELL X strcat(buffer, "!)shell, "); X#endif X strcat(buffer, "or <return>."); X Centerline(INSTRUCT_LINE, buffer); X} X Xstatic Xput_header(hline, hcount, field, value) Xint hline, hcount; Xchar *field, *value; X{ X char *p; X int x, y; X X MoveCursor(hline, 0); X X if (field) { X for (p = field; *p; ++p) X Writechar(*p); X Writechar(':'); X Writechar(' '); X } X X GetXYLocation(&x, &y); X X for (p = value; *p; ++p) { X if (x >= (hline + hcount)) X break; X /* neat hack alert -- danger will robinson */ X if ((x + 1) == (hline + hcount) X && (y + 4) == COLUMNS && strlen(p) > 4) X p = " ..."; X Writechar(*p); X ++y; X if (*p < 0x20 || *p >= 0x7F || y >= COLUMNS) X GetXYLocation(&x, &y); X } X X if (x < (hline + hcount)) { X CleartoEOLN(); X X while (++x < (hline + hcount)) { X MoveCursor(x, 0); X CleartoEOLN(); X } X } X} X Xenter_date(datebuf) Xchar *datebuf; X{ X /** Enter the number of days this message is valid for, then X display at (x,y) the actual date of expiration. This X routine relies heavily on the routine 'days_ahead()' in X the file date.c X **/ X X int days; X char numdaysbuf[SLEN]; X X static char prompt[] = X "How many days in the future should this message expire? "; X X PutLine0(INPUT_LINE,0, prompt); X CleartoEOLN(); X *datebuf = *numdaysbuf = '\0'; X X optionally_enter(numdaysbuf, INPUT_LINE, strlen(prompt), FALSE, FALSE); X sscanf(numdaysbuf, "%d", &days); X if (days < 1) X Centerline(ERROR_LINE, "That doesn't make sense!"); X else if (days > 56) X Centerline(ERROR_LINE, X "Expiration date must be within eight weeks of today."); X else { X days_ahead(days, datebuf); X } X} X Xcheck_user_header(header) Xchar *header; X{ X /** check the header format...if bad print error and erase! **/ X X register int i = -1; X X if (strlen(header) == 0) X return; X X if (whitespace(header[0])) { X error ("You can't have leading white space in a header!"); X header[0] = '\0'; X ClearLine(USER_DEFINED_HDR_LINE); X return; X } X X if (header[0] == ':') { X error ("You can't have a colon as the first character!"); X header[0] = '\0'; X ClearLine(USER_DEFINED_HDR_LINE); X return; X } X X while (header[++i] != ':') { X if (header[i] == '\0') { X Centerline(ERROR_LINE, "You need to have a colon ending the field name!"); X header[0] = '\0'; X ClearLine(USER_DEFINED_HDR_LINE); X return; X } X else if (whitespace(header[i])) { X Centerline(ERROR_LINE, "You can't have white space imbedded in the header name!"); X header[0] = '\0'; X ClearLine(USER_DEFINED_HDR_LINE); X return; X } X } X X return; X} SHAR_EOF echo "File src/hdrconfg.c is complete" chmod 0444 src/hdrconfg.c || echo "restore of src/hdrconfg.c fails" echo "x - extracting src/help.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/help.c && X Xstatic char rcsid[] = "@(#)$Id: help.c,v 4.1 90/04/28 22:43:11 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989, 1990 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: help.c,v $ X * Revision 4.1 90/04/28 22:43:11 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/*** help routine for ELM program X X***/ X X#include <ctype.h> X#include "headers.h" X Xhelp(pager_help) Xint pager_help; X{ X /** Process the request for help [section] from the user. X If pager_help is TRUE, then act a little differently from X if pager_help is FALSE (index screen) X **/ X X char ch; /* character buffer for input */ X char *s; /* string pointer... */ X int prompt_line, info_line; X static char help_message[] = X "Press the key you want help for, '?' for a key list, or '.' to exit help"; X static char help_prompt[] = "Help for key: "; X X MoveCursor(LINES-4,0); X CleartoEOS(); X X if(pager_help) { X put_border(); X Centerline(LINES, help_message); X prompt_line = LINES-3; X } else { X Centerline(LINES-4, "ELM Help System"); X Centerline(LINES-3, help_message); X prompt_line = LINES-2; X } X info_line = prompt_line + 1; X X PutLine0(prompt_line, 0, help_prompt); X X do { X MoveCursor(prompt_line, strlen(help_prompt)); X ch = ReadCh(); X X if (ch == '.') return(0); /* zero means footer rewrite only */ X X s = "Unknown command. Use '?' for a list of commands."; X X switch (ch) { X X case '?': display_helpfile(pager_help? PAGER_HELP : MAIN_HELP); X return(1); X X case '$': if(!pager_help) s = X"$ = Force resynchronization of the current folder. This will purge deleted mail."; X break; X X case '!': s = X "! = Escape to the Unix shell of your choice, or just to enter commands."; X break; X X case '@': if(!pager_help) s = X "@ = Debug - display a summary of the messages on the header page."; X break; X X case '|': s = X "| = Pipe the current message or tagged messages to the command specified."; X break; X X case '#': if(!pager_help) s = X "# = Debug - display all information known about current message."; X break; X X case '%': s = X "% = Debug - display the computed return address of the current message."; X break; X X case '*': if(!pager_help) X s = "* = Go to the last message in the current folder."; X break; X X case '-': if(!pager_help) s = X"- = Go to the previous page of messages. This is the same as the LEFT arrow."; X break; X X case '=': if(!pager_help) s = X "'=' = Go to the first message in the current folder."; X break; X X case ' ': if(pager_help) s = X "<space> = Display next screen of current message (or first screen of next)."; X else s = "<space> = Display the current message."; X break; X X case '+': if(!pager_help) X s = X "+ = Go to the next page of messages. This is the same as the RIGHT arrow."; X break; X X case '/': if(!pager_help) X s = "/ = Search for specified pattern in folder."; X break; X X case '<': s = X "< = Scan current message for calendar entries (if enabled)."; X break; X X case '>': s = X "> = Save current message or tagged messages to specified file."; X break; X X case '^': if(!pager_help) s = X "^ = Toggle the Delete/Undelete status of the current message."; X break; X X case 'a': if(!pager_help) s = X "a = Enter the alias sub-menu section. Create and display aliases."; X break; X X case 'b': s = X "b = Bounce (remail) a message to someone as if you have never seen it."; X break; X X case 'C': s = X "C = Copy current message or tagged messages to specified file."; X break; X X case 'c': if(!pager_help) s = X "c = Change folders, leaving the current folder as if 'quitting'."; X break; X X case 'd': s = "d = Mark the current message for future deletion."; X break; X X case ctrl('D') : if(!pager_help) s = X "^D = Mark for deletion all messages with the specified pattern."; X break; X X case 'e': if(!pager_help) s = X "e = Invoke the editor on the entire folder, resynchronizing when done."; X break; X X case 'f': s = X "f = Forward the current message to someone, return address is yours."; X break; X X case 'g': s = X "g = Group reply not only to the sender, but to everyone who received msg."; X break; X X case 'h': s = X "h = Display message with all Headers (ignore weedout list)."; X break; X X case 'i': if(pager_help) s = "i = Return to the index."; X break; X X case 'J': s = "J = Go to the next message."; X break; X X case 'j': s = X "j = Go to the next undeleted message. This is the same as the DOWN arrow."; X break; X X case 'K': s = "K = Go to the previous message."; X break; X X case 'k': s = X"k = Go to the previous undeleted message. This is the same as the UP arrow."; X break; X X case 'l': if(!pager_help) s = X "l = Limit displayed messages based on the specified criteria."; X break; X X case 'm': s = X "m = Create and send mail to the specified person or persons."; X break; X X case 'n': if(pager_help) X s = "n = Display the next message."; X else X s = X "n = Display the current message, then move current to next messge."; X break; X X case 'o': if(!pager_help) s = "o = Go to the options submenu."; X break; X X case 'p': s = X "p = Print the current message or the tagged messages."; X break; X X case 'q': if(pager_help) s = X "q = Quit the pager and return to the index."; X else s = X "q = Quit the mailer, asking about deletion, saving, etc."; X break; X X case 'r': s = X"r = Reply to the message. This only sends to the originator of the message."; X break; X X case 's': s = X "s = Save current message or tagged messages to specified file."; X break; X X case 't': s = X "t = Tag a message for further operations (or untag if tagged)."; X break; X X case ctrl('T') : if(!pager_help) s = X "^T = Tag all messages with the specified pattern."; X break; X X case 'u': s = X "u = Undelete - remove the deletion mark on the message."; X break; X X case 'x': s = "x = Exit the mail system quickly."; X break; X X case 'Q': if(!pager_help) s = X "Q = Quick quit the mailer, save read, leave unread, delete deleted."; X break; X X case '\n': X case '\r': if(pager_help) X s = X "<return> = Display current message, or (builtin pager only) scroll forward."; X else X s = "<return> = Display the current message."; X break; X X case ctrl('L'): if(!pager_help) s = "^L = Rewrite the screen."; X break; X X case ctrl('?'): /* DEL */ X case ctrl('Q'): if(!pager_help) s = "Exit the mail system quickly."; X break; X X default : if (isdigit(ch) && !pager_help) X s = "<number> = Make specified number the current message."; X } X X ClearLine(info_line); X Centerline(info_line, s); X X } while (ch != '.'); X X /** we'll never actually get here, but that's okay... **/ X X return(0); X} X Xdisplay_helpfile(section) Xint section; X{ X /*** Help me! Read file 'helpfile.<section>' and echo to screen ***/ X X char buffer[SLEN]; X X sprintf(buffer, "%s/%s.%d", helphome, helpfile, section); X return(display_file(buffer)); X} X Xdisplay_file(file) Xchar *file; X{ X /*** Display file to screen ***/ X X FILE *fileptr; X int lines=0; X char buffer[SLEN]; X X if ((fileptr = fopen(file,"r")) == NULL) { X dprint(1, (debugfile, X "Error: Couldn't open file %s (help)\n", file)); X error1("Couldn't open file %s.",file); X return(FALSE); X } X X ClearScreen(); X X while (fgets(buffer, SLEN, fileptr) != NULL) { X if (lines > LINES-3) { X PutLine0(LINES,0,"Press <space> to continue, 'q' to return."); X if(ReadCh() == 'q') { X clear_error(); X fclose(fileptr); X return(TRUE); X } X lines = 0; X ClearScreen(); X Write_to_screen("%s\r", 1, buffer); X } X else X Write_to_screen("%s\r", 1, buffer); X X lines += strlen(buffer)/COLUMNS + 1; X } X X PutLine0(LINES,0,"Press any key to return."); X X (void) ReadCh(); X clear_error(); X X fclose(fileptr); X return(TRUE); X} SHAR_EOF chmod 0444 src/help.c || echo "restore of src/help.c fails" echo "x - extracting src/in_utils.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/in_utils.c && X Xstatic char rcsid[] = "@(#)$Id: in_utils.c,v 4.1 90/04/28 22:43:13 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989, 1990 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: in_utils.c,v $ X * Revision 4.1 90/04/28 22:43:13 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** Mindless I/O routines for ELM X X**/ X X#include "headers.h" X#include <errno.h> X#include <ctype.h> X X#ifdef BSD X# undef tolower X#endif X Xextern int errno; /* system error number */ X Xunsigned alarm(); X X#define isstopchar(c) (c == ' ' || c == '\t' || c == '/') X#define isslash(c) (c == '/') X#define erase_a_char() { Writechar(BACKSPACE); Writechar(' '); \ X Writechar(BACKSPACE); fflush(stdout); } X Xint Xwant_to(question, dflt) Xchar *question, dflt; X{ X /** Ask 'question' on LINES-2 left enough to just leave room for an X answer, returning the answer in lower case. X Echo answer as full "Yes" or "No". 'dflt' is the X default answer if <return> is pressed. (Note: 'dflt' is also what X will be returned if <return> is pressed!) X **/ X register int ch, cols; X X cols = COLUMNS - (strlen(question) + 5 ); /* 5 for "Yes." + 1 */ X X MoveCursor(LINES-3, cols); X CleartoEOLN(); X PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE); X fflush(stdout); X fflush(stdin); X X ch = ReadCh(); X ch = tolower(ch); X X while (!( ch == 'y' || ch == 'n' || ch == '\n' || ch == '\r')) { X ch = ReadCh(); X ch = tolower(ch); X } X if(ch == '\n' || ch == '\r') X ch = dflt; X X if(ch == 'y') X Write_to_screen("Yes.", 0); X else X Write_to_screen("No.", 0); X X return(ch); X} X Xint Xread_number(ch) Xchar ch; X{ X /** Read a number, where 'ch' is the leading digit! **/ X X char buff[NLEN]; X int num; X X buff[0] = ch; X buff[1] = '\0'; X X PutLine0(LINES-3, COLUMNS-40,"Set current message to :"); X if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE, FALSE) == -1) X return(current); X X sscanf(buff,"%d", &num); X return(num); X} X Xint Xoptionally_enter(string, x, y, append_current, passwd) Xchar *string; Xint x,y, append_current, passwd; X{ X /** This will display the string on the screen and allow the user to X either accept it (by pressing RETURN) or alter it according to X what the user types. The various flags are: X string is the buffer to use (with optional initial value) X x,y is the location we're at on the screen (-1,-1 means X that we can't use this info and need to find out X the current location) X append_current means that we have an initial string and that X the cursor should be placed at the END of the line, X not the beginning (the default). X passwd accept non-printing characters and do not echo X entered characters. X X If we hit an interrupt or EOF we'll return non-zero. X **/ X X int ch; X register int ch_count = 0, iindex = 0, escaped = OFF; X X clearerr(stdin); X X if(!passwd) { X if(!(x >=0 && y >= 0)) X GetXYLocation(&x, &y); X PutLine1(x, y, "%s", string); X } X X CleartoEOLN(); X X if (! append_current) { X MoveCursor(x,y); X } X else X iindex = strlen(string); X X if (cursor_control) X transmit_functions(OFF); X X /** now we have the screen as we want it and the cursor in the X right place, we can loop around on the input and return the X string as soon as the user presses <RETURN> X **/ X X do { X ch = getchar(); X X if (ch == ctrl('D') || ch == EOF) { /* we've hit EOF */ X if (cursor_control) X transmit_functions(ON); X return(1); X } X X if (ch_count++ == 0) { X if (ch == '\n' || ch == '\r') { X if (cursor_control) X transmit_functions(ON); X return(0); X } X else if (! append_current) { X CleartoEOLN(); X iindex = (append_current? strlen(string) : 0); X } X } X X /* the following is converted from a case statement to X allow the variable characters (backspace, kill_line X and break) to be processed. Case statements in X C require constants as labels, so it failed ... X */ X X if (ch == backspace && X (!escaped || (!isprint(ch) && !passwd))) { X /* This is tricky. Here we are dealing with all situations X * under which a backspace (really whatever erase char is X * set to, not necessarily \b) erases the previous character. X * It will erase unless escaped, because if it's escaped X * it is taken literally. There is one exception to that -- X * if backspace would be rejected (we don't accept non-printing X * characters in non-passwd mode), we accept it here as an X * erasing character, for it if got rejected there would X * be no way of erasing a preceding backslash. */ X escaped = OFF; X if (iindex > 0) { X if(!passwd) X Writechar(BACKSPACE); X iindex--; X } X if(!passwd) { X Writechar(' '); X Writechar(BACKSPACE); X fflush(stdout); X } X } X else if (ch == EOF || ch == '\n' || ch == '\r') { X escaped = OFF; X string[iindex] = '\0'; X if (cursor_control) X transmit_functions(ON); X return(0); X } X else if (!passwd && ch == ctrl('W')) { /* back up a word! */ X escaped = OFF; X if (iindex == 0) X continue; /* no point staying here.. */ X iindex--; X if (isslash(string[iindex])) { X erase_a_char(); X } X else { X while (iindex >= 0 && isspace(string[iindex])) { X iindex--; X erase_a_char(); X } X X while (iindex >= 0 && ! isstopchar(string[iindex])) { X iindex--; X erase_a_char(); X } X iindex++; /* and make sure we point at the first AVAILABLE slot */ X } X } X else if (!passwd && ch == ctrl('R')) { X escaped = OFF; X string[iindex] = '\0'; X PutLine1(x,y, "%s", string); X CleartoEOLN(); X } X else if (!escaped && ch == kill_line) { X /* needed to test if escaped since kill_line character could X * be a desired valid printing character */ X escaped = OFF; X if(!passwd) { X MoveCursor(x,y); X CleartoEOLN(); X } X iindex = 0; X } X else if (ch == '\0') { X escaped = OFF; X if (cursor_control) X transmit_functions(ON); X fflush(stdin); /* remove extraneous chars, if any */ X string[0] = '\0'; /* clean up string, and... */ X return(-1); X } X else if (!passwd && !isprint(ch)) { X /* non-printing character - warn with bell*/ X /* don't turn off escaping backslash since current character X * doesn't "use it up". X */ X Writechar('\007'); X } X else { /* default case */ X if(escaped && (ch == backspace || ch == kill_line)) { X /* if last character was a backslash, X * and if this character is escapable X * simply write this character over it even if X * this character is a backslash. X */ X if(!passwd) X Writechar(BACKSPACE); X iindex--; X string[iindex++] = ch; X if(!passwd) X Writechar(ch); X escaped = OFF; X } else { X string[iindex++] = ch; X if(!passwd) X Writechar(ch); X escaped = ( ch == '\\' ? ON : OFF); X } X } X } while (iindex < SLEN); X X string[iindex] = '\0'; X X if (cursor_control) X transmit_functions(ON); X X return(0); X} X Xint Xpattern_enter(string, alt_string, x, y, alternate_prompt) Xchar *string, *alt_string, *alternate_prompt; Xint x,y; X{ X /** This function is functionally similar to the routine X optionally-enter, but if the first character pressed X is a '/' character, then the alternate prompt and string X are used rather than the normal one. This routine X returns 1 if alternate was used, 0 if not X **/ X X int ch; X register iindex = 0, escaped = OFF; X X PutLine1(x, y, "%s", string); X CleartoEOLN(); X MoveCursor(x,y); X X if (cursor_control) X transmit_functions(OFF); X X ch = getchar(); X X if (ch == '\n' || ch == '\r') { X if (cursor_control) X transmit_functions(ON); X return(0); /* we're done. No change needed */ X } X X if (ch == '/') { X PutLine1(x, 0, "%s", alternate_prompt); X CleartoEOLN(); X (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1, X FALSE, FALSE); X return(1); X } X X CleartoEOLN(); X X iindex = 0; X X if (ch == kill_line) { X MoveCursor(x,y); X CleartoEOLN(); X iindex = 0; X } X else if (ch != backspace) { X if(ch == '\\') escaped = ON; X Writechar(ch); X string[iindex++] = ch; X } X else if (iindex > 0) { X iindex--; X erase_a_char(); X } X else { X Writechar(' '); X Writechar(BACKSPACE); X } X X do { X fflush(stdout); X ch = getchar(); X X /* the following is converted from a case statement to X allow the variable characters (backspace, kill_line X and break) to be processed. Case statements in X C require constants as labels, so it failed ... X */ X X if (ch == backspace && X (!escaped || !isprint(ch)) ) { X /* This is tricky. Here we are dealing with all situations X * under which a backspace (really whatever erase char is X * set to, not necessarily \b) erases the previous character. X * It will erase unless escaped, because if it's escaped X * it is taken literally. There is one exception to that -- X * if backspace would be rejected (we don't accept non-printing X * characters in non-passwd mode), we accept it here as an X * erasing character, for it if got rejected there would X * be no way of erasing a preceding backslash. */ X escaped = OFF; X if (iindex > 0) { X iindex--; X erase_a_char(); X } X else { X Writechar(' '); X Writechar(BACKSPACE); X } X } X else if (ch == '\n' || ch == '\r') { X escaped = OFF; X string[iindex] = '\0'; X if (cursor_control) X transmit_functions(ON); X return(0); X } X else if (ch == ctrl('W')) { X escaped = OFF; X if (iindex == 0) X continue; /* no point staying here.. */ X iindex--; X if (isslash(string[iindex])) { X erase_a_char(); X } X else { X while (iindex >= 0 && isspace(string[iindex])) { X iindex--; X erase_a_char(); X } X X while (iindex >= 0 && ! isstopchar(string[iindex])) { X iindex--; X erase_a_char(); X } X iindex++;/* and make sure we point at the first AVAILABLE slot */ X } X } X else if (ch == ctrl('R')) { X escaped = OFF; X string[iindex] = '\0'; X PutLine1(x,y, "%s", string); X CleartoEOLN(); X } X else if (!escaped && ch == kill_line) { X /* needed to test if escaped since kill_line character could X * be a desired valid printing character */ X escaped = OFF; X MoveCursor(x,y); X CleartoEOLN(); X iindex = 0; X } X else if (ch == '\0') { X escaped = OFF; X if (cursor_control) X transmit_functions(ON); X fflush(stdin); /* remove extraneous chars, if any */ X string[0] = '\0'; /* clean up string, and... */ X return(-1); X } X else if (!isprint(ch)) { X /* non-printing character - warn with bell*/ X /* don't turn off escaping backslash since current character X * doesn't "use it up". X */ X Writechar('\007'); X } X else { /* default case */ X if(escaped && (ch == backspace || ch == kill_line)) { X /* if last character was a backslash, X * and if this character is escapable X * simply write this character over it even if X * this character is a backslash. X */ X Writechar(BACKSPACE); X iindex--; X string[iindex++] = ch; X Writechar(ch); X escaped = OFF; X } else { X string[iindex++] = ch; X Writechar(ch); X escaped = ( ch == '\\' ? ON : OFF); X } X } X } while (iindex < SLEN); X X string[iindex] = '\0'; X X if (cursor_control) X transmit_functions(ON); X return(0); X} X Xint XGetPrompt() X{ X /** This routine does a read/timeout for a single character. X The way that this is determined is that the routine to X read a character is called, then the "errno" is checked X against EINTR (interrupted call). If they match, this X returns NO_OP_COMMAND otherwise it returns the normal X command. On BSD systems, the EINTR will never be returned X so we instead longjmp from the signal handler. X **/ X X int ch; X X if (timeout > 0) { X alarm((unsigned) timeout); X#ifdef BSD X if (setjmp(GetPromptBuf)) { X InGetPrompt = 0; X ch = NO_OP_COMMAND; X alarm((unsigned) 0); X } X else { X InGetPrompt = 1; X ch = ReadCh(); X InGetPrompt = 0; X alarm((unsigned) 0); X } X#else X errno = 0; /* we actually have to do this. *sigh* */ X ch = ReadCh(); X if (errno == EINTR) ch = NO_OP_COMMAND; X alarm((unsigned) 0); X#endif X } X else X ch = ReadCh(); X X return(ch); X} SHAR_EOF chmod 0444 src/in_utils.c || echo "restore of src/in_utils.c fails" echo "x - extracting src/init.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/init.c && X Xstatic char rcsid[] = "@(#)$Id: init.c,v 4.1 90/04/28 22:43:15 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989, 1990 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: init.c,v $ X * Revision 4.1 90/04/28 22:43:15 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/***** Initialize - read in all the defaults etc etc X*****/ X X#include "headers.h" X#include "patchlevel.h" X X#ifdef TERMIOS X# include <termios.h> X typedef struct termios term_buff; X#else X# ifdef TERMIO X# include <termio.h> X# define tcgetattr(fd,buf) ioctl((fd),TCGETA,(buf)) X typedef struct termio term_buff; X# else X# include <sgtty.h> X# define tcgetattr(fd,buf) ioctl((fd),TIOCGETP,(buf)) X typedef struct sgttyb term_buff; X# endif X#endif X X#ifdef PWDINSYS X# include <sys/pwd.h> X#else X# include <pwd.h> X#endif X X#ifdef I_TIME X# include <time.h> X#endif X#ifdef I_SYSTIME X# include <sys/time.h> X#endif X X#include <signal.h> X#include <ctype.h> X#include <errno.h> X X#ifdef BSD X#undef toupper X#undef tolower X#endif X Xextern int errno; /* system error number on failure */ Xextern char version_buff[]; X Xchar *error_name(), *error_description(); X Xchar *getenv(), *getlogin(), *strcpy(), *strcat(), *index(); Xunsigned short getgid(), getuid(); Xvoid exit(); X#ifndef _POSIX_SOURCE Xstruct passwd *getpwuid(); X#endif Xchar *get_full_name(); X X#ifdef VOIDSIG X void X#else X int X#endif X#ifdef SIGTSTP X sig_user_stop(), sig_return_from_user_stop(), X#endif X quit_signal(), term_signal(), ill_signal(), X fpe_signal(), bus_signal(), segv_signal(), X alarm_signal(), pipe_signal(), hup_signal(); X Xinitialize(requestedmfile) Xchar *requestedmfile; /* first mail file to open, empty if the default */ X{ X /** initialize the whole ball of wax. X **/ X struct passwd *pass; X register int i, hostlen, domlen; X X#if defined(SIGVEC) & defined(SV_INTERRUPT) X struct sigvec alarm_vec; X#endif X char buffer[SLEN], *cp; X X sprintf(version_buff, "%s PL%d", VERSION, PATCHLEVEL); X Raw(ON); X X /* save original user and group ids */ X userid = getuid(); X groupid = getgid(); X X /* make all newly created files private */ X original_umask = umask(077); X X /* Get username (logname), home (login directory), and full_username X * (part of GCOS) field from the password entry for this user id. X * Full_username will get overridden by fullname in elmrc, if defined. X */ X X if((pass = getpwuid(userid)) == NULL) { X error("You have no password entry!"); X Raw(OFF); X exit(1); X } X strcpy(username, pass->pw_name); X strcpy(home, pass->pw_dir); X X if((cp = get_full_name(username)) != NULL) X strcpy(full_username, cp); X else X strcpy(full_username, username); /* fall back on logname */ X X#ifdef DEBUG X if (debug) { /* setup for dprint() statements! */ X char newfname[SLEN], filename[SLEN]; X X sprintf(filename, "%s/%s", home, DEBUGFILE); X if (access(filename, ACCESS_EXISTS) == 0) { /* already one! */ X sprintf(newfname,"%s/%s", home, OLDEBUG); X (void) rename(filename, newfname); X } X X /* Note what we just did up there: we always save the old X version of the debug file as OLDEBUG, so users can mail X copies of bug files without trashing 'em by starting up X the mailer. Dumb, subtle, but easy enough to do! X */ X X if ((debugfile = fopen(filename, "w")) == NULL) { X debug = 0; /* otherwise 'leave' will try to log! */ X leave(fprintf(stderr,"Could not open file %s for debug output!\n", X filename)); X } X chown(filename, userid, groupid); /* file owned by user */ X X fprintf(debugfile, X "Debug output of the ELM program (at debug level %d). Version %s\n\n", X debug, version_buff); X } X#endif X X /* X * If debug level is fairly low, ignore keyboard signals X * until the screen is set up. X */ X if (debug < 5) { X signal(SIGINT, SIG_IGN); X signal(SIGQUIT, SIG_IGN); X } X X if(!check_only && !batch_only) { X if ((i = InitScreen()) < 0) { X if (i == -1) { X printf( X"Sorry, but you must specify what type of terminal you're on if you want to\n"); X printf( X"run the \"elm\" program. (You need your environment variable \"TERM\" set.)\n" X ); X dprint(1,(debugfile,"No $TERM variable in environment!\n")); X } X else if (i == -2) { X printf( X"You need a cursor-addressable terminal to run \"elm\" and I can't find any\n"); X printf( X"kind of termcap entry for \"%s\" - check your \"TERM\" setting...\n", X getenv("TERM")); X dprint(1, X (debugfile,"$TERM variable is an unknown terminal type!\n")); X } else { X printf("Failed trying to initialize your terminal entry: unknown return code %d\n", i); X dprint(1, (debugfile, "Initscreen returned unknown code: %d\n", X i)); X } X Raw(OFF); X exit(1); /* all the errors share this exit statement */ X } X } X X if (debug < 5) { /* otherwise let the system trap 'em! */ X signal(SIGQUIT, quit_signal); /* Quit signal */ X signal(SIGTERM, term_signal); /* Terminate signal */ X signal(SIGILL, ill_signal); /* Illegal instruction */ X signal(SIGFPE, fpe_signal); /* Floating point exception */ X signal(SIGBUS, bus_signal); /* Bus error */ X signal(SIGSEGV, segv_signal); /* Segmentation Violation */ X signal(SIGHUP, hup_signal); /* HangUp (line dropped) */ X } X else { X dprint(3,(debugfile, X "\n*** Elm-Internal Signal Handlers Disabled due to debug level %d ***\n\n", X debug)); X } X#if defined(SIGVEC) & defined(SV_INTERRUPT) X alarm_vec.sv_handler = alarm_signal; X alarm_vec.sv_flags = SV_INTERRUPT; X sigvec (SIGALRM, &alarm_vec, (struct sigvec *)0); /* Process Timer Alarm */ X#else X signal(SIGALRM, alarm_signal); /* Process Timer Alarm */ X#endif X signal(SIGPIPE, pipe_signal); /* Illegal Pipe Operation */ X#ifdef SIGTSTP X signal(SIGTSTP, sig_user_stop); /* Suspend signal from tty */ X signal(SIGCONT, sig_return_from_user_stop); /* Continue Process */ X#endif X X get_term_chars(); X X /* X * Get the host name as per configured behavior. X */ X#ifdef HOSTCOMPILED X strncpy(hostname, HOSTNAME, sizeof(hostname) - 1); X hostname[sizeof(hostname) - 1] = '\0'; X#else X gethostname(hostname, sizeof(hostname)); X#endif X X /* X * now get the domain name, used to build the full name X */ X gethostdomain(hostdomain, sizeof(hostdomain)); X X /* X * now the tough part: X * we need to make three variables out of this stuff: X * hostname = just the hostname, as in bangpaths, X * this is whatever the user gave us so far, X * we wont change this one X * hostdomain = this is the domain considered local to this X * machine, and should be what we got above. X * hostfullname = this is the full FQDN of this machine, X * and is a strange combination of the first two. X * if tail(hostname) == hostdomain X * then hostfullname = hostname X * ie: node.ld.domain.type, ld.domain.type -> node.ld.domain.type X * else if hostname == hostdomain + 1 X * then hostfullname = hostname X * ie: domain.type, .domain.type -> domain.type X * X * else hostfullname = hostname + hostdomain X * ie: host, .domain.type -> host.domain.type X * lost yet? X */ X hostlen = strlen(hostname); X domlen = strlen(hostdomain); X if (hostlen >= domlen) { X if (strcmp(&hostname[hostlen - domlen], hostdomain) == 0) X strcpy(hostfullname, hostname); X else { X strcpy(hostfullname, hostname); X strcat(hostfullname, hostdomain); X } X } else { X if (strcmp(hostname, hostdomain + 1) == 0) X strcpy(hostfullname, hostname); X else { X strcpy(hostfullname, hostname); X strcat(hostfullname, hostdomain); X } X } X X /* Determine the default mail file name. X * X * First look for an environment variable MAIL, then X * use then mailhome if it is not found X */ X if ((cp = getenv("MAIL")) == NULL) X sprintf(defaultfile, "%s%s", mailhome, username); X else X strcpy(defaultfile, cp); X X /* Determine options that might be set in the .elm/elmrc */ X read_rc_file(); X X /* Determine the mail file to read */ X if (*requestedmfile == '\0') X strcpy(requestedmfile, defaultfile); X else if(!expand_filename(requestedmfile, FALSE)) { X Raw(OFF); X exit(0); X } X if (check_size) X if(check_mailfile_size(requestedmfile) != 0) { X Raw(OFF); X exit(0); X } X X /* check for permissions only if not send only mode file */ X if (! mail_only) { X if ((errno = can_access(requestedmfile, READ_ACCESS)) != 0) { X if (strcmp(requestedmfile, defaultfile) != 0 || errno != ENOENT) { X dprint(1, (debugfile, X "Error: given file %s as folder - unreadable (%s)!\n", X requestedmfile, error_name(errno))); X fprintf(stderr,"Can't open folder '%s' for reading!\n", X requestedmfile); X Raw(OFF); X exit(1); X } X } X } X X /** check to see if the user has defined a LINES or COLUMNS X value different to that in the termcap entry (for X windowing systems, of course!) **/ X X ScreenSize(&LINES, &COLUMNS); X X if ((cp = getenv("LINES")) != NULL && isdigit(*cp)) { X sscanf(cp, "%d", &LINES); X LINES -= 1; /* kludge for HP Window system? ... */ X } X X if ((cp = getenv("COLUMNS")) != NULL && isdigit(*cp)) X sscanf(cp, "%d", &COLUMNS); X X /** fix the shell if needed **/ X X if (shell[0] != '/') { X sprintf(buffer, "/bin/%s", shell); X strcpy(shell, buffer); X } X X if (! mail_only && ! check_only) { X X /* get the cursor control keys... */ X X cursor_control = FALSE; X X if ((cp = return_value_of("ku")) != NULL) { X strcpy(up, cp); X if ((cp = return_value_of("kd")) != NULL) { X strcpy(down, cp); X if ((cp = return_value_of("kl")) != NULL) { X strcpy(left, cp); X if ((cp = return_value_of("kr")) != NULL) { X strcpy(right, cp); X cursor_control = TRUE; X transmit_functions(ON); X } X } X } X } X X strcpy(start_highlight, "->"); X end_highlight[0] = '\0'; X X if (!arrow_cursor) { /* try to use inverse bar instead */ X if ((cp = return_value_of("so")) != NULL) { X strcpy(start_highlight, cp); X if ((cp = return_value_of("se")) == NULL) X strcpy(start_highlight, "->"); X else { X strcpy(end_highlight, cp); X has_highlighting = TRUE; X } X } X } X } X X /** clear the screen **/ X if(!check_only && !batch_only) X ClearScreen(); X X if (! mail_only && ! check_only) { X if (mini_menu) X headers_per_page = LINES - 13; X else X headers_per_page = LINES - 8; /* 5 more headers! */ X X newmbox(requestedmfile, FALSE); /* read in the folder! */ X } X X#ifdef DEBUG X if (debug >= 2 && debug < 10) { X fprintf(debugfile, X"hostname = %-20s \tusername = %-20s \tfullname = %-20s\n", X hostname, username, full_username); X X fprintf(debugfile, X"home = %-20s \teditor = %-20s \trecvd_mail = %-20s\n", X home, editor, recvd_mail); X X fprintf(debugfile, X"cur_folder = %-20s \tfolders = %-20s \tprintout = %-20s\n", X cur_folder, folders, printout); X X fprintf(debugfile, X"sent_mail = %-20s \tprefix = %-20s \tshell = %-20s\n\n", X sent_mail, prefixchars, shell); X X if (local_signature[0]) X fprintf(debugfile, "local_signature = \"%s\"\n", X local_signature); X if (remote_signature[0]) X fprintf(debugfile, "remote_signature = \"%s\"\n", X remote_signature); X if (local_signature[0] || remote_signature[0]) X fprintf(debugfile, "\n"); X } X#endif X} X Xget_term_chars() X{ X /** This routine sucks out the special terminal characters X ERASE and KILL for use in the input routine. The meaning X of the characters are (dare I say it?) fairly obvious... **/ X X term_buff term_buffer; X X if (tcgetattr(STANDARD_INPUT,&term_buffer) == -1) { X dprint(1, (debugfile, X "Error: %s encountered on ioctl call (get_term_chars)\n", X error_name(errno))); X /* set to defaults for terminal driver */ X backspace = BACKSPACE; X kill_line = ctrl('U'); X } X else { X#if defined(TERMIO) || defined(TERMIOS) X backspace = term_buffer.c_cc[VERASE]; X kill_line = term_buffer.c_cc[VKILL]; X#else X backspace = term_buffer.sg_erase; X kill_line = term_buffer.sg_kill; X#endif X } X} SHAR_EOF chmod 0444 src/init.c || echo "restore of src/init.c fails" echo "x - extracting src/leavembox.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/leavembox.c && X Xstatic char rcsid[] = "@(#)$Id: leavembox.c,v 4.1 90/04/28 22:43:18 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989, 1990 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: leavembox.c,v $ X * Revision 4.1 90/04/28 22:43:18 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** leave current folder, updating etc. as needed... X X**/ X X#include "headers.h" X#include <sys/types.h> X#include <sys/stat.h> X#ifdef LOCK_BY_FLOCK X#include <sys/file.h> X#endif X#include <errno.h> X X/********** X Since a number of machines don't seem to bother to define the utimbuf X structure for some *very* obscure reason.... X X Suprise, though, BSD has a different utime() entirely...*sigh* X**********/ X X#ifndef BSD X# ifdef NOUTIMBUF X Xstruct utimbuf { X time_t actime; /** access time **/ X time_t modtime; /** modification time **/ X }; X X X# endif /* NOUTIMBUF */ X#endif /* BSD */ X Xextern int errno; X Xchar *error_name(), *error_description(), *strcpy(), *rindex(); Xunsigned short getegid(); X#ifndef _POSIX_SOURCE Xunsigned long sleep(); X#endif X Xint Xleave_mbox(resyncing, quitting, prompt) Xint resyncing, quitting, prompt; X{ X /** Close folder, deleting some messages, storing others in mbox, X and keeping others, as directed by user input and elmrc options. X X Return 1 Folder altered X 0 Folder not altered X -1 New mail arrived during the process and X closing was aborted. X If "resyncing" we are just writing out folder to reopen it. We X therefore only consider deletes and keeps, not stores to mbox. X Also we don't remove NEW status so that it can be preserved X across the resync. X X If "quitting" and "prompt" is false, then no prompting is done. X Otherwise prompting is dependent upon the variable X question_me, as set by an elmrc option. This behavior makes X the 'q' command prompt just like 'c' and '$', while X retaining the 'Q' command for a quick exit that never X prompts. X **/ X X FILE *temp; X char temp_keep_file[SLEN], buffer[SLEN]; X struct stat buf; /* stat command */ X#ifdef BSD X time_t utime_buffer[2]; /* utime command */ X#else X struct utimbuf utime_buffer; /* utime command */ X#endif X register int to_delete = 0, to_store = 0, to_keep = 0, i, X marked_deleted, marked_read, marked_unread, X last_sortby, ask_questions, asked_storage_q, X num_chgd_status, need_to_copy; X char answer; X long bytes(); X X dprint(1, (debugfile, "\n\n-- leaving folder --\n\n")); X X if (message_count == 0) X return(0); /* nothing changed */ X X ask_questions = ((quitting && !prompt) ? FALSE : question_me); X X /* YES or NO on softkeys */ X if (hp_softkeys && ask_questions) { X define_softkeys(YESNO); X softkeys_on(); X } X X /* Clear the exit dispositions of all messages, just in case X * they were left set by a previous call to this function X * that was interrupted by the receipt of new mail. X */ X for(i = 0; i < message_count; i++) X headers[i]->exit_disposition = UNSET; X X /* Determine if deleted messages are really to be deleted */ X X /* we need to know if there are none, or one, or more to delete */ X for (marked_deleted=0, i=0; i<message_count && marked_deleted<2; i++) X if (ison(headers[i]->status, DELETED)) X marked_deleted++; X X if(marked_deleted) { X answer = (always_del ? 'y' : 'n'); /* default answer */ X if(ask_questions) { X sprintf(buffer, "Delete message%s? (y/n) ", plural(marked_deleted)); X answer = want_to(buffer, answer); X } X X if(answer == 'y') { X for (i = 0; i < message_count; i++) { X if (ison(headers[i]->status, DELETED)) { X headers[i]->exit_disposition = DELETE; X to_delete++; X } X } X } X } X dprint(3, (debugfile, "Messages to delete: %d\n", to_delete)); X X /* If this is a non spool file, or if we are merely resyncing, X * all messages with an unset disposition (i.e. not slated for X * deletion) are to be kept. X * Otherwise, we need to determine if read and unread messages X * are to be stored or kept. X */ X if(folder_type == NON_SPOOL || resyncing) { X to_store = 0; X for (i = 0; i < message_count; i++) { X if(headers[i]->exit_disposition == UNSET) { X headers[i]->exit_disposition = KEEP; X to_keep++; X } X } X } else { X X /* Let's first see if user wants to store read messages X * that aren't slated for deletion */ X X asked_storage_q = FALSE; X X /* we need to know if there are none, or one, or more marked read */ X for (marked_read=0, i=0; i < message_count && marked_read < 2; i++) { X if((isoff(headers[i]->status, UNREAD)) X && (headers[i]->exit_disposition == UNSET)) X marked_read++; X } X if(marked_read) { X answer = (always_store ? 'y' : 'n'); /* default answer */ X if(ask_questions) { X sprintf(buffer, "Move read message%s to \"received\" folder? (y/n) ", X plural(marked_read)); X answer = want_to(buffer, answer); X asked_storage_q = TRUE; X } X X for (i = 0; i < message_count; i++) { X if((isoff(headers[i]->status, UNREAD)) X && (headers[i]->exit_disposition == UNSET)) { X X if(answer == 'y') { X headers[i]->exit_disposition = STORE; X to_store++; X } else { X headers[i]->exit_disposition = KEEP; X to_keep++; X } X } X } X } X X /* If we asked the user if read messages should be stored, X * and if the user wanted them kept instead, then certainly the X * user would want the unread messages kept as well. X */ X if(asked_storage_q && answer == 'n') { X X for (i = 0; i < message_count; i++) { X if((ison(headers[i]->status, UNREAD)) X && (headers[i]->exit_disposition == UNSET)) { X headers[i]->exit_disposition = KEEP; X to_keep++; X } X } X X } else { X X /* Determine if unread messages are to be kept */ X X /* we need to know if there are none, or one, or more unread */ X for (marked_unread=0, i=0; i<message_count && marked_unread<2; i++) X if((ison(headers[i]->status, UNREAD)) X && (headers[i]->exit_disposition == UNSET)) X marked_unread++; X X if(marked_unread) { X answer = (always_keep ? 'y' : 'n'); /* default answer */ X if(ask_questions) { X sprintf(buffer, X "Keep unread message%s in incoming mailbox? (y/n) ", X plural(marked_unread)); X answer = want_to(buffer, answer); X } X X for (i = 0; i < message_count; i++) { X if((ison(headers[i]->status, UNREAD)) X && (headers[i]->exit_disposition == UNSET)) { X X if(answer == 'n') { X headers[i]->exit_disposition = STORE; X to_store++; X } else { X headers[i]->exit_disposition = KEEP; X to_keep++; X } X X } X } X } X } X } X X dprint(3, (debugfile, "Messages to store: %d\n", to_store)); X dprint(3, (debugfile, "Messages to keep: %d\n", to_keep)); X X if(to_delete + to_store + to_keep != message_count) { X dprint(1, (debugfile, X "Error: %d to delete + %d to store + %d to keep != %d message cnt\n", X to_delete, to_store, to_keep, message_count)); X error("Something wrong in message counts! Folder unchanged."); X emergency_exit(); X } X X X /* If we are not resyncing, we are leaving the mailfile and X * the new messages are new no longer. Note that this changes X * their status. X */ X if(!resyncing) { X for (i = 0; i < message_count; i++) { X if (ison(headers[i]->status, NEW)) { X clearit(headers[i]->status, NEW); X headers[i]->status_chgd = TRUE; X } X } X } X X /* If all messages are to be kept and none have changed status X * we don't need to do anything because the current folder won't X * be changed by our writing it out - unless we are resyncing, in X * which case we force the writing out of the mailfile. SHAR_EOF echo "End of part 16" echo "File src/leavembox.c is continued in part 17" echo "17" > s2_seq_.tmp exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.