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

#ifdef linux
extern int close __ARGS((int)); /* this should be in fcntl.h... */
extern int unlink __ARGS((char *)); /* can't include unistd.h, collisions */
#endif

extern FILE *subdir_fopen __ARGS((char *name, char *mode));
extern char *nntp_name_expansion __ARGS((char *name));

/* 	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,buf,len) != -1) {
		register char *p = buf;

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

		/* check for end of message . or escaped .. */
		if (*p == '.') {
			if (*++p == '\n') {
				if (trace >= 3)
					log(s,"received %d lines", lines);
				return lines;
			} else if ( *p != '.' ) {
				p--;
			}
		} 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)
char *buf;	/* Line buffer */
unsigned len;	/* Length of buffer */
FILE *wfp;	/* File to copy from */
{
FILE *mfp = NULLFILE;
char *cp;
int first = 0;
struct list *cclist = NULLLIST;
char from[256], to[256];


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

		if (!from[0] && !strncmp ("From: ", buf, 6))	{
			rip (buf);
			strcpy (from, &buf[6]);
			if ((cp = strchr (from, ' ')) != 0)
				*cp = 0;
		}
		if (!to[0] && !strncmp ("To: ", buf, 4))	{
			rip (buf);
			strcpy (to, &buf[4]);
			if ((cp = strchr (from, ' ')) != 0)
				*cp = 0;
		}
	}
	addlist(&cclist,to,0,to);
	fseek(mfp,0L,0);
	pwait (NULL);		/* just to be nice to others */
	if (to[0] && from[0])
		queuejob(mfp,Hostname,cclist,from);
	fclose(mfp);

	return 0;
}
#endif


/* 	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(dir,id)
char *dir,*id;
{
	char lockname[FILE_PATH_SIZE];
	int fd;
	FILE *fp;
#ifdef notdef
/* This is NOT a good idea ! This prevents all mailfiles in subdirs
 * to be accessed; thus no nntp access etc... - WG7J
 */

#ifdef	MSDOS
	if(strlen(id) > 8) {		/* truncate long filenames */
		id[8] = '\0';
		if(id[7] == '/')
			id[7] = '\0';
	}
#endif
#endif

	/* Try to create the lock file in an atomic operation */
	sprintf(lockname,"%s/%s",dir,id);
	nntp_name_expansion (lockname);
	strcat(lockname,".lck");
#ifdef        AMIGA
	/* don't ask, really, just don't ask... I'd do file locking on
	 * an Amiga much more differently than this.
	 */
	if(access(lockname, 0) == 0)
		return -1;
#endif
	/* this is to create any needed directories for nntp-style areas */
	fp = subdir_fopen (lockname, "w");
	if (fp)	{
		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 */
int
rmlock(dir,id)
char *dir,*id;
{
	char lockname[FILE_PATH_SIZE];

#ifdef notdef /* See mlock() above - WG7J */
#ifdef  MSDOS
	if(strlen(id) > 8) {		/* truncate long filenames */
		id[8] = '\0';
		if(id[7] == '/')
			id[7] = '\0';
	}
#endif
#endif

	sprintf(lockname,"%s/%s.lck",dir,id);
	return(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 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;
	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;
}


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: ",
    "Newsgroup: ",
    "Path: ",
    "X-BBS-Hold: ",
    "X-Mail-Group: ",
    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])) == 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)
register char *addr;
{
char *argv[10], buf[PLINELEN];
register char *cp, *cp2, *retstr;
register int cnt;
register FILE *fp;

	if ((fp = fopen(Rewritefile,READ_TEXT)) == NULLFILE)
		return NULLCHAR;

	memset((char *)argv,0,10*sizeof(char *));
	while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
		pwait (NULL);
		if(*buf == '#')		/* skip commented lines */
			continue;
		if((cp = strpbrk(buf," \t")) == NULLCHAR) /* get the first word */
			continue;
		*cp = '\0';
		if((cp2 = strchr(buf,'\t')) != NULLCHAR){
			*cp = ' ';
			cp = cp2;
			*cp = '\0';
		}
		if(!wildmat(addr,buf,argv))
			continue;		/* no match */
		rip(++cp);
		cp2 = retstr = (char *) callocw(1,PLINELEN);
		while(*cp != '\0' && *cp != ' ' && *cp != '\t')
			if(*cp == '$') {
				if(isdigit(*(++cp)))
					if(argv[*cp - '0'-1] != '\0')
						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]);
		fclose(fp);
		/* 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)) != NULLCHAR) {
				free(retstr);
				return cp2;
			}
		}
		return retstr;
	}
	fclose(fp);
	return NULLCHAR;
}

