Subject: v18i098: Elm mail system, release 2.2, Part19/22 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein) Posting-number: Volume 18, Issue 98 Archive-name: elm2.2/part19 #!/bin/sh # this is part 19 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/read_rc.c continued # CurArch=19 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/read_rc.c" sed 's/^X//' << 'SHAR_EOF' >> src/read_rc.c X strcpy(raw_recvdmail, word2); X expand_env(recvd_mail, word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "editor") || equal(word1,"mailedit")) { X strcpy(raw_editor, word2); X expand_env(editor, word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "sentmail") || X equal(word1, "savemail") || equal(word1, "saveto")) { X /* the last two were old names of this option - here for X * compatibility in case the user has never written out X * a new elmrc while in elm since the name change. X */ X rc_has_sentmail = TRUE; X strcpy(raw_sentmail, word2); X expand_env(sent_mail, word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "calendar")) { X strcpy(raw_calendar_file, word2); X expand_env(calendar_file, word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "print") || equal(word1, "printmail")) { X strcpy(raw_printout, word2); X expand_env(printout, word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "pager") || equal(word1, "page")) { X strcpy(raw_pager, word2); X expand_env(pager, word2); X if (equal(pager,"builtin+") || equal(pager,"internal+")) X clear_pages++; X last = NOTWEEDOUT; X } X else if (equal(word1, "signature")) { X if (equal(shift_lower(word2), "on") || X equal(shift_lower(word2), "off")) { X errors++; X printf( X "\"signature\" used in obsolete way in .elm/elmrc file. Ignored!\n\r"); X printf( X "\t(Signature should specify the filename to use rather than on/off.)\n\r\n"); X } X else { X strcpy(raw_local_signature, word2); X strcpy(raw_remote_signature, raw_local_signature); X expand_env(local_signature, word2); X strcpy(remote_signature, local_signature); X } X last = NOTWEEDOUT; X } X else if (equal(word1, "localsignature")) { X strcpy(raw_local_signature, word2); X expand_env(local_signature, word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "remotesignature")) { X strcpy(raw_remote_signature, word2); X expand_env(remote_signature, word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "escape")) { X escape_char = word2[0]; X last = NOTWEEDOUT; X } X else if (equal(word1, "autocopy")) { X auto_copy = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "copy") || equal(word1, "auto_cc")) { X auto_cc = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "names")) { X names_only = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "resolve")) { X resolve_mode = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "weed")) { X filter = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "noheader")) { X noheader = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "titles")) { X title_messages = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "savebyname") || equal(word1, "savename")) { X save_by_name = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "movepage") || equal(word1, "page") || X equal(word1, "movewhenpaged")) { X move_when_paged = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "pointnew") || equal(word1, "pointtonew")) { X point_to_new = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "keypad") || equal(word1, "hpkeypad")) { X hp_terminal = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "softkeys") || equal(word1, "hpsoftkeys")) { X if (hp_softkeys = is_it_on(word2)) X hp_terminal = TRUE; /* must be set also! */ X last = NOTWEEDOUT; X } X else if (equal(word1, "arrow")) { X arrow_cursor += is_it_on(word2); /* may have been set already */ X last = NOTWEEDOUT; /* with command line flag -a */ X } X else if (strncmp(word1, "form", 4) == 0) { X allow_forms = (is_it_on(word2)? MAYBE : NO); X last = NOTWEEDOUT; X } X else if (equal(word1, "promptafter")) { X prompt_after_pager = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (strncmp(word1, "menu", 4) == 0) { X /* if not turned off by -m cmd line arg, X * obey elmrc file setting */ X if(mini_menu) X mini_menu = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (strncmp(word1, "warning", 7) == 0) { X warnings = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "alwaysleave")) { X /* this is an old option - here for X * compatibility in case the user has never written out X * a new elmrc while in elm since the split of X * alwaysleave into alwayskeep and alwaysstore X */ X always_keep = is_it_on(word2); X always_store = !is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "alwayskeep")) { X always_keep = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "alwaysstore") || equal(word1, "store")) { X always_store = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "alwaysdelete") || equal(word1, "delete")) { X always_del = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "askcc") || equal(word1, "cc")) { X prompt_for_cc = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "ask") || equal(word1, "question")) { X question_me = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "keep") || equal(word1, "keepempty")) { X keep_empty_files = is_it_on(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "bounce") || equal(word1, "bounceback")) { X bounceback = atoi(word2); X if (bounceback > MAX_HOPS) { X errors++; X printf( X "Warning: bounceback is set to greater than %d (max-hops). Ignored.\n", X MAX_HOPS); X bounceback = 0; X } X last = NOTWEEDOUT; X } X else if (equal(word1, "userlevel")) { X user_level = atoi(word2); X last = NOTWEEDOUT; X } X else if (equal(word1, "timeout")) { X timeout = atoi(word2); X if (timeout < 10) { X errors++; X printf( X "Warning: timeout is set to less than 10 seconds. Ignored.\n"); X timeout = 0; X } X last = NOTWEEDOUT; X } X else if (equal(word1, "weedout")) { X weedout(word2); X last = WEEDOUT; X } X else if (equal(word1, "alternatives")) { X alternatives(word2); X last = ALTERNATIVES; X } X else if (last == WEEDOUT) /* could be multiple line weedout */ X weedout(buffer); X else if (last == ALTERNATIVES) /* multi-line addresses */ X alternatives(buffer); X else { X errors++; X printf( X "I can't understand line %d in your \".elm/elmrc\" file:\n> %s\n", X lineno, buffer); X } X } X /* sleep two seconds for each error and then some so user X * can read them before screen is cleared */ X if(errors) X sleep((errors * 2) + 2); X } X X /* see if the user has a folders directory */ X if (access(folders, 00) == -1) { X if(batch_only) { X printf("\n\rNotice:\ X\n\rELM requires the use of a folders directory to store your mail folders in.\ X\n\rI'd like to create the directory %s for you,\ X\n\rbut I can't in \"batch mode\". Please run ELM in \"normal mode\" first.\ X\n\r", folders); X exit(0); X } X X printf("\n\rNotice:\ X\n\rELM requires the use of a folders directory to store your mail folders in.\ X\n\rShall I create the directory %s for you (y/n)? y%c", folders, BACKSPACE); X X fflush(stdout); X ch=getchar(); X if (ch == 'n' || ch == 'N') { X printf("No.\n\rVery well. I won't create it.\ X \n\rBut, you may run into difficulties later.\n\r"); X sleep(4); X } X else { X printf("Yes.\n\rGreat! I'll do it now.\n\r"); X create_new_folders(); X } X } X X /* If recvd_mail or sent_mail havent't yet been established in X * the elmrc, establish them from their defaults. X * Then if they begin with a metacharacter, replace it with the X * folders directory name. X */ X if(!rc_has_recvdmail) { X strcpy(raw_recvdmail, default_recvdmail); X strcpy(recvd_mail, raw_recvdmail); X } X if(metachar(recvd_mail[0])) { X strcpy(buffer, &recvd_mail[1]); X sprintf(recvd_mail, "%s/%s", folders, buffer); X } X X if(!rc_has_sentmail) { X sprintf(raw_sentmail, default_sentmail); X sprintf(sent_mail, default_sentmail); X } X if(metachar(sent_mail[0])) { X strcpy(buffer, &sent_mail[1]); X sprintf(sent_mail, "%s/%s", folders, buffer); X } X X if (debug > 10) /** only do this if we REALLY want debug! **/ X dump_rc_results(); X X} X Xweedout(string) Xchar *string; X{ X /** This routine is called with a list of headers to weed out. **/ X X char *strptr, *header; X register int i; X X strptr = string; X X while ((header = strtok(strptr, "\t ,\"'")) != NULL) { X if (strlen(header) > 0) { X if (! strcmp(header, "*end-of-user-headers*")) break; X if (weedcount > MAX_IN_WEEDLIST) { X printf("Too many weed headers! Leaving...\n"); X exit(1); X } X if ((weedlist[weedcount] = pmalloc(strlen(header) + 1)) X == NULL) { X printf("Too many weed headers! Out of memory! Leaving...\n"); X exit(1); X } X X for (i=0; i< strlen(header); i++) X if (header[i] == '_') header[i] = ' '; X X strcpy(weedlist[weedcount], header); X weedcount++; X } X strptr = NULL; X } X} X Xalternatives(string) Xchar *string; X{ X /** This routine is called with a list of alternative addresses X that you may receive mail from (forwarded) **/ X X char *strptr, *address; X struct addr_rec *current_record, *previous_record; X X previous_record = alternative_addresses; /* start 'er up! */ X /* move to the END of the alternative addresses list */ X X if (previous_record != NULL) X while (previous_record->next != NULL) X previous_record = previous_record->next; X X strptr = (char *) string; X X while ((address = strtok(strptr, "\t ,\"'")) != NULL) { X if (previous_record == NULL) { X previous_record = (struct addr_rec *) pmalloc(sizeof X *alternative_addresses); X X strcpy(previous_record->address, address); X previous_record->next = NULL; X alternative_addresses = previous_record; X } X else { X current_record = (struct addr_rec *) pmalloc(sizeof X *alternative_addresses); X X strcpy(current_record->address, address); X current_record->next = NULL; X previous_record->next = current_record; X previous_record = current_record; X } X strptr = (char *) NULL; X } X} X Xdefault_weedlist() X{ X /** Install the default headers to weed out! Many gracious X thanks to John Lebovitz for this dynamic method of X allocation! X **/ X X static char *default_list[] = { ">From", "In-Reply-To:", X "References:", "Newsgroups:", "Received:", X "Apparently-To:", "Message-Id:", "Content-Type:", X "From", "X-Mailer:", "Status:", X "*end-of-defaults*", NULL X }; X X for (weedcount = 0; default_list[weedcount] != (char *) 0;weedcount++){ X if ((weedlist[weedcount] = X pmalloc(strlen(default_list[weedcount]) + 1)) == NULL) { X printf("\n\rNot enough memory for default weedlist. Leaving.\n\r"); X leave(1); X } X strcpy(weedlist[weedcount], default_list[weedcount]); X } X} X Xint Xmatches_weedlist(buffer) Xchar *buffer; X{ X /** returns true iff the first 'n' characters of 'buffer' X match an entry of the weedlist **/ X X register int i; X X for (i=0;i < weedcount; i++) X if (strncmp(buffer, weedlist[i], strlen(weedlist[i])) == 0) X return(1); X X return(0); X} X Xint Xbreakup(buffer, word1, word2) Xchar *buffer, *word1, *word2; X{ X /** This routine breaks buffer down into word1, word2 where X word1 is alpha characters only, and there is an equal X sign delimiting the two... X alpha = beta X For lines with more than one 'rhs', word2 is set to the X entire string. X Return -1 if word 2 is of zero length, else 0. X **/ X X register int i; X X for (i=0;buffer[i] != '\0' && ok_char(buffer[i]); i++) X if (buffer[i] == '_') X word1[i] = '-'; X else if (isupper(buffer[i])) X word1[i] = tolower(buffer[i]); X else X word1[i] = buffer[i]; X X word1[i++] = '\0'; /* that's the first word! */ X X /** spaces before equal sign? **/ X X while (whitespace(buffer[i])) i++; X if (buffer[i] == '=') i++; X X /** spaces after equal sign? **/ X X while (whitespace(buffer[i])) i++; X X if (buffer[i] != '\0') X strcpy(word2, (char *) (buffer + i)); X else X word2[0] = '\0'; X X /* remove trailing spaces from word2! */ X i = strlen(word2) - 1; X while(i && (whitespace(word2[i]) || word2[i] == '\n')) X word2[i--] = '\0'; X X return(*word2 == '\0' ? -1 : 0 ); X X} X Xexpand_env(dest, buffer) Xchar *dest, *buffer; X{ X /** expand possible metacharacters in buffer and then copy X to dest... X X BEWARE!! Because strtok() is used on buffer, buffer may be changed. X X This routine knows about "~" being the home directory, X and "$xxx" being an environment variable. X **/ X X char *word, *string, next_word[SLEN]; X X if (buffer[0] == '/') { X dest[0] = '/'; X dest[1] = '\0'; X } X else X dest[0] = '\0'; X X string = (char *) buffer; X X while ((word = strtok(string, "/")) != NULL) { X if (word[0] == '$') { X next_word[0] = '\0'; X if (getenv((char *) (word + 1)) != NULL) X strcpy(next_word, getenv((char *) (word + 1))); X if (strlen(next_word) == 0) X leave(printf("\n\rCan't expand environment variable '%s'.\n\r", X word)); X } X else if (word[0] == '~' && word[1] == '\0') X strcpy(next_word, home); X else X strcpy(next_word, word); X X sprintf(dest, "%s%s%s", dest, X (strlen(dest) > 0 && lastch(dest) != '/' ? "/":""), X next_word); X X string = (char *) NULL; X } X} X X#define on_off(s) (s == 1? "ON " : "OFF") Xdump_rc_results() X{ X X register int i, len; X X fprintf(debugfile, "folders = %s ", folders); X fprintf(debugfile, "recvd_mail = %s ", recvd_mail); X fprintf(debugfile, "editor = %s\n", editor); X fprintf(debugfile, "printout = %s ", printout); X fprintf(debugfile, "sent_mail = %s ", sent_mail); X fprintf(debugfile, "calendar_file = %s\n", calendar_file); X fprintf(debugfile, "prefixchars = %s ", prefixchars); X fprintf(debugfile, "shell = %s ", shell); X fprintf(debugfile, "pager = %s\n", pager); X fprintf(debugfile, "\n"); X fprintf(debugfile, "escape = %c\n", escape_char); X fprintf(debugfile, "\n"); X X fprintf(debugfile, "mini_menu = %s ", on_off(mini_menu)); X fprintf(debugfile, "filter_hdrs = %s ", on_off(filter)); X fprintf(debugfile, "auto_copy = %s\n", on_off(auto_copy)); X X fprintf(debugfile, "resolve_mode = %s ", on_off(resolve_mode)); X fprintf(debugfile, "auto_save_copy = %s ", on_off(auto_cc)); X fprintf(debugfile, "noheader = %s\n", on_off(noheader)); X X fprintf(debugfile, "title_msgs = %s ", on_off(title_messages)); X fprintf(debugfile, "hp_terminal = %s ", on_off(hp_terminal)); X fprintf(debugfile, "hp_softkeys = %s ", on_off(hp_softkeys)); X fprintf(debugfile, "save_by_name = %s\n", on_off(save_by_name)); X X fprintf(debugfile, "move_paged = %s ", on_off(move_when_paged)); X fprintf(debugfile, "point_to_new = %s ", on_off(point_to_new)); X fprintf(debugfile, "prompt_after_pager = %s ", X on_off(prompt_after_pager)); X fprintf(debugfile, "bounceback = %s\n", on_off(bounceback)); X X fprintf(debugfile, "always_keep = %s ", on_off(always_keep)); X fprintf(debugfile, "always_store = %s ", on_off(always_store)); X fprintf(debugfile, "always_delete = %s ", on_off(always_del)); X fprintf(debugfile, "arrow_cursor = %s ", on_off(arrow_cursor)); X fprintf(debugfile, "names = %s\n", on_off(names_only)); X X fprintf(debugfile, "warnings = %s ", on_off(warnings)); X fprintf(debugfile, "question_me = %s ", on_off(question_me)); X fprintf(debugfile, "keep_nil_files = %s\n\n", X on_off(keep_empty_files)); X X fprintf(debugfile, "local_signature = %s\n", local_signature); X fprintf(debugfile, "remote_signature = %s\n", remote_signature); X X fprintf(debugfile, "Userlevel is set to %s user: %d\n", X user_level == 0 ? "beginning" : X user_level > 1 ? "expert" : "intermediate", user_level); X X fprintf(debugfile, "\nAnd we're skipping the following headers:\n\t"); X X for (len=8, i=0; i < weedcount; i++) { X if (weedlist[i][0] == '*') continue; /* skip '*end-of-defaults*' */ X if (len + strlen(weedlist[i]) > 80) { X fprintf(debugfile, " \n\t"); X len = 8; X } X fprintf(debugfile, "%s ", weedlist[i]); X len += strlen(weedlist[i]) + 3; X } X X fprintf(debugfile, "\n\n"); X} X Xis_it_on(word) Xchar *word; X{ X /** Returns TRUE if the specified word is either 'ON', 'YES' X or 'TRUE', and FALSE otherwise. We explicitly translate X to lowercase here to ensure that we have the fastest X routine possible - we really DON'T want to have this take X a long time or our startup will be major pain each time. X **/ X X static char mybuffer[NLEN]; X register int i, j; X X for (i=0, j=0; word[i] != '\0'; i++) X mybuffer[j++] = isupper(word[i]) ? tolower(word[i]) : word[i]; X mybuffer[j] = '\0'; X X return( (strncmp(mybuffer, "on", 2) == 0) || X (strncmp(mybuffer, "yes", 3) == 0) || X (strncmp(mybuffer, "true", 4) == 0) X ); X} SHAR_EOF echo "File src/read_rc.c is complete" chmod 0444 src/read_rc.c || echo "restore of src/read_rc.c fails" echo "x - extracting src/remail.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/remail.c && X Xstatic char rcsid[] = "@(#)$Id: remail.c,v 2.8 89/03/25 21:47:04 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.8 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: remail.c,v $ X * Revision 2.8 89/03/25 21:47:04 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** For those cases when you want to have a message continue along X to another person in such a way as they end up receiving it with X the return address the person YOU received the mail from (does X this comment make any sense yet??)... X X**/ X X#include "headers.h" X#include X Xextern int errno; X Xchar *error_name(), *error_description(); X Xint Xremail() X{ X /** remail a message... returns TRUE if new foot needed ... **/ X X FILE *mailfd; X char entered[VERY_LONG_STRING], expanded[VERY_LONG_STRING]; X char *filename, buffer[VERY_LONG_STRING], ch; X extern char *tempnam(); X X entered[0] = '\0'; X X get_to(entered, expanded); X if (strlen(entered) == 0) X return(0); X X display_to(expanded); X X if((filename=tempnam(temp_dir, "snd.")) == NULL) { X dprint(1, (debugfile, "couldn't make temp file nam! (remail)\n")); X sprintf(buffer, "Sorry - couldn't make file temp file name."); X set_error(buffer); X return(1); X } X X if ((mailfd = fopen(filename, "w")) == NULL) { X dprint(1, (debugfile, "couldn't open temp file %s! (remail)\n", X filename)); X dprint(1, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X sprintf(buffer, "Sorry - couldn't open file %s for writing (%s).", X error_name(errno)); X set_error(buffer); X return(1); X } X X /** now let's copy the message into the newly opened X buffer... **/ X X chown (filename, userid, groupid); X X copy_message("", mailfd, FALSE, TRUE, FALSE); X X fclose(mailfd); X X /** Got the messsage, now let's ensure the person really wants to X remail it... **/ X X ClearLine(LINES-1); X ClearLine(LINES); X PutLine1(LINES-1,0, X "Are you sure you want to remail this message (y/n)? y%c", X BACKSPACE); X fflush(stdin); X fflush(stdout); X ch = ReadCh(); X if (tolower(ch) == 'n') { /* another day, another No... */ X Write_to_screen("No.", 0); X set_error("Bounce of message cancelled."); X return(1); X } X Write_to_screen("Yes.", 0); X X sprintf(buffer,"( (%s %s ; %s %s) & ) < %s", X mailer, strip_parens(strip_commas(expanded)), X remove_cmd, filename, filename); X X PutLine0(LINES,0,"Resending mail..."); X system_call(buffer, SH, FALSE); X set_error("Mail resent."); X X return(1); X} SHAR_EOF chmod 0444 src/remail.c || echo "restore of src/remail.c fails" echo "x - extracting src/reply.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/reply.c && X Xstatic char rcsid[] = "@(#)$Id: reply.c,v 2.9 89/03/25 21:47:06 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.9 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: reply.c,v $ X * Revision 2.9 89/03/25 21:47:06 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/*** routine allows replying to the sender of the current message X X***/ X X#include "headers.h" X#include X X#ifndef BSD X# include X# include X#endif X X/** Note that this routine generates automatic header information X for the subject and (obviously) to lines, but that these can X be altered while in the editor composing the reply message! X**/ X Xchar *strip_parens(), *get_token(); X Xextern int errno; X Xchar *error_name(), *strcat(), *strcpy(); X Xint Xreply() X{ X /** Reply to the current message. Returns non-zero iff X the screen has to be rewritten. **/ X X char return_address[SLEN], subject[SLEN]; X int return_value, form_letter; X X form_letter = (headers[current-1]->status & FORM_LETTER); X X get_return(return_address, current-1); X X if (first_word(headers[current-1]->from, "To:")) { X strcpy(subject, headers[current-1]->subject); X if (form_letter) X return_value = mail_filled_in_form(return_address, subject); X else X return_value = sendmsg(return_address, "", subject, TRUE, NO, TRUE); X } X else if (headers[current-1]->subject[0] != '\0') { X if ((strncmp("Re:", headers[current-1]->subject, 3) == 0) || X (strncmp("RE:", headers[current-1]->subject, 3) == 0) || X (strncmp("re:", headers[current-1]->subject, 3) == 0)) X strcpy(subject, headers[current-1]->subject); X else { X strcpy(subject,"Re: "); X strcat(subject,headers[current-1]->subject); X } X if (form_letter) X return_value = mail_filled_in_form(return_address, subject); X else X return_value = sendmsg(return_address, "", subject, TRUE, NO, TRUE); X } X else X if (form_letter) X return_value = mail_filled_in_form(return_address, X "Filled in Form"); X else X return_value = sendmsg(return_address, "", "Re: your mail", X TRUE, NO, TRUE); X X return(return_value); X} X Xint Xreply_to_everyone() X{ X /** Reply to everyone who received the current message. X This includes other people in the 'To:' line and people X in the 'Cc:' line too. Returns non-zero iff the screen X has to be rewritten. **/ X X char return_address[SLEN], subject[SLEN]; X char full_address[VERY_LONG_STRING]; X int return_value; X X get_return(return_address, current-1); X X full_address[0] = '\0'; /* no copies yet */ X get_and_expand_everyone(return_address, full_address); X X if (headers[current-1]->subject[0] != '\0') { X if ((strncmp("Re:", headers[current-1]->subject, 3) == 0) || X (strncmp("RE:", headers[current-1]->subject, 3) == 0) || X (strncmp("re:", headers[current-1]->subject, 3) == 0)) X strcpy(subject, headers[current-1]->subject); X else { X strcpy(subject,"Re: "); X strcat(subject,headers[current-1]->subject); X } X return_value = sendmsg(return_address, full_address, subject, X TRUE, NO, TRUE); X } X else X return_value = sendmsg(return_address, full_address, X "Re: your mail", TRUE, NO, TRUE); X X return(return_value); X X} X Xint Xforward() X{ X /** Forward the current message. What this actually does is X to temporarily set forwarding to true, then call 'send' to X get the address and route the mail. Modified to also set X 'noheader' to FALSE also, so that the original headers X of the message sent are included in the message body also. X Return TRUE if the main part of the screen has been changed X (useful for knowing whether a redraw is needed. X **/ X X char subject[SLEN], address[VERY_LONG_STRING]; X int results, edit_msg = FALSE; X X forwarding = TRUE; X X address[0] = '\0'; X X if (headers[current-1]->status & FORM_LETTER) X PutLine0(LINES-3,COLUMNS-40,""); X else { X edit_msg = (want_to("Edit outgoing message? (y/n) ",'y') != 'n'); X } X X if (strlen(headers[current-1]->subject) > 0) { X X strcpy(subject, headers[current-1]->subject); X X /* this next strange compare is to see if the last few chars are X already '(fwd)' before we tack another on */ X X if (strlen(subject) < 6 || (strcmp((char *) subject+strlen(subject)-5, X "(fwd)") != 0)) X strcat(subject, " (fwd)"); X X results = sendmsg(address, "", subject, edit_msg, X headers[current-1]->status & FORM_LETTER? X PREFORMATTED : allow_forms, FALSE); X } X else X results = sendmsg(address, "", "Forwarded mail...", edit_msg, X headers[current-1]->status & FORM_LETTER? X PREFORMATTED : allow_forms, FALSE); X X forwarding = FALSE; X X return(results); X} X Xget_and_expand_everyone(return_address, full_address) Xchar *return_address, *full_address; X{ X /** Read the current message, extracting addresses from the 'To:' X and 'Cc:' lines. As each address is taken, ensure that it X isn't to the author of the message NOR to us. If neither, X prepend with current return address and append to the X 'full_address' string. X **/ X X char ret_address[SLEN], buf[SLEN], new_address[SLEN], X address[SLEN], comment[SLEN]; X int in_message = 1, first_pass = 0, iindex, line_pending = 0; X X /** First off, get to the first line of the message desired **/ X X if (fseek(mailfile, headers[current-1]->offset, 0) == -1) { X dprint(1,(debugfile,"Error: seek %ld resulted in errno %s (%s)\n", X headers[current-1]->offset, error_name(errno), X "get_and_expand_everyone")); X error2("ELM [seek] couldn't read %d bytes into file (%s).", X headers[current-1]->offset, error_name(errno)); X return; X } X X /** okay! Now we're there! **/ X X /** let's fix the ret_address to reflect the return address of this X message with '%s' instead of the persons login name... **/ X X translate_return(return_address, ret_address); X X /** now let's parse the actual message! **/ X X while (in_message) { X if (! line_pending) X in_message = (int) (fgets(buf, SLEN, mailfile) != NULL); X line_pending = 0; X if (first_word(buf, "From ") && first_pass++ != 0) X in_message = FALSE; X else if (first_word(buf, "To:") || first_word(buf, "Cc:") || X first_word(buf, "CC:") || first_word(buf, "cc:")) { X do { X no_ret(buf); X X /** we have a buffer with a list of addresses, each of either the X form "address (name)" or "name
". Our mission, should X we decide not to be too lazy, is to break it into the two parts. X **/ X X if (!whitespace(buf[0])) X iindex = chloc(buf, ':')+1; /* skip header field */ X else X iindex = 0; /* skip whitespace */ X X while (break_down_tolist(buf, &iindex, address, comment)) { X X if (okay_address(address, return_address)) { X sprintf(new_address, ret_address, address); X optimize_and_add(new_address, full_address); X } X } X X in_message = (int) (fgets(buf, SLEN, mailfile) != NULL); X X if (in_message) dprint(2, (debugfile, "> %s", buf)); X X } while (in_message && whitespace(buf[0])); X line_pending++; X } X else if (strlen(buf) < 2) /* done with header */ X in_message = FALSE; X } X} X Xint Xokay_address(address, return_address) Xchar *address, *return_address; X{ X /** This routine checks to ensure that the address we just got X from the "To:" or "Cc:" line isn't us AND isn't the person X who sent the message. Returns true iff neither is the case **/ X X char our_address[SLEN]; X struct addr_rec *alternatives; X X if (in_string(address, return_address)) X return(FALSE); X X sprintf(our_address, "%s!%s", hostname, username); X X if (in_string(address, our_address)) X return(FALSE); X X sprintf(our_address, "%s@%s", username, hostname); X X if (in_string(address, our_address)) X return(FALSE); X X alternatives = alternative_addresses; X X while (alternatives != NULL) { X if (in_string(address, alternatives->address)) X return(FALSE); X alternatives = alternatives->next; X } X X return(TRUE); X} X Xoptimize_and_add(new_address, full_address) Xchar *new_address, *full_address; X{ X /** This routine will add the new address to the list of addresses X in the full address buffer IFF it doesn't already occur. It X will also try to fix dumb hops if possible, specifically hops X of the form ...a!b...!a... and hops of the form a@b@b etc X **/ X X register int len, host_count = 0, i; X char hosts[MAX_HOPS][SLEN]; /* array of machine names */ X char *host, *addrptr; X X if (in_string(full_address, new_address)) X return(1); /* duplicate address */ X X /** optimize **/ X /* break down into a list of machine names, checking as we go along */ X X addrptr = (char *) new_address; X X while ((host = get_token(addrptr, "!", 1)) != NULL) { X for (i = 0; i < host_count && ! equal(hosts[i], host); i++) X ; X X if (i == host_count) { X strcpy(hosts[host_count++], host); X if (host_count == MAX_HOPS) { X dprint(2, (debugfile, X "Error: hit max_hops limit trying to build return address (%s)\n", X "optimize_and_add")); X error("Can't build return address. Hit MAX_HOPS limit!"); X return(1); X } X } X else X host_count = i + 1; X addrptr = NULL; X } X X /** fix the ARPA addresses, if needed **/ X X if (chloc(hosts[host_count-1], '@') > -1) X fix_arpa_address(hosts[host_count-1]); X X /** rebuild the address.. **/ X X new_address[0] = '\0'; X X for (i = 0; i < host_count; i++) X sprintf(new_address, "%s%s%s", new_address, X new_address[0] == '\0'? "" : "!", X hosts[i]); X X if (full_address[0] == '\0') X strcpy(full_address, new_address); X else { X len = strlen(full_address); X full_address[len ] = ','; X full_address[len+1] = ' '; X full_address[len+2] = '\0'; X strcat(full_address, new_address); X } X X return(0); X} X Xget_return_name(address, name, trans_to_lowercase) Xchar *address, *name; Xint trans_to_lowercase; X{ X /** Given the address (either a single address or a combined list X of addresses) extract the login name of the first person on X the list and return it as 'name'. Modified to stop at X any non-alphanumeric character. **/ X X /** An important note to remember is that it isn't vital that this X always returns just the login name, but rather that it always X returns the SAME name. If the persons' login happens to be, X for example, joe.richards, then it's arguable if the name X should be joe, or the full login. It's really immaterial, as X indicated before, so long as we ALWAYS return the same name! **/ X X /** Another note: modified to return the argument as all lowercase X always, unless trans_to_lowercase is FALSE... **/ X X char single_address[SLEN]; X register int i, loc, iindex = 0; X X dprint(6, (debugfile,"get_return_name called with (%s, <>, shift=%s)\n", X address, onoff(trans_to_lowercase))); X X /* First step - copy address up to a comma, space, or EOLN */ X X for (i=0; address[i] != ',' && ! whitespace(address[i]) && X address[i] != '\0'; i++) X single_address[i] = address[i]; X single_address[i] = '\0'; X X /* Now is it an ARPA address?? */ X X if ((loc = chloc(single_address, '@')) != -1) { /* Yes */ X X /* At this point the algorithm is to keep shifting our copy X window left until we hit a '!'. The login name is then X located between the '!' and the first metacharacter to X it's right (ie '%', ':' or '@'). */ X X for (i=loc; single_address[i] != '!' && i > -1; i--) X if (single_address[i] == '%' || X single_address[i] == ':' || X single_address[i] == '@') loc = i-1; X X if (i < 0 || single_address[i] == '!') i++; X X for (iindex = 0; iindex < loc - i + 1; iindex++) X if (trans_to_lowercase) X name[iindex] = tolower(single_address[iindex+i]); X else X name[iindex] = single_address[iindex+i]; X name[iindex] = '\0'; X } X else { /* easier - standard USENET address */ X X /* This really is easier - we just cruise left from the end of X the string until we hit either a '!' or the beginning of the X line. No sweat. */ X X loc = strlen(single_address)-1; /* last char */ X X for (i = loc; single_address[i] != '!' && single_address[i] != '.' X && i > -1; i--) X if (trans_to_lowercase) X name[iindex++] = tolower(single_address[i]); X else X name[iindex++] = single_address[i]; X name[iindex] = '\0'; X reverse(name); X } X} X Xint Xbreak_down_tolist(buf, iindex, address, comment) Xchar *buf, *address, *comment; Xint *iindex; X{ X /** This routine steps through "buf" and extracts a single address X entry. This entry can be of any of the following forms; X X address (name) X name
X address X X Once it's extracted a single entry, it will then return it as X two tokens, with 'name' (e.g. comment) surrounded by parens. X Returns ZERO if done with the string... X **/ X X char buffer[LONG_STRING]; X register int i, loc = 0, hold_index; X X if (*iindex > strlen(buf)) return(FALSE); X X while (whitespace(buf[*iindex])) (*iindex)++; X X if (*iindex > strlen(buf)) return(FALSE); X X /** Now we're pointing at the first character of the token! **/ X X hold_index = *iindex; X X while (buf[*iindex] != ',' && buf[*iindex] != '\0') X buffer[loc++] = buf[(*iindex)++]; X X (*iindex)++; X buffer[loc] = '\0'; X X while (whitespace(buffer[loc])) /* remove trailing whitespace */ X buffer[--loc] = '\0'; X X if (strlen(buffer) == 0) return(FALSE); X X dprint(5, (debugfile, "\n* got \"%s\"\n", buffer)); X X if (buffer[loc-1] == ')') { /* address (name) format */ X for (loc = 0;buffer[loc] != '(' && loc < strlen(buffer); loc++) X /* get to the opening comment character... */ ; X X loc--; /* back up to just before the paren */ X while (whitespace(buffer[loc])) loc--; /* back up */ X X /** get the address field... **/ X X for (i=0; i <= loc; i++) X address[i] = buffer[i]; X address[i] = '\0'; X X /** now get the comment field, en toto! **/ X X loc = 0; X X for (i = chloc(buffer, '('); i < strlen(buffer); i++) X comment[loc++] = buffer[i]; X comment[loc] = '\0'; X } X else if (buffer[loc-1] == '>') { /* name
format */ X dprint(7, (debugfile, "\tcomment
\n")); X for (loc = 0;buffer[loc] != '<' && loc < strlen(buffer); loc++) X /* get to the opening comment character... */ ; X while (whitespace(buffer[loc])) loc--; /* back up */ X X /** get the comment field... **/ X X comment[0] = '('; X for (i=1; i < loc; i++) X comment[i] = buffer[i-1]; X comment[i++] = ')'; X comment[i] = '\0'; X X /** now get the address field, en toto! **/ X X loc = 0; X X for (i = chloc(buffer,'<') + 1; i < strlen(buffer) - 1; i++) X address[loc++] = buffer[i]; X X address[loc] = '\0'; X } X else { X /** the next section is added so that all To: lines have commas X in them accordingly **/ X X for (i=0; buffer[i] != '\0'; i++) X if (whitespace(buffer[i])) break; X if (i < strlen(buffer)) { /* shouldn't be whitespace */ X buffer[i] = '\0'; X *iindex = hold_index + strlen(buffer) + 1; X } X strcpy(address, buffer); X comment[0] = '\0'; X } X X dprint(5, (debugfile, "-- returning '%s' '%s'\n", address, comment)); X X return(TRUE); X} SHAR_EOF chmod 0444 src/reply.c || echo "restore of src/reply.c fails" echo "x - extracting src/returnadd.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/returnadd.c && X Xstatic char rcsid[] = "@(#)$Id: returnadd.c,v 2.8 89/03/25 21:47:08 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.8 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: returnadd.c,v $ X * Revision 2.8 89/03/25 21:47:08 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This set of routines is used to generate real return addresses X and also return addresses suitable for inclusion in a users X alias files (ie optimized based on the pathalias database). X X**/ X X#include "headers.h" X X#include X X#include X#include X Xchar *shift_lower(); X Xextern int errno; X Xchar *error_name(), *strcat(), *strcpy(); X X#ifdef OPTIMIZE_RETURN X Xoptimize_return(address) Xchar *address; X{ X /** This routine tries to create an optimized address, that is, X an address that has the minimal information needed to X route a message to this person given the current path X database... X **/ X X#ifndef INTERNET X char bogus_internet[SLEN]; X X sprintf(bogus_internet, "@%s%s", hostname, hostdomain); X X /** first off, let's see if we need to strip off the localhost X address crap... **/ X X /** if we have a uucp part (e.g.a!b) AND the bogus address...**/ X X if (chloc(address,'!') != -1 && in_string(address, bogus_internet)) X address[strlen(address)-strlen(bogus_internet)] = '\0'; X#endif X X /** next step is to figure out what sort of address we have... **/ X X if (chloc(address, '%') != -1) X optimize_cmplx_arpa(address); X else if (chloc(address, '@') != -1) X optimize_arpa(address); X else X optimize_usenet(address); X} X Xoptimize_cmplx_arpa(address) Xchar *address; X{ X /** Try to optimize a complex ARPA address. A Complex address is one X that contains '%' (deferred '@'). For example: X veeger!hpcnof!hplabs!joe%sytech@syte X is a complex address (no kidding, right?). The algorithm for X trying to resolve it is to move all the way to the right, then X back up left until the first '!' then from there to the SECOND X metacharacter on the right is the name@host address...(in this X example, it would be "joe%sytech"). Check this in the routing X table. If not present, keep backing out to the right until we X find a host that is present, or we hit the '@' sign. Once we X have a 'normal' ARPA address, hand it to optimize_arpa(). X **/ X X char name[NLEN], buffer[SLEN], junk[SLEN]; X char host[NLEN], old_host[NLEN]; X register int i, loc, nloc = 0, hloc = 0, passes = 1; X X /** first off, get the name%host... **/ X X for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) X ; X X while (address[loc] != '\0') { X X if (passes == 1) { X loc++; X X while (address[loc] != '%' && address[loc] != '@') X name[nloc++] = address[loc++]; X } X else { X for (i=0; old_host[i] != '\0'; i++) X name[nloc++] = old_host[i]; X } X X loc++; X X while (address[loc] != '%' && address[loc] != '@') X host[hloc++] = address[loc++]; X X host[hloc] = name[nloc] = '\0'; X X strcpy(old_host, host); X X sprintf(buffer, "%s@%s", name, shift_lower(host)); X X if (expand_site(buffer, junk) == 0) { X strcpy(address, buffer); X return; X } X else if (address[loc] == '@') { X optimize_arpa(address); X return; X } X else X name[nloc++] = '%'; /* for next pass through */ X X } X} X Xoptimize_arpa(address) Xchar *address; X{ X /** Get an arpa address and simplify it to the minimal X route needed to get mail to this person... **/ X X char name[NLEN], buffer[SLEN], junk[SLEN]; X char host[NLEN]; X register int loc, nloc = 0, hloc = 0, at_sign = 0; X X for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) { X if (address[loc] == '@') X at_sign++; /* remember this spot! */ X else if (at_sign) X name[nloc++] = address[loc]; X else X host[hloc++] = address[loc]; X } X X name[nloc] = host[hloc] = '\0'; X X reverse(name); X reverse(host); X X sprintf(buffer,"%s@%s", name, shift_lower(host)); X X if (expand_site(buffer, junk) == 0) { X strcpy(address, buffer); X return; X } X X optimize_usenet(address); /* that didn't work... */ X} X Xoptimize_usenet(address) Xchar *address; X{ X /** optimize the return address IFF it's a standard usenet X address... X **/ X X char name[NLEN], new_address[SLEN], buffer[SLEN], junk[SLEN]; X register int loc, nloc = 0, aloc = 0, passes = 1; X X for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) X name[nloc++] = address[loc]; X name[nloc] = '\0'; X X reverse(name); X X new_address[0] = '\0'; X X /* got name, now get machine until we can get outta here */ X X while (loc > -1) { X X new_address[aloc++] = address[loc--]; /* the '!' char */ X X while (address[loc] != '!' && loc > -1) X new_address[aloc++] = address[loc--]; X X new_address[aloc] = '\0'; X X strcpy(buffer, new_address); X reverse(buffer); X X if (expand_site(buffer, junk) == 0) { X if (passes == 1 && chloc(name, '@') == -1) { X buffer[strlen(buffer) - 1] = '\0'; /* remove '!' */ X sprintf(address, "%s@%s", name, buffer); X } X else X sprintf(address, "%s%s", buffer, name); X return; /* success! */ X } X passes++; X } X X return; /* nothing to do! */ X} X X#endif /* OPTIMIZE_RETURN */ X Xget_return(buffer, msgnum) Xchar *buffer; Xint msgnum; X{ X /** reads msgnum message again, building up the full return X address including all machines that might have forwarded X the message. **/ X X char buf[SLEN], name1[SLEN], name2[SLEN], lastname[SLEN]; X char hold_return[SLEN], alt_name2[SLEN], *cptr; X int ok = 1, lines; X X /* now initialize all the char buffers [thanks Keith!] */ X X buf[0] = name1[0] = name2[0] = lastname[0] = '\0'; X hold_return[0] = alt_name2[0] = '\0'; X X /** get to the first line of the message desired **/ X X if(msgnum < 0 || msgnum >= message_count || message_count < 1) { X dprint(1, (debugfile, X "Error: %d not a valid message number message_count = %d (%s)", X msgnum, message_count, "get_return")); X error1("%d not a valid message number!"); X return; X } X X if (fseek(mailfile, headers[msgnum]->offset, 0) == -1) { X dprint(1, (debugfile, X "Error: seek %ld bytes into file hit errno %s (%s)", X headers[msgnum]->offset, error_name(errno), X "get_return")); X error2("Couldn't seek %d bytes into file (%s).", X headers[msgnum]->offset, error_name(errno)); X return; X } X X /** okay! Now we're there! **/ X X lines = headers[msgnum]->lines; X X buffer[0] = '\0'; X X while (ok && lines) { X ok = (int) (fgets(buf, SLEN, mailfile) != NULL); X if (ok) X if(buffer[strlen(buffer)-1] == '\n') lines--; /* got a full line */ X if (first_word(buf, "From ")) X sscanf(buf, "%*s %s", hold_return); X else if (first_word(buf, ">From")) { X sscanf(buf,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s %s", X name1, name2, alt_name2); X if (strcmp(name2, "from") == 0) /* remote from xyz */ X strcpy(name2, alt_name2); X else if (strcmp(name2, "by") == 0) /* forwarded by xyz */ X strcpy(name2, alt_name2); X add_site(buffer, name2, lastname); X } X X#ifdef USE_EMBEDDED_ADDRESSES X X else if (first_word(buf, "From:")) { X get_address_from("From:", buf, hold_return); X buffer[0] = '\0'; X } X else if (first_word(buf, "Reply-To:")) { X get_address_from("Reply-To:", buf, buffer); X return; X } X X#endif X X else if (strlen(buf) < 2) /* done with header */ X lines = 0; /* let's get outta here! We're done!!! */ X } X X if (buffer[0] == '\0') X strcpy(buffer, hold_return); /* default address! */ X else X add_site(buffer, name1, lastname); /* get the user name too! */ X X if ((ok = chloc(buffer, '!')) >= 0) X { X strcpy(buf, hostname); X strcat(buf, "!"); X if (strncmp(buf, buffer, strlen(buf)) == 0) /* strip off our node name */ X { X strcpy(buf, buffer); X strcpy(buffer, &buf[ok + 1]); X } X } X X if ((ok = chloc(buffer, '@')) >= 0) X { X sprintf(buf, "%s%s", hostname, hostdomain); X if (strcmp(&buffer[ok+1], buf) == 0 /* @host.dom */ X || strcmp(&buffer[ok+1], hostname) == 0) /* @host */ X buffer[ok] = '\0'; X } X X if (first_word(buffer, "To:")) /* response to savecopy! */ X get_existing_address(buffer,msgnum); X else X /* if we have a space character, or we DON'T have '!' or '@' chars */ X X if (chloc(headers[msgnum]->from, ' ') >= 0 || X (chloc(headers[msgnum]->from, '!') < 0 && X chloc(headers[msgnum]->from, '@') < 0)) { X sprintf(name2, " (%s)", headers[msgnum]->from); X strcat(buffer, name2); X } X} X Xget_existing_address(buffer, msgnum) Xchar *buffer; Xint msgnum; X{ X /** This routine is called when the message being responded to has X "To:xyz" as the return address, signifying that this message is X an automatically saved copy of a message previously sent. The X correct to address can be obtained fairly simply by reading the X To: header from the message itself and (blindly) copying it to X the given buffer. Note that this header can be either a normal X "To:" line (Elm) or "Originally-To:" (previous versions e.g.Msg) X **/ X X char mybuf[LONG_STRING]; X register char ok = 1, in_to = 0; X X buffer[0] = '\0'; X X /** first off, let's get to the beginning of the message... **/ X X if(msgnum < 0 || msgnum >= message_count || message_count < 1) { X dprint(1, (debugfile, X "Error: %d not a valid message number message_count = %d (%s)", X msgnum, message_count, "get_existing_address")); X error1("%d not a valid message number!"); X return; X } X if (fseek(mailfile, headers[msgnum]->offset, 0) == -1) { X dprint(1, (debugfile, X "Error: seek %ld bytes into file hit errno %s (%s)", X headers[msgnum]->offset, error_name(errno), X "get_existing_address")); X error2("Couldn't seek %d bytes into the file (%s).", X headers[msgnum]->offset, error_name(errno)); X return; X } X X /** okay! Now we're there! **/ X X while (ok) { X ok = (int) (fgets(mybuf, LONG_STRING, mailfile) != NULL); X no_ret(mybuf); /* remove return character */ X X if (first_word(mybuf, "To: ")) { X in_to = TRUE; X strcpy(buffer, (char *) mybuf + strlen("To: ")); X } X else if (first_word(mybuf, "Original-To:")) { X in_to = TRUE; X strcpy(buffer, (char *) mybuf + strlen("Original-To:")); X } X else if (in_to && whitespace(mybuf[0])) { X strcat(buffer, " "); /* tag a space in */ X strcat(buffer, (char *) mybuf + 1); /* skip 1 whitespace */ X } X else if (strlen(mybuf) < 2) X return; /* we're done for! */ X else X in_to = 0; X } X} SHAR_EOF chmod 0444 src/returnadd.c || echo "restore of src/returnadd.c fails" echo "x - extracting src/save_opts.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/save_opts.c && X Xstatic char rcsid[] = "@(#)$Id: save_opts.c,v 2.17 89/03/25 21:47:09 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.17 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* SHAR_EOF echo "End of part 19" echo "File src/save_opts.c is continued in part 20" echo "20" > s2_seq_.tmp exit 0