#include "util.h"
#include "mmdf.h"
#include "hdr.h"
#include "ch.h"
#include "ap.h"
/*
 *     MULTI-CHANNEL MEMO DISTRIBUTION FACILITY  (MMDF)
 *
 *
 *     Copyright (C) 1979,1980,1981  University of Delaware
 *
 *     Department of Electrical Engineering
 *     University of Delaware
 *     Newark, Delaware  19711
 *
 *     Phone:  (302) 738-1163
 *
 *
 *     This program module was developed as part of the University
 *     of Delaware's Multi-Channel Memo Distribution Facility (MMDF).
 *
 *     Acquisition, use, and distribution of this module and its listings
 *     are subject restricted to the terms of a license agreement.
 *     Documents describing systems using this module must cite its source.
 *
 *     The above statements must be retained with all copies of this
 *     program and may not be removed without the consent of the
 *     University of Delaware.
 *
 *
 *     version  -1    David H. Crocker    March   1979
 *     version   0    David H. Crocker    April   1980
 *     version  v7    David H. Crocker    May     1981
 *     version   1    David H. Crocker    October 1981
 *
 */
/* This module has bits extracted from submit modules                   */
/* It is used by the Q NIFTP channel to extract a sender address        */
/* From the text                                                        */
/* This is really a pretty ugly way to do things - but I didnt write    */
/* the protocol                                                         */
/*                                                                      */
/*      Steve Kille             August 1982                             */
/*      Steve Kille             Feb 83          extensive rehack        */


extern struct ll_struct *logptr;

extern Chan *curchan;

extern char *index ();
extern char *compress ();
extern char *ap_p2s();
extern char *multcat();
extern AP_ptr ap_new();

extern char *locfullmachine;
extern char *locfullname;
/*
*/


LOCFUN AP_ptr newdomain (domn)
    register char *domn;
{
    return (ap_new ((*domn == '[')? APV_DLIT : APV_DOMN, domn));
}

				/* This is used to get the sender name  */
				/* Passes over JNT header and then      */
				/* examines the 822 header fields       */
				/* Takes Sender field if it exists      */
				/* If not takes first From field        */
hdr_sender (sender, ack, hdr_fp, viahost)
char    *sender;                /* Where to stuff name of sender        */
char    **ack;                  /* ack address - note double indirection*/
FILE    *hdr_fp;                /* File being examined                  */
char    *viahost;               /* Host message receoved from           */
{
    char        line[LINESIZE];         /* temp buffer                  */
    char        name[LINESIZE];         /* Name of header field         */
    char        contents[LINESIZE];     /* Contents of header field     */
    int         gotfrom;                /* Got address from From        */
    int         len;
    int         donevia;
    char        *p;
    AP_ptr      ap_ack,
		ap_sender,
		jntroute,
		ap,
		domain,
		route,
		mbox;

#ifdef DEBUG
   ll_log (logptr, LLOGBTR, "hdr_sender (%s)", viahost);
#endif

    gotfrom = FALSE;
    ap_sender = (AP_ptr) 0;
    sender [0] = '\0';
    jntroute = (AP_ptr) 0;

				/* We are at start of file              */
				/* Therefore skip JNT mail header       */
    while ((len = gcread (hdr_fp, line, LINESIZE, "\n\377")) > 1)
    {
	line [len - 1] = '\0';
	for (p = line ; isspace(*p) ;p++);
	if (*p == '\0')
	    break;
    }
    if (len == NOTOK)
    {
	ll_err (logptr, LLOGFAT, "Can't find 733 header");
	return (RP_NO);
    }



				/* Now process header lines             */
   FOREVER
   {
				/* Get a line                           */
	if ((len = gcread (hdr_fp, line, LINESIZE, "\n\377")) < 1)
	{
	    ll_log (logptr, LLOGTMP, "Message has no body" );
				/* someone MIGHT want to do this so     */
				/* just log and pass on through         */
	    if (gotfrom)        /* drop down and return adr             */
		break;
	    return (RP_NO);
	}
	line [len] = '\0';
	ll_log (logptr, LLOGFTR, "gcread (in header) = '%s' (%d)", line, len);

	switch (hdr_parse (line, name, contents))
	{
	    case        HDR_NAM:
				/* No name so contine through header    */
		continue;

	    case        HDR_EOH:
				/* End of header                        */
		if (gotfrom)    /* if we have From address pass it back */
		       break;
		return (RP_NO);

	    case        HDR_NEW:
	    case        HDR_MOR:
				/* Real field so check it               */
		if (lexequ (name, "Via"))
		{
		    if ((p = index (contents, ';')) == 0)
		    {
			ll_log (logptr, LLOGTMP, "Illegal via: field '%s'",
				contents);
			continue;
		    }
		    *p = '\0';
		    compress (contents, contents);
		    /*
		     * must take comments out of via field, ( to get info
		     * correct )
		     * ( delete RFC822 comments from via field )
		     */
		    while ((p = index (contents, '(')) != NULL)
		    {
			char    *q;
			if ((q = index(p, ')')) == NULL)
			{
			     ll_log(logptr, LLOGTMP,
				"Illegal comment in via: field '%s'", contents);
			     break;
			}
			strcpy(p, q+1);         /* zap () comment */
		    }
		    if(p != NULL)               /* only non null if no ')' */
			continue;
		    compress (contents, contents);
#ifdef DEBUG
		    ll_log (logptr, LLOGFTR, "%s: %s", name, contents);
#endif
		    ap = newdomain (contents);
		    ap -> ap_chain = jntroute;
		    jntroute = ap;
		}

		if (lexequ (name, "acknowledge-to"))
		    if (*ack == (char *) 0)
		    {
			ap_ack = ap_s2tree (contents);
			if (ap_ack != (AP_ptr) NOTOK)
			{
			    if(ap_t2s (ap_ack, ack) == (AP_ptr)MAYBE)
				return(RP_NS);
#ifdef DEBUG
			    ll_log (logptr, LLOGFTR, "Ack field '%s", &ack);
#endif
			    ap_sqdelete (ap_ack, (AP_ptr) 0);
			}
		    }

		if (lexequ (name, "Sender"))
		{
		    ap_sender = ap_s2tree (contents);
		    if (ap_sender == (AP_ptr) NOTOK)
		    {
			ll_log (logptr, LLOGFTR, "Illegal sender field: %s",
					contents);
			return (RP_NO);
		    }
		    break;      /* now build route */
		}

		if (lexequ (name, "From") && !gotfrom)
		{
		    if ((ap_sender = ap_s2tree (contents)) !=
					(AP_ptr) NOTOK)
			gotfrom = TRUE;
		}
		continue;
	}
	break;          /* always fall out of loop */
    }
				/* build on the route from the trace */
    ap_t2parts (ap_sender, (AP_ptr *) 0, (AP_ptr *) 0,
		&mbox, &domain, &route);

    donevia = FALSE;
    FOREVER {
	if (jntroute != (AP_ptr) 0) {
	    ap = jntroute;
	    jntroute = jntroute -> ap_chain;
	}
	else if (donevia)
	    break;
	else {
	    donevia = TRUE;
	    if (viahost [0] == '\0') {
		char *vh;
		if (curchan->ch_lname) {
		    vh = multcat(curchan->ch_lname, ".", curchan->ch_ldomain,
			(char *)0);
		    ap = newdomain (vh);
		    free(vh);
		}
		else {
		    ap = newdomain (
		    	    isstr(locfullmachine)?locfullmachine:locfullname
			);
		}
	    }
	    else
		ap = newdomain (viahost);
	}

	if (domain == (AP_ptr) 0)
	    domain = ap;
	else {
	    ap -> ap_chain = route;
	    route = ap;
	}
    }

				/* now normalise the domains        */
    if(ap_dmnormalize (domain, (Chan *) NULL) == MAYBE)
	return(RP_NS);
    for (ap = route; ap != (AP_ptr) 0; ap = ap -> ap_chain)
	if(ap_dmnormalize (ap, (Chan *) NULL) == MAYBE){
		ap_free (route);	/* I suspect this is not needed */
		return(RP_NS);
	}

				/* eliminating redundant entries     */
				/* This made into a loop by Peter C UKC */
				/* I found that the route could contain */
				/* several instances of the same string */
				/* it is prudent to remove them */
    while (route != (AP_ptr) 0)
    {
	for (ap = route; ap -> ap_chain != (AP_ptr) 0; )
    	{
		if (ap -> ap_chain ->ap_obtype == APV_NIL)
			break;
		ap = ap -> ap_chain;
	}

	if (lexequ (domain -> ap_obvalue, ap -> ap_obvalue))
	{
		ap -> ap_obtype = APV_NIL;
		free (ap -> ap_obvalue);
		ap -> ap_obvalue = (char *) 0;
		if (ap == route)
		{
			ap_free (route);
			route = (AP_ptr) 0;
			break;
		}
	}
    	else
		break;
    }
    p = ap_p2s ((AP_ptr) 0, (AP_ptr) 0, mbox, domain, route);
    if(p == (char *)MAYBE)
	return(RP_NS);
    strcpy (sender, p);
    free (p);
    ll_log (logptr, LLOGFTR, "Sender = '%s'", sender);
    return (RP_OK);
}
/*
*/
/* basic processing of incoming header lines */
LOCFUN
hdr_parse (src, name, contents)   /* parse one header line              */
    register char *src;           /* a line of header text              */
    char *name,                   /* where to put field's name          */
	 *contents;               /* where to put field's contents      */
{
    extern char *compress ();
    char linetype;
    register char *dest;

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "hdr_parse(%s)", src);
#endif

    if (isspace (*src))
    {                             /* continuation text                  */
#ifdef DEBUG
	ll_log (logptr, LLOGFTR, "cmpnt more");
#endif
	if (*src == '\n')
	    return (HDR_EOH);
	linetype = HDR_MOR;
    }
    else
    {                             /* copy the name                      */
	linetype = HDR_NEW;
	for (dest = name; *dest = *src++; dest++)
	{
	    if (*dest == ':')
		break;            /* end of the name                    */
	    if (*dest == '\n')
	    {                     /* oops, end of the line              */
		*dest = '\0';
		return (HDR_NAM);
	    }
	}
	*dest = '\0';
	compress (name, name);    /* strip extra & trailing spaces      */
#ifdef DEBUG
	ll_log (logptr, LLOGFTR, "cmpnt name '%s'", name);
#endif
    }

    for (dest = contents; isspace (*src); )
	if (*src++ == '\n')       /* skip leading white space           */
	{                         /* unfulfilled promise, no contents   */
	    *dest = '\0';
	    return ((linetype == HDR_MOR) ? HDR_EOH : linetype);
	}                          /* hack to fix up illegal spaces      */

    while ((*dest = *src) != '\n' && *src != 0)
	     src++, dest++;       /* copy contents and then, backup     */
    while (isspace (*--dest));    /*   to eliminate trailing spaces     */
    *++dest = '\0';

    return (linetype);
}
