/*                                                                      */
/*                  CH_QNIFTP: NIFTP MAIL RECEIVER CHANNEL              */
/*                                                                      */
/*      Developed originally by Chris Bennett - May 1981                */
/*                                                                      */
/*      Rewritten completely by Steve Kille - August 1982               */

#include "util.h"
#include "mmdf.h"
#include "ap.h"
#include "ch.h"
#include "dm.h"

extern struct ll_struct   *logptr;

extern Chan *curchan;

extern Table *tb_nm2struct();
extern Chan *ch_nm2struct();
extern Domain *dm_v2route();
extern char *ap_dmflip();
extern char *ap_p2s();

extern qn_rdchar ();

LOCVAR  FILE    *qn_fp;         /* File pointer for current file        */
LOCVAR  long    curpos;         /* Current position in file             */
LOCVAR  char    eoheader;       /* Have we reached end of JNT header    */
LOCVAR  char    adr_keyend[] = "\r\n,\377";
				/* Set of characters terminating JNT    */
				/* Mail address                         */
LOCVAR  char    *ack_adr;       /* acknowlege-to address                */

LOCVAR  char    qn_nichanlist [LINESIZE]; /* list of valid channels     */

/*
*/
qn_init (ni_queue)              /* Initialise channel                   */
				/* No-op                                */
char    *ni_queue;              /* NIFTP queue associated with channel  */
{
    Table *tb_niftp;

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_init (%s)", ni_queue);
#endif

    if ((tb_niftp = tb_nm2struct ("niftp.nets")) == (Table *) NOTOK)
    {
	ll_err (logptr, LLOGTMP, "Failure to locate NIFTP net table");
	return (RP_NO);
    }
				/* Extract name of current channel      */
				/* from list of NIFTP channels          */
    if (tb_k2val (tb_niftp, TRUE, ni_queue, qn_nichanlist)!=OK)
    {
	ll_err (logptr, LLOGFAT, "Unknown NIFTP queue \"%s\"", ni_queue );
	return (RP_PARM);
				/* all NIFTP channels should be in the  */
				/* mapping table - if not then error    */
    }

    return (RP_OK);
}

qn_end (state)                  /* Terminate channel                    */
int state;                      /* No-op                                */
{
#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_end (%d)", state);
#endif
    return (RP_OK);
}

qn_pkinit ()                    /* Initialise for batch submission      */
				/* Not now, but perhaps later on again  */
				/* when NIFTP is working properly       */
				/* No-op                                */
{
#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_pkinit ()");
#endif
    return (RP_OK);
}

qn_pkend ()                     /* End batch submission                 */
				/* No-op                                */
{
#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_pkend ()");
#endif
    return (RP_OK);
}

/*
*/
				/* Initialise for processing message    */
qn_rinit (fname, TSname, info, sender)
char    *fname;                 /* Name of file containing JNT message  */
char    *TSname;                /* TS name of calling host              */
char    *info;                  /* place to stuff info                  */
char    *sender;                /* place to stuff name of message sender*/
{
     char       *reverse;       /* Pointer to reverse ordered domain    */
     char       tmpstr [LINESIZE];
     char       official [LINESIZE];
     Dmn_route  route;
     char       chan_buf [LINESIZE];
     int        argc, n;
     char       *argv[20];      /* lots of channels */

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_rinit (%s, %s)", fname, TSname );
#endif

    rtn_init ();
    ack_adr = (char *) 0;

    reverse = ap_dmflip (TSname);
    official [0] = 0;

    strcpy (chan_buf, qn_nichanlist);
    if ((argc = str2arg (chan_buf, 20, argv, (char *)0)) == NOTOK)
    {
	ll_err (logptr, LLOGFAT, "qn_rinit: str2arg failed '%s'", chan_buf);
	return (RP_LIO);
    }
    for ( n = 0 ; n < argc ; n++)
    {
	if ((curchan = ch_nm2struct (argv[n])) == (Chan *) NOTOK)
	{
	    ll_err (logptr, LLOGTMP, "qn_rinit: Bad channel '%s'", argv[n]);
	    continue;
	}

			/* See if we know it, NRS order first    */
	if (tb_k2val (curchan -> ch_table, TRUE, reverse, tmpstr)==OK)
	{
	    /* should check return value ?? */
	    dm_v2route (reverse, official, &route);
	    sprintf (info, "h%s*", official);
	    break;
	}
	else if (tb_k2val (curchan -> ch_table, TRUE, TSname, tmpstr)==OK)
	{
	    /* should check return value ?? */
	    dm_v2route (TSname, official, &route);
	    sprintf (info, "h%s*", official);
	    break;
	}
    }
				/* Strip "," and "*" from host name     */
				/* as it may be TS name with funnies    */
				/* we might as well munge this!!        */
    if (official [0] == '\0')
    {
	ll_err (logptr, LLOGTMP, "qnrinit: Unknown source address '%s'",TSname);
	return (RP_NDEL);
    }

#ifdef DEBUG
    ll_log (logptr, LLOGFTR, "We are channel '%s'", curchan -> ch_name);
#endif
    free (reverse);
    ch_llinit(curchan);

#ifdef DEBUG
    ll_log (logptr, LLOGFTR, "Info string is \"%s\"", info);
#endif

				/* Now open up the message file         */

    if ((qn_fp = fopen (fname, "r")) == NULL )
    {
	ll_err (logptr, LLOGTMP, "can't open file '%s'",
			    fname);
	return (RP_FIO);
    }

				/* Extract sender name from text        */
				/* This is pretty ugly, but the best    */
				/* That JNT mail can do                 */
				/* If there is no sender field valid    */
				/* dont worry about it                  */
    sender [0] = '\0';
    if (rp_isbad(hdr_sender (sender, &ack_adr, qn_fp, official)))
	return (RP_NDEL);
				/* now return to the start of the file  */

    ll_log (logptr, LLOGFST, "sender: '%s'", sender);

    fseek (qn_fp, 0L, 0);
    if (ferror (qn_fp))
    {
	ll_err (logptr, LLOGTMP, "Fail to seek on file '%s'", fname);
	return (RP_FIO);
    }
    curpos = 0;                 /* mark postition                       */

    eoheader = FALSE;           /* ready to read JNT header             */

    return (RP_OK);
}
/*
*/
extern char *rindex ();

qn_radr (host, adr)             /* extract next address from file       */
				/* might get confused by very badly     */
				/* damaged files                        */
char    *host;
char    *adr;
{
    char        *strptr;
    char        *cp;
    AP_ptr      local,          /* pointers for parse coponents         */
		domain,
		route;
    AP_ptr      ptr;
    AP_ptr      ap;

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_radr ()");
#endif

    if ((ptr = ap_pinit (qn_rdchar)) == (AP_ptr) NOTOK)
    {
	ll_err (logptr, LLOGTMP, "Problem initialising for parse");
	return (RP_LIO);
    }

#ifdef DEBUG
     ll_log (logptr, LLOGFTR, "Parse corectly initialised");
#endif

    switch ( ap_1adr ())
    {
	case NOTOK:
	    ap_free (ptr);
	    ll_log (logptr, LLOGFAT, "Bad format address in JNT header");
	    return (RP_HUH);
	case DONE:
	    ap_free (ptr);
	    return (RP_DONE);   /* end of address list                  */
    }

				/* Now analyse address                  */

    ap_t2parts (ptr, (AP_ptr *) 0, (AP_ptr *) 0, &local, &domain, &route);
				/* remove any trailing DLIT          */
    if (route == (AP_ptr) 0)
    {
	if (domain ->  ap_obtype == APV_DLIT)
	{
	    ap_free (domain);
	    domain = (AP_ptr) 0;
	}
    }
    else
    {
	if (route -> ap_obtype == APV_DLIT)
	{
	    ap = route;
	    route = ap -> ap_chain;
	    if (route -> ap_obtype != APV_DLIT ||
		route ->  ap_obtype != APV_DOMN)
	    route = (AP_ptr) 0;
	    ap_free (ap);
	}
    }

    strptr = ap_p2s ((AP_ptr) 0, (AP_ptr) 0, local, domain, route);
    if(strptr == (char *)MAYBE)
	return(RP_NS);

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "Full address is '%s'", strptr);
#endif
    strcpy (adr, strptr);
    cp = rindex (adr, '@');
    if (cp == (char *) 0)
	host [0] = '\0';
    else
    {
	*cp  = '\0';
	strcpy (host, ++cp);
    }
    free (strptr);

    ll_log (logptr, LLOGFST, "JNT Address h='%s', a='%s'", host, adr);
    return (RP_AOK);
}


/*
*/
qn_raend ()                      /* Reached end of address list          */
				/* skip ofver any LWSP before 733 header*/
{
    int         c;

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_raend ()");
#endif

    FOREVER
    {
	if ((c = getc (qn_fp)) == EOF)
	{
	    ll_err (logptr, LLOGTMP, "JNT mail header with no body" );
	    return (RP_NO);
	}
	curpos++;
	if (!isspace (c))       /* reached start of 733 header          */
	{
	    fseek (qn_fp, --curpos, 0);
				/* set back one character               */
	    if (ferror (qn_fp))
		return (RP_FIO);
	    return (RP_OK);
	}
    }
}
/*
*/
qn_wrply (reply, adr, host)     /* Used to mark status of address       */
				/* If reply is bad, passed downwards    */
				/* to build up list of erroneous        */
				/* addresses to be passed back          */
struct rp_bufstruct  *reply;
char    *adr,
	*host;
{
    char   line[LINESIZE];
#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_wrply ()");
#endif

    if (rp_isgood (reply -> rp_val))
    {
	sprintf (line, "%s@%s", adr, host);
	return (rtn_adr (line, TRUE));
    }
    else
    {
	strcpy (line, reply -> rp_line);
	return (rtn_adr (line, FALSE));
    }

}
/*
*/
qn_rtxt (buffer, len)             /* read buffered block of text        */
char   *buffer;                   /* where to stuff next part of text   */
int    *len;                      /* where to stuff length of part      */
{
#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_rtxt ()");
#endif


    switch (*len = gcread (qn_fp, buffer, *len - 1, "\n\000\377"))
    {                             /* raw read of the file               */
	case NOTOK:
	    ll_err (logptr, LLOGFAT, "File read error");
	    return (RP_FIO);

	case OK:                  /* end of message; not treated as EOF */
#ifdef DEBUG
	    ll_log (logptr, LLOGBTR, "qn_rtxt (DONE)");
#endif
	    return (RP_DONE);
    }
    switch (*len)
    {
	case 0:
	    return (RP_DONE);

	case 1:
	    if (isnull (buffer[0]))
		return (RP_DONE);
    }
    buffer[*len] = '\0';          /*   so it can be ll_loged as a string  */
#ifdef DEBUG
    ll_log (logptr, LLOGFTR, "\"%s\"", buffer);
#endif
    return (RP_OK);
}
/**/
extern char *supportaddr;

qn_rtend (sender, fname, alright)
				/* finished reading text - close file      */
				/* send off error message                  */
char    *sender;        /* sender of message                               */
char    *fname;         /* full pathname of file                           */
int     alright;
{
    int retval;
#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "qn_rtend ()");
#endif

    retval = RP_OK;
    if (rp_isgood (alright))
    {
	if (ack_adr  != (char *) 0)
	{
	    rtn_ack (ack_adr, qn_fp);
				/* don't care if this fails             */
	    free (ack_adr);
	}

	if (rtn_errmsg (sender, qn_fp) == NOTOK)
	{
	    ll_log (logptr,  LLOGTMP, "Failed to send error mesage to '%s'",
				sender);
	    if (rtn_errmsg (supportaddr, qn_fp) == NOTOK)
	    {
		ll_log (logptr, LLOGTMP, "Failed to send error message to spport addr");
		retval = RP_NO;
	    }
	}
				/* fire off error message                  */
				/* pass error upwards if it fails          */
    }


    if ((qn_fp != NULL) && (fclose (qn_fp) == NOTOK)) /* close file */
    {
	ll_err (logptr, LLOGFAT, "Failure to close file '%s'", fname);
	return (RP_FIO);
    }

    if (rp_isgood (alright) && unlink (fname) == NOTOK)
				/* delete file                            */
    {
	ll_err (logptr, LLOGFAT, "Failure to unlink file '%s'", fname);
	return (RP_FOPN);
    }

    return (retval);
}
/**/

LOCFUN
qn_rdchar ()                    /* read chars from jnt header           */
				/* stop when we reach blank line        */
{
    int         c;

#ifdef DEBUG
   ll_log (logptr, LLOGMAX, "qn_rdchar ()");
#endif

    if (eoheader)
	return (EOF);

    if ((c = getc (qn_fp)) == EOF)
    {
	ll_err (logptr, LLOGTMP, "Premature end of JNT Mail Header");
	return (EOF);
    }
    curpos++;

    if (c != '\n')
    {
#ifdef DEBUG
    ll_log (logptr, LLOGMAX, "Returning (%c)", c);
#endif
	return (c);
    }

    while (isspace (c = getc (qn_fp)) && c != '\n')
	curpos++;

    curpos++;
    if (c == '\n')              /* note NIFTP changes <CRLF> sequence */
    {
#ifdef DEBUG
    ll_log (logptr, LLOGMAX, "Returning EOF");
#endif
	eoheader = TRUE;
	return (EOF);
    }
				/* end of JNT header                   */

#ifdef DEBUG
    ll_log (logptr, LLOGMAX, "Returning (%c)", c);
#endif

    return (c);                 /* Just a newline                       */
}
