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 <hurtta+elm@posti.FMI.FI> 
 *                           (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 <user> <weekday> <month> <day> <hr:min:sec>
     *	    [TZ1 [TZ2]] <year> [remote from sitelist]
     *
     * We insist that all of the <angle bracket> fields are present.
     * If two timezone fields are present, the first is used for date
     * information.  We do not look at anything beyond the <year> field.
     * We just insist that everything up to the <year> 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));

    /* <user> or <weekday> */
    if ((len = get_word(buffer, 0, field, sizeof(field))) < 0)
	goto failed;
    buffer += len;

    /* <weekday> or <month> */
    if ((len = get_word(buffer, 0, field2, sizeof(field2))) < 0)
	goto failed;
    buffer += len;

    /* <month> or <day> */
    if ((len = get_word(buffer, 0, field3, sizeof(field3))) < 0 )
	goto failed;
    buffer += len;

    /* is <month> 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) {
		/* <user> */
		if (entry != NULL)
		    *( entry->env_from ) = '\0';
		DPRINT(Debug,7,(&Debug, 
				"  user=\n"));
	    }

          /* <day> */
          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';
	    }

	    /* <user> */ 
	    if (entry != NULL) 
		strfcpy(entry->env_from, X, sizeof(entry->env_from));
	    DPRINT(Debug,7,(&Debug,
			    "  user=%s\n", X));
	    
	}

        /* <day> */
        if ((len = get_word(buffer, 0, field, sizeof(field))) < 0 ||
	    (day = atonum(field)) < 0 || day < 1 || day > 31)
	    goto failed;
        buffer += len;
    }
    
    /* <hr:min:sec> */
    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));
    
    /*
     * [ <tz> ... ] <year>
     *
     * 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 ? "<premature eol>" : 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:
 */


syntax highlighted by Code2HTML, v. 0.9.1