/* Mail Command Line Interface -- Clients
 * Copyright 1992 William Allen Simpson
 *	partly based on a MAIL client design by Anders Klemets, SM0RGV
 *
 * Mods by PA0GRI
 * Improved param cracking
 */
#include "global.h"
#include "ctype.h"
#include <time.h>
#include "timer.h"
#include "proc.h"
#include "socket.h"
#include "domain.h"
#include "cmdparse.h"
#include "files.h"
#include "netuser.h"
#include "mailcli.h"
#include "mailutil.h"
#include "smtp.h"


#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: mailcli.c,v 1.18 1997/09/07 21:18:28 root Exp $";
#endif

/* Tracing levels:
	0 - no tracing
	1 - serious errors reported
	2 - transient errors reported
	3 - session progress reported
 */
unsigned short Mailtrace = 1;

#ifdef MAILCLIENT
int Mailquiet = FALSE;

#ifdef LZW
int poplzw = TRUE;
#endif

static struct mailservers *Mailservers = NULLMAIL;

static int domsquiet (int argc, char *argv[], void *p);
static int domstrace (int argc, char *argv[], void *p);
static int doadds (int argc, char *argv[], void *p);
static int dodrops (int argc, char *argv[], void *p);
static int dokicks (int argc, char *argv[], void *p);
static int dolists (int argc, char *argv[], void *p);
#ifdef LZW
static int dopoplzw (int argc, char *argv[], void *p);
#endif
static void mailtick (void *tp);

static char mreaderr[] = "popmail: Missing";

static struct cmds Mailcmds[] =
{
	{ "addserver",	doadds,		0, 2, "popmail addserver <mailserver> [<seconds>] [hh:mm-hh:mm] <protocol> <mailbox> <username> <password>" },
	{ "dropserver",	dodrops,	0, 2, "popmail dropserver <mailserver>" },
	{ "kick",	dokicks,	0, 2, "popmail kick <mailserver>" },
	{ "list",	dolists,	0, 0, NULLCHAR },
#ifdef LZW
	{ "lzw",	dopoplzw,	0, 0, NULLCHAR },
#endif
	{ "quiet",	domsquiet,	0, 0, NULLCHAR },
	{ "trace",	domstrace,	0, 0, NULLCHAR },
	{ NULLCHAR,	NULL,		0, 0, NULLCHAR }
};


#ifdef LZW
static
int 
dopoplzw (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&poplzw, "pop lzw", argc, argv);
}
#endif


int
domsread (int argc, char *argv[], void *p)
{
	return subcmd (Mailcmds, argc, argv, p);
}


static int
domsquiet (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Mailquiet, "mail quiet", argc, argv);
}



static int
domstrace (int argc, char *argv[], void *p OPTIONAL)
{
	return setshort (&Mailtrace, "mail tracing", argc, argv);
}



static int
doadds (int argc, char *argv[], void *p OPTIONAL)
{
struct mailservers *np;
char *fullname;
int i = 2;

	fullname = domainsuffix (argv[1]);
	if (resolve (fullname) == (uint32) 0) {
		tprintf ("Unknown host %s\n", fullname);
		/* domainsuffix() ALLOCATED memory !, so free it - WG7J */
		free (fullname);
		return 1;
	}

	np = (struct mailservers *) callocw (1, sizeof (struct mailservers));

	np->hostname = fullname;
	np->next = Mailservers;
	Mailservers = np;
	np->lowtime = np->hightime = -1;
	np->timer.func = mailtick;	/* what to call on timeout */
	np->timer.arg = (void *) np;

	if (argc > i && isdigit (*argv[i])) {
		if (strchr (argv[i], '-') == NULLCHAR)
			/* set timer duration */
			set_timer (&np->timer, atol (argv[i++]) * 1000L);
	}

	if (argc > i && isdigit (*argv[i])) {
		int lh, ll, hh, hl;

		sscanf (argv[i++], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
		np->lowtime = lh * 100 + ll;
		np->hightime = hh * 100 + hl;
	}

	if (argc > i) {
		struct daemon *dp = Mailreaders;

		for (; dp->name != NULLCHAR; dp++) {
			if (stricmp (dp->name, argv[i]) == 0) {
				np->reader = dp;
				break;
			}
		}
		if (np->reader == NULLDAEMON) {
			tprintf ("unrecognized protocol '%s'\n", argv[i]);
			goto quit;
		}
		i++;
	} else {
		tprintf ("%s protocol\n", mreaderr);
		goto quit;
	}

	if (argc > i) {
		np->mailbox = strdup (argv[i++]);
	} else {
		tprintf ("%s mailbox\n", mreaderr);
		goto quit;
	}

	if (argc > i) {
		np->username = strdup (argv[i++]);
	} else {
		tprintf ("%s username\n", mreaderr);
		goto quit;
	}

	if (argc > i) {
		np->password = strdup (argv[i++]);
	} else {
		tprintf ("%s password\n", mreaderr);
		goto quit;
	}

	start_detached_timer (&np->timer);	/* and fire it up */
	return 0;

quit:
	Mailservers = np->next;
	free (np->hostname);
	free (np->username);
	free (np->password);
	free (np->mailbox);
	free ((char *) np);
	return -1;
}


static int
dodrops (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct mailservers *np, *npprev = NULLMAIL;
char *fullname;

	fullname = domainsuffix (argv[1]);
	for (np = Mailservers; np != NULLMAIL; npprev = np, np = np->next) {
		if (strnicmp (np->hostname, fullname, strlen (fullname)) == 0) {
			stop_timer (&np->timer);
			free (np->hostname);
			np->hostname = NULLCHAR;
			free (np->username);
			free (np->password);
			free (np->mailbox);

			if (npprev != NULLMAIL)
				npprev->next = np->next;
			else
				Mailservers = np->next;
			free ((char *) np);
			np = (struct mailservers *) 0;
			free (fullname);
			return 0;
		}
	}
	tputs ("No such server enabled.\n");
	free (fullname);
	return -1;
}


static int
dolists (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct mailservers *np;

	for (np = Mailservers; np != NULLMAIL; np = np->next) {
		char tbuf[80];

		if (np->lowtime != -1 && np->hightime != -1)
			sprintf (tbuf, " %02d:%02d-%02d:%02d",
				 np->lowtime / 100,
				 np->lowtime % 100,
				 np->hightime / 100,
				 np->hightime % 100);
		else
			tbuf[0] = '\0';
		tprintf ("%-32s (%lu/%lu%s) %s %s\n",
			 np->hostname,
			 read_timer (&np->timer) / 1000L,
			 dur_timer (&np->timer) / 1000L,
			 tbuf,
			 np->reader->name,
			 np->username);
	}
	return 0;
}


static int
dokicks (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct mailservers *np;
char *fullname;

	fullname = domainsuffix (argv[1]);
	for (np = Mailservers; np != NULLMAIL; np = np->next) {
		if (strnicmp (np->hostname, fullname, strlen (fullname)) == 0) {
			/* If the timer is not running, the timeout function
			 * has already been called, and we don't want to call
			 * it again.
			 */
#if 0
			if (np->timer.duration == 0 || run_timer (&np->timer)) {
#endif
				stop_timer (&np->timer);
				(void) newproc (np->reader->name, np->reader->stksize,
					    np->reader->fp, 0, np, NULL, 0);
#if 0
			}
#endif
			free (fullname);
			return 0;
		}
	}
	tputs ("No such server enabled.\n");
	free (fullname);
	return -1;
}


static void
mailtick (void *tp)
{
struct mailservers *np = tp;
struct tm *ltm;
time_t t;
int now;

	(void) time (&t);
	ltm = localtime (&t);
	now = ltm->tm_hour * 100 + ltm->tm_min;
	if (np->lowtime < np->hightime) {	/* doesn't cross midnight */
		if (now < np->lowtime || now >= np->hightime) {
			if (Mailtrace >= 2)
				log (-1, "%s window to '%s' not open",
				     np->reader->name,
				     np->hostname);
			start_detached_timer (&np->timer);
			return;
		}
	} else {
		if (now < np->lowtime && now >= np->hightime) {
			if (Mailtrace >= 2)
				log (-1, "%s window to '%s' not open",
				     np->reader->name,
				     np->hostname);
			start_detached_timer (&np->timer);
			return;
		}
	}

	(void) newproc (np->reader->name, np->reader->stksize, np->reader->fp, 0, tp, NULL, 0);
}


int
mailresponse (s, buf, comment)
int s;				/* Socket index */
char *buf;			/* User buffer */
const char *comment;		/* comment for error message */
{
	if (recvline (s, (unsigned char *) buf, RLINELEN) != -1) {
		if (Mailtrace >= 3) {
			rip (buf);
			log (s, "%s <== %s", comment, buf);
		}
		return 0;
	}
	if (Mailtrace >= 2)
		log (s, "receive error for %s response", comment);
	return -1;
}


/* Check to see if mailbox is already busy (or perpetually locked) */
int
mailbusy (struct mailservers *np)
{
int countdown = 10;

	while (mlock (Mailspool, np->mailbox)) {
		if (--countdown > 0)
			(void) kpause (60000L);	/* 60 seconds */
		else {
			start_detached_timer (&np->timer);
			return TRUE;
		}
	}

	/* release while processing */
	rmlock (Mailspool, np->mailbox);
	return FALSE;
}


#endif /* MAILCLIENT */
