/* The following code will broadcast 'Mail for:' beacons
 * for private users with unread mail on a regular interval
 *
 * Also contains the commands to set the R: header read options
 * with the 'bulletin' command.
 *
 * original: 920306
 * rewritten: 920326
 * Copyright 1992, Johan. K. Reinalda, WG7J/PA3DIS
 * Permission granted for non-commercial use only!
 */
#include <stdio.h>
#ifdef MSDOS
#include <dir.h>
#include <dos.h>
#endif
#ifdef UNIX
#include <ctype.h>
#endif
#include "global.h"
#include "files.h"
#include "dirutil.h"
#include "bm.h"
#include "cmdparse.h"
#include "timer.h"
#include "pktdrvr.h"
#include "ax25.h"
#include "mailfor.h"
#include "socket.h"

#ifdef MAILFOR
#ifdef AX25

#define MAXMFLEN 256
static struct timer Mftimer;
static char ax_mftext[MAXMFLEN+1] = "Mail for:";
#define DEFMFLEN 9
int mflen = DEFMFLEN; /*Initial lenght of mail-for string*/

struct no_mf *No_mf = NULLMF;


/*Read a private message area's control file, searching for unread mail
 *this is indicated by the status int
 */

int
#ifdef PROTOTYPES
checknewmail(char *area)
#else
checknewmail(area)
char *area;
#endif
{
FILE *fp;
char mailbox[100];
long size;
int i, nmsgs;
struct	let *cmsg;
struct let *new;
int ret = 0;

	sprintf(mailbox,"%s/control/%s.ctl",Mailspool,area);
	if((fp = fopen(mailbox,READ_BINARY)) != NULLFILE)	{
		size = filelength (fileno(fp));
		new = (struct let *) malloc (size);
		pwait (NULL);
		fread (new, size, 1, fp);
		fclose(fp);
		pwait (NULL);
		nmsgs = (int) (size / (long) sizeof(struct let));
		for (cmsg = new,i = 0; i < nmsgs; i++, cmsg++)	{
			if (!(cmsg->status & BM_READ))	{
				ret = 1;
				break;
				}
			}
		free (new);
		}
	return ret;
}


/* Check name with exclude list;
 * returns 1 if found, 0 if not
 */
int
#ifdef PROTOTYPES
mf_exclude(char *name)
#else
mf_exclude(name)
char *name;
#endif
{
struct no_mf *nm;

    /*Now check the 'exclude' list*/
    for(nm=No_mf;nm!=NULLMF;nm=nm->next) {
        if(!stricmp(nm->area,name))
            return 1;
    }
    return 0;
}


#ifdef CONVERS
static char ActiveMessages[] = "Active Messages: %ld  (%s in conference sessions)";
#else
static char ActiveMessages[] = "Active Messages: %ld";
#endif
long ACTIVEMessages;

void
countMessages()
{
char buf[128];
struct ffblk ff;
long size;

	ACTIVEMessages = 0;
	sprintf(buf,"%s/control/*.ctl",Mailspool);
	if (findfirst(buf, &ff, 0) == 0) {
		do {
			pwait(NULL);    /* Let others run */
			sprintf (buf, "%s/control/%s", Mailspool, ff.ff_name);
			size = fsize (buf);
			ACTIVEMessages += (size / 14L);
		} while (findnext(&ff) == 0);
	}
}


int
#ifdef PROTOTYPES
setmailfor(void)
#else
setmailfor()
#endif
{
char buf[80];
struct ffblk ff;

    sprintf(buf,"%s/*.txt",Mailspool);
    if (findfirst(buf, &ff, 0) == 0) {
        do {
            pwait(NULL);    /* Let others run */
            *(strchr(ff.ff_name,'.')) = '\0';
            /*must be private mail area, and not on exclude list !*/
            if(!issysarea(ff.ff_name) && !mf_exclude(ff.ff_name)) {
                if((strlen(ax_mftext) + strlen(ff.ff_name)) > MAXMFLEN - 1)
                    break; /* That's all folks */
                if(checknewmail(ff.ff_name)) {
                    strcat(ax_mftext," ");
                    strcat(ax_mftext,ff.ff_name);
                }
            }
           } while (findnext(&ff) == 0);
    }

    countMessages();

    return strlen(ax_mftext);
}


/*This is the low-level broadcast function.*/
void
#ifdef PROTOTYPES
ax_mf(struct iface *ifp)
#else
ax_mf(ifp)
struct iface *ifp;
#endif
{
struct mbuf *bp;
int inconference = 0;
char fakestr[8];

	/* prepare the header */
    if((bp = alloc_mbuf(mflen)) == NULLBUF)
		return;

    /*copy the data into the packet*/
    bp->cnt = mflen;
    memcpy(bp->data,ax_mftext,mflen);

    /* send it */
    (*ifp->output)(ifp, Ax25multi[MAILCALL], ifp->hwaddr,
        PID_NO_L3, bp);


	/* prepare the header */
    if((bp = alloc_mbuf(strlen(ActiveMessages)+16)) == NULLBUF)
		return;

    /*copy the data into the packet*/
#ifdef CONVERS
    inconference = CountConfUsers();
    sprintf(bp->data,ActiveMessages, ACTIVEMessages, (inconference) ? itoa(inconference, fakestr, 10) : "NONE");
#else
    sprintf(bp->data,ActiveMessages, ACTIVEMessages);
#endif
    bp->cnt = strlen (bp->data);

    /* send it */
    (*ifp->output)(ifp, Ax25multi[MAILCALL], ifp->hwaddr,
        PID_NO_L3, bp);
}


void
#ifdef PROTOTYPES
Mftick(void *v)
#else
Mftick(v)
void *v;
#endif
{
struct iface *ifp = Ifaces;

    stop_timer(&Mftimer); /* in case this was 'kicked' with a 'mailfor now'*/

    /*Now find private mail areas with unread mail.
     *add these to the info-line
     */
    ax_mftext[DEFMFLEN] = '\0'; /* Back to only 'Mail for:' again*/
    if((mflen=setmailfor()) < DEFMFLEN+1) {
        start_timer(&Mftimer);
        return; /* No unread mail */
    }

    /*broadcast it on all configured interfaces*/
    for(ifp=Ifaces;ifp != NULL;ifp=ifp->next)
        if(ifp->flags & MAIL_BEACON)
            ax_mf(ifp);
	/* Restart timer */
    start_timer(&Mftimer) ;
}


int
#ifdef PROTOTYPES
dombmailfor(int argc,char **argv,void *p)
#else
dombmailfor(argc,argv,p)
int argc;
char *argv[];
void *p;
#endif
{
register int i;
struct no_mf *nm;
int inconference = 0;
char fakestr[8];

	if(argc < 2)	{    /* set the timer */
	        tprintf("Mail-for timer: %lu/%lu\n",
        	read_timer(&Mftimer)/1000L,
	        dur_timer(&Mftimer)/1000L);
		if(ACTIVEMessages)	{
#ifdef CONVERS
			inconference = CountConfUsers();
			tprintf(ActiveMessages, ACTIVEMessages, (inconference) ? itoa(inconference, fakestr, 10) : "NONE");
#else
			tprintf(ActiveMessages, ACTIVEMessages);
#endif
			tputs ("\n");
		}
        	if(mflen > DEFMFLEN)
			tprintf("%s\n",ax_mftext);
		tputs ("\n");
	        return 0;
		}
	if(*argv[1] == 'n') 	{ /*send mailfor 'now' !!*/
        	Mftick(NULL);
	        return 0;
		}
	if(*argv[1] == 'e') 	{ /*exclude list */
	        /*the exclude subcommand*/
        	if(argc == 2) { /*just list them*/
			for(nm=No_mf;nm!=NULLMF;nm=nm->next)
		                tprintf("%s ",nm->area);
			tputc('\n');
		} else { /*add some call(s)*/
			for(i=0;i<argc-2;i++) {
		                if(strlen(argv[i+2]) > 8) {
                			tprintf("Invalid: %s\n",argv[i+2]);
					continue;
                			}
				nm = callocw(1,sizeof(struct no_mf));
		                strcpy(nm->area,argv[i+2]);
                		/* add to list */
		                nm->next = No_mf;
                		No_mf = nm;
            			}
        		}
        	return 0;
    		}
	Mftimer.func = (void (*)__ARGS((void *)))Mftick;/* what to call on timeout */
	Mftimer.arg = NULL;        /* dummy value */
	set_timer(&Mftimer,atol(argv[1])*1000L); /* set timer duration */
	Mftick(NULL); /* Do one now and start it all!*/
	return 0;
}
#endif /* AX25 */
#endif /* MAILFOR */

/*************************************************************************/

#ifdef RLINE

/* Depending on the flag set, the mailbox will
 * read the message's original date,
 * the correct 'from' address (instead of the user%forwardbbs@myhost),
 * and for buls set the X-Forwarded options to prevent
 * unneccesary forward attempts
 * all from the R: lines supplied by the bbs system
 * 920311 - WG7J
 */
static int dordate __ARGS((int argc,char *argv[],void *p));
static int dorreturn __ARGS((int argc,char *argv[],void *p));
static int dombloophold __ARGS((int argc,char *argv[],void *p));
static int dofwdcheck __ARGS((int argc,char *argv[],void *p));
static int dombhold __ARGS((int argc,char *argv[],void *p));

char MyFwds[NUMFWDBBS][FWDBBSLEN+1];
int Numfwds = 0;
int Checklock = 0;   /* get increased to lock list of forward bbses */
int Rdate = 0;
int Rreturn = 0;
int Rfwdcheck = 0;

static struct cmds Rlinetab[] = {
    "check",    dofwdcheck,0, 0, NULLCHAR,
    "date",     dordate,   0, 0, NULLCHAR,
    "hold",     dombhold,  0, 0, NULLCHAR,
    "loophold", dombloophold,0,0, NULLCHAR,
    "return",   dorreturn, 0, 0, NULLCHAR,
    NULLCHAR,
};

void ReadFwdBbs();

static int
dordate(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&Rdate,"Use R: for orig. date",argc,argv);
}

int Mbloophold = 2;

/* set loop detection threshold - WG7J */
static int
dombloophold(argc, argv,p)
int argc;
char *argv[];
void *p;
{
    return setint(&Mbloophold,"Loop hold after",argc,argv);
}

static int
dorreturn(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&Rreturn,"Use R: for ret. addr.",argc,argv);
}


static int
dofwdcheck(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    register int i;

    setbool(&Rfwdcheck,"Use R: to check buls",argc,argv);
    if((argc == 1) && Rfwdcheck && Numfwds) { /*list the bbses we check*/
        tputs("Checking for:");
        for(i=0;i<Numfwds;i++)
            tprintf(" %s",MyFwds[i]);
        tputc('\n');
    } else {
        if(Rfwdcheck)
            ReadFwdBbs();
    }
    return 0;
}




static int
dombhold(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setbool(&MbHolding,"Hold local bulletins for review",argc,argv);
}

int
#ifdef PROTOTYPES
dombrline(int argc,char **argv,void *p)
#else
dombrline(argc,argv,p)
int argc;
char *argv[];
void *p;
#endif
{
    return subcmd(Rlinetab,argc,argv,p);
}


void
ReadFwdBbs() {
    FILE *fp;
    int start = 1;
    char *cp;
    char line[80];

    if(Checklock) {
        tputs("Bbs-list locked, forward.bbs not re-read\n");
        return;
    }
    Numfwds = 0;    /* reset */
    if((fp=fopen(Forwardfile,READ_TEXT)) == NULLFILE) {
        tputs("forward.bbs not found\n");
        return;
    }
    /*Now scan the forward.bbs file to find bbs's*/
    while(fgets(line,sizeof(line),fp) != NULLCHAR && (Numfwds < NUMFWDBBS)) {
        if(*line == '\n')
            continue;
        if(*line == '#')
        	continue;
        if((*line == '.') || (*line == '+') || (*line == '@'))
        	continue;
        /* lines starting with '-' separate the forwarding records */
        if(*line == '-') {
            start = 1;
            continue;
        }
        if(start) {
            start = 0;
            /* get the name of this forwarding record */
            if((cp=strpbrk(line," \n\t")) != NULLCHAR)
                *cp = '\0';
            if(strlen(line) > FWDBBSLEN)
                continue;   /*What kind of bbs-call is this ?*/
            strcpy(MyFwds[Numfwds++],strupr(line));
        }
    }
    fclose(fp);
    return;
}

#endif /* RLINE */


int
BBSlookup (bbs)
char *bbs;
{
int retval;

    for (retval = 0; retval < Numfwds; retval++)
    	if (!stricmp (MyFwds[retval], bbs))
    		break;
    if (retval == Numfwds)
    	return -1;
    else
    	return retval;
}


