static char rcsid[] = "@(#)$Id: addr_util.c,v 1.6 1999/03/24 14:03:57 wfp5p Exp $"; /******************************************************************************* * The Elm Mail System - $Revision: 1.6 $ $State: Exp $ * * Copyright (c) 1988-1995 USENET Community Trust * Copyright (c) 1986,1987 Dave Taylor ******************************************************************************* * Bug reports, patches, comments, suggestions should be sent to: * * Bill Pemberton, Elm Coordinator * flash@virginia.edu * ******************************************************************************* * $Log: addr_util.c,v $ * Revision 1.6 1999/03/24 14:03:57 wfp5p * elm 2.5PL0 * * Revision 1.5 1996/05/09 15:51:14 wfp5p * Alpha 10 * * Revision 1.4 1996/03/14 17:27:49 wfp5p * Alpha 9 * * Revision 1.3 1995/09/29 17:41:56 wfp5p * Alpha 8 (Chip's big changes) * * Revision 1.2 1995/05/24 15:34:36 wfp5p * Change to deal with parenthesized comments in when eliminating members from * an alias. (from Keith Neufeld ) * * Allow a shell escape from the alias screen (just like from * the index screen). It does not put the shell escape onto the alias * screen menu. (from Keith Neufeld ) * * Allow the use of "T" from the builtin pager. (from Keith Neufeld * ) * * Revision 1.1.1.1 1995/04/19 20:38:34 wfp5p * Initial import of elm 2.4 PL0 as base for elm 2.5. * ******************************************************************************/ /** This file contains addressing utilities **/ #include "elm_defs.h" #include "elm_globals.h" #include "s_elm.h" translate_return(addr, ret_addr) char *addr, *ret_addr; { /** Return ret_addr to be the same as addr, but with the login of the person sending the message replaced by '%s' for future processing... Fixed to make "%xx" "%%xx" (dumb 'C' system!) **/ register int loc, loc2, iindex = 0; register char *remaining_addr; /* * check for RFC-822 source route: format @site:usr@site * if found, skip to after the first : and then retry. * source routes can be stacked */ remaining_addr = addr; while (*remaining_addr == '@') { loc = qchloc(remaining_addr, ':'); if (loc == -1) break; remaining_addr += loc + 1; } loc2 = qchloc(remaining_addr,'@'); loc = qchloc(remaining_addr, '%'); if ((loc < loc2) && (loc != -1)) loc2 = loc; if (loc2 != -1) { /* ARPA address. */ /* algorithm is to get to '@' sign and move backwards until we've hit the beginning of the word or another metachar. */ for (loc = loc2 - 1; loc > -1 && remaining_addr[loc] != '!'; loc--) ; } else { /* usenet address */ /* simple algorithm - find last '!' */ loc2 = strlen(remaining_addr); /* need it anyway! */ for (loc = loc2; loc > -1 && remaining_addr[loc] != '!'; loc--) ; } /** now copy up to 'loc' into destination... **/ while (iindex <= loc) { ret_addr[iindex] = remaining_addr[iindex]; iindex++; } /** now append the '%s'... **/ ret_addr[iindex++] = '%'; ret_addr[iindex++] = 's'; /* * and, finally, if anything left, add that * however, just pick up the address part, we do * not want any comments. Thus stop copying at * the first blank character. */ if ((loc = qchloc(remaining_addr,' ')) == -1) loc = strlen(addr); while (loc2 < loc) { ret_addr[iindex++] = remaining_addr[loc2++]; if (remaining_addr[loc2-1] == '%') /* tweak for "printf" */ ret_addr[iindex++] = '%'; } ret_addr[iindex] = '\0'; } int build_address(to, full_to) char *to, *full_to; { /** loop on all words in 'to' line...append to full_to as we go along, until done or length > len. Modified to know that stuff in parens are comments...Returns non-zero if it changed the information as it copied it across... **/ register int i, j, k, l, in_parens = 0, a_in_parens, expanded_information = 0, eliminated = 0; int too_long = FALSE; int to_len; char word[SLEN], next_word[SLEN], *ptr, buffer[SLEN]; char elim_list[SLEN], word_a[SLEN], next_word_a[SLEN]; char *gecos; full_to[0] = '\0'; to_len = 0; elim_list[0] = '\0'; i = get_word(to, 0, word, sizeof(word)); /** Look for addresses to be eliminated from aliases **/ while (i > 0) { j = get_word(to, i, next_word, sizeof(next_word)); if(word[0] == '(') in_parens++; if (in_parens) { if(word[strlen(word)-1] == ')') in_parens--; } else if (word[0] == '-') { for (k = 0; word[k] != '\0'; word[k] = word[k+1], k++); if (elim_list[0] != '\0') strcat(elim_list, " "); /* expand alias and eliminate all members */ if ((ptr = get_alias_address(word, TRUE, &too_long)) != NULL) { /* ignores overflow, like every bloody other place in elm */ strcat(elim_list, ptr); too_long = FALSE; } else strcat(elim_list, word); } if ((i = j) > 0) strcpy(word, next_word); } if (elim_list[0] != '\0') eliminated++; i = get_word(to, 0, word, sizeof(word)); while (i > 0) { j = get_word(to, i, next_word, sizeof(next_word)); try_new_word: if(word[0] == '(') in_parens++; if (in_parens) { if(word[strlen(word)-1] == ')') in_parens--; strcpy(full_to+to_len, " "); strcpy(full_to+to_len+1, word); to_len += strlen(word)+1; } else if (word[0] == '-') { ; /* huh??? I don't understand this (*FOO*) */ } else if (qstrpbrk(word,"!@:") != NULL) { if (to_len > 0) { (void) strcpy(full_to+to_len, ", "); to_len += 2; } (void) strcpy(full_to+to_len, word); to_len += strlen(word); } else if ((ptr = get_alias_address(word, TRUE, &too_long)) != NULL) { /** check aliases for addresses to be eliminated **/ if (eliminated) { k = get_word(strip_commas(ptr), 0, word_a, sizeof(word_a)); while (k > 0) { l = get_word(ptr, k, next_word_a, sizeof(next_word_a)); if (in_list(elim_list, word_a) == 0) { if (to_len > 0) { (void) strcpy(full_to+to_len, ", "); to_len += 2; } (void) strcpy(full_to+to_len, word_a); to_len += strlen(word_a); /** copy possible () comment **/ if (next_word_a[0] == '(') { a_in_parens = 0; while (l > 0) { if (to_len > 0) { (void) strcpy(full_to+to_len, " "); ++to_len; } (void) strcpy(full_to+to_len, next_word_a); to_len += strlen(next_word_a); if (next_word_a[0] == '(') ++a_in_parens; if (next_word_a[strlen(next_word_a)-1] == ')') --a_in_parens; l = get_word(ptr, l, next_word_a, sizeof(next_word_a)); if (! a_in_parens) break; } } } else { /** skip possible () comment **/ if (next_word_a[0] == '(') { a_in_parens = 0; while (l > 0) { if (next_word_a[0] == '(') ++a_in_parens; if (next_word_a[strlen(next_word_a)-1] == ')') --a_in_parens; l = get_word(ptr, l, next_word_a, sizeof(next_word_a)); if (! a_in_parens) break; } } } if ((k = l) > 0) strcpy(word_a, next_word_a); } } else { if (to_len > 0) { (void) strcpy(full_to+to_len, ", "); to_len += 2; } (void) strcpy(full_to+to_len, ptr); to_len += strlen(ptr); } expanded_information++; } else if (too_long) { /* * We don't do any real work here. But we need some * sort of test in this line of tests to make sure * that none of the other else's are tried if the * alias expansion failed because it was too long. */ dprint(2,(debugfile,"Overflowed alias expansion for %s\n", word)); } else if (word[0] != '\0') { if (to_len > 0) { (void) strcpy(full_to+to_len, ", "); to_len += 2; } if (valid_name(word)) { #if defined(INTERNET) & defined(USE_DOMAIN) sprintf(full_to+to_len, "%s@%s", word, host_fullname); to_len += strlen(word)+1+strlen(host_fullname); #else /* INTERNET and USE_DOMAIN */ (void) strcpy(full_to+to_len, word); to_len += strlen(word); #endif /* INTERNET and USE_DOMAIN */ if (next_word[0] != '(') if ((gecos = get_full_name(word)) != NULL && *gecos != '\0') { sprintf(full_to+to_len, " (%s)", gecos); to_len += strlen(gecos)+3; } } else { (void) strcpy(full_to+to_len, word); to_len += strlen(word); } } if((i = j) > 0) strcpy(word, next_word); } return( expanded_information > 0 ? 1 : 0 ); } forwarded(buffer, entry) char *buffer; struct header_rec *entry; { /** Change 'from' and date fields to reflect the ORIGINATOR of the message by iteratively parsing the >From fields... Modified to deal with headers that include the time zone of the originating machine... **/ char machine[SLEN], buff[SLEN], holding_from[SLEN]; int len; machine[0] = holding_from[0] = '\0'; sscanf(buffer, "%*s %s", holding_from); /* after skipping over From and address, process rest as date field */ while (!isspace(*buffer)) buffer++; /* skip From */ while (isspace(*buffer)) buffer++; while (*buffer) { len = len_next_part(buffer); if (len > 1) { buffer += len; } else { if (isspace(*buffer)) break; buffer++; } } while (isspace(*buffer)) buffer++; parse_arpa_date(buffer, entry); /* the following fix is to deal with ">From xyz ... forwarded by xyz" which occasionally shows up within AT&T. Thanks to Bill Carpenter for the fix! */ if (strcmp(machine, holding_from) == 0) machine[0] = '\0'; if (machine[0] == '\0') strcpy(buff, holding_from[0] ? holding_from : "anonymous"); else sprintf(buff,"%s!%s", machine, holding_from); strfcpy(entry->from, buff, STRING); } fix_arpa_address(address) char *address; { /** Given a pure ARPA address, try to make it reasonable. This means that if you have something of the form a@b@b make it a@b. If you have something like a%b%c%b@x make it a%b@x... **/ register int host_count = 0, i; char hosts[MAX_HOPS][LONG_STRING]; /* array of machine names */ char *host, *addrptr; extern char *get_token(); /* break down into a list of machine names, checking as we go along */ addrptr = (char *) address; while ((host = get_token(addrptr, "%@", 2)) != NULL) { for (i = 0; i < host_count && ! streq(hosts[i], host); i++) ; if (i == host_count) { strcpy(hosts[host_count++], host); if (host_count == MAX_HOPS) { dprint(2, (debugfile, "Can't build return address - hit MAX_HOPS in fix_arpa_address\n")); error(catgets(elm_msg_cat, ElmSet, ElmCantBuildRetAddr, "Can't build return address - hit MAX_HOPS limit!")); return(1); } } else host_count = i + 1; addrptr = NULL; } /** rebuild the address.. **/ address[0] = '\0'; for (i = 0; i < host_count; i++) sprintf(address, "%s%s%s", address, address[0] == '\0'? "" : (i == host_count - 1 ? "@" : "%"), hosts[i]); return(0); }