/*	General Mail Utilities
 *	culled from other files to reduce unnecessary cross references.
 *	This material is believed to be in the public domain.
 */
#include "global.h"
#include "ctype.h"
#include "commands.h"
#include <fcntl.h>
#include "socket.h"
#include "mailutil.h"
#include "smtp.h"
#include "hardware.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: mailutil.c,v 1.26 2001/05/06 16:32:57 brian Exp $";
#endif

extern int Rewritetrace;
extern FILE *subdir_fopen (char *name, const char *mode);
extern char *nntp_name_expansion (char *name);

static void mklockname (char *lockname, const char *dir, char *id);


/* 	Jan 92	Bill Simpson
 *		The following routines were combined from smtpserv.c,
 *		pop3cli.c and nntpcli.c
 */

 
#ifdef POP3CLIENT

/* Receive message from socket, copying to file.
 * Returns number of lines received, -1 indicates error
 */
int
recvmail (s, buf, len, fp, trace)
int s;		/* Socket index */
char *buf;	/* Line buffer */
unsigned len;	/* Length of buffer */
FILE *fp;	/* File to copy into */
int trace;	/* to trace or not to trace */
{
int lines = 0;

	while (recvline (s, (unsigned char *) buf, len) != -1) {
		register char *p = buf;

		if (trace >= 4)
			log (s, "<==%s", buf);

		/* check for end of message */
		if (*p == '.') {
			if (*++p == '\n') {
				if (trace >= 3)
					log (s, "received %d lines", lines);
				return lines;
			}
		} else if (strncmp (p, "From ", 5) == 0) {
			/* for UNIX mail compatiblity */
			(void) putc ('>', fp);
		}
		/* Append to data file */
		fputs (p, fp);
		++lines;
	}
	if (trace >= 1)
		log (s, "receive error after %d lines", lines);
	return -1;
}
#endif


#if (defined(POP2CLIENT) || defined(POP3CLIENT))

/* Copy from the work file into the mailbox.
 * -1 indicates error
 */
int
copymail (buf, len, wfp, mail_to)
char *buf;	/* Line buffer */
unsigned len;	/* Length of buffer */
FILE *wfp;	/* File to copy from */
char *mail_to;	/* Address to queue to */
{
FILE *mfp = NULLFILE;
char *cp;
int first = 0;
struct list *cclist = NULLLIST;
char from[256], to[256];


	rewind (wfp);
	from[0] = 0;
	strncpy (to, mail_to, 256);	
	if (strchr (to, '@') == NULL)	{
		strcat (to, "@");
		strcat (to, Hostname);
	}
	while (fgets (buf, (int)len, wfp) != NULLCHAR)	{
		kwait (NULL);	/* give other processes time in long copy */
		if (!first)	{
			mfp = tmpfile();
			if (!mfp)
				return -1;
			(void) putc ('>', mfp);
			first = 1;
		} else if (!mfp)
			return -1;
		else if (!strncmp (buf, "From ", 5))	{
			(void) addlist (&cclist, to, 0, to);
			fseek (mfp, 0L, 0);	/* lint !e668 */
			kwait (NULL);		/* just to be nice to others */
			if (to[0] && from[0])
				(void) queuejob (mfp, Hostname, cclist, from);	/*lint !e668 */
			del_list (cclist);
			cclist = NULLLIST;
			(void) fclose (mfp);		/* lint !e668 */
			from[0] = 0;
			to[0] = 0;
			mfp = tmpfile();
			if (!mfp)
				return -1;
			(void) putc ('>', mfp);
		}
		fputs (buf, mfp);		/* lint !e668 */
		

		if (!from[0] && !strncmp ("From: ", buf, 6))	{
			rip (buf);
			strncpy (from, &buf[6], 256);
			if ((cp = strchr (from, ' ')) != 0)
				*cp = 0;
		}
	}
	if (!mfp)
		return -1;
	(void) addlist (&cclist, to, 0, to);
	fseek (mfp, 0L, 0);			/* lint !e668 */
	kwait (NULL);		/* just to be nice to others */
	if (to[0] && from[0])
		(void) queuejob (mfp, Hostname, cclist, from);	/* lint !e668 */
	(void) fclose (mfp);						/* lint !e668 */

	return 0;
}
#endif


static void
mklockname (char *lockname, const char *thedir, char *id)
{
	if (id == NULLCHAR)
		strcpy (lockname, thedir);
	else
		sprintf (lockname, "%s/%s", thedir, id);
	(void) nntp_name_expansion (lockname);
	strcat (lockname, ".lck");
}


/* 	Jan 92	Bill Simpson
 * 		The following routines were extracted from smtpserv.c
 *		and smtpcli.c, since they are used from several places.
 */

/* create mail lockfile */
int
mlock (thedir, id)
const char *thedir;
char *id;
{
char lockname[FILE_PATH_SIZE];
int fd;
FILE *fp;

	/* Try to create the lock file in an atomic operation */
	mklockname (lockname, thedir, id);

	if (access (lockname, 0) == 0)
		return -1;

	/* this is to create any needed directories for nntp-style areas */
	fp = subdir_fopen (lockname, "w");
	if (fp)	{
		(void) fclose (fp);
		unlink (lockname);
	}
#ifndef TNOS_68K
	if ((fd = open (lockname, O_WRONLY|O_EXCL|O_CREAT, 0600)) == -1)
#else
	if ((fd = creat (lockname, S_ISHARE)) == -1)
#endif
		return -1;
	close (fd);
	return 0;
}


/* remove mail lockfile */
void
rmlock (thedir, id)
const char *thedir;
char *id;
{
char lockname[FILE_PATH_SIZE];

	mklockname (lockname, thedir, id);
	unlink (lockname);
}


/* Given a string of the form <user@host>, extract the part inside the
 * angle brackets and return a pointer to it.
 */
char *
getname (cp)
register char *cp;
{
register char *cp1;

	if ((cp = strchr (cp, '<')) == NULLCHAR)
		return NULLCHAR;
	cp++;			/* cp -> first char of name */
	if ((cp1 = strchr (cp, '>')) == NULLCHAR)
		return NULLCHAR;
	*cp1 = '\0';
	return (skipwhite (cp));
}


/*      Jan 92  Bill Simpson
 *		The following routines were extracted from mailbox.c,
 *		since they are used from several places.
 */


/* Parse a string in the "Text: Text <user@host>" or "Text: user@host (Text)"
 * formats for the address user@host.
 */
char *
getaddress (string, cont)
char *string;
int cont;		/* true if string is a continued header line */
{
char *cp, *ap = NULLCHAR;
int par = 0;

	if ((cp = getname (string)) != NULLCHAR) /* Look for <> style address */
		return cp;

	cp = string;
	if (!cont)	{
		if ((cp = strchr (string, ':')) == NULLCHAR)	/* Skip the token */
			return NULLCHAR;
		else
			++cp;
	}
	cp = skipwhite (cp);
	for(; *cp != '\0'; ++cp) {
		if (par && *cp == ')') {
			--par;
			continue;
		}
		if (*cp == '(')		/* Ignore text within parenthesis */
			++par;
		if (par)
			continue;
		if (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
			if (ap != NULLCHAR)
				break;
			continue;
		}
		if (ap == NULLCHAR)
			ap = cp;
	}
	*cp = '\0';
	return ap;
}


const char *Hdrs[] = {
	"Approved: ",
	"From: ",
	"To: ",
	"Date: ",
	"Message-Id: ",
	"Subject: ",
	"Received: ",
	"Sender: ",
	"Reply-To: ",
	"Status: ",
	"X-BBS-Msg-Type: ",
	"X-Forwarded-To: ",
	"Cc: ",
	"Return-Receipt-To: ",
	"Apparently-To: ",
	"Errors-To: ",
	"Organization: ",
	"Newsgroups: ",
	"Path: ",
	"X-BBS-Hold: ",
	"X-Mail-Group: ",
	"X-msgtype: ",
	"X-BID: ",
	"Distribution: ",
	"NNTP-Posting-Host: ",
	"Lines: ",
	"References: ",
	"Date-Received: ",
	"X-Message-ID: ",
	"X-NNTP-Gate: ",
	"X-BBS-To: ",
	"X-NNTP-Newsgroups: ",
	NULLCHAR
};


/* return the header type */
int
htype (s)
char *s;
{
register char *p;
register int i;

	p = s;
	/* check to see if there is a ':' before and white space */
	while (*p != '\0' && *p != ' ' && *p != ':')
		p++;
	if (*p != ':')
		return NOHEADER;

	for (i = 0; Hdrs[i] != NULLCHAR; i++) {
		if (strnicmp (Hdrs[i], s, strlen (Hdrs[i]) - 1) == 0)
			return i;
	}
	return UNKNOWN;
}


/* Read the rewrite file for lines where the first word is a regular
 * expression and the second word are rewriting rules. The special
 * character '$' followed by a digit denotes the string that matched
 * a '*' character. The '*' characters are numbered from 1 to 9.
 * Example: the line "*@*.* $2@$1.ampr.org" would rewrite the address
 * "foo@bar.xxx" to "bar@foo.ampr.org".
 * $H is replaced by our hostname, and $$ is an escaped $ character.
 * If the third word on the line has an 'r' character in it, the function
 * will recurse with the new address.
 */
char *
rewrite_address (addr, recursionlevel)
register const char *addr;
int recursionlevel;
{
char *argv[10], buf[PLINELEN];
register char *cp, *cp2, *retstr;
register int cnt;
register FILE *fp = NULLFILE;

	if (recursionlevel > MAXREWRITERECURSION)	{
		if (Rewritetrace)
			tcmdprintf ("  Rewrite[%d]: recursion maximum reached: %s\n", recursionlevel + 1, addr);
		log (-1, "Rewrite recursion maximum reached: %s", addr);
		return NULLCHAR;
	}
	if ((fp = fopen (Rewritefile, READ_TEXT)) == NULLFILE)
		return NULLCHAR;
	memset ((char *)argv, 0, 10 * sizeof (char *));
	while (fp != NULLFILE && fgets (buf, sizeof (buf), fp) != NULLCHAR) {
		kwait (NULL);
		if(*buf == '#')		/* skip commented lines */
			continue;
		if((cp = strpbrk (buf," \t")) == NULLCHAR) /* get the first word */
			continue;
		*cp = '\0';

		if (!wildmat (addr, buf, argv))
			continue;		/* no match */
		rip (++cp);
		cp = skipwhite (cp);
		cp2 = retstr = (char *) callocw (1, PLINELEN);
		while (*cp != '\0' && *cp != ' ' && *cp != '\t')
			if (*cp == '$') {
				if (isdigit (*(++cp)))
					if (argv[*cp - '0'-1] != '\0')	/*lint !e58 */
						strcat (cp2, argv[*cp - '0'-1]);
				if (*cp == 'h' || *cp == 'H') /* Our hostname */
					strcat (cp2,Hostname);
				if (*cp == '$')	/* Escaped $ character */
					strcat (cp2, "$");
				cp2 = retstr + strlen (retstr);
				cp++;
			}
			else
				*cp2++ = *cp++;
		for (cnt=0; argv[cnt] != NULLCHAR; ++cnt)
			free (argv[cnt]);
		(void) fclose (fp);
		fp = NULLFILE;

		if (Rewritetrace)
			tcmdprintf ("  Rewrite[%d]: %s->%s\n", recursionlevel + 1, addr, retstr);

		/* If there remains an 'r' character on the line, repeat
		 * everything by recursing.
		 */
		if (strchr (cp,'r') != NULLCHAR || strchr (cp, 'R') != NULLCHAR) {
			if ((cp2 = rewrite_address (retstr, recursionlevel + 1)) != NULLCHAR) {
				free (retstr);
				return cp2;
			}
		}
		return retstr;
	}
	if (fp != NULLFILE)
		(void) fclose (fp);
	return NULLCHAR;
}

#if (defined (NNTPSERV)) || (defined (UKIP))
int
look_for_t_line (char *buf, int bufsize, FILE *data, const char *type)
{
int en = 0;
char *cp;
	/* Assume there are boxes out there which leave
	 * a line or two between the R and T lines,         */

	while ((fgets (buf, bufsize, data)) != 0) {
		if (*buf == '\n')
			en ++;
		if (en <= 3) {
			if (strncmp (buf, "T:", 2) == 0) {
				cp = buf+2;
				if (strnicmp (cp, type, strlen(type)) == 0)
					return 0;
			}
		}
		if (en == 3)
			return 1;
	}
	return 1;
}
#endif
