This is addr_util.c in view mode; [Download] [Up]
static char rcsid[] = "@(#)$Id: addr_util.c,v 5.5 1992/12/11 01:45:04 syd Exp $";
/*******************************************************************************
* The Elm Mail System - $Revision: 5.5 $ $State: Exp $
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*******************************************************************************
* Bug reports, patches, comments, suggestions should be sent to:
*
* Syd Weinstein, Elm Coordinator
* elm@DSI.COM dsinc!elm
*
*******************************************************************************
* $Log: addr_util.c,v $
* Revision 5.5 1992/12/11 01:45:04 syd
* remove sys/types.h include, it is now included by defs.h
* and this routine includes defs.h or indirectly includes defs.h
* From: Syd
*
* Revision 5.4 1992/11/26 00:46:13 syd
* changes to first change screen back (Raw off) and then issue final
* error message.
* From: Syd
*
* Revision 5.3 1992/10/31 18:52:51 syd
* Corrections to Unix date parsing and time zone storage
* From: eotto@hvlpa.att.com
*
* Revision 5.2 1992/10/25 02:18:01 syd
* fix found_year flag
* From: Syd
*
* Revision 5.1 1992/10/03 22:58:40 syd
* Initial checkin as of 2.4 Release at PL0
*
*
******************************************************************************/
/** This file contains addressing utilities
**/
#include "headers.h"
#include "s_elm.h"
#include <sys/stat.h>
#ifdef PWDINSYS
# include <sys/pwd.h>
#else
# include <pwd.h>
#endif
#include <ctype.h>
#ifdef BSD
#undef tolower
#undef toupper
#endif
char *get_full_name(), *get_alias_address(), *get_token();
char *strcpy(), *strcat(), *strncpy();
#define SKIP_WS(p) while (isspace(*p)) p++
#define SKIP_ALPHA(p) while (isalpha(*p)) p++
#define SKIP_DIGITS(p) while (isdigit(*p)) p++
static char *day_name[8] = {
"sun", "mon", "tue", "wed", "thu", "fri", "sat", 0
};
static char *month_name[13] = {
"jan", "feb", "mar", "apr",
"may", "jun", "jul", "aug",
"sep", "oct", "nov", "dec", 0
};
static int month_len[12] = {
31, 28, 31, 30, 31, 30, 31,
31, 30, 31, 30, 31 };
/* The following time zones are taken from a variety of sources. They
* are by no means exhaustive, but seem to include most of those
* in common usage. A comprehensive list is impossible, since the same
* abbreviation is sometimes used to mean different things in different
* parts of the world.
*/
static struct tzone {
char *str;
int offset; /* offset, in minutes, EAST of GMT */
} tzone_info[] = {
/* the following are from rfc822 */
"ut", 0, "gmt", 0,
"est", -5*60, "edt", -4*60,
"cst", -6*60, "cdt", -5*60,
"mst", -7*60, "mdt", -6*60,
"pst", -8*60, "pdt", -7*60,
"z", 0, /* zulu time (the rest of the military codes are bogus) */
/* these are also popular in Europe */
"wet", 0*60, "wet dst", 1*60, /* western european */
"met", 1*60, "met dst", 2*60, /* middle european */
"eet", 2*60, "eet dst", 3*60, /* eastern european */
"bst", 1*60, /* ??? british summer time (=+0100) */
/* ... and Canada */
"ast", -4*60, "adt", -3*60, /* atlantic */
"nst", -3*60-30, "ndt", -2*60-30, /* newfoundland */
"yst", -9*60, "ydt", -8*60, /* yukon */
"hst", -10*60, /* hawaii (not really canada) */
/* ... and Asia */
"jst", 9*60, /* japan */
"sst", 8*60, /* singapore */
/* ... and the South Pacific */
"nzst", 12*60, "nzdt", 13*60, /* new zealand */
"wst", 8*60, "wdt", 9*60, /* western australia */
/* there's also central and eastern australia, but they insist on using
* cst, est, etc., which would be indistinguishable for the us zones */
(char *) 0, 0
};
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, changed = 0, in_parens = 0, expanded_information = 0;
register int k, l, eliminated = 0;
char word[SLEN], next_word[SLEN], *ptr, buffer[SLEN];
char new_to_list[VERY_LONG_STRING];
char elim_list[SLEN], word_a[SLEN], next_word_a[SLEN];
char *qstrpbrk(), *gecos;
new_to_list[0] = '\0';
i = get_word(to, 0, word);
full_to[0] = '\0';
elim_list[0] = '\0';
/** Look for addresses to be eliminated from aliases **/
while (i > 0) {
j = get_word(to, i, 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]; word[k] = word[k+1],k++);
if (elim_list[0] != '\0')
strcat(elim_list, " ");
strcat(elim_list, word);
}
if ((i = j) > 0)
strcpy(word, next_word);
}
if (elim_list[0] != '\0')
eliminated++;
i = get_word(to, 0, word);
while (i > 0) {
j = get_word(to, i, next_word);
try_new_word:
if(word[0] == '(')
in_parens++;
if (in_parens) {
if(word[strlen(word)-1] == ')')
in_parens--;
strcat(full_to, " ");
strcat(full_to, word);
}
else if (word[0] == '-') {
}
else if (qstrpbrk(word,"!@:") != NULL) {
sprintf(full_to, "%s%s%s", full_to,
full_to[0] != '\0'? ", " : "", word);
}
else if ((ptr = get_alias_address(word, TRUE)) != NULL) {
/** check aliases for addresses to be eliminated **/
if (eliminated) {
k = get_word(strip_commas(ptr), 0, word_a);
while (k > 0) {
l = get_word(ptr, k, next_word_a);
if (in_list(elim_list, word_a) == 0)
sprintf(full_to, "%s%s%s", full_to,
full_to[0] != '\0' ? ", " : "", word_a);
if ((k = l) > 0)
strcpy(word_a, next_word_a);
}
} else
sprintf(full_to, "%s%s%s", full_to,
full_to[0] != '\0'? ", " : "", ptr);
expanded_information++;
}
else if (strlen(word) > 0) {
if (valid_name(word)) {
if (j > 0 && next_word[0] == '(') /* already has full name */
gecos = NULL;
else /* needs a full name */
gecos = get_full_name(word);
#if defined(INTERNET) & defined(USE_DOMAIN)
sprintf(full_to, "%s%s%s@%s%s%s%s",
full_to,
(full_to[0] != '\0'? ", " : ""),
word,
hostfullname,
(gecos ? " (" : ""),
(gecos ? gecos : ""),
(gecos ? ")" : ""));
#else /* INTERNET and USE_DOMAIN */
sprintf(full_to, "%s%s%s%s%s%s",
full_to,
(full_to[0] != '\0'? ", " : ""),
word,
(gecos ? " (" : ""),
(gecos ? gecos : ""),
(gecos ? ")" : ""));
#endif /* INTERNET and USE_DOMAIN */
} else if (check_only) {
printf(catgets(elm_msg_cat, ElmSet, ElmAliasUnknown,
"(alias \"%s\" is unknown)\n\r"), word);
changed++;
}
else if (! isatty(fileno(stdin)) ) { /* batch mode error! */
Raw(OFF);
fprintf(stderr, catgets(elm_msg_cat, ElmSet, ElmCannotExpandNoCR,
"Cannot expand alias '%s'!\n"), word);
fprintf(stderr, catgets(elm_msg_cat, ElmSet, ElmUseCheckalias,
"Use \"checkalias\" to find valid addresses!\n"));
dprint(1, (debugfile,
"Can't expand alias %s - bailing out of build_address\n",
word));
leave(0);
}
else {
dprint(2,(debugfile,"Entered unknown address %s\n", word));
sprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmUnknownAddress,
"'%s' is an unknown address. Replace with: "),
word);
word[0] = '\0';
changed++;
PutLine0(LINES, 0, buffer);
(void)optionally_enter(word, LINES, strlen(buffer), FALSE, FALSE);
clear_error();
if (strlen(word) > 0) {
dprint(3,(debugfile, "Replaced with %s in build_address\n",
word));
goto try_new_word;
}
else
dprint(3,(debugfile,
"Address removed from TO list by build_address\n"));
continue;
}
}
/* and this word to the new to list */
if(*new_to_list != '\0')
strcat(new_to_list, " ");
strcat(new_to_list, word);
if((i = j) > 0)
strcpy(word, next_word);
}
/* if new to list is different from original, update original */
if (changed)
strcpy(to, new_to_list);
return( expanded_information > 0 ? 1 : 0 );
}
/* Return smallest i such that table[i] is a prefix of str. Return -1 if not
* found.
*/
static int prefix(table, str)
char **table;
char *str;
{
int i;
for (i=0;table[i];i++)
if (strncmp(table[i],str,strlen(*table))==0)
return i;
return -1;
}
/*
Quoting from RFC 822:
5. DATE AND TIME SPECIFICATION
5.1. SYNTAX
date-time = [ day "," ] date time ; dd mm yy
; hh:mm:ss zzz
day = "Mon" / "Tue" / "Wed" / "Thu"
/ "Fri" / "Sat" / "Sun"
date = 1*2DIGIT month 2DIGIT ; day month year
; e.g. 20 Jun 82
month = "Jan" / "Feb" / "Mar" / "Apr"
/ "May" / "Jun" / "Jul" / "Aug"
/ "Sep" / "Oct" / "Nov" / "Dec"
time = hour zone ; ANSI and Military
hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
; 00:00:00 - 23:59:59
zone = "UT" / "GMT" ; Universal Time
; North American : UT
/ "EST" / "EDT" ; Eastern: - 5/ - 4
/ "CST" / "CDT" ; Central: - 6/ - 5
/ "MST" / "MDT" ; Mountain: - 7/ - 6
/ "PST" / "PDT" ; Pacific: - 8/ - 7
/ 1ALPHA ; Military: Z = UT;
; A:-1; (J not used)
; M:-12; N:+1; Y:+12
/ ( ("+" / "-") 4DIGIT ) ; Local differential
; hours+min. (HHMM)
*/
/* Translate a symbolic timezone name (e.g. EDT or NZST) to a number of
* minutes *east* of gmt (if the local time is t, the gmt equivalent is
* t - tz_lookup(zone)).
* Return 0 if the timezone is not recognized.
*/
static int tz_lookup(str)
char *str;
{
struct tzone *p;
for (p = tzone_info; p->str; p++) {
if (strcmp(p->str,str)==0) return p->offset;
}
dprint(5,(debugfile,"unknown time zone %s\n",str));
return 0;
}
/* The following routines, get_XXX(p,...), expect p to point to a string
* of the appropriate syntax. They return decoded values in result parameters,
* and return p updated to point past the parsed substring (also stripping
* trailing whitespace).
* Return 0 on syntax errors.
*/
/* Parse a time: hours ':' minutes [ ':' seconds ] WS
* Check that 0<=hours<24, 0<=minutes,seconds<60.
* Also allow the syntax "digit digit digit digit" with implied ':' in the
* middle.
* Convert to minutes and seconds, with results in (*m,*s).
*/
static char *
get_time(p,m,s)
char *p;
int *m, *s;
{
int hours, minutes, seconds;
/* hour */
if (!isdigit(*p)) {
dprint(5,(debugfile,"missing time: %s\n",p));
return 0;
}
hours = atoi(p);
SKIP_DIGITS(p);
if (*p++ != ':') {
/* perhaps they just wrote hhmm instead of hh:mm */
minutes = hours % 60;
hours /= 60;
}
else {
if (hours<0 || hours>23) {
dprint(5,(debugfile,"ridiculous hour: %d\n",hours));
return 0;
}
minutes = atoi(p);
if (minutes<0 || minutes>59) {
dprint(5,(debugfile,"ridiculous minutes: %d\n",minutes));
return 0;
}
}
SKIP_DIGITS(p);
if (*p == ':') {
p++;
seconds = atoi(p);
if (seconds<0 || seconds>59) {
dprint(5,(debugfile,"ridiculous seconds: %d\n",seconds));
return 0;
}
SKIP_DIGITS(p);
}
else seconds = 0;
minutes += hours*60;
SKIP_WS(p);
*m = minutes;
*s = seconds;
return p;
}
/* Parse a year: ['1' '9'] digit digit WS
*/
static char *
get_year(p, result)
char *p;
int *result;
{
int year;
if (!isdigit(*p)) {
dprint(5,(debugfile,"missing year: %s\n",p));
return 0;
}
year = atoi(p);
/* be nice and allow xx and 19xx */
if (year>69 && year <= 99)
year += 1900;
else if (year > 0 && year < 70)
year += 2000;
if (year<1900 || year>2099) {
dprint(5,(debugfile,"ridiculous year %d\n",year));
return 0;
}
SKIP_DIGITS(p);
SKIP_WS(p);
*result = year;
return p;
}
/* Parse a Unix date from which the leading week-day has been stripped.
* The syntax is "Jun 21 06:45:44 CDT 1989" with timezone optional.
* i.e., month day time [ zone ] year
* where day::=digit*, year and time are as defined above,
* and month and zone are alpha strings starting with a known 3-char prefix.
* The month has already been processed by the caller, so we just skip over
* a leading alpha* WS.
*
* Unlike the preceding routines, the result is not an updated pointer, but
* simply 1 for success and 0 for failure.
*/
static int
get_unix_date(p,y,d,m,s,t)
char *p;
int *y, *d, *m, *s, *t;
{
char time_zone[STRING];
SKIP_ALPHA(p);
SKIP_WS(p);
if (!isdigit(*p)) return 0;
*d = atoi(p); /* check the value for sanity after we know the month */
SKIP_DIGITS(p);
SKIP_WS(p);
p = get_time(p,m,s);
if (!p) return 0;
if (isalpha(*p)) {
get_word(p,0,time_zone);
*t = tz_lookup(time_zone);
SKIP_ALPHA(p);
SKIP_WS(p);
}
else if (*p == '+') {
p++;
*t = atoi(p);
SKIP_DIGITS(p);
SKIP_WS(p);
}
else if (*p == '-') {
p++;
*t = - atoi(p);
SKIP_DIGITS(p);
SKIP_WS(p);
}
else *t = 0;
p = get_year(p,y);
if (!p) return 0;
return 1;
}
int
real_from(buffer, entry)
char *buffer;
struct header_rec *entry;
{
/***** Returns true iff 's' has at least the seven 'from' fields,
8 or 9 indicates time zone, 10+ include remote from host.
Initialize the date and from entries in the record
and also the message received date/time if 'entry'
is not NULL. *****/
struct header_rec temp_rec, *rec_ptr;
char junk[STRING], timebuff[STRING], holding_from[SLEN];
char time_zone[STRING];
char mybuf[BUFSIZ], *p, *q, *t;
int mday, month, year, minutes, seconds, tz, i, found_year;
long gmttime;
/* set rec_ptr according to whether the data is to be returned
* in the second argument */
rec_ptr = (entry == NULL ? &temp_rec : entry);
rec_ptr->time_sent = 0;
rec_ptr->tz_offset = 0;
rec_ptr->time_zone[0] = '\0';
timebuff[0] = '\0';
junk[0] = '\0';
year = 0;
/* From <user> <weekday> <month> <day> <hr:min:sec> [TZ1 [TZ2]] <year> [remote from sitelist] */
if ((i = get_word(buffer, 0, junk)) < 0) /* skip From */
return(FALSE);
if (!equal("From", junk))
return(FALSE);
if ((i = get_word(buffer, 5, holding_from)) < 0)
return(FALSE);
buffer += 5 + strlen(holding_from);
if ((i = get_word(buffer, 0, junk)) < 0) /* skip day of week */
return(FALSE);
buffer += i;
if ((i = get_word(buffer, 0, timebuff)) < 0) /* get month */
return(FALSE);
buffer += i;
if ((i = get_word(buffer, 0, junk)) < 0) /* get day */
return(FALSE);
strcat(timebuff, " ");
strcat(timebuff, junk);
buffer += i;
if ((i = get_word(buffer, 0, junk)) < 0) /* get hr:mm:ss */
return(FALSE);
strcat(timebuff, " ");
strcat(timebuff, junk);
buffer += i;
found_year = FALSE;
if ((i = get_word(buffer, 0, time_zone)) >= 0) { /* get tz1? */
strcat(timebuff, " ");
tz = strlen(time_zone);
if ((*time_zone == '+' || *time_zone == '-') && tz == 5) {
/* numeric tz */
strcat(timebuff, time_zone);
} else if ((*time_zone == '+' || *time_zone == '-') && tz == 3) {
/* numeric tz 2 digits long */
strcat(timebuff, time_zone);
strcat(timebuff, "00"); /* make it 4 digits long */
} else if (isdigit(*time_zone)) {
year = atoi(time_zone);
/* be nice and allow xx and 19xx */
if (year>69 && year <= 99)
year += 1900;
else if (year > 0 && year < 70)
year += 2000;
if (year<1900 || year>2099) {
found_year = FALSE;
} else {
found_year = TRUE;
strcat(timebuff, time_zone);
}
/* No time_zone found */
time_zone[0] = '\0';
} else if (strlen(time_zone) <= 4) {
/* alpha tz */
strcat(timebuff, time_zone);
}
buffer += i;
}
if (found_year == FALSE) {
if ((i = get_word(buffer, 0, junk)) >= 0) { /* get tz2? */
strcat(timebuff, " ");
if (isdigit(*junk)) {
found_year = TRUE;
strcat(timebuff, junk);
} else if (strlen(junk) <= 4) /* alpha tz */
strcat(timebuff, junk);
buffer += i;
}
}
if (found_year == FALSE) {
if ((i = get_word(buffer, 0, junk)) < 0) /* get year */
return(FALSE);
strcat(timebuff, " ");
strcat(timebuff, junk);
buffer += i;
}
if (*time_zone) {
/* convert time_zone to lower case */
for (p=mybuf, q=mybuf+sizeof mybuf, t = time_zone;
*t && p<q; p++, t++) {
*p = isupper(*t) ? tolower(*t) : *t;
}
*p = 0;
p = mybuf;
strncpy(rec_ptr->time_zone, p, sizeof(rec_ptr->time_zone) - 1);
}
/** now process the info gotten out of the record! **/
strncpy(rec_ptr->from, holding_from, STRING-1);
rec_ptr->from[STRING-1] = '\0';
/* first get time into lower case */
for (p=mybuf, q=mybuf+sizeof mybuf, t = timebuff;
*t && p<q; p++, t++) {
*p = isupper(*t) ? tolower(*t) : *t;
}
*p = 0;
p = mybuf;
month = prefix(month_name, p);
get_unix_date(p, &year, &mday, &minutes, &seconds, &tz);
month_len[1] = (year % 4) ? 28 : 29;
if (mday <= 0 || mday > month_len[month]) {
dprint(5, (debugfile, "ridiculous day %d of month %d\n", mday, month));
}
gmttime = year - 1970; /* make base year */
/* now we have days adjusted for leap years */
gmttime = gmttime * 365 + (gmttime + 1) / 4;
for (i = 0; i < month; i++)
gmttime += month_len[i];
gmttime += mday - 1; /* and now to the day */
gmttime *= 24 * 60; /* convert to minutes */
gmttime += minutes - tz;
rec_ptr->time_sent = gmttime * 60 + seconds; /* now unix seconds since 1/1/70 00:00 GMT */
rec_ptr->received_time = rec_ptr->time_sent;
rec_ptr->tz_offset = tz * 60;
return(year != 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 */
SKIP_WS(buffer);
while (*buffer) {
len = len_next_part(buffer);
if (len > 1) {
buffer += len;
} else {
if (isspace(*buffer))
break;
buffer++;
}
}
SKIP_WS(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);
strncpy(entry->from, buff, STRING-1);
entry->from[STRING-1] = '\0';
}
/* Parse an rfc822 (with extensions) date. Return 1 on success, 0 on failure.
*/
parse_arpa_date(string, entry)
char *string;
struct header_rec *entry;
{
char buffer[BUFSIZ], *p, *q;
int mday, month, year, minutes, seconds, tz, i;
long gmttime;
/* first get everything into lower case */
for (p=buffer, q=buffer+sizeof buffer; *string && p<q; p++, string++) {
*p = isupper(*string) ? tolower(*string) : *string;
}
*p = 0;
p = buffer;
SKIP_WS(p);
if (prefix(day_name,p)>=0) {
/* accept anything that *starts* with a valid day name */
/* also, don't check whether it's right! */
SKIP_ALPHA(p);
SKIP_WS(p);
if (*p==',') {
p++;
SKIP_WS(p);
}
/* A comma is required here, but we'll be nice guys and look the other
* way if it's missing.
*/
}
/* date */
/* day of the month */
if (!isdigit(*p)) {
/* Missing day. Maybe this is a Unix date?
*/
month = prefix(month_name,p);
if (month >= 0 &&
get_unix_date(p, &year, &mday, &minutes, &seconds, &tz)) {
goto got_date;
}
dprint(5,(debugfile,"missing day: %s\n",p));
return 0;
}
mday = atoi(p); /* check the value for sanity after we know the month */
SKIP_DIGITS(p);
SKIP_WS(p);
/* month name */
month = prefix(month_name,p);
if (month < 0) {
dprint(5,(debugfile,"missing month: %s\n",p));
return 0;
}
SKIP_ALPHA(p);
SKIP_WS(p);
/* year */
if (!(p = get_year(p,&year))) return 0;
/* time */
if (!(p = get_time(p,&minutes,&seconds))) return 0;
/* zone */
for (q=p; *q && !isspace(*q); q++) continue;
*q = 0;
if (*p=='-' || *p=='+') {
char sign = *p++;
if (isdigit(*p)) {
for (i=0; i<4; i++) {
if (!isdigit(p[i])) {
dprint(5,(debugfile,"ridiculous numeric timezone: %s\n",p));
return 0;
}
p[i] -= '0';
}
tz = p[0]*10 + p[1];
tz *= 60;
tz += p[2]*10 + p[3];
sprintf(entry->time_zone, "%c%2.2d%2.2d", sign, tz / 60, tz % 60);
if (sign=='-') tz = -tz;
}
else {
/* some brain-damaged dates use a '-' before a symbolic time zone */
SKIP_WS(p);
strncpy(entry->time_zone, p, sizeof(entry->time_zone) - 1);
tz = tz_lookup(p);
}
}
else {
tz = tz_lookup(p);
strncpy(entry->time_zone, p, sizeof(entry->time_zone) - 1);
}
got_date:
month_len[1] = (year%4) ? 28 : 29; /* account for leap year */
if (mday<=0 || mday>month_len[month]) {
dprint(5,(debugfile,"ridiculous day %d of month %d\n",mday,month));
return 0;
}
gmttime = year - 1970; /* make base year */
gmttime = gmttime * 365 + (gmttime + 1) / 4; /* now we have days adjusted for leap years */
for (i = 0; i < month; i++)
gmttime += month_len[i];
gmttime += mday - 1; /* and now to the day */
gmttime *= 24 * 60; /* convert to minutes */
gmttime += minutes - tz;
gmttime *= 60;
gmttime += seconds;
entry->time_sent = gmttime; /* now unix seconds since 1/1/70 00:00 GMT */
entry->tz_offset = tz * 60; /* and the tz for reconversion to local zone */
return 1;
}
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][NLEN]; /* array of machine names */
char *host, *addrptr;
/* 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 && ! equal(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);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.