rsalz@bbn.com (Rich Salz) (05/31/90)
Submitted-by: Syd Weinstein <syd@dsinc.dsi.com> Posting-number: Volume 22, Issue 70 Archive-name: elm2.3/part11 ---- Cut Here and unpack ---- #!/bin/sh # this is part 11 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/addr_util.c continued # CurArch=11 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/addr_util.c" sed 's/^X//' << 'SHAR_EOF' >> src/addr_util.c X X if(can_access(fullnamefile, READ_ACCESS) != 0) X return(NULL); /* fullname file not accessible to user */ X if((fp = fopen(fullnamefile, "r")) == NULL) X return(NULL); /* fullname file cannot be opened! */ X if(fgets(fullname, SLEN, fp) == NULL) { X fclose(fp); X return(NULL); /* fullname file empty! */ X } X fclose(fp); X no_ret(fullname); /* remove trailing '\n' */ X#endif X return(fullname); X} X Xint Xtalk_to(sitename) Xchar *sitename; X{ X /** If we talk to the specified site, return true, else X we're going to have to expand this baby out, so X return false! **/ X X struct lsys_rec *sysname; X X sysname = talk_to_sys; X X if (sysname == NULL) { X dprint(2, (debugfile, X "Warning: talk_to_sys is currently set to NULL!\n")); X return(0); X } X X while (sysname != NULL) { X if (strcmp(sysname->name, sitename) == 0) X return(1); X else X sysname = sysname->next; X } X X return(0); X} X Xadd_site(buffer, site, lastsite) Xchar *buffer, *site, *lastsite; X{ X /** add site to buffer, unless site is 'uucp' or site is X the same as lastsite. If not, set lastsite to site. X **/ X X char local_buffer[SLEN], *stripped; X char *strip_parens(); X X stripped = strip_parens(site); X X if (strcmp(stripped, "uucp") != 0) X if (strcmp(stripped, lastsite) != 0) { X if (buffer[0] == '\0') X strcpy(buffer, stripped); /* first in list! */ X else { X sprintf(local_buffer,"%s!%s", buffer, stripped); X strcpy(buffer, local_buffer); X } X strcpy(lastsite, stripped); /* don't want THIS twice! */ X } X} X X#ifdef USE_EMBEDDED_ADDRESSES X Xget_address_from(prefix, line, buffer) Xchar *prefix, *line, *buffer; X{ X /** This routine extracts the address from either a 'From:' line X or a 'Reply-To:' line. The strategy is as follows: if the X line contains a '<', then the stuff enclosed is returned. X Otherwise we go through the line and strip out comments X and return that. White space will be elided from the result. X **/ X X register char *s; X X /** Skip start of line over prefix, e.g. "From:". **/ X line += strlen(prefix); X X /** If there is a '<' then copy from it to '>' into the buffer. **/ X if ( (s = index(line,'<')) != NULL ) { X while ( ++s , *s != '\0' && *s != '>' ) { X if ( !isspace(*s) ) X *buffer++ = *s; X } X *buffer = '\0'; X return; X } X X /** Otherwise, strip comments and get address with whitespace elided. **/ X for ( s = strip_parens(line) ; *s != '\0' ; ++s ) { X if ( !isspace(*s) ) X *buffer++ = *s; X } X *buffer = '\0'; X X} X X#endif X Xtranslate_return(addr, ret_addr) Xchar *addr, *ret_addr; X{ X /** Return ret_addr to be the same as addr, but with the login X of the person sending the message replaced by '%s' for X future processing... X Fixed to make "%xx" "%%xx" (dumb 'C' system!) X **/ X X register int loc, loc2, iindex = 0; X X loc2 = chloc(addr,'@'); X if ((loc = chloc(addr, '%')) < loc2) X loc2 = loc; X X if (loc2 != -1) { /* ARPA address. */ X /* algorithm is to get to '@' sign and move backwards until X we've hit the beginning of the word or another metachar. X */ X for (loc = loc2 - 1; loc > -1 && addr[loc] != '!'; loc--) X ; X } X else { /* usenet address */ X /* simple algorithm - find last '!' */ X X loc2 = strlen(addr); /* need it anyway! */ X X for (loc = loc2; loc > -1 && addr[loc] != '!'; loc--) X ; X } X X /** now copy up to 'loc' into destination... **/ X X while (iindex <= loc) { X ret_addr[iindex] = addr[iindex]; X iindex++; X } X X /** now append the '%s'... **/ X X ret_addr[iindex++] = '%'; X ret_addr[iindex++] = 's'; X X /** and, finally, if anything left, add that **/ X X loc = strlen(addr); X while (loc2 < loc) { X ret_addr[iindex++] = addr[loc2++]; X if (addr[loc2-1] == '%') /* tweak for "printf" */ X ret_addr[iindex++] = '%'; X } X X ret_addr[iindex] = '\0'; X} X Xint Xbuild_address(to, full_to) Xchar *to, *full_to; X{ X /** loop on all words in 'to' line...append to full_to as X we go along, until done or length > len. Modified to X know that stuff in parens are comments...Returns non-zero X if it changed the information as it copied it across... X **/ X X register int i, j, changed = 0, in_parens = 0, expanded_information = 0; X char word[SLEN], next_word[SLEN], *ptr, buffer[SLEN]; X char new_to_list[SLEN]; X char *strpbrk(), *strcat(), *gecos; X#ifndef DONT_TOUCH_ADDRESSES X char *expand_system(); X#endif X X new_to_list[0] = '\0'; X X i = get_word(to, 0, word); X X full_to[0] = '\0'; X X while (i > 0) { X X j = get_word(to, i, next_word); X Xtry_new_word: X if(word[0] == '(') X in_parens++; X X if (in_parens) { X if(word[strlen(word)-1] == ')') X in_parens--; X strcat(full_to, " "); X strcat(full_to, word); X } X else if (strpbrk(word,"!@:") != NULL) { X#ifdef DONT_TOUCH_ADDRESSES X sprintf(full_to, "%s%s%s", full_to, X full_to[0] != '\0'? ", " : "", word); X#else X sprintf(full_to, "%s%s%s", full_to, X full_to[0] != '\0'? ", " : "", expand_system(word, 1)); X#endif X } X else if ((ptr = get_alias_address(word, TRUE)) != NULL) { X sprintf(full_to, "%s%s%s", full_to, X full_to[0] != '\0'? ", " : "", ptr); X expanded_information++; X } X else if (strlen(word) > 0) { X if (valid_name(word)) { X if (j > 0 && next_word[0] == '(') /* already has full name */ X gecos = NULL; X else /* needs a full name */ X gecos=get_full_name(word); X#if defined(INTERNET) & defined(USE_DOMAIN) X sprintf(full_to, "%s%s%s@%s%s%s%s", X full_to, X (full_to[0] != '\0'? ", " : ""), X word, X hostfullname, X (gecos ? " (" : ""), X (gecos ? gecos : ""), X (gecos ? ")" : "")); X#else /* INTERNET and USE_DOMAIN */ X sprintf(full_to, "%s%s%s%s%s%s", X full_to, X (full_to[0] != '\0'? ", " : ""), X word, X (gecos ? " (" : ""), X (gecos ? gecos : ""), X (gecos ? ")" : "")); X#endif /* INTERNET and USE_DOMAIN */ X } else if (check_only) { X printf("(alias \"%s\" is unknown)\n\r", word); X changed++; X } X else if (! isatty(fileno(stdin)) ) { /* batch mode error! */ X fprintf(stderr,"Cannot expand alias '%s'!\n\r", word); X fprintf(stderr,"Use \"checkalias\" to find valid addresses!\n\r"); X dprint(1, (debugfile, X "Can't expand alias %s - bailing out of build_address\n", X word)); X leave(0); X } X else { X dprint(2,(debugfile,"Entered unknown address %s\n", word)); X sprintf(buffer, "'%s' is an unknown address. Replace with: ", X word); X word[0] = '\0'; X changed++; X X PutLine0(LINES, 0, buffer); X X (void)optionally_enter(word, LINES, strlen(buffer), FALSE, FALSE); X clear_error(); X if (strlen(word) > 0) { X dprint(3,(debugfile, "Replaced with %s in build_address\n", X word)); X goto try_new_word; X } X else X dprint(3,(debugfile, X "Address removed from TO list by build_address\n")); X continue; X } X } X X /* and this word to the new to list */ X if(*new_to_list != '\0') X strcat(new_to_list, " "); X strcat(new_to_list, word); X X if((i = j) > 0) X strcpy(word, next_word); X } X X /* if new to list is different from original, update original */ X if (changed) X strcpy(to, new_to_list); X X return( expanded_information > 0 ? 1 : 0 ); X} X Xint Xreal_from(buffer, entry) Xchar *buffer; Xstruct header_rec *entry; X{ X /***** Returns true iff 's' has the seven 'from' fields, (or X 8 - some machines include the TIME ZONE!!!) X Initialize the date and from entries in the record X and also the message received date/time if 'entry' X is not NULL. *****/ X X struct header_rec temp_rec, *rec_ptr; X char junk[STRING], timebuff[STRING], holding_from[SLEN], hold_tz[12]; X char mybuf[BUFSIZ], *p, *q; X int eight_fields = 0; X int mday, month, year, minutes, seconds, tz, i; X long gmttime; X X /* set rec_ptr according to whether the data is to be returned X * in the second argument */ X rec_ptr = (entry == NULL ? &temp_rec : entry); X X rec_ptr->year[0] = '\0'; X timebuff[0] = '\0'; X junk[0] = '\0'; X hold_tz[0] = '\0'; X X /* From <user> <day> <month> <day> <hr:min:sec> <year> */ X X sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %s", timebuff, junk); X X if (strlen(timebuff) < 3) { X dprint(3,(debugfile, X "Real_from returns FAIL [no time field] on\n-> %s\n", X buffer)); X return(FALSE); X } X X if (timebuff[1] != ':' && timebuff[2] != ':') { X dprint(3,(debugfile, X "Real_from returns FAIL [bad time field] on\n-> %s\n", X buffer)); X return(FALSE); X } X if (junk[0] != '\0') { /* try for 8 field entry */ X junk[0] = '\0'; X sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %*s %s", timebuff, junk); X if (junk[0] != '\0') { X dprint(3, (debugfile, X "Real_from returns FAIL [too many fields] on\n-> %s\n", X buffer)); X return(FALSE); X } X eight_fields++; X } X X /** now get the info out of the record! **/ X X if (eight_fields) X sscanf(buffer, "%s %s %s %s %s %s %s %s", X junk, holding_from, rec_ptr->dayname, rec_ptr->month, X rec_ptr->day, rec_ptr->time, hold_tz, rec_ptr->year); X else X sscanf(buffer, "%s %s %s %s %s %s %s", X junk, holding_from, rec_ptr->dayname, rec_ptr->month, X rec_ptr->day, rec_ptr->time, rec_ptr->year); X X strncpy(rec_ptr->from, holding_from, STRING-1); X rec_ptr->from[STRING-1] = '\0'; X resolve_received(rec_ptr); X X /* first get everything into lower case */ X for (p=mybuf, q=mybuf+sizeof mybuf; X *buffer && p<q; X p++, buffer++) { X *p = isupper(*buffer) ? tolower(*buffer) : *buffer; X } X *p = 0; X p = mybuf; X while (!isspace(*p)) p++; /* skip "from" */ X SKIP_WS(p); X while (!isspace(*p)) p++; /* skip from address */ X SKIP_WS(p); X while (!isspace(*p)) p++; /* skip day of week */ X SKIP_WS(p); X month = prefix(month_name, p); X get_unix_date(p,&year, &mday, &minutes, &seconds, &tz); X month_len[1] = (year%4) ? 28 : 29; X if (mday < 0 || mday>month_len[month]) { X dprint(5,(debugfile, "ridiculous day %d of month %d\n",mday,month)); X } X X minutes -= tz; X if (tz > 0) { /* east of Greenwich */ X if (minutes < 0) { X if (--mday < 0) { X if (--month < 0) { X year--; /* don't worry about 1900! */ X month = 11; X } X mday = month_len[month]; X } X minutes += 24*60; X } X } X if (tz < 0) { /* west of Greenwich */ X if (minutes <= 24*60) { X if (++mday > month_len[month]) { X if (++month >= 12) { X year++; /* don't worry about 1999! yet?? */ X month = 0; X } X mday = 0; X } X minutes -= 24*60; X } X } X gmttime = year - 70; /* make base year */ X if (gmttime < 0) X gmttime += 100; X gmttime = gmttime * 365 + (gmttime + 1) / 4; /* now we have days adjusted for leap years */ X for (i = 0; i < month; i++) X gmttime += month_len[i]; X if (month > 1 && (year % 4) == 0) X gmttime++; /* now to month adjusted for leap year if after feb */ X gmttime += mday - 1; /* and now to the day */ X gmttime *= 24 * 60; /* convert to minutes */ X gmttime += minutes; X rec_ptr->time_sent = gmttime * 60; /* now unix seconds since 1/1/70 00:00 GMT */ X X return(rec_ptr->year[0] != '\0'); X} X Xforwarded(buffer, entry) Xchar *buffer; Xstruct header_rec *entry; X{ X /** Change 'from' and date fields to reflect the ORIGINATOR of X the message by iteratively parsing the >From fields... X Modified to deal with headers that include the time zone X of the originating machine... **/ X X char machine[SLEN], buff[SLEN], holding_from[SLEN]; X X machine[0] = holding_from[0] = '\0'; X X sscanf(buffer, "%*s %s %s %s %s %s %s %*s %*s %s", X holding_from, entry->dayname, entry->month, X entry->day, entry->time, entry->year, machine); X X if (isdigit(entry->month[0])) { /* try for veeger address */ X sscanf(buffer, "%*s %s %s%*c %s %s %s %s %*s %*s %s", X holding_from, entry->dayname, entry->day, entry->month, X entry->year, entry->time, machine); X } X if (isalpha(entry->year[0])) { /* try for address including tz */ X sscanf(buffer, "%*s %s %s %s %s %s %*s %s %*s %*s %s", X holding_from, entry->dayname, entry->month, X entry->day, entry->time, entry->year, machine); X } X X /* the following fix is to deal with ">From xyz ... forwarded by xyz" X which occasionally shows up within AT&T. Thanks to Bill Carpenter X for the fix! */ X X if (strcmp(machine, holding_from) == 0) X machine[0] = '\0'; X X if (machine[0] == '\0') X strcpy(buff, holding_from[0] ? holding_from : "anonymous"); X else X sprintf(buff,"%s!%s", machine, holding_from); X X strncpy(entry->from, buff, STRING-1); X entry->from[STRING-1] = '\0'; X} X Xparse_arpa_who(buffer, newfrom, is_really_a_to) Xchar *buffer, *newfrom; Xint is_really_a_to; X{ X /** try to parse the 'From:' line given... It can be in one of X two formats: X From: Dave Taylor <hplabs!dat> X or From: hplabs!dat (Dave Taylor) X X Added: removes quotes if name is quoted (12/12) X Added: only copies STRING characters... X Added: if no comment part, copy address instead! X Added: if is_really_a_to, this is really a 'to' line X and treat as if we allow embedded addresses X **/ X X int use_embedded_addresses; X char temp_buffer[SLEN], *temp; X register int i, j = 0, in_parens; X X temp = (char *) temp_buffer; X temp[0] = '\0'; X X no_ret(buffer); /* blow away '\n' char! */ X X if (lastch(buffer) == '>') { X for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' && X buffer[i] != '('; i++) X temp[j++] = buffer[i]; X temp[j] = '\0'; X } X else if (lastch(buffer) == ')') { X in_parens = 1; X for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '<'; i--) { X switch(buffer[i]) { X case ')': in_parens++; X break; X case '(': in_parens--; X break; X } X if(!in_parens) break; X temp[j++] = buffer[i]; X } X temp[j] = '\0'; X reverse(temp); X } X X#ifdef USE_EMBEDDED_ADDRESSES X use_embedded_addresses = TRUE; X#else X use_embedded_addresses = FALSE; X#endif X X if(use_embedded_addresses || is_really_a_to) { X /** if we have a null string at this point, we must just have a X From: line that contains an address only. At this point we X can have one of a few possibilities... X X From: address X From: <address> X From: address () X **/ X X if (strlen(temp) == 0) { X if (lastch(buffer) != '>') { X for (i=strlen("From:");buffer[i] != '\0' && buffer[i] != '('; i++) X temp[j++] = buffer[i]; X temp[j] = '\0'; X } X else { /* get outta '<>' pair, please! */ X for (i=strlen(buffer)-2;buffer[i] != '<' && buffer[i] != ':';i--) X temp[j++] = buffer[i]; X temp[j] = '\0'; X reverse(temp); X } X } X } X X if (strlen(temp) > 0) { /* mess with buffer... */ X X /* remove leading spaces and quotes... */ X X while (whitespace(temp[0]) || quote(temp[0])) X temp = (char *) (temp + 1); /* increment address! */ X X /* remove trailing spaces and quotes... */ X X i = strlen(temp) - 1; X X while (whitespace(temp[i]) || quote(temp[i])) X temp[i--] = '\0'; X X /* if anything is left, let's change 'from' value! */ X X if (strlen(temp) > 0) { X strncpy(newfrom, temp, STRING-1); X newfrom[STRING-1] = '\0'; X } X } X} X X/* XQuoting from RFC 822: X 5. DATE AND TIME SPECIFICATION X X 5.1. SYNTAX X X date-time = [ day "," ] date time ; dd mm yy X ; hh:mm:ss zzz X X day = "Mon" / "Tue" / "Wed" / "Thu" X / "Fri" / "Sat" / "Sun" X X date = 1*2DIGIT month 2DIGIT ; day month year X ; e.g. 20 Jun 82 X X month = "Jan" / "Feb" / "Mar" / "Apr" X / "May" / "Jun" / "Jul" / "Aug" X / "Sep" / "Oct" / "Nov" / "Dec" X X time = hour zone ; ANSI and Military X X hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] X ; 00:00:00 - 23:59:59 X X zone = "UT" / "GMT" ; Universal Time X ; North American : UT X / "EST" / "EDT" ; Eastern: - 5/ - 4 X / "CST" / "CDT" ; Central: - 6/ - 5 X / "MST" / "MDT" ; Mountain: - 7/ - 6 X / "PST" / "PDT" ; Pacific: - 8/ - 7 X / 1ALPHA ; Military: Z = UT; X ; A:-1; (J not used) X ; M:-12; N:+1; Y:+12 X / ( ("+" / "-") 4DIGIT ) ; Local differential X ; hours+min. (HHMM) X*/ X X/* Translate a symbolic timezone name (e.g. EDT or NZST) to a number of X * minutes *east* of gmt (if the local time is t, the gmt equivalent is X * t - tz_lookup(zone)). X * Return 0 if the timezone is not recognized. X */ Xstatic int tz_lookup(str) Xchar *str; X{ X struct tzone *p; X X for (p = tzone_info; p->str; p++) { X if (strcmp(p->str,str)==0) return p->offset; X } X dprint(5,(debugfile,"unknown time zone %s\n",str)); X return 0; X} X X/* Return smallest i such that table[i] is a prefix of str. Return -1 if not X * found. X */ Xstatic int prefix(table, str) Xchar **table; Xchar *str; X{ X int i; X X for (i=0;table[i];i++) X if (strncmp(table[i],str,strlen(*table))==0) X return i; X return -1; X} X X/* The following routines, get_XXX(p,...), expect p to point to a string X * of the appropriate syntax. They return decoded values in result parameters, X * and return p updated to point past the parsed substring (also stripping X * trailing whitespace). X * Return 0 on syntax errors. X */ X X/* Parse a year: ['1' '9'] digit digit WS X */ Xstatic char * Xget_year(p, result) Xchar *p; Xint *result; X{ X int year; X X if (!isdigit(*p)) { X dprint(5,(debugfile,"missing year: %s\n",p)); X return 0; X } X year = atoi(p); X /* be nice and allow 19xx, althought that's not really kosher */ X if (year>=1900 && year <=1999) year -= 1900; X if (year<0 || year>99) { X dprint(5,(debugfile,"ridiculous year %d\n",year)); X return 0; X } X SKIP_DIGITS(p); X SKIP_WS(p); X *result = year; X return p; X} X X/* Parse a time: hours ':' minutes [ ':' seconds ] WS X * Check that 0<=hours<24, 0<=minutes,seconds<60. X * Also allow the syntax "digit digit digit digit" with implied ':' in the X * middle. X * Convert to minutes and seconds, with results in (*m,*s). X */ Xstatic char * Xget_time(p,m,s) Xchar *p; Xint *m, *s; X{ X int hours, minutes, seconds; X X /* hour */ X if (!isdigit(*p)) { X dprint(5,(debugfile,"missing time: %s\n",p)); X return 0; X } X hours = atoi(p); X SKIP_DIGITS(p); X if (*p++ != ':') { X /* perhaps they just wrote hhmm instead of hh:mm */ X minutes = hours % 60; X hours /= 60; X } X else { X if (hours<0 || hours>23) { X dprint(5,(debugfile,"ridiculous hour: %d\n",hours)); X return 0; X } X minutes = atoi(p); X if (minutes<0 || minutes>59) { X dprint(5,(debugfile,"ridiculous minutes: %d\n",minutes)); X return 0; X } X } X SKIP_DIGITS(p); X if (*p == ':') { X p++; X seconds = atoi(p); X if (seconds<0 || seconds>59) { X dprint(5,(debugfile,"ridiculous seconds: %d\n",seconds)); X return 0; X } X SKIP_DIGITS(p); X } X else seconds = 0; X minutes += hours*60; X SKIP_WS(p); X *m = minutes; X *s = seconds; X return p; X} X X/* Parse a Unix date from which the leading week-day has been stripped. X * The syntax is "Jun 21 06:45:44 CDT 1989" with timezone optional. X * i.e., month day time [ zone ] year X * where day::=digit*, year and time are as defined above, X * and month and zone are alpha strings starting with a known 3-char prefix. X * The month has already been processed by the caller, so we just skip over X * a leading alpha* WS. X * X * Unlike the preceding routines, the result is not an updated pointer, but X * simply 1 for success and 0 for failure. X */ Xstatic int Xget_unix_date(p,y,d,m,s,t) Xchar *p; Xint *y, *d, *m, *s, *t; X{ X X SKIP_ALPHA(p); X SKIP_WS(p); X if (!isdigit(*p)) return 0; X *d = atoi(p); /* check the value for sanity after we know the month */ X SKIP_DIGITS(p); X SKIP_WS(p); X p = get_time(p,m,s); X if (!p) return 0; X if (isalpha(*p)) { X *t = tz_lookup(p); X SKIP_ALPHA(p); X SKIP_WS(p); X } X else *t = 0; X p = get_year(p,y); X if (!p) return 0; X return 1; X} X X X/* Parse an rfc822 (with extensions) date. Return 1 on success, 0 on failure. X */ Xparse_arpa_date(string, entry) Xchar *string; Xstruct header_rec *entry; X{ X char buffer[BUFSIZ], *p, *q; X int mday, month, year, minutes, seconds, tz, i; X long gmttime; X X /* first get everything into lower case */ X for (p=buffer, q=buffer+sizeof buffer; *string && p<q; p++, string++) { X *p = isupper(*string) ? tolower(*string) : *string; X } X *p = 0; X p = buffer; X SKIP_WS(p); X X if (prefix(day_name,p)>=0) { X /* accept anything that *starts* with a valid day name */ X /* also, don't check whether it's right! */ X X (void)strncpy(entry->dayname, p, 3); X entry->dayname[3] = 0; X SKIP_ALPHA(p); X SKIP_WS(p); X X if (*p==',') { X p++; X SKIP_WS(p); X } X /* A comma is required here, but we'll be nice guys and look the other X * way if it's missing. X */ X } X X /* date */ X X /* day of the month */ X if (!isdigit(*p)) { X /* Missing day. Maybe this is a Unix date? X */ X month = prefix(month_name,p); X if (month >= 0 && X get_unix_date(p, &year, &mday, &minutes, &seconds, &tz)) { X goto got_date; X } X dprint(5,(debugfile,"missing day: %s\n",p)); X return 0; X } X mday = atoi(p); /* check the value for sanity after we know the month */ X SKIP_DIGITS(p); X SKIP_WS(p); X X /* month name */ X month = prefix(month_name,p); X if (month < 0) { X dprint(5,(debugfile,"missing month: %s\n",p)); X return 0; X } X SKIP_ALPHA(p); X SKIP_WS(p); X X /* year */ X if (!(p = get_year(p,&year))) return 0; X X /* time */ X if (!(p = get_time(p,&minutes,&seconds))) return 0; X X /* zone */ X for (q=p; *q && !isspace(*q); q++) continue; X *q = 0; X if (*p=='-' || *p=='+') { X char sign = *p++; X X if (isdigit(*p)) { X for (i=0; i<4; i++) { X if (!isdigit(p[i])) { X dprint(5,(debugfile,"ridiculous numeric timezone: %s\n",p)); X return 0; X } X p[i] -= '0'; X } X tz = (p[0]*10 + p[1])*60 + p[2]*10 + p[3]; X if (sign=='-') tz = -tz; X sprintf(entry->time_zone, "%d", tz); X } X else { X /* some brain-damaged dates use a '-' before a symbolic time zone */ X SKIP_WS(p); X strncpy(entry->time_zone, p, sizeof(entry->time_zone) - 1); X tz = tz_lookup(p); X } X } X else { X tz = tz_lookup(p); X strncpy(entry->time_zone, p, sizeof(entry->time_zone) - 1); X } X Xgot_date: X month_len[1] = (year%4) ? 28 : 29; X if (mday<0 || mday>month_len[month]) { X dprint(5,(debugfile,"ridiculous day %d of month %d\n",mday,month)); X return 0; X } X X /* convert back to symbolic form (silly, but the rest of the program X * expects it and I'm not about to change all that!) X */ X sprintf(entry->year, "%02d", year); X sprintf(entry->month, "%s", month_name[month]); X entry->month[0] = toupper(entry->month[0]); X sprintf(entry->day, "%d", mday); X sprintf(entry->time, "%02d:%02d:%02d",minutes/60,minutes%60,seconds); X X /* shift everything to UTC (aka GMT) before making long time for sorting */ X minutes -= tz; X if (tz > 0) { /* east of Greenwich */ X if (minutes < 0) { X if (--mday < 0) { X if (--month < 0) { X year--; /* don't worry about 1900! */ X month = 11; X } X mday = month_len[month]; X } X minutes += 24*60; X } X } X if (tz < 0) { /* west of Greenwich */ X if (minutes >= 24*60) { X if (++mday > month_len[month]) { X if (++month >= 12) { X year++; /* don't worry about 1999! */ X month = 0; X } X mday = 0; X } X minutes -= 24*60; X } X } X gmttime = year - 70; /* make base year */ X if (gmttime < 0) X gmttime += 100; X gmttime = gmttime * 365 + (gmttime + 1) / 4; /* now we have days adjusted for leap years */ X for (i = 0; i < month; i++) X gmttime += month_len[i]; X if (month > 1 && (year % 4) == 0) X gmttime++; /* now to month adjusted for leap year if after feb */ X gmttime += mday - 1; /* and now to the day */ X gmttime *= 24 * 60; /* convert to minutes */ X gmttime += minutes; X entry->time_sent = gmttime * 60; /* now unix seconds since 1/1/70 00:00 GMT */ X X return 1; X} X Xfix_arpa_address(address) Xchar *address; X{ X /** Given a pure ARPA address, try to make it reasonable. X X This means that if you have something of the form a@b@b make X it a@b. If you have something like a%b%c%b@x make it a%b@x... X **/ X X register int host_count = 0, i; X char hosts[MAX_HOPS][NLEN]; /* array of machine names */ X char *host, *addrptr; X X /* break down into a list of machine names, checking as we go along */ X X addrptr = (char *) address; X X while ((host = get_token(addrptr, "%@", 2)) != 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 "Can't build return address - hit MAX_HOPS in fix_arpa_address\n")); 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 /** rebuild the address.. **/ X X address[0] = '\0'; X X for (i = 0; i < host_count; i++) X sprintf(address, "%s%s%s", address, X address[0] == '\0'? "" : X (i == host_count - 1 ? "@" : "%"), X hosts[i]); X X return(0); X} X Xfigure_out_addressee(buffer, mail_to) Xchar *buffer; Xchar *mail_to; X{ X /** This routine steps through all the addresses in the "To:" X list, initially setting it to the first entry (if mail_to X is NULL) or, if the user is found (eg "alternatives") to X the current "username". X X Modified to know how to read quoted names... X also modified to look for a comma or eol token and then X try to give the maximal useful information when giving the X default "to" entry (e.g. "Dave Taylor <taylor@hpldat>" X will now give "Dave Taylor" rather than just "Dave") X **/ X X char *address, *bufptr, mybuf[SLEN]; X register int index2 = 0; X X if (equal(mail_to, username)) return; /* can't be better! */ X X bufptr = (char *) buffer; /* use the string directly */ X X if (index(buffer,'"') != NULL) { /* we have a quoted string */ X while (*bufptr != '"') X bufptr++; X bufptr++; /* skip the leading quote */ X while (*bufptr != '"' && *bufptr) X mail_to[index2++] = *bufptr++; X mail_to[index2] = '\0'; X } X X else { X X while ((address = strtok(bufptr, ",\t\n\r")) != NULL) { X X if (! okay_address(address, "don't match me!")) { X strcpy(mail_to, username); /* it's to YOU! */ X return; X } X else if (strlen(mail_to) == 0) { /* it's SOMEthing! */ X X /** this next bit is kinda gory, but allows us to use the X existing routines to parse the address - by pretending X it's a From: line and going from there... X Ah well - you get what you pay for, right? X **/ X X if (strlen(address) > (sizeof mybuf) - 7) /* ensure it ain't */ X address[(sizeof mybuf)-7] = '\0'; /* too long mon! */ X X sprintf(mybuf, "From: %s", address); X parse_arpa_who(mybuf, mail_to, TRUE); X/** X get_return_name(address, mail_to, FALSE); X**/ X } X X bufptr = (char *) NULL; /* set to null */ X } X } X X return; X} SHAR_EOF echo "File src/addr_util.c is complete" chmod 0444 src/addr_util.c || echo "restore of src/addr_util.c fails" echo "x - extracting src/alias.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/alias.c && X Xstatic char rcsid[] = "@(#)$Id: alias.c,v 4.1 90/04/28 22:42:25 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: alias.c,v $ X * Revision 4.1 90/04/28 22:42:25 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** This file contains alias stuff X X**/ X X#include "headers.h" X#include <errno.h> X#include <ctype.h> X#include <sys/types.h> X#include <sys/stat.h> X X#ifdef BSD X#undef tolower X#endif X X#define ECHOIT 1 /* echo on for prompting */ X Xchar *get_alias_address(); Xchar *error_name(), *error_description(), *strip_parens(), *index(); X Xextern int errno; X X#ifndef DONT_TOUCH_ADDRESSES Xchar *expand_system(); X Xextern int findnode_has_been_initialized; X#endif X Xint Xok_alias_name(name) Xchar *name; X{ X while ( *name != '\0' && ok_alias_char(*name) ) X ++name; X return ( *name == '\0' ); X} X X Xread_alias_files() X{ X /** read the system and user alias files, if present, and if they X have changed since last we read them. X **/ X X read_system_aliases(); X read_user_aliases(); X} X Xread_system_aliases() X{ X /** read the system alias file, if present, X and if it has changed since last we read it. X **/ X X struct stat hst; X static time_t system_ctime, system_mtime; X X /* If hash file hasn't changed, don't bother re-reading. */ X X if (system_data != -1 X && stat(system_hash_file, &hst) == 0 X && hst.st_ctime == system_ctime X && hst.st_mtime == system_mtime) X return; X X /* Close system data file if it was open. */ X X if (system_data != -1) { X close(system_data); X system_data = -1; X } X X /* Read system hash table. If we can't, just return. */ X X if (read_hash_file(system_hash_file, (char *) system_hash_table, X sizeof system_hash_table) < 0) X return; X X /* Open system data table. */ X X if ((system_data = open(system_data_file, O_RDONLY)) == -1) { X dprint(1, (debugfile, X "Warning: Can't open system alias data file %s\n", X system_data_file)); X return; X } X X /* Remember hash file times. */ X X system_ctime = hst.st_ctime; X system_mtime = hst.st_mtime; X} X Xread_user_aliases() X{ X /** read the system alias file, if present, X and if it has changed since last we read it. X **/ X X struct stat hst; X char fname[SLEN]; X static time_t user_ctime, user_mtime; X X /* If hash file hasn't changed, don't bother re-reading. */ X X sprintf(fname, "%s/%s", home, ALIAS_HASH); X X if (user_data != -1 X && stat(fname, &hst) == 0 X && hst.st_ctime == user_ctime X && hst.st_mtime == user_mtime) X return; X X /* Close user data file if it was open. */ X X if (user_data != -1) { X close(user_data); X user_data = -1; X } X X /* Read user hash table. If we can't, just return. */ X X if (read_hash_file(fname, (char *) user_hash_table, X sizeof user_hash_table) < 0) X return; X X /* Open user data table. */ X X sprintf(fname, "%s/%s", home, ALIAS_DATA); X if ((user_data = open(fname, O_RDONLY)) == -1) { X dprint(1, (debugfile, X "Warning: Can't open user alias data file %s\n", fname)); X return; X } X X /* Remember hash file times. */ X X user_ctime = hst.st_ctime; X user_mtime = hst.st_mtime; X} X Xint Xread_hash_file(file, table, table_size) Xchar *file, *table; Xint table_size; X{ X /** read the specified alias hash file into the specified table. X it must be _exactly_ the right size or forget it. X **/ X X struct stat st; X int hash; X X /* Open the hash file. */ X X if ((hash = open(file, O_RDONLY)) == -1) { X dprint(2, (debugfile, X "Warning: Can't open alias hash file %s\n", file)); X return -1; X } X X /* Be sure the hash file is the correct size. */ X X if (fstat(hash, &st) == 0 && st.st_size != table_size) { X dprint(2, (debugfile, X "Warning: Alias hash file %s is wrong size (%ld/%d)\n", X file, st.st_size, table_size)); X close(hash); X return -1; X } X X /* Read the hash file into memory. */ X X if (read(hash, (char *) table, table_size) != table_size) { X dprint(2, (debugfile, X "Warning: Can't read alias hash file %s\n", file)); X close(hash); X return -1; X } X X /* Close the hash file; return success. */ X X close(hash); X return 0; X} X Xint Xadd_alias() X{ X /** add an alias to the user alias text file. Return zero X if alias not added in actuality **/ X X char name[SLEN], *address, address1[LONG_STRING], buffer[LONG_STRING]; X char comment[SLEN], ch; X char *strcpy(); X X strcpy(buffer, "Enter alias name: "); X PutLine0(LINES-2,0, buffer); X CleartoEOLN(); X *name = '\0'; X optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE); X if (strlen(name) == 0) X return(0); X if ( !ok_alias_name(name) ) { X error1("Bad character(s) in alias name %s.", name); X return(0); X } X if ((address = get_alias_address(name, FALSE)) != NULL) { X dprint(3, (debugfile, X "Attempt to add a duplicate alias [%s] in add_alias\n", X address)); X if (address[0] == '!') { X address[0] = ' '; X error1("Already a group with name %s.", address); X } X else X error1("Already an alias for %s.", address); X return(0); X } X X sprintf(buffer, "Enter full name for %s: ", name); X PutLine0(LINES-2,0, buffer); X CleartoEOLN(); X *comment = '\0'; X optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE); X if (strlen(comment) == 0) strcpy(comment, name); X X sprintf(buffer, "Enter address for %s: ", name); X PutLine0(LINES-2,0, buffer); X CleartoEOLN(); X *address1 = '\0'; X optionally_enter(address1, LINES-2, strlen(buffer), FALSE, FALSE); X Raw(ON); X if (strlen(address1) == 0) { X error("No address specified!"); X return(0); X } X PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1); X CleartoEOLN(); X if((ch = want_to("Accept new alias? (y/n) ",'y')) == 'y') X add_to_alias_text(name, comment, address1); X ClearLine(LINES-2); X return(ch == 'y' ? 1 : 0); X} X Xint Xdelete_alias() X{ X /** delete an alias from the user alias text file. Return zero X if alias not deleted in actuality **/ X X char name[SLEN], *address, buffer[LONG_STRING]; X char *strcpy(); X X strcpy(buffer, "Enter alias name for deletion: "); X PutLine0(LINES-2,0, buffer); X CleartoEOLN(); X *name = '\0'; X optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE); X if (strlen(name) == 0) X return(0); X if ((address = get_alias_address(name, FALSE))!=NULL) X { X if (address[0] == '!') X { X address[0] = ' '; X PutLine1(LINES-1,0,"Group alias: %-60.60s", address); X CleartoEOLN(); X } X else X PutLine1(LINES-1,0,"Aliased address: %-60.60s", address); X } X else X { X dprint(3, (debugfile, X "Attempt to delete a non-existent alias [%s] in delete_alias\n", X name)); X error1("No alias for %s.", name); X return(0); X } X if (want_to("Delete this alias? (y/n) ", 'y') == 'y') X { X if (!delete_from_alias_text(name)) X { X CleartoEOS(); X return(1); X } X } X CleartoEOS(); X return(0); X} X Xint Xadd_current_alias() X{ X /** alias the current message to the specified name and X add it to the alias text file, for processing as X the user leaves the program. Returns non-zero iff X alias actually added to file **/ X X char name[SLEN], address1[LONG_STRING], buffer[LONG_STRING], *address; X char comment[SLEN], ch; X struct header_rec *current_header; X X if (current == 0) { X dprint(4, (debugfile, X "Add current alias called without any current message!\n")); X error("No message to alias to!"); X return(0); X } X current_header = headers[current - 1]; X X strcpy(buffer, "Current message address aliased to: "); X PutLine0(LINES-2,0, buffer); X CleartoEOLN(); X *name = '\0'; X optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE); X if (strlen(name) == 0) /* cancelled... */ X return(0); X if ( !ok_alias_name(name) ) { X error1("Bad character(s) in alias name %s.", name); X return(0); X } X if ((address = get_alias_address(name, FALSE)) != NULL) { X dprint(3, (debugfile, X "Attempt to add a duplicate alias [%s] in add_current_alias\n", X address)); X if (address[1] == '!') { X address[0] = ' '; X error1("Already a group with name %s.", address); X } X else X error1("Already an alias for %s.", address); X return(0); X } X X sprintf(buffer, "Enter full name for %s: ", name); X PutLine0(LINES-2,0, buffer); X CleartoEOLN(); X X /* use full name in current message for default comment */ X tail_of(current_header->from, comment, current_header->to); X if(index(comment, '!') || index(comment, '@')) X /* never mind - it's an address not a full name */ X *comment = '\0'; X X optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE); X X /* grab the return address of this message */ X get_return(address1, current-1); X X strcpy(address1, strip_parens(address1)); /* remove parens! */ X#ifdef OPTIMIZE_RETURN X optimize_return(address1); X#endif X PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1); X CleartoEOLN(); X if((ch = want_to("Accept new alias? (y/n) ",'y')) == 'y') X add_to_alias_text(name, comment, address1); X ClearLine(LINES-2); X return(ch == 'y' ? 1 : 0); X} X Xadd_to_alias_text(name, comment, address) Xchar *name, *comment, *address; X{ X /** Add the data to the user alias text file. Return zero if we X succeeded, 1 if not **/ X X FILE *file; X char fname[SLEN]; X X sprintf(fname,"%s/%s", home, ALIAS_TEXT); X X save_file_stats(fname); X if ((file = fopen(fname, "a")) == NULL) { X dprint(2, (debugfile, X "Failure attempting to add alias to file %s within %s", X fname, "add_to_alias_text")); X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X error1("Couldn't open %s to add new alias!", fname); X return(1); X } X X if (fprintf(file,"%s = %s = %s\n", name, comment, address) == EOF) { X dprint(2, (debugfile, X "Failure attempting to write alias to file within %s", X fname, "add_to_alias_text")); X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X error1("Couldn't write alias to file %s!", fname); X fclose(file); X return(1); X } X X fclose(file); X X restore_file_stats(fname); X X return(0); X} X Xdelete_from_alias_text(name) Xchar *name; X{ X /** Delete the data from the user alias text file. Return zero if we X succeeded, 1 if not **/ X X FILE *file, *tmp_file; X char fname[SLEN], tmpfname[SLEN]; X char line_in_file[SLEN+3+SLEN+3+LONG_STRING]; /* name = comment = address */ X char name_with_equals[SLEN+2]; X X strcpy(name_with_equals, name); X strcat(name_with_equals, " ="); X X sprintf(fname,"%s/%s", home, ALIAS_TEXT); X sprintf(tmpfname,"%s/%s.tmp", home, ALIAS_TEXT); X X save_file_stats(fname); X X if ((file = fopen(fname, "r")) == NULL) { X dprint(2, (debugfile, X "Failure attempting to delete alias from file %s within %s", X fname, "delete_from_alias_text")); X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X error1("Couldn't open %s to delete alias!", fname); X return(1); X } X X if ((tmp_file = fopen(tmpfname, "w")) == NULL) { X dprint(2, (debugfile, X "Failure attempting to open temp file %s within %s", X tmpfname, "delete_from_alias_text")); X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X error1("Couldn't open tempfile %s to delete alias!", tmpfname); X return(1); X } X X while (fgets(line_in_file, sizeof(line_in_file), file) != (char *)NULL) X { X if (strncmp(name_with_equals, line_in_file, X strlen(name_with_equals)) != 0) X if (fprintf(tmp_file,"%s", line_in_file) == EOF) { X dprint(2, (debugfile, X "Failure attempting to write to temp file %s within %s", X tmpfname, "delete_from_alias_text")); X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X error1("Couldn't write to tempfile %s!", tmpfname); X fclose(file); X fclose(tmp_file); X unlink(tmpfname); X return(1); X } X } X fclose(file); X fclose(tmp_file); X if (rename(tmpfname, fname) != 0) X { X error1("Couldn't rename tempfile %s after deleting alias!", tmpfname); X return(1); X } X X restore_file_stats(fname); X X return(0); X} X Xshow_alias_menu() X{ X MoveCursor(LINES-7,0); CleartoEOS(); X X PutLine0(LINES-7,COLUMNS-45, "Alias commands"); X Centerline(LINES-6, X "a)lias current message, d)elete an alias, check a p)erson or s)ystem,"); X Centerline(LINES-5, X "l)ist existing aliases, m)ake new alias, or r)eturn"); X} X Xalias() X{ X /** work with alias commands... **/ X /** return non-0 if main part of screen overwritten, else 0 **/ X X char name[NLEN], *address, ch, buffer[SLEN]; X int newaliases = 0, redraw = 0; X X if (mini_menu) X show_alias_menu(); X X /** now let's ensure that we've initialized everything! **/ X X#ifndef DONT_TOUCH_ADDRESSES X X if (! findnode_has_been_initialized) { X if (warnings) X error("Initializing internal tables..."); X#ifndef USE_DBM X get_connections(); X open_domain_file(); X#endif X init_findnode(); X clear_error(); X findnode_has_been_initialized = TRUE; X } X X#endif X X define_softkeys(ALIAS); X X while (1) { X prompt("Alias: "); X CleartoEOLN(); X ch = ReadCh(); X MoveCursor(LINES-1,0); CleartoEOS(); X X dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch)); X X switch (tolower(ch)) { X case '?': redraw += alias_help(); break; X X case 'a': newaliases += add_current_alias(); break; X case 'd': if (delete_alias()) install_aliases(); break; X case 'l': display_aliases(); X redraw++; X if (mini_menu) show_alias_menu(); X break; X case 'm': newaliases += add_alias(); break; X X case RETURN: X case LINE_FEED: X case 'q': X case 'x': X case 'r': if (newaliases) install_aliases(); X clear_error(); X return(redraw); X case 'p': if (newaliases) X error("Warning: new aliases not installed yet!"); X X strcpy(buffer, "Check for person: "); X PutLine0(LINES-2,0, buffer); X CleartoEOLN(); X *name = '\0'; X optionally_enter(name, LINES-2, strlen(buffer), X FALSE, FALSE); X X if ((address = get_alias_address(name, FALSE))!=NULL) { X if (address[0] == '!') { X address[0] = ' '; X PutLine1(LINES-1,0,"Group alias:%-60.60s", address); X CleartoEOLN(); X } X else X PutLine1(LINES-1,0,"Aliased address: %-60.60s", X address); X } X else X error("Not found."); X break; X X case 's': strcpy(buffer, "Check for system: "); X PutLine0(LINES-2,0, buffer); X CleartoEOLN(); X *name = '\0'; X optionally_enter(name, LINES-2, strlen(buffer), X FALSE, FALSE); X if (talk_to(name)) X#ifdef INTERNET X PutLine1(LINES-1,0, X "You have a direct connection. The address is USER@%s.", X name); X#else X PutLine1(LINES-1,0, X "You have a direct connection. The address is %s!USER.", X name); X#endif X else { X sprintf(buffer, "USER@%s", name); X#ifdef DONT_TOUCH_ADDRESSES X address = buffer; X#else X address = expand_system(buffer, FALSE); X#endif X if (strlen(address) > strlen(name) + 7) X PutLine1(LINES-1,0,"Address is: %.65s", address); X else X error1("Couldn't expand system %s.", name); X } X break; X X case '@': strcpy(buffer, "Fully expand alias: "); X PutLine0(LINES-2,0, buffer); X CleartoEOS(); X *name = '\0'; X optionally_enter(name, LINES-2, strlen(buffer), X FALSE, FALSE); X if ((address = get_alias_address(name, TRUE)) != NULL) { X ClearScreen(); X PutLine1(3,0,"Aliased address:\n\r%s", address); X PutLine0(LINES-1,0,"Press <return> to continue."); X (void) getchar(); X redraw++; X } X else X error("Not found."); X if (mini_menu) show_alias_menu(); X break; X default : error("Invalid input!"); X } X } X} X Xinstall_aliases() X{ X /** run the 'newalias' program and update the X aliases before going back to the main program! X **/ X X X error("Updating aliases..."); X sleep(2); X X if (system_call(newalias, SH, FALSE, FALSE) == 0) { X error("Re-reading the database in..."); X sleep(2); X read_alias_files(); X set_error("Aliases updated successfully."); X } X else X set_error("'Newalias' failed. Please check alias_text."); X} X Xalias_help() X{ X /** help section for the alias menu... **/ X /** return non-0 if main part of screen overwritten, else 0 */ X X char ch; X int redraw=0; X char *alias_prompt = mini_menu ? "Key: " : "Key you want help for: "; X X MoveCursor(LINES-3, 0); CleartoEOS(); X X if (mini_menu) { X Centerline(LINES-3, X "Press the key you want help for, '?' for a key list, or '.' to exit help"); X } X X lower_prompt(alias_prompt); X X while ((ch = ReadCh()) != '.') { X ch = tolower(ch); X switch(ch) { X case '?' : display_helpfile(ALIAS_HELP); X redraw++; X if (mini_menu) show_alias_menu(); X return(redraw); X case 'a': error( X "a = Add (return) address of current message to alias database."); X break; X case 'd': error("d = Delete a user alias from alias database."); X break; X case 'l': error("l = List all aliases in database."); X break; X case 'm': error( X "m = Make a new user alias, adding to alias database when done."); X break; X X case RETURN: X case LINE_FEED: X case 'q': X case 'x': X case 'r': error("Return from alias menu."); X break; X X case 'p': error("p = Check for a person in the alias database."); X break; X X case 's': error( X "s = Check for a system in the host routing/domain database."); X break; X X default : error("That key isn't used in this section."); X break; X } X lower_prompt(alias_prompt); X } X return(redraw); X} X Xdisplay_aliases() X{ X char fname[SLEN]; X X sprintf(fname,"%s/%s", home, ALIAS_TEXT); X display_file(fname); X ClearScreen(); X return; X} SHAR_EOF chmod 0444 src/alias.c || echo "restore of src/alias.c fails" echo "x - extracting src/aliasdb.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/aliasdb.c && X Xstatic char rcsid[] = "@(#)$Id: aliasdb.c,v 4.1 90/04/28 22:42:28 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: aliasdb.c,v $ X * Revision 4.1 90/04/28 22:42:28 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** Alias database files... X X**/ X X X#include "headers.h" X X#include <sys/types.h> X#include <sys/stat.h> X#include <errno.h> X Xextern int errno; X X#ifdef USE_DBM X# include <dbm.h> X#endif X X#define absolute(x) ((x) > 0 ? x : -(x)) X Xchar *find_path_to(), *strcat(), *strcpy(); Xunsigned long sleep(); X X#ifndef DONT_TOUCH_ADDRESSES Xint findnode_has_been_initialized = FALSE; X#endif X Xfindnode(name, display_error) Xchar *name; Xint display_error; X{ X /** break 'name' into machine!user or user@machine and then X see if you can find 'machine' in the path database.. X If so, return name as the expanded address. If not, X return what was given to us! If display_error, then X do so... X **/ X X#ifndef DONT_TOUCH_ADDRESSES X X char old_name[SLEN]; X char address[SLEN]; X X if (strlen(name) == 0) X return; X X if (! findnode_has_been_initialized) { X if (warnings) X error("Initializing internal tables..."); SHAR_EOF echo "End of part 11" echo "File src/aliasdb.c is continued in part 12" echo "12" > 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.