#ifndef	POP
/* bb_wtmail.c - write mail to a BBoard */
#else /* POP */
/* po_wtmail.c - write mail for a POP subscriber */
#endif /* POP */


#include "util.h"
#include "mmdf.h"
#include "bboards.h"
#include "cnvtdate.h"
#include "ch.h"
#include "phs.h"
#include <pwd.h>
#include <sys/stat.h>

/*  */

#ifndef	RP_DOK
#define	submitopts	"vmth%s*"
#else /* RP_DOK */
#define	submitopts	"vkmth%s*"
#endif /* RP_DOK */

#ifndef	POP
#define	RP_NOPE	RP_AOK

#define	MBXMODE	BBMODE
#else /* POP */
#define	RP_NOPE	RP_USER

#define	MBXMODE	sentprotect

extern int   sentprotect;
#endif /* POP */


int	err_fd = NOTOK;

int     ds_address ();

extern int  errno;

int    bbrduid, bbrdgid;

char   *chnlname,
        chnlinfo[LINESIZE];
#ifndef	POP
char	bbrdaddr[LINESIZE],
        bbrdfrom[LINESIZE],
        bbrdheader[LINESIZE],
	bbrdhome[LINESIZE],
        bbrdtime[LINESIZE];
#endif /* not POP */

extern char *qu_msgfile,
            *delim1,
            *delim2,
	    *lckdfldir,
            *locfullmachine,
            *locfullname,
	    *sitesignature,
	    *supportaddr;

struct bboard  *curbb;

extern LLog *logptr;

FILE *lk_fopen();

long    lseek ();
char   *index (), *rindex ();
#ifdef SYS5
int sprintf ();
#else
char *sprintf ();
#endif
struct passwd  *getpwnam ();

/*  */

bb_init (chanptr)
Chan * chanptr;
{
    int     uid,
            eid;
    struct passwd *pw;

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "bb_init(chanptr=%s)", chanptr -> ch_name);
#endif

    chnlname = chanptr -> ch_name;
#ifndef	notdef
    sprintf (chnlinfo, submitopts, chnlname);
#else /* notdef			/* the following is probably a BAD idea */
    if (chanptr -> ch_host == NULL)
	chnlinfo[0] = NULL;	/* local delivery ONLY */
    else
	sprintf (chnlinfo, submitopts, chanptr -> ch_host);
#endif /* notdef */

#ifndef	POP
    if ((pw = getpwnam (BBOARDS)) == NULL)
	err_abrt (RP_BHST, "no passwd entry for '%s'", BBOARDS);
#else /* POP */
    if ((pw = getpwnam (POPUID)) == NULL)
	err_abrt (RP_BHST, "no passwd entry for '%s'", POPUID);
#endif /* POP */

    bbrduid = pw -> pw_uid;
    bbrdgid = pw -> pw_gid;
#ifndef	POP
    if (isstr (locfullmachine))
	sprintf (bbrdfrom, "%s@%s", pw -> pw_name, locfullmachine);
    else
	sprintf (bbrdfrom, "%s@%s", pw -> pw_name, locfullname);
#ifdef DEBUG
    ll_log (logptr, LLOGGEN, "distributing as '%s'", bbrdfrom);
#endif
    sprintf (bbrdhome, pw -> pw_dir);
#endif /* not POP */

#ifndef	POP
    if (!setbbent ())
	err_abrt (RP_BHST, "setbbent() failed");
#else /* POP */
    if (!setpwinfo (pw, POPDB, 1))
	err_abrt (RP_BHST, "setbbinfo(%s, %s, 1) failed",
		pw -> pw_name, POPDB);
#endif /* POP */

    getwho (&uid, &eid);
    if (eid != 0)
	err_abrt (RP_BHST, "not running as root");

    return RP_OK;
}


bb_end (result)
short   result;
{
#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "bb_end(result=0%o)", result);
#endif

    return RP_OK;
}

/*  */

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

    return RP_OK;
}


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

    return RP_OK;
}

/*  */

bb_winit (info, sender)
char   *info,
       *sender;
{
#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "bb_winit(info='%s',sender='%s')",
	    info, sender);
#endif

    return RP_OK;
}

/*  */

bb_wtadr (host, adr)
char   *host,
       *adr;
{
    short   count,
            result;
    int     len,
	    md,
            offset,
	    size;
    long    start,
            stop,
            pos;
    char   *cp,
            buffer[BUFSIZ];

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "bb_wtadr(host=%s,adr=%s)", host, adr);
#endif

    if ((cp = index (adr, '@')) != NULL)
	*cp = NULL;
    make_lower (adr, adr);
    if ((curbb = getbbnam (adr)) == NULL)
	return RP_USER;
#ifndef	POP
    if (isstr (locfullmachine))
	sprintf(bbrdaddr,"local-%s-request@%s", curbb->bb_name, locfullmachine);
    else
	sprintf(bbrdaddr,"local-%s-request@%s", curbb->bb_name, locfullname);
#endif /* not POP */
#ifdef DEBUG
    ll_log (logptr, LLOGGEN, "=> BBoard %s: file='%s' info='%s'",
	    curbb -> bb_name, curbb -> bb_file, curbb -> bb_info);
#endif

    if (curbb -> bb_file == NULL || *curbb -> bb_file == NULL)
	return RP_NOPE;
#ifdef DEBUG
    ll_log (logptr, LLOGGEN, "begin local delivery...");
#endif
    printx ("\r\nperforming local delivery to file %s...\n",
	    curbb -> bb_file);

    qu_rtinit (0L);

    if ((md = mbx_open (curbb -> bb_file, bbrduid, bbrdgid, MBXMODE)) == NOTOK)
	return RP_FIO;

#ifndef	POP
    if (rp_isbad (result = mbx_init ())) {
	mbx_close (curbb -> bb_file, md);
	return result;
    }
#endif /* not POP */

    pos = lseek (md, 0L, 1);
    count = strlen (delim1);
    if (write (md, delim1, count) != count) {
	ll_log (logptr, LLOGTMP, "error writing delim1");
	result = NOTOK;
	goto clean_up;
    }
    start = lseek (md, 0L, 1);
    size = 0;

#ifndef	POP
    count = strlen (bbrdheader);
    if (write (md, bbrdheader, count) != count) {
	ll_log (logptr, LLOGTMP, "error writing BBoard information");
	result = NOTOK;
	goto clean_up;
    }
    for (cp = bbrdheader; *cp; cp++, size++)
	if (*cp == '\n')
	    size++;
#endif /* not POP */

    for (len = BUFSIZ;
	    rp_gval (result = qu_rtxt (buffer, &len)) == RP_OK;
	    len = BUFSIZ) {
	for (offset = 0;
		(offset = strindex (delim1, buffer)) >= 0;
		buffer[offset]++)
	    continue;
	for (offset = 0;
		(offset = strindex (delim2, buffer)) >= 0;
		buffer[offset]++)
	    continue;
	if (write (md, buffer, len) != len) {
	    ll_log (logptr, LLOGTMP, "error writing to file '%s'",
		    curbb -> bb_file);
	    result = NOTOK;
	    goto clean_up;
	}
	for (offset = 0, cp = buffer; offset < len; offset++, size++)
	    if (*cp++ == '\n')
		size++;
    }

    if (result < 0)
	ll_log (logptr, LLOGTMP, "error reading from message file '%s'",
		qu_msgfile);
clean_up: ;

    stop = lseek (md, 0L, 1);
    count = strlen (delim2);
    if (write (md, delim2, count) != count)
	ll_log (logptr, LLOGTMP, "error writing delim2");
    map_write (curbb -> bb_file, md, curbb -> bb_maxima, start, stop, pos,
	size, 0);
#ifdef DEBUG
    ll_log (logptr, LLOGGEN, "end local delivery...");
#endif

    if (result < 0)
	mbx_close (curbb -> bb_file, md);
    else
	result = mbx_close (curbb -> bb_file, md);

    return (result != NOTOK ? RP_OK : RP_FIO);
}

/*  */

bb_txtcpy () {
#ifndef	POP
    short   result;

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

    if (curbb -> bb_dist == NULL
	    || *curbb -> bb_dist == NULL
	    || chnlinfo[0] == NULL)
	return RP_MOK;
#ifdef DEBUG
    ll_log (logptr, LLOGGEN, "begin distribution...");
#endif
    if (curbb -> bb_file == NULL || *curbb -> bb_file == NULL)
	printx ("\r\n");
    printx("\rperforming remote distribution\n");

    if (rp_isbad (result = dist_init ())
	    || rp_isbad (result = dist_adrs ())
	    || rp_isbad (result = dist_text ())
	    || rp_isbad (result = dist_end ()))
	return dist_lose (result);
#ifdef DEBUG
    ll_log (logptr, LLOGGEN, "end distribution...");
#endif

    if (err_fd != NOTOK)
	dist_lose (RP_MOK);
    else
	printx ("\rmessage distributed\n");
#endif /* not POP */

    return RP_MOK;
}

/*  */

#ifndef	POP
/* **************** (dist_)  BBOARD DISTRIBUTION **************** */

dist_init () {
    short   result;
#ifdef	RP_NS
    int	    len;
    struct rp_bufstruct reply;
#endif /* RP_NS */

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

    if (rp_isbad (result = mm_init ()))
	return ds_log (result, LLOGFAT, "mm_init() failed [%s]",
		rp_valstr (result));
    if (rp_isbad (result = mm_sbinit ()))
	return ds_log (result, LLOGFAT, "mm_sbinit() failed [%s]",
		rp_valstr (result));
    if (rp_isbad (result = mm_winit (chnlname, chnlinfo, bbrdaddr)))
	return ds_log (result, LLOGFAT,
		"mm_winit('%s','%s','%s') failed [%s]",
		chnlname, chnlinfo, bbrdaddr, rp_valstr (result));
#ifdef	RP_NS
	if (rp_isbad (result = mm_rrply (&reply, &len)))
	    return ds_log (result, LLOGFAT, "problem with sender address [%s]",
		    rp_valstr (result));
#endif /* RP_NS */

    return result;
}

/*  */

dist_adrs ()
{
    short   result;

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

    if (getbbdist (curbb, ds_address))
	return ds_log (RP_NO, LLOGTMP, "getbbdist failed: %s", getbberr ());

    if (rp_isbad (result = mm_waend ()))
	return ds_log (result, LLOGFAT, "mm_waend() failed [%s]",
		rp_valstr (result));

    return result;
}

/*  */

ds_address (addr, host)
char *addr,			/* local part */
     *host;			/* rest */
{
    short   result;
    int     len;
    struct rp_bufstruct reply;

#ifdef DEBUG
    ll_log (logptr, LLOGBTR, "ds_address(addr='%s',host='%s')", addr, host);
#endif

    printx ("\rperforming distribution to %s@%s...\n", addr, host);
    if (rp_isbad (result = mm_wadr (host, addr))) {
	ds_log (result, LLOGFAT, "mm_wadr('%s','%s') failed [%s]",
		host, addr, rp_valstr (result));
	return NOTOK;
    }
    if (rp_isbad (result = mm_rrply (&reply, &len))) {
	ds_log (result, LLOGFAT,
		"mm_rrply() failed [%s] getting status of '%s@%s'",
		rp_valstr (result), addr, host);
	return NOTOK;
    }

    switch (rp_gval (reply.rp_val)) {
	case RP_AOK:
#ifdef	RP_DOK
	case RP_DOK:
#endif /* RP_DOK */
#ifdef DEBUG
	    ll_log (logptr, LLOGGEN, "address '%s@%s' [%s] -- %s",
		    addr, host, rp_valstr (reply.rp_val), reply.rp_line);
#endif
	    return OK;

	case RP_NO:
#ifdef	RP_NS
	case RP_NS:
#endif /* RP_NS */
	case RP_USER:
	case RP_NDEL:
	case RP_AGN:
	case RP_NOOP:
	    ds_log (reply.rp_val, LLOGTMP, "address '%s@%s' [%s] -- %s",
		    addr, host, rp_valstr (reply.rp_val), reply.rp_line);
	    return OK;		/* fail-soft */

	default:
	    ds_log (reply.rp_val, LLOGFAT, "unexpected reply [%s] -- %s",
		    rp_valstr (reply.rp_val), reply.rp_line);
	    return NOTOK;
    }
}

/*  */

dist_text ()
{
    short   result;
    int     len;
    char    buffer[BUFSIZ];

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

    qu_rtinit (0L);
    for (len = BUFSIZ;
	    rp_gval (result = qu_rtxt (buffer, &len)) == RP_OK;
	    len = BUFSIZ)
	if (rp_isbad (result = mm_wtxt (buffer, len)))
	    return ds_log (result, LLOGFAT, "mm_wtxt() failed [%s]",
		    rp_valstr (result));

    if (result < 0)
	return ds_log (RP_FIO, LLOGTMP,
		"error reading from message file '%s'", qu_msgfile);

    if (rp_isbad (result = mm_wtend ()))
	return ds_log (result, LLOGFAT, "mm_wtend() failed [%s]",
		rp_valstr (result));

    return result;
}

/*  */

dist_end ()
{
    short   result;
    int     len;
    struct rp_bufstruct reply;

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

    if (rp_isbad (result = mm_rrply (&reply, &len)))
	return ds_log (result, LLOGFAT,
		"mm_rrply() failed [%s] getting final status",
		rp_valstr (result));

    switch (rp_gval (reply.rp_val)) {
	case RP_OK:
	case RP_MOK:
#ifdef DEBUG
	    ll_log (logptr, LLOGGEN, "message [%s] -- %s",
		    rp_valstr (reply.rp_val), reply.rp_line);
#endif
	    mm_sbend ();
	    mm_end (OK);
	    return result;

	case RP_NO:
	case RP_NDEL:
	case RP_AGN:
	case RP_NOOP:
	    return ds_log (RP_NO, LLOGTMP, "not delivered [%s] -- %s",
		    rp_valstr (reply.rp_val), reply.rp_line);

	default:
	    return ds_log (RP_RPLY, LLOGFAT,
		    "unexpected final reply [%s] -- %s",
		    rp_valstr (reply.rp_val), reply.rp_line);
    }
}

/*  */

dist_lose (result)
short   result;
{
    int     i;
    char   *cp,
            intro[BUFSIZ],
            buffer[BUFSIZ];

#ifdef	DEBUG
    ll_log (logptr, LLOGBTR, "dist_lose(result=0%o)", result);
#endif /* DEBUG */

    mm_end (NOTOK);

    printx ("\rerrors during distribution: ");
    if (domsg)
	(void) fflush (stdout);
    (void) sprintf (intro, "bboards%d distribution for %s failed [%s]\n",
	    getpid (), curbb -> bb_name, rp_valstr (result));
    if (loseaux (bbrdaddr, bbrdfrom, intro) != OK
	    && loseaux (bbrdfrom, (char *) 0, intro) != OK) {
	printx ("unable to post advisory.\n");
	ll_log (logptr, LLOGFAT, "unable to post failure notice");
	if (err_fd != NOTOK) {
	    (void) lseek (err_fd, 0L, 0);
	    if ((i = read (err_fd, buffer, sizeof buffer)) > 0) {
		buffer[i] = NULL;
		if (cp = index (buffer, '\n'))
		    *cp = NULL;
		ll_log (logptr, LLOGFAT, "info: %s", buffer);
	    }
	}
	if (loseaux (supportaddr, (char *) 0, intro) != NOTOK)
	    ll_log (logptr, LLOGFAT, "unable to advise %s of failure!",
		    supportaddr);
    }
    else
	printx ("advisory posted.\n");
    if (domsg)
	(void) fflush (stdout);

    if (err_fd != NOTOK) {
	close (err_fd);
	err_fd = NOTOK;
    }
    return RP_MOK;
}

/*  */

int	loseaux (to, cc, intro)
char   *to,
       *cc,
       *intro;
{
    int     i;
    char    buffer[BUFSIZ];

    if (ml_init (NO, NO, sitesignature, "Re-distribution Failure") != OK
	    || ml_adr (to) != OK)
	return NOTOK;
    if (cc && (ml_cc () != OK || ml_adr (cc) != OK))
	return NOTOK;
    if (ml_aend () != OK || ml_tinit () != OK)
	return NOTOK;

    ml_txt (intro);
    if (err_fd != NOTOK) {
	lseek (err_fd, 0L, 0);
	while ((i = read (err_fd, buffer, sizeof buffer)) > 0) {
	    buffer[i] = NULL;
	    ml_txt (buffer);
	}
    }
    encap ();

    return ml_end (OK);
}

/*  */

/* very similar to sbr/cpydgst.c */

#define	S1	0
#define	S2	1

#define	output(c)	if (bp >= dp) {flush (); *bp++ = c;} else *bp++ = c
#define	flush()		if (bp - outbuf) \
			    *bp = NULL, ml_txt (outbuf), bp = outbuf

static  encap () {
    register int    state;
    short   result;
    int     len,
	    init;
    register char  *cp,
                   *ep;
    char    buffer[BUFSIZ];
    register char  *bp,
                   *dp;
    char    outbuf[BUFSIZ];

    qu_rtinit (0L);

    dp = (bp = outbuf) + sizeof outbuf;
    init = 0;
    for (state = S1, len = BUFSIZ;
	    rp_gval (result = qu_rtxt (buffer, &len)) == RP_OK;
	    len = BUFSIZ)
	for (ep = (cp = buffer) + len; cp < ep; cp++) {
	    if (*cp == NULL)
		continue;
	    switch (state) {
		case S1: 
		    if (*cp == '-') {
			if (init == 0) {
			    ml_txt ("\n------- Forwarded Message\n\n");
			    init++;
			}
			output ('-');
			output (' ');
		    }
		    state = S2;	/* fall */

		case S2: 
		    if (init == 0) {
			ml_txt ("\n------- Forwarded Message\n\n");
			init++;
		    }
		    output (*cp);
		    if (*cp == '\n')
			state = S1;
		    break;
	    }
	}

    flush ();

    if (result < 0) {
	ll_log (logptr, LLOGTMP, "error reading message when noting failure");
	if (init)
	    ml_txt ("\n------- End of Forwarded Message\n\n");
	ml_txt ("[ error reading message ]\n");
    }
    else
	if (init)
	    ml_txt ("\n------- End of Forwarded Message\n\n");
	else {
	    ll_log (logptr, LLOGTMP, "message empty when noting failure");
	    ml_txt ("[ message empty ]\n");
	}
}

/*  */

/* VARARGS3 */

ds_log (result, level, fmt, a, b, c, d, e)
short   result;
int     level;
char   *fmt,
       *a,
       *b,
       *c,
       *d,
       *e;
{
    int     i;
    char    buffer[BUFSIZ],
	    tmpfil[BUFSIZ];

    ll_log (logptr, level, fmt, a, b, c, d, e);

    sprintf (buffer, fmt, a, b, c, d, e);
    strcat (buffer, "\n");

    printx ("\rerror: %s", buffer);

    if (err_fd == NOTOK) {
	unlink (mktemp (strcpy (tmpfil, "/tmp/bboardsXXXXXX")));
	if ((err_fd = creat (tmpfil, 0600)) == NOTOK)
	    return result;
	close (err_fd);
	if ((err_fd = open (tmpfil, 2)) == NOTOK)
	    return result;
	unlink (tmpfil);
	lseek (err_fd, 0L, 0);
    }
    i = strlen (buffer);
    write (err_fd, buffer, i);

    return result;
}
#endif /* not POP */

/*  */

/* mbx_	    local mailbox routines */

#ifndef	POP
mbx_init () {
    int     fd,
            clear;
    char    name[BUFSIZ];
    FILE * fp;

    if ((fd = mbx_Xopen (curbb -> bb_info, bbrduid, bbrdgid, MBXMODE, &clear))
	    == NOTOK) {
	if (errno == ETXTBSY) {
	    printx ("\runable to lock %s\n", curbb -> bb_info);
	    ll_err (logptr, LLOGTMP, "unable to lock %s",
		    curbb -> bb_info);
	    return RP_LOCK;
	}
	printx ("\runable to open '%s'", curbb -> bb_info);
	ll_log (logptr, LLOGTMP, "unable to open '%s'", curbb -> bb_info);
	return RP_FOPN;
    }
    if ((fp = fdopen (fd, "w")) == (FILE *) NULL) {
	printx ("\runable to fdopen '%s'", curbb -> bb_info);
	ll_err (logptr, LLOGTMP, "unable to fdopen '%s'", curbb -> bb_info);
	mbx_close (curbb -> bb_info, fd);
	return RP_LIO;
    }

    strcpy (name, curbb -> bb_name);
    if ((curbb = getbbnam (name)) == (struct bboard *) NULL) {
	printx ("\runable to get information on BBoard %s\n", name);
	ll_err (logptr, LLOGFAT, "unable to get info on %s", name);
	lkfclose (fp, curbb -> bb_info);
	return RP_LIO;
    }
    sprintf (bbrdheader, "BBoard-ID: %d\nBB-Posted: %s\n",
	    ++curbb -> bb_maxima, cnvtdate (TIMREG, bbrdtime));
    fprintf (fp, "%d\n%s\n", curbb -> bb_maxima, bbrdtime);

    lkfclose (fp, curbb -> bb_info);

    return RP_OK;
}
#endif /* not POP */
