sources-request@mirror.TMC.COM (05/01/87)
Submitted by: rs (Rich Salz) Mod.sources: Volume 9, Issue 64 Archive-name: elm2/Patch2 [ Sorry about the delay on this one -- I had to dig it out of a tape library... --r$ ] #! /bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # If this archive is complete, you will see the message: # "End of shell archive." # Contents: reply.c # Wrapped by rs@mirror on Thu Apr 30 16:55:12 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo shar: Extracting \"reply.c\" \(13964 characters\) if test -f reply.c ; then echo shar: Will not over-write existing file \"reply.c\" else sed "s/^X//" >reply.c <<'END_OF_reply.c' X/** reply.c **/ X X/*** routine allows replying to the sender of the current message X X (C) Copyright 1985, Dave Taylor X***/ X X#include "headers.h" X#include <errno.h> X X#ifndef BSD X# include <sys/types.h> X# include <sys/utsname.h> 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[LONG_SLEN], subject[SLEN]; X int return_value, form_letter; X X form_letter = (header_table[current-1].status & FORM_LETTER); X X get_return(return_address); X X if (first_word(header_table[current-1].from, "To:")) { X strcpy(subject, header_table[current-1].subject); X if (form_letter) X return_value = mail_filled_in_form(return_address, subject); X else X return_value = send(return_address, subject, TRUE, NO); X } X else if (header_table[current-1].subject[0] != '\0') { X if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) || X (strncmp("RE:", header_table[current-1].subject, 3) == 0) || X (strncmp("re:", header_table[current-1].subject, 3) == 0)) X strcpy(subject, header_table[current-1].subject); X else { X strcpy(subject,"Re: "); X strcat(subject,header_table[current-1].subject); X } X if (form_letter) X return_value = mail_filled_in_form(return_address, subject); X else X return_value = send(return_address, subject, TRUE, NO); 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 = send(return_address, "Re: your mail", TRUE, NO); 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[LONG_SLEN], subject[SLEN]; X char full_address[VERY_LONG_STRING]; X int return_value; X X get_return(return_address); X X strcpy(full_address, return_address); /* sender gets copy */ X X get_and_expand_everyone(return_address, full_address); X X if (header_table[current-1].subject[0] != '\0') { X if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) || X (strncmp("RE:", header_table[current-1].subject, 3) == 0) || X (strncmp("re:", header_table[current-1].subject, 3) == 0)) X strcpy(subject, header_table[current-1].subject); X else { X strcpy(subject,"Re: "); X strcat(subject,header_table[current-1].subject); X } X return_value = send(full_address, subject, TRUE, NO); X } X else X return_value = send(full_address, "Re: your mail", TRUE, NO); X X return(return_value); X X} X Xint Xforward() X{ X /** Forward the current message. What this actually does is X to set auto_copy to true, then call 'send' to get the X address and route the mail. X **/ X X char subject[SLEN], address[VERY_LONG_STRING]; X int original_cc, results, edit_msg = FALSE; X X original_cc = auto_copy; X address[0] = '\0'; X X if (header_table[current-1].status & FORM_LETTER) X PutLine0(LINES-3,COLUMNS-40,"<no editing allowed>"); X else { X edit_msg = (want_to("Edit outgoing message (y/n) ? ",'y',FALSE)!='n'); X Write_to_screen("%s", 1, edit_msg? "Yes" : "No"); X } X X auto_cc = TRUE; /* we want a copy */ X X if (strlen(header_table[current-1].subject) > 0) { X strcpy(subject,header_table[current-1].subject); X results = send(address, subject, edit_msg, X header_table[current-1].status & FORM_LETTER? X PREFORMATTED : allow_forms); X } X else X results = send(address, "Forwarded Mail...", edit_msg, X header_table[current-1].status & FORM_LETTER? X PREFORMATTED : allow_forms); X X auto_copy = original_cc; 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[LONG_SLEN], buf[LONG_SLEN], new_address[LONG_SLEN], X address[LONG_SLEN], comment[LONG_SLEN]; X int in_message = 1, first_pass = 0, index; X X /** First off, get to the first line of the message desired **/ X X if (fseek(mailfile, header_table[current-1].offset, 0) == -1) { X dprint3(1,"Error: seek %ld resulted in errno %s (%s)\n", X header_table[current-1].offset, error_name(errno), X "get_and_expand_everyone"); X error2("ELM [seek] couldn't read %d bytes into file (%s)", X header_table[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 in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL); 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 <address>". 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 index = chloc(buf, ':')+1; /* skip header field */ X else X index = 0; /* skip whitespace */ X X while (break_down_tolist(buf, &index, 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, LONG_SLEN, mailfile) != NULL); X X if (in_message) dprint1(1,"> %s", buf); X X } while (in_message && whitespace(buf[0])); X 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 dprint1(2, 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, shift_lower) Xchar *address, *name; Xint shift_lower; 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 shift_lower is FALSE... **/ X X char single_address[LONG_SLEN]; X register int i, loc, index = 0; X X dprint2(6,"get_return_name called with (%s, <>, shift=%s)\n", X address, onoff(shift_lower)); 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] == '.' || /* no domains */ X single_address[i] == '@') loc = i-1; X X if (i < 0 || single_address[i] == '!') i++; X X for (index = 0; index < loc - i + 1; index++) X if (shift_lower) X name[index] = tolower(single_address[index+i]); X else X name[index] = single_address[index+i]; X name[index] = '\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 (shift_lower) X name[index++] = tolower(single_address[i]); X else X name[index++] = single_address[i]; X name[index] = '\0'; X reverse(name); X } X} X Xint Xbreak_down_tolist(buf, index, address, comment) Xchar *buf, *address, *comment; Xint *index; 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 <address> 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; X X if (*index > strlen(buf)) return(FALSE); X X while (whitespace(buf[*index])) (*index)++; X X if (*index > strlen(buf)) return(FALSE); X X /** Now we're pointing at the first character of the token! **/ X X while (buf[*index] != ',' && buf[*index] != '\0') X buffer[loc++] = buf[(*index)++]; X X (*index)++; X X while (whitespace(buffer[loc])) loc--; /* remove trailing whitespace */ X X buffer[loc] = '\0'; X X if (strlen(buffer) == 0) return(FALSE); X X dprint1(5, "\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 <address> format */ X dprint0(7, "\tcomment <address>\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 strcpy(address, buffer); X comment[0] = '\0'; X } X X dprint2(5,"-- returning '%s' '%s'\n", address, comment); X X return(TRUE); X} END_OF_reply.c if test 13964 -ne `wc -c <reply.c`; then echo shar: \"reply.c\" unpacked with wrong size!? fi # end of overwriting check fi echo shar: End of shell archive. exit 0