static char rcsid[] = "@(#)$Id: realfrom.c,v 1.3 2006/04/09 07:37:08 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.3 $ $State: Exp $ * * Modified by: Kari Hurtta * (was hurtta+elm@ozone.FMI.FI) ****************************************************************************** * The Elm Mail System * * Copyright (c) 1993 USENET Community Trust *****************************************************************************/ #include "def_mbox.h" DEBUG_VAR(Debug,__FILE__,"addr"); int real_from(buffer, entry) char *buffer; struct header_rec *entry; { /* * Breakup and validate the "From_" line in the "buffer". If "entry" * is not NULL then the structure is filled in with sender and time * information. Returns TRUE if the "From_" line is valid, otherwise * FALSE. * * A valid from line will be in the following format: * * From * [TZ1 [TZ2]] [remote from sitelist] * * We insist that all of the fields are present. * If two timezone fields are present, the first is used for date * information. We do not look at anything beyond the field. * We just insist that everything up to the field is present * and valid. */ char field[STRING]; /* buffer for current field of line */ char field2[STRING]; /* buffer for current field of line */ char field3[STRING]; /* buffer for current field of line */ char save_tz[STRING]; /* extracted time zone field */ int len=0; /* length of current field */ int month, day, year, hours, mins, secs, tz, i; int ef = give_dt_enumerate_as_int(&env_from_source); int islocal = 0; /* * Zero out the portions of the record we fill in. */ if (entry != NULL) { entry->time_zone[0] = '\0'; entry->env_from[0] = '\0'; entry->time_sent = 0; entry->received_time = 0; entry->tz_offset = 0; } /* env_from_source: 0 == forward-from, 1 == from, 2 == return-path */ DPRINT(Debug,9,(&Debug, "env_from_source=%d\n",ef)); /* From */ if (strncmp(buffer, "From ", 5) != 0) { DPRINT(Debug,4,(&Debug, "real_from failed at beginning: \"*.5s\"",buffer)); return FALSE; } buffer += 5; DPRINT(Debug,7,(&Debug, "real_from parsing %s", buffer)); /* or */ if ((len = get_word(buffer, 0, field, sizeof(field))) < 0) goto failed; buffer += len; /* or */ if ((len = get_word(buffer, 0, field2, sizeof(field2))) < 0) goto failed; buffer += len; /* or */ if ((len = get_word(buffer, 0, field3, sizeof(field3))) < 0 ) goto failed; buffer += len; /* is in field2 or field3? */ if (!cvt_monthname_to_monthnum(field3, &month)) if (!cvt_monthname_to_monthnum(field2, &month)) goto failed; else { /* field2 is month, field3 is day */ if (ef < 2) { /* */ if (entry != NULL) *( entry->env_from ) = '\0'; DPRINT(Debug,7,(&Debug, " user=\n")); } /* */ if ((day = atonum(field3)) < 0 || day < 1 || day > 31) goto failed; } else { if (ef < 2) { char *X = field; int l; if (0 != strcmp(field,"<>") && '<' == field[0] && (l = strlen(field)) && '>' == field[l-1]) { X = field+1; field[l-1] = '\0'; } /* */ if (entry != NULL) strfcpy(entry->env_from, X, sizeof(entry->env_from)); DPRINT(Debug,7,(&Debug, " user=%s\n", X)); } /* */ if ((len = get_word(buffer, 0, field, sizeof(field))) < 0 || (day = atonum(field)) < 0 || day < 1 || day > 31) goto failed; buffer += len; } /* */ if ((len = get_word(buffer, 0, field, sizeof(field))) < 0 || !cvt_timestr_to_hhmmss(field, &hours, &mins, &secs)) goto failed; buffer += len; DPRINT(Debug,7,(&Debug, " hours=%d mins=%d secs=%d\n", hours, mins, secs)); /* * [ ... ] * * This is messy. Not only is the timezone field optional, there * might be multiple fields (e.g. "MET DST"), or it might be entirely * bogus (e.g. some MTAs produce "0600" instead of "+0600". */ tz = 0; save_tz[0] = save_tz[1] = '\0'; for (;;) { if ((len = get_word(buffer, 0, field, sizeof(field))) < 0) goto failed; buffer += len; /* * First check if this is a TZ field. If so, pull in the info * and continue onto the next field. */ if (cvt_timezone_to_offset(field, &i, sizeof field)) { tz += i; i = strlen(save_tz); (void) strfcpy(save_tz+i, " ", sizeof(save_tz)-i); ++i; (void) strfcpy(save_tz+i, field, sizeof(save_tz)-i); continue; } /* * If this isn't a valid TZ then it should be a year. If so * then save off the year info and break out of this loop. */ if (cvt_yearstr_to_yearnum(field, &year)) break; /* * This isn't either a valid TZ or year. Assume it is a bogus * timezone we don't understand, and continue processing the line. */ DPRINT(Debug,7,(&Debug, " assuming \"%s\" is a bogus timezone, skipping it\n", field)); } if (!save_tz[0] && tz == 0) { /* Assume local timezone */ long tzmin; /* number of minutes off gmt */ int tzsign; /* + or - gmt */ /* Try take account that timezone is different on summer time */ time_t XXX = make_gmttime(year, month, day, hours, mins, secs); if ((tz = (tzmin = -get_tz_mins(XXX))) >= 0) { tzsign = '+'; } else { tzsign = '-'; tzmin = -tzmin; } elm_sfprintf(save_tz, sizeof save_tz, FRM(" %c%02d%02d"), tzsign,tzmin / 60, tzmin % 60); DPRINT(Debug,7,(&Debug, " assuming local timezone %s", save_tz)); islocal++; } if (entry != NULL) { entry->tz_offset = tz * 60; (void) strfcpy(entry->time_zone, save_tz+1, sizeof(entry->time_zone)); entry->received_time = entry->time_sent = make_gmttime(year, month, day, hours, mins-tz, secs); } DPRINT(Debug,7,(&Debug, " tz=%s tz_offset=%d", save_tz+1, tz)); DPRINT(Debug,7,(&Debug, " month=%d day=%d year=%d\n", month, day, year)); if (islocal && entry) { /* Debug */ char * buf = ctime(& entry->received_time); DPRINT(Debug,7,(&Debug," ctime=%s",buf)); } /* * The line is parsed and valid. There might be more but we don't care. */ DPRINT(Debug,7,(&Debug, " return success\n")); return TRUE; failed: DPRINT(Debug,4,(&Debug, "real_from failed at \"%s\"\n", (len <= 0 ? "" : field))); return FALSE; } #ifdef _TEST int debug = 9999; main() { struct header_rec hdr; char buf[1024]; extern char *ctime(); while (gets(buf) != NULL) { if (!real_from(buf, &hdr)) printf("FAIL %s\n", buf); else { printf("OK %s\n", buf); printf("from=%s time_zone=%s tz_offset=%d\n", hdr.env_from, hdr.time_zone, hdr.tz_offset); printf("time_sent=%ld received_time=%ld %s", hdr.time_sent, hdr.received_time, ctime(&hdr.received_time)); } putchar('\n'); } exit(0); } #endif /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */