/*
 *	pop3d		- IP/TCP/POP3 server for UNIX 4.3BSD
 *			  Post Office Protocol - Version 3 (RFC1225)
 *
 *      (C) Copyright 1991 Regents of the University of California
 *
 *      Permission to use, copy, modify, and distribute this program
 *      for any purpose and without fee is hereby granted, provided
 *      that this copyright and permission notice appear on all copies
 *      and supporting documentation, the name of University of California
 *      not be used in advertising or publicity pertaining to distribution
 *      of the program without specific prior permission, and notice be
 *      given in supporting documentation that copying and distribution is
 *      by permission of the University of California.
 *      The University of California makes no representations about
 *      the suitability of this software for any purpose.  It is provided
 *      "as is" without express or implied warranty.
 *
 *	Katie Stevens
 *	dkstevens@ucdavis.edu
 * 	Information Technology -- Technology Support Program
 *	University of California, Davis
 *
 **************************************
 *
 *	folder.c
 *
 *	REVISIONS:
 *		02-27-90 [ks]	original implementation
 *	1.000	03-04-90 [ks]
 *	1.001	06-24-90 [ks]	allow TRANS state if 0 msgs in folder
 *				implement optional TOP command
 *	1.002	07-22-91 [ks]	reset index counter after folder rewind
 *				in fld_release (Thanks to John Briggs,
 *				vaxs09@vitro.com, Vitro Corporation,
 *				Silver Spring, MD for finding this bug!)
 *	1.004	11-13-91 [ks]	leave original mailbox intact during POP
 *				session (Thanks to Dave Cooley,
 *				dwcooley@colby.edu for suggesting this)
 *		08-93	 [ks]	Thanks to Kurt Jordan, Purdue Calumet
 *				for the port to SVR3.2
 *	1.005	06-17-94 [ks]	port to SVR4/ANSIC; fold BSD, SVR3.2, SVR4
 *				into one source ( Thanks to Mark Horstman,
 *				Southwester Bell Telephone for this work )
 *	1.008	03-23-95 [ks]	check for occupied lock on mailbox
 *      1.009   10-26-95 [ks]   remove fld_write_ok flag; thanks to
 *                              Craig D. von Land for pointing out a bug
 *	1.010   06-07-96 [ks]   -- added AIX define conditional compilation
 *                              flag to open in r+ mode before file lock.
 *                              Thanks to Danny Cohen for this suggestion.
 *                              -- moved HOST and MBOX extension commands
 *                              and routines to conditional compilation
 *                              status HOST_EXT; no longer used at UC Davis
 *                              -- corrected response to TOP n 0 command.
 *                              Thanks to Stephen R. van den Berg. 
 *                              -- add UIDL command, under conditional 
 *                              compilation flag UIDL_OKAY ( FromSP only ).
 *                              Thanks to Henry Holtzman for his patches.
 *      1.011  01-21-97 [ks]    -- added code to prevent duplicated
 *                              messages and left-over /tmp files. Thanks
 *                              to Blaise Camp, UC Davis for his patches.
 *                              -- no need to rewrite mailbox unless one
 *                              or more messages were deleted. Thanks to
 *                              Jim Stevens, JRCS Ltd for his help.
 *      1.012  03-28-97 [ks]    -- bug fix: handle condition when UIDL_OKAY
 *                              and missing Message-Id header
 *	1.013  07-17-97 [ks]    -- add LOCK_EX flag to flock() call; thanks
 *                              to Shao Hua for suggesting this
 *	1.014  02-11-98 [ks]	-- added patches provided by Blaise Camp.
 *				Create lockfile only if mailbox is non-zero
 *				size.
 *      1.015  02-19-98 [ks]    -- added patches provided by Blaise Camp.
 *                              Add an expiration time on the lockfiles.
 */

#ifdef ANSIC
#include <stdlib.h>
#include <unistd.h>
#endif /* ANSIC */
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <errno.h>
#include "pop3.h"

#ifndef SVR4
extern int sys_nerr;
extern char *sys_errlist[];
#endif

/* In main.c */
extern char *svr_hostname;
extern char svr_buf[];
extern char cli_user[];

/* In util.c */
extern char flash_buf[];

#ifdef DEBUG
extern FILE *logfp;
#endif

/* Constants used when closing a folder after POP session */
#define REMOVE_MBOX	1
#define SAVE_NEW	2
#define SAVE_ALL	3

static char *svr_nomsg = "-ERR no messages in mailbox\r\n";
static char *cli_mbox = NULL;		/* Filename of mailbox folder */

/*static char fld_fname[32];		   [1.011]Filename for working folder */
char fld_fname[32];		   	/* [1.011]Filename for working folder */
static FILE *fld_fp = NULL;		/* Stream pointer for mailbox */
static struct fld_item *fld_msg;	/* Struct for mailbox stats */
static int fld_max = -1;		/* Actual # msgs in mailbox */
static int fld_highest = -1;		/* Max msg accessed by client */
static int fld_hostmbox = 0;		/* 0=FromSP mailbox; 1=BSMTP */
#ifdef notdef
					/* [1.009] commented out */
static int fld_write_ok = -1;		/* -1=client doesnt have write privs */
#endif
static long fld_orig_size;		/* [1.004] size of mbox when loaded */
static time_t fld_orig_mod_time;	/* [1.004] timestamp on mbox file */

#define isfromsp_start(buf)	(strncmp(buf,"From ",5) == 0)
#define isbsmtp_helo(buf)	(strncmp(buf,"helo",4) == 0)
#define isbsmtp_end(buf)	((buf[0] == DOT_CHAR)&&(strlen(buf) == 2))

#ifdef POPMOTD
#include "popmotd.h"
#include <pwd.h>
#include <dirent.h>
#include <ctype.h>
int check_file_for_fromsp(FILE **infp, int *file_counter, POP *p);
int get_bulletin_numbers(POP *p);
char temp_name[50];
int is_popmotd = 0;
#endif /* POPMOTD */


#ifdef UCD
extern char new_mbox[64];
#endif

#ifdef PINE_IMAP
int imap_done = 0;
#endif

#ifdef ANSIC
static void retr_fromsp(int, int);
#ifdef POPMOTD
static int msg_fromsp(FILE *, FILE *, POP *);
static int fld_select(char *, int, POP *);
#else
static int msg_fromsp(FILE *, FILE *);
static int fld_select(char *, int);
#endif
void svr_data_out(char *);	/* [1.015] */
#ifdef HOST_EXT /* [1.010] */
static void retr_bsmtp(int, int);
static int msg_bsmtp(FILE *, FILE *);
static char *bsmtp_rcpt(char *);
#endif
#else /* !ANSIC */
static int fld_select();
static void retr_fromsp();
static int msg_fromsp();
void svr_data_out();		/* [1.015] */
#ifdef HOST_EXT /* [1.010] */
static void retr_bsmtp();
static int msg_bsmtp();
static char *bsmtp_rcpt();
#endif
#endif /* ANSIC */

#ifdef NO_MULTIPLE
#include <fcntl.h>
extern char lockfile[128];	/* [1.014] */
extern int remove_lockfile;	/* [1.014] */
#endif

#ifdef LOG_SESSIONS
extern long byte_count;
#endif


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

/* Open a FromSpace delimited mailbox */
int
#ifdef ANSIC
fld_fromsp(char *fname)
#else /* !ANSIC */
fld_fromsp(fname)
char *fname;
#endif /* ANSIC */
{
	int cnt;

#ifdef POPMOTD
        char mail_file[64];     /* to place name of inbox  */
        POP p;  /* p is the struct that holds info needed to manipulate
                 * the popmotd bulletins -- struct POP is in popmotd.h 
                 */
        struct passwd *pwd_info;

        mail_file[0] = '\0';
#endif /* POPMOTD */

	/* Release previously opened mailbox */
	if (fld_fp != NULL)
		fld_release();
	/* Construct filename for new mailbox */
	cli_mbox = (char *)malloc(strlen(fname)+1);
	if (cli_mbox == NULL)
		fail(FAIL_OUT_OF_MEMORY, 0);
	strcpy(cli_mbox,fname);
	/* Open mailbox */

#ifdef POPMOTD
        sprintf(p.bulldir, "%s", BULLDIR);
        pwd_info = getpwnam(cli_user);
        if (pwd_info == NULL) {
            sprintf(svr_buf,"-ERR Can't get required password information on user\r\n");
            fail(FAIL_PROGERR);
        }
        strcpy(p.user, pwd_info->pw_name);
        strcpy((char *)p.homedir, pwd_info->pw_dir);
        if ((cnt = fld_select(cli_mbox,0, &p)) == -1) {
#else /* !POPMOTD */
        if ((cnt = fld_select(cli_mbox,0)) == -1) {
#endif /* POPMOTD */

#ifdef SVR4
		sprintf(svr_buf,"-ERR cannot open mailbox %s: %s\r\n",
			cli_mbox, strerror(errno));
#else
		sprintf(svr_buf,"-ERR cannot open mailbox %s: %s\r\n",
			cli_mbox,
			(errno<sys_nerr ? sys_errlist[errno]:"Unknown error"));
#endif
		free(cli_mbox);
		cli_mbox = NULL;
		return(SVR_FOLD_STATE);
	} else {
#ifdef PINE_IMAP
	    if (imap_done == 1) {
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
			cnt-1,cli_user,cli_mbox);
#ifdef DEBUG
		fprintf (logfp, "%s: +OK %d messages ready for %s in %s\r\n",
			cli_user, cnt-1,cli_user,cli_mbox);
#endif
	    }
	    else {
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
			cnt,cli_user,cli_mbox);
#ifdef DEBUG
		fprintf (logfp, "%s: +OK %d messages ready for %s in %s\r\n",
			cli_user, cnt,cli_user,cli_mbox);
#endif
	    }
#else
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
			cnt,cli_user,cli_mbox);
#ifdef DEBUG
		fprintf (logfp, "%s: +OK %d messages ready for %s in %s\r\n",
			cli_user, cnt,cli_user,cli_mbox);
#endif
#endif

		return(SVR_TRANS_STATE);
	}
}

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

/* Mark a message for deletion */
void
#ifdef ANSIC
fld_delete(int msgnum)
#else /* !ANSIC */
fld_delete(msgnum)
int msgnum;
#endif /* ANSIC */
{
    	int offset = 0;
	int offset2 = 1;
#ifdef PINE_IMAP
	if (imap_done == 1) {
	    offset = 1;
	    offset2 = 0;
	}
#endif
	if (fld_fp == NULL) {
		strcpy(svr_buf, svr_nomsg);
		return;
	}

	if ((msgnum < 1)||(msgnum > fld_max - offset)) {
		sprintf(svr_buf,"-ERR invalid message; number out of range\r\n");
	} else {
		fld_msg[msgnum-offset2].status |= MSG_DELETED;
		sprintf(svr_buf,"+OK message %d marked for deletion\r\n",
			msgnum);
#ifdef DEBUG
		fprintf (logfp, "%s: +OK sage %d marked for deletion\r\n",
				cli_user, msgnum);
#endif
		if ((msgnum-1) > fld_highest)
			fld_highest =(msgnum-1);
	}
}

/* Report the highest access number for this mailbox */
void
#ifdef ANSIC
fld_last(void)
#else /* !ANSIC */
fld_last()
#endif /* ANSIC */
{
	sprintf(svr_buf,"+OK %d\r\n",(fld_highest+1));
#ifdef DEBUG
	fprintf (logfp, "%s: +OK %d\r\n",cli_user,(fld_highest+1));
#endif
}

/* Give information about messages in mailbox folder */
void
#ifdef ANSIC
fld_list(int msgnum)
#else /* !ANSIC */
fld_list(msgnum)
int msgnum;
#endif /* ANSIC */
{
	int i = 0;
	int offset = 1;
#ifdef PINE_IMAP
	if (imap_done == 1) {
	    i = 1;
/*	    fprintf (stderr, "Setting i = 1 in list\n"); */
	    offset = 0;
	}
#endif

	if (fld_fp == NULL) {
		strcpy(svr_buf, svr_nomsg);
		return;
	}

	if (msgnum == -1) {
#ifdef PINE_IMAP
	    if (imap_done == 1) {
		sprintf(svr_buf,"+OK %d messages; msg# and size (in octets) for undeleted messages:\r\n",fld_max - 1);
	    }
	    else {
		sprintf(svr_buf,"+OK %d messages; msg# and size (in octets) for undeleted messages:\r\n",fld_max);
	    }
#else 
		sprintf(svr_buf,"+OK %d messages; msg# and size (in octets) for undeleted messages:\r\n",fld_max);
#endif
		svr_data_out(svr_buf);
		for (; i<fld_max; ++i) {
			if ((fld_msg[i].status & MSG_DELETED) == 0) {
#ifdef PINE_IMAP
			    if (imap_done == 1) {
				sprintf(svr_buf,"%d %ld\r\n",
					(i),fld_msg[i].bcount);
			    }
			    else {
				sprintf(svr_buf,"%d %ld\r\n",
					(i+1),fld_msg[i].bcount);
			    }
#else
				sprintf(svr_buf,"%d %ld\r\n",
					(i+1),fld_msg[i].bcount);
#endif
				svr_data_out(svr_buf);
			}
		}
		sprintf(svr_buf,".\r\n");
	} else {
		if ((msgnum < 1)||(msgnum > fld_max))
			sprintf(svr_buf,"-ERR invalid message; number out of range\r\n");
		else if (fld_msg[msgnum-offset].status & MSG_DELETED)
			sprintf(svr_buf,"-ERR message %d has been marked for deletion\r\n",
				msgnum);
		else {
			sprintf(svr_buf,"+OK %d %ld\r\n",
				msgnum,fld_msg[msgnum-offset].bcount);
#ifdef DEBUG
			fprintf (logfp, "%s +OK %d %ld\r\n", 
				cli_user, msgnum,fld_msg[msgnum-offset].bcount);
#endif
		}
	}
}

/* Reset deleted messages and highest access number */
void
#ifdef ANSIC
fld_reset(void)
#else /* !ANSIC */
fld_reset()
#endif /* ANSIC */
{
	int i;

	if (fld_fp == NULL) {
		sprintf(svr_buf, "+OK no messages in %s\r\n", cli_mbox);
		return;
	}
	/* Reset messages marked for deletion */
	for (i=0; i<fld_max; ++i) {
		fld_msg[i].status &= ~MSG_DELETED;
	}
	/* Reset highest access number for this mailbox */
	fld_highest = -1;
#ifdef PINE_IMAP
	if (imap_done == 1) {
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
		   fld_max - 1,cli_user,cli_mbox);
	} else {
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
		   fld_max,cli_user,cli_mbox);
	}

#else 
	sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
		fld_max,cli_user,cli_mbox);
#endif

}

/* Retrieve a message from mailbox */
#ifdef LOG_SESSIONS
int
#else
void
#endif
#ifdef ANSIC
fld_retr(int msgnum, int linecnt)
#else /* !ANSIC */
fld_retr(msgnum,linecnt)
int msgnum;
int linecnt;
#endif /* ANSIC */
{
    	int offset = 0;
	int offset2 = 1;
#ifdef PINE_IMAP
	if (imap_done == 1) {
	    offset = 1;
	    offset2 = 0;
	}
#endif
	if (fld_fp == NULL) {
		strcpy(svr_buf, svr_nomsg);
#ifdef LOG_SESSIONS
		return 0;
#else
		return;
#endif
	}

	if ((msgnum < 1)||(msgnum > fld_max - offset)) {
	    sprintf(svr_buf,"-ERR invalid message; number out of range\r\n");
#ifdef LOG_SESSIONS
	    return 0;
#endif

	} else if (fld_msg[msgnum-offset2].status & MSG_DELETED) {
	    sprintf(svr_buf,"-ERR message %d has been marked for deletion\r\n",
			msgnum);
#ifdef LOG_SESSIONS
	    return 0;
#endif
	} else {
	    sprintf(svr_buf,"+OK message %d (%ld octets):\r\n",
			msgnum,fld_msg[msgnum-offset2].bcount);
	    svr_data_out(svr_buf);
	    if (fld_hostmbox == 0)
		retr_fromsp(--msgnum + offset,linecnt);
#ifdef HOST_EXT /* [1.010] */
	    else
		retr_bsmtp(--msgnum + offset,linecnt);
#endif
	    sprintf(svr_buf,".\r\n");
	    if ((linecnt != -1)&&(msgnum > fld_highest))
		fld_highest = msgnum;
	}
#ifdef LOG_SESSIONS
	return 1;
#endif
}

/* Give message count and total size (in octets) of a mailbox folder */
void
#ifdef ANSIC
fld_stat(void)
#else /* !ANSIC */
fld_stat()
#endif /* ANSIC */
{
    	int offset = 0;
	int i = 0;
	long total_cnt = 0L;
#ifdef PINE_IMAP
	if (imap_done == 1) {
	    i = 1;
	    offset = 1;
	}
#endif


	if (fld_fp == NULL) {
		strcpy(svr_buf, "+OK 0 0\r\n");
		return;
	}
	for (; i<fld_max; ++i) {
		total_cnt += fld_msg[i].bcount;
	}
	sprintf(svr_buf,"+OK %d %ld\r\n",fld_max - offset,total_cnt);
}

#ifdef UIDL_OKAY /* [1.010] */
/* Give message ID of messages in a mailbox folder */
void
#ifdef ANSIC
fld_uidl(int msgnum)
#else /* !ANSIC */
fld_uidl(msgnum)
int msgnum;
#endif /* ANSIC */
{
    	int offset = 0;
	int offset2 = 1;
	int i = 0;
#ifdef PINE_IMAP
	/* 'i' is the array iterator for the messages.  If we have a pine-imap
	   message, we want to start iterating at index 1 rather than 0, to
	   skip over the imap message.  'offset' is then set to 1 so we can
	   subtract it from 'fld_max', which is the count of messages in the
	   mailbox (including the pine-imap message).  We don't want the pine-
	   imap msg showing up in the count - we don't want users knowing
	   about it at all.  'offset2' is added to the index 'i', so that
	   the messages are listed numbering from 1 up.  But if we start
	   at message 1, because of a pine-imap msg, we don't want to add 1,
	   so we set 'offset2' to zero.
	   'offset2' is also subtracted from 'msgnum' (the message number
	   the user requests).  If there is no pine-imap msg, then we want
	   to subtract 1 from 'msgnum' so that if the user requests msg 1,
	   they get index 0, which is the first mailbox msg.  If there is a
	   pine-imap msg, then we want them to get index 1, so the pine-imap
	   msg is skipped over.  Hope that makes sense...
	*/
	if (imap_done == 1) {
	    i = 1;
	    offset = 1;
	    offset2 = 0;
	}
#endif

	if (fld_fp == NULL) {
		strcpy(svr_buf, svr_nomsg);
		return;
	}

	if (msgnum == -1) {
#ifdef PINE_IMAP
	    if (imap_done == 1) {
		sprintf(svr_buf,"+OK %d messages; msg# and message ID for undeleted messages:\r\n",fld_max - 1);
	    } else {
		sprintf(svr_buf,"+OK %d messages; msg# and message ID for undeleted messages:\r\n",fld_max);
	    }
#else 
		sprintf(svr_buf,"+OK %d messages; msg# and message ID for undeleted messages:\r\n",fld_max);
#endif
		svr_data_out(svr_buf);
		for (; i<fld_max; ++i) {
			if ((fld_msg[i].status & MSG_DELETED) == 0) {
				/* [1.012] check for NULL msg_id */
				if ( fld_msg[i].msg_id != NULL ) {
					sprintf(svr_buf,"%d %s\r\n",
					        (i+offset2),fld_msg[i].msg_id);
				} else {
				/* [1.012] No Message-Id, use size instead */
				/* [1.015] Possibly large message size */
					sprintf(svr_buf,
					   "%d <%ld@fabricated.message.id>\r\n",
					   (i+offset2),fld_msg[i].bcount);
				}
				svr_data_out(svr_buf);
			}
		}
		sprintf(svr_buf,".\r\n");
	} else {
		if ((msgnum < 1)||(msgnum > fld_max - offset)) {
			sprintf(svr_buf,"-ERR invalid message; number out of range\r\n");
#ifdef DEBUG
			fprintf (logfp, 
			    "%s:-ERR invalid message; number out of range\r\n",
			    cli_user);
#endif
		}
		else if (fld_msg[msgnum-offset2].status & MSG_DELETED) {
			sprintf(svr_buf,
			"-ERR message %d has been marked for deletion\r\n",
				msgnum);
#ifdef DEBUG
			fprintf (logfp, 
			    "%s:-ERR message %d has been marked for deletion\r\n", cli_user, msgnum);
#endif /* DEBUG */
		}
		else {
		    if (fld_msg[msgnum-offset2].msg_id != NULL) {
			sprintf(svr_buf,"+OK %d %s\r\n",
				msgnum,fld_msg[msgnum-offset2].msg_id);
#ifdef DEBUG
		fprintf (logfp, "%s: uidl #", cli_user);
#endif
		    }
		    else {
			sprintf(svr_buf, 
				"+OK %d <%ld@fabricated.message.id>\r\n",
				msgnum, fld_msg[msgnum - offset2].bcount);
		    }
		}
	}
}
#endif

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

/* Attempt to load a mailbox folder */
static int
#ifdef ANSIC
#ifdef POPMOTD
fld_select(char *mbox, int host_fld, POP *p)
#else /* !POPMOTD */
fld_select(char *mbox, int host_fld)
#endif /* POPMOTD */
#else /* !ANSIC */
fld_select(mbox,host_fld)
char *mbox;
int host_fld;
#endif /* ANSIC */
{

	struct stat stat_buf;
	FILE *mboxfp;
	char *mode;
	int	lock;

	/* Reset folder variables */
	fld_hostmbox = host_fld;
	fld_fp = NULL;
	/* fld_write_ok = -1;     [1.009] commented out */
	fld_highest = -1;

	/* Make sure mailbox is present and non-zero size */
	if (stat(mbox,&stat_buf) == -1)
	{
		return 0;
	}

#ifdef POPMOTD
        get_bulletin_numbers(p);
        if (stat_buf.st_size == 0L && p->bullfiles[0] == -1)
        {
                return 0;
        }
#else
        if (stat_buf.st_size == 0L)
        {
                return 0;
        }
#endif /* POPMOTD */

#ifdef NO_MULTIPLE
/* [1.014] */
/* [1.014] */
	creat(lockfile, O_CREAT);
	remove_lockfile = 1;			/* [1.014] */
#endif /* NO_MULTIPLE */

	/* Save current mailbox size and last-modified-timestamp */
	fld_orig_size = stat_buf.st_size;	/* [1.004] */
	fld_orig_mod_time = stat_buf.st_mtime;	/* [1.004] */

	/* Create/save mailbox names */
	strcpy(fld_fname, POP3_TMPFILE);
	if (mktemp(fld_fname) == NULL)
	{
		return -1;
	}
#ifdef POPMOTD
        strcpy(temp_name, fld_fname); /* -BC */ 
#endif
	
	/* Secure mailbox for POP3 session; copy to temporary file */
#if defined (SYSV) || defined (SVR4) || defined (AIX)
	mode = "r+";
#else /* !(defined (SYSV) || defined (SVR4)) */
	mode = "r";
#endif /* defined (SYSV) || defined (SVR4) */
	if ((mboxfp = fopen(mbox, mode)) == NULL)
	{
		return -1;
	}
	if ((lock = dup(fileno(mboxfp))) == -1) {
		fclose(mboxfp);
		return -1;
	}
#if defined (SYSV) || defined (SVR4)
	if (lockf(lock, F_TLOCK, 0L) == -1)	/* [1.008] non-blocking */
	{					/* [1.008] */
		if ( errno == EAGAIN ) {	/* Already locked? */
			sleep(5);		/* Yes, wait then try again */
			if (lockf(lock, F_TLOCK, 0L ) == -1 ) {
				fclose(mboxfp);	/* Give up for now */
				return -1;
			}
		} else {
#else /* !(defined (SYSV) || defined (SVR4)) */
						/* [1.008] non-blocking */
						/* [1.013] add LOCK_EX */
	if (flock(lock, (LOCK_EX|LOCK_NB)) == -1)		
	{					/* [1.008] */
		if ( errno == EWOULDBLOCK ) {	/* Already locked? */
			sleep(5);		/* Yes, wait then try again */
			if (flock(lock, (LOCK_EX|LOCK_NB)) == -1 ) {
				fclose(mboxfp);	/* Give up for now */
				return -1;
			}
		} else {
#endif /* defined(SYSV) || defined(SVR4) */
			fclose(mboxfp);
			return -1;
		}
	}
	if ((fld_fp = fopen(fld_fname,"w")) == NULL)
	{
		fclose(mboxfp);
#if (defined (SYSV) || defined (SVR4))
		lockf(lock, F_ULOCK, 0L);
#else /* !(defined (SYSV) || defined (SVR4)) */
		flock(lock, LOCK_UN);
#endif /* !(defined(SYSV) || defined(SVR4)) */
		close(lock);
		return -1;
	}

	/* Load messages from folder */
	if (fld_hostmbox == 0)
	{
#ifdef POPMOTD
                fld_max = msg_fromsp(mboxfp, fld_fp, p);
#else
                fld_max = msg_fromsp(mboxfp, fld_fp);
#endif
	}
#ifdef HOST_EXT /* [1.010] */
	else
	{
		fld_max = msg_bsmtp(mboxfp, fld_fp);
	}
#endif

#ifdef notdef /* [1.004] */
	/* Zero out the mailbox so other processes can use it */
	/* while we are using the temporary copy just made.   */
	if (fld_max > 0)
	{
		if ((mboxfp = freopen(mbox,"w", mboxfp)) == NULL || 
				fclose(mboxfp) == EOF)
			fld_max = -1;
	}
#endif	/* [1.004] */

	/* Unlock mailbox */
#if (defined (SYSV) || defined (SVR4))
	lockf(lock, F_ULOCK, 0L);
#else !(defined (SYSV) || defined (SVR4))
	flock(lock, LOCK_UN);
#endif /* !(defined (SYSV) || defined (SVR4)) */
	close(lock);

	/* Prepare to use temporary file for POP3 session */
	if (fld_max > 0)
	{
		if ((fld_fp = freopen(fld_fname,"r", fld_fp)) == NULL)
		{
			unlink(fld_fname);
			fld_max = -1;
		}
	}
	else
	{
		/* Either zero messages or error */
		unlink(fld_fname);
		fld_fp = NULL;
	}
	return(fld_max);
}

/* Close a mailbox folder; remove messages marked for deletion */
void
#ifdef ANSIC
fld_release(void)
#else /* !ANSIC */
fld_release()
#endif /* ANSIC */
{
	char temp_fname[32];
	char	*mode;
	FILE *mboxfp;
	FILE *tempfp;
	int	lock;
	int i = 0;
	int savemsg = 1;
	int zap_orig_mbox;
#ifdef HOST_EXT
	int bsmtp_helo = 0;	/* [1.015] Declare variable only if needed */
#endif
	struct stat stat_buf;

#ifdef UCD
	if (new_mbox[0] != NULL) {
	    unlink(new_mbox);
	}
#endif /* UCD */
	/* If no messages in folder, just free memory for filename */
	if (fld_fp == NULL) {
		if (cli_mbox != NULL) {
			free(cli_mbox);
			cli_mbox = NULL;
		}
		return;
	}

        /* [1.011] Original mailbox file was untouched;  */
        /* only need to re-write if one or more messages */
        /* were deleted                                  */
	/* If no messages were deleted, just remove */
	/* the working mailbox file.                */
	for (i=0; i<fld_max; ++i) {
#ifdef POPMOTD
		/* If there are popmotds that should be appended to the  */
		/* mailbox... act the same as if there were msgs deleted */
		/* so that they get into the real mailbox.		 */
		if (is_popmotd) {
			break;
		}
#endif
		if ((fld_msg[i].status & MSG_DELETED) != 0)
			break;
	}
	if (i == fld_max)
		goto cleanup;

	/* [1.004] Check size and timestamp on the original mailbox file */
	if (stat(cli_mbox, &stat_buf) == -1) {
		/* Another user agent removed it while we were working */
		zap_orig_mbox = REMOVE_MBOX;
	} else {
		if ((stat_buf.st_mtime == fld_orig_mod_time) &&
		    (stat_buf.st_size  == fld_orig_size)) {
			/* Nothing added to mailbox while we were working */
			zap_orig_mbox = REMOVE_MBOX;
		} else {
			if (stat_buf.st_size > fld_orig_size) {
				/* More messages were added to end of mbox */
				zap_orig_mbox = SAVE_NEW;
	
			} else {
				/* Another user agent made changes while
				 * we were working; save it all to be safe
				 */
				zap_orig_mbox = SAVE_ALL;
			}
		}
	}

	/* Save changes made to original mailbox folder during
	 * this POP3 session
	 */
	if (zap_orig_mbox == REMOVE_MBOX) {
		/* No changes to save */
		if ((mboxfp = fopen(cli_mbox, "w")) == NULL)
			fail(FAIL_FILE_ERROR, 0);
	} else {
		/* Save parts of this mailbox */
#if defined (SYSV) || defined (SVR4) || defined (AIX)
		mode = "r+";
#else /* !(defined (SYSV) || defined (SVR4)) */
		mode = "r";
#endif /* defined (SYSV) || defined (SVR4) */
		if ((mboxfp = fopen(cli_mbox, mode)) == NULL)
			fail(FAIL_FILE_ERROR, 0);
	}
	/* Lock original mailbox folder */
	if ((lock = dup(fileno(mboxfp))) == -1) {
		fclose(mboxfp);
		fail(FAIL_FILE_ERROR, 0);
	}
#if defined (SYSV) || defined (SVR4)
	if (lockf(lock, F_LOCK, 0L))
#else /* !(defined (SYSV) || defined (SVR4)) */
	if (flock(lock, LOCK_EX) == -1)
#endif /* defined(SYSV) || defined(SVR4) */
		fail(FAIL_FILE_ERROR, 0);

	/* Adjust position in original mailbox file */
	if (zap_orig_mbox == SAVE_NEW) {
		/* Save only the messages added while we were working */
		if (fseek(mboxfp, fld_orig_size, 0) == -1)
			fail(FAIL_FILE_ERROR, 0);
	} else if ((zap_orig_mbox == SAVE_ALL) && (fld_hostmbox != 0)) {
		/* BSMTP: Skip past HELO line in original mailbox file */
		while (fgetl(svr_buf,SVR_BUFSIZ,mboxfp) != -1) {
			cmd_prepare(svr_buf);
			if (isbsmtp_helo(svr_buf)) {
				break;
			}
		}
		if (ferror(mboxfp))
			fail(FAIL_FILE_ERROR, 0);
	}

	/* Transfer messages we want to save */
	if (zap_orig_mbox == REMOVE_MBOX) {
		/* Nothing to save, close file we just openned for write */
		if (fclose(mboxfp) == EOF)
			fail(FAIL_FILE_ERROR, 0);
		temp_fname[0] = '\0';
	} else {
		/* Copy from the original mailbox to a temp file */
		strcpy(temp_fname, POP3_TMPFILE);
		if (mktemp(temp_fname) == NULL)
			fail(FAIL_FILE_ERROR, 0);
		if ((tempfp = fopen(temp_fname,"w")) == NULL)
			fail(FAIL_FILE_ERROR, 0);

		while (fgetl(svr_buf,SVR_BUFSIZ,mboxfp) != -1) {
			fputs(svr_buf,tempfp);
			if (ferror(tempfp))
				fail(FAIL_FILE_ERROR, 0);
		}
		if (ferror(mboxfp))
			fail(FAIL_FILE_ERROR, 0);
		if (fclose(mboxfp) == EOF)
			fail(FAIL_FILE_ERROR, 0);
		if (fclose(tempfp) == EOF)
			fail(FAIL_FILE_ERROR, 0);
	}
	
	/* Transfer contents of working folder to original */
	/* mailbox folder; dont copy deleted messages.     */
	if ((mboxfp = fopen(cli_mbox,"w")) == NULL)
		fail(FAIL_FILE_ERROR, 0);

/* [1.011] added none-deleted check earlier; don't check again here */
#ifdef notdef
	/* If all messages were deleted, we don't need to look */
	/* throught the working mailbox file.                  */
	for (i=0; i<fld_max; ++i) {
		if ((fld_msg[i].status & MSG_DELETED) == 0)
			break;
	}
	if (i == fld_max)
		goto addnew;
#endif

	/* Transfer undeleted messages from the working mailbox */
	rewind(fld_fp);
	i = 0;				/* [1.002] reset index counter */
#ifdef HOST_EXT /* [1.010] */
	if (fld_hostmbox != 0) {
		/* BSMTP: Transfer all text upto and including HELO */
		while (fgetl(svr_buf,SVR_BUFSIZ,fld_fp) != -1) {
			fputs(svr_buf,mboxfp);
			if (ferror(mboxfp))
				fail(FAIL_FILE_ERROR, 0);
			cmd_prepare(svr_buf);
			if (isbsmtp_helo(svr_buf)) {
				bsmtp_helo = 1;
				break;
			}
		}
		/* Transfer first message, unless marked for deletion */
		savemsg = !(fld_msg[i++].status & MSG_DELETED);
	}
#endif
	while (fgetl(svr_buf,SVR_BUFSIZ,fld_fp) != -1) {
		if ((fld_hostmbox == 0) && (isfromsp_start(svr_buf))) {
			/* FromSPACE delimited mailbox */
			/* Transfer next msg, unless deleted */
			savemsg = !(fld_msg[i++].status & MSG_DELETED);
		}
		if (savemsg) {
			fputs(svr_buf,mboxfp);
			if (ferror(mboxfp))
				fail(FAIL_FILE_ERROR, 0);
		}
#ifdef HOST_EXT /* [1.010] */
		if ((fld_hostmbox != 0) && (isbsmtp_end(svr_buf))) { 
			/* BSMTP mailbox */
			/* Transfer next msg, unless deleted */
			savemsg = !(fld_msg[i++].status & MSG_DELETED);
		}
#endif
	}
	if (ferror(fld_fp))
		fail(FAIL_FILE_ERROR, 0);

	if (temp_fname[0] == '\0') {
		/* Nothing more to add, close the original mailbox file */
		if (fclose(mboxfp) == EOF)
			fail(FAIL_FILE_ERROR, 0);
	}


#ifdef notdef
addnew:	/* [1.015] No longer needed */
#endif
	if (temp_fname[0] != '\0') {
		/* There were changes to the original mailbox file
		 * while we were working. Save the messages that
		 * chnaged in the original mailbox file.
		 */
#ifdef HOST_EXT /* [1.010] */
		if ((fld_hostmbox != 0) && (bsmtp_helo == 0)) {
			/* BSMTP: Transfer all text upto and including HELO */
			rewind(fld_fp);
			while (fgetl(svr_buf,SVR_BUFSIZ,fld_fp) != -1) {
				fputs(svr_buf,mboxfp);
				if (ferror(mboxfp))
					fail(FAIL_FILE_ERROR, 0);
				cmd_prepare(svr_buf);
				if (isbsmtp_helo(svr_buf)) {
					bsmtp_helo = 1;
					break;
				}
			}
			if (ferror(fld_fp))
				fail(FAIL_FILE_ERROR, 0);
		}
#endif
		/* Transfer contents of temp file (messages added */
		/* to original mailbox during this POP3 session)  */
		/* back to mailbox folder                         */
		if ((tempfp = fopen(temp_fname,"r")) == NULL)
			fail(FAIL_FILE_ERROR, 0);
		while (fgets(svr_buf,SVR_BUFSIZ,tempfp) != NULL) {
			fputs(svr_buf,mboxfp);
			if (ferror(mboxfp))
				fail(FAIL_FILE_ERROR, 0);
		}
		if (ferror(tempfp))
			fail(FAIL_FILE_ERROR, 0);
		if (fclose(tempfp) == EOF)
			fail(FAIL_FILE_ERROR, 0);
		unlink(temp_fname);
		if (fclose(mboxfp) == EOF)
			fail(FAIL_FILE_ERROR, 0);
	}

#if (defined (SYSV) || defined (SVR4))
	lockf(lock, F_ULOCK, 0L);
#else /* !(defined (SYSV) || defined (SVR4)) */
	/* Unlock original mailbox folder */
	flock(lock, LOCK_UN);
#endif /* !(defined(SYSV) || defined(SVR4)) */
	close(lock);

cleanup:
	/* Close and remove working copy of mailbox folder */
	fclose(fld_fp);
	fld_fp = NULL;
	unlink(fld_fname);
	for (i=0; i<fld_max; ++i) {
		if (fld_msg[i].pop_hdr != NULL)
			free(fld_msg[i].pop_hdr);
#ifdef UIDL_OKAY /* [1.010] */
		if (fld_msg[i].msg_id != NULL)
			free(fld_msg[i].msg_id);
#endif
	}
	free( (char *)fld_msg );
	free(cli_mbox);
	cli_mbox = NULL;
}

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

/* Send a FromSP delimited message to the POP3 client */
static void
#ifdef ANSIC
retr_fromsp(int msgnum, int linecnt)
#else /* !ANSIC */
retr_fromsp(msgnum,linecnt)
int msgnum;
int linecnt;
#endif /* ANSIC */
{
	char *cp, *tp;
	int msgbody = 0;
#ifdef LOG_SESSIONS
	long b_tmp = 0;
#endif

	/* Locate start of message in mailbox file */
	if (fseek(fld_fp, fld_msg[msgnum].fmsg_entry, 0) == -1)
		return;

	/* Setup for byte-stuff on lines that start with '.' */
	cp = svr_buf;
	*cp = DOT_CHAR;
	++cp;
	/* Display message for the client */
	if (fld_msg[msgnum].pop_hdr != NULL)
		svr_data_out(fld_msg[msgnum].pop_hdr);
#ifdef LOG_SESSIONS
	while ((b_tmp = fgetl(cp,SVR_BUFSIZ,fld_fp)) != -1) {
#else
	while (fgetl(cp,SVR_BUFSIZ,fld_fp) != -1) {
#endif
		if (isfromsp_start(cp))
			break;
                if ((msgbody)&&(linecnt-- == 0)) /* [1.010] */
                        break;
#ifdef LOG_SESSIONS
		byte_count += b_tmp + 1;
#endif
		/* Use CR-LF line terminator */
		tp = strchr(cp,LF_CHAR);
		if (tp != NULL)
			strcpy(tp,"\r\n");
		/* Byte-stuff lines that start with '.' */
		if (*cp == DOT_CHAR) {
			svr_data_out(svr_buf);
		} else {
			svr_data_out(cp);
			if (*cp == CR_CHAR)
				msgbody = 1;
		}
	}
#ifdef LOG_SESSIONS
	byte_count += strlen(flash_buf);
#endif
}

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

/* This function will go through the popmotd directory and find which files the 
   user has not read/been given.  It will then put those in an array.  A large
   portion of this code is paranoia-inspired error checking. ;)
*/
#ifdef POPMOTD
int get_bulletin_numbers(POP *p) {
    DIR *dirp;
    FILE *popBull;
#ifdef NODIRENT
    struct direct *dp;
#else
    struct dirent *dp;
#endif
    long copy_count = 0;                /* number of lowest motd to start
                                           copying from if .popbull is invalid
                                        */
    long maxBullNumber = 0;
    long bullNumber;
    long tmp = 0;
    long lastBullSent = 0;
    char buffer[MAXMSGLINELEN];
    char popBullName[100];

    long allBulls[100];                 /* List of all motd's in the dir */
    int counter = 0;

    int i = 0;
    int bull_count = 0;

   /* Construct full path name of .popbull file (in the user's home). */
    sprintf(popBullName, "%s/.popbull", p->homedir);
    p->bullfiles[0] = -1;

    /* Scan bulletin directory and compute the maximum current
        bulletin number. */
    dirp = opendir(p->bulldir);
    if (dirp == NULL) {
        /* If we can't open the directory with popmotds, abandon the popmotd 
           attempt, but continue with regular mail operations.
        */
#ifdef DEBUG
        fprintf(logfp, "%s: Unable to open bulletin directory.\n", cli_user);
#endif
        return POP_SUCCESS;
    }

    /* This while() counts the number of legit popmotds, and finds the
        one  with the largest number.
    */
    while ((dp = readdir(dirp)) != NULL) {
        if (!isdigit((int)*dp->d_name)) continue;    /* if the directory entry
                                                   isn't a digit. */
        bullNumber = atol(dp->d_name);
        if (bull_count > 0) {
            /*  This next part to insert the numbers in order.  If the current
                motd is larger than the last, then insert it in the right place.
            */
            if (allBulls[bull_count - 1] > bullNumber) {
                /* Find the spot where we want to insert... */
                while( (allBulls[counter] < bullNumber) && 
                (counter < bull_count) ) {
                    counter++;
                }
                i = bull_count - counter;
                tmp = bull_count;
                /* Shift everything after insertion pt one space to the right.*/
                memmove(&(allBulls[counter + 1]), &(allBulls[counter]), 
                        sizeof(long) * i);
                allBulls[counter] = bullNumber;
                counter = 0;
            }
            else {
                allBulls[bull_count] = bullNumber;
            }
        }
        else {
            allBulls[bull_count] = bullNumber;
        }
        ++bull_count;
        /* Current point */
        if (bullNumber > maxBullNumber) {
            maxBullNumber = bullNumber;
        }
    }
    closedir(dirp);

   /* Open the user's .popbull file and read the number of the last
      bulletin sent to this user. If the file doesn't exist, create
      it and seed it with a number which will cause pop to send the user
      the max number of motds.
   */
    popBull = fopen(popBullName, "r");
    if (popBull == NULL) { /* If we can't open it for reading, try for 
                              write. */
        popBull = fopen(popBullName, "w");
        if (popBull == NULL) {  /* If can't open for write either, abandon
                                   popmotd attempt, and continue with regular
                                   operations.
                                */
#ifdef DEBUG
            fprintf(logfp, "%s: Unable to create .popbull file\n",cli_user);
#endif
            return POP_SUCCESS;         /* Return success because even if
                                           we for some reason can't deal with
                                           POPMOTD's, we still want to do
                                           regular mail.
                                        */
        }
        if (bull_count > NEWUSERBULLS) {
            copy_count = allBulls[bull_count - NEWUSERBULLS];
        }
        else {
            copy_count = 0;
        }
                        /* newuserbulls is 
                           max # of bulletins 
                           to give a new pop user
                        */
        fprintf(popBull, "%ld\n", copy_count);
        sprintf(buffer, "%ld", copy_count);
    } else {    /* We can open the .popbull for reading... now check it for
                   valid stuff (i.e. a number).
                */
        if (fgets(buffer, MAXMSGLINELEN, popBull) == NULL || 
        !isdigit((int)*buffer)) {
            /* But there isn't anything valid in the file, so we do the
               same as above, seeding with a max number.
            */
            fclose(popBull);
            popBull = fopen(popBullName, "w");
            if (popBull == NULL) {
#ifdef DEBUG
                fprintf(logfp, "%s: Unable to write to .popbull file\n",
			cli_user);
#endif
                return POP_SUCCESS;
            }
            if (bull_count > NEWUSERBULLS) {
                copy_count = allBulls[bull_count - NEWUSERBULLS];
            }
            else { 
                copy_count = 0;
            }
            fprintf(popBull, "%ld\n", copy_count);
            sprintf(buffer, "%ld", copy_count);
        }
        lastBullSent = atol(buffer);
        fclose(popBull);
    }

    /* If there aren't any new bulletins for this user, return. */
    if (lastBullSent >= maxBullNumber) {
        return POP_SUCCESS;
    }

    /* Get a list of the bulletin files we want to append to the user's
        temporary mail file.
    */

    counter = 0;
    while ((allBulls[counter] <= lastBullSent) && (allBulls[counter] != -1)) {
        ++counter;
    }
    i = bull_count - counter;
    if (i > 0) {
        memcpy(&(p->bullfiles[0]), &(allBulls[counter]), sizeof(long) * i);
    }
    p->bullfiles[i] = -1;
    return i;
}

#endif /* POPMOTD */

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


/**************************************************************************/
/*
#ifdef PINE_IMAP

static int
go_to_next_msg(FILE *infp)
{
    while (fgetl(svr_buf,SVR_BUFSIZ,infp) != -1) {
	if (isfromsp_start(svr_buf)) {
	    fseek (infp, -(strlen(svr_buf)), SEEK_CUR);
	    return (1);
	}
    }
    return (1);
}
#endif  PINE_IMAP */

int find_msg_id(FILE *infp, struct fld_item *mp)
{
    long pos;
    char *ptr;
    char buf[SVR_BUFSIZ];
    
    pos = ftell(infp);
    if (fgetl(buf,SVR_BUFSIZ,infp) == -1) {
	fseek (infp, pos, 0);
	return (0);
    }
    ptr = buf;
    while ((*ptr == ' ') || (*ptr == '\t')) {
	ptr++;
    }
    if (*ptr != '<') {
	fseek (infp, pos, 0);
	return (0);
    }
    else {
	mp->msg_id=realloc (mp->msg_id, strlen (MESSAGE_ID_HDR) + strlen (ptr));
	strncat (mp->msg_id, ptr, strlen(ptr));
	return (1);
    }
}

/* Load messages from a mailbox delimited by FromSPACE */
static int
#ifdef ANSIC
#ifdef POPMOTD
msg_fromsp(FILE *infp, FILE *outfp, POP *p)
#else
msg_fromsp(FILE *infp, FILE *outfp)
#endif /* POPMOTD */
#else /* !ANSIC */
msg_fromsp(infp, outfp)
FILE *infp;
FILE *outfp;
#endif /* ANSIC */
{
	int i = 0;
	register struct fld_item *mp;
        char *idp;

#ifdef POPMOTD
    int file_counter = 0;   /* Keep track of which file name in array
                                we are currently accessing. */
    FILE *dot_popbull;       /* File in user's home directory */
    int file_res = 0;
    char dot_pb_name[50];    /* String to hold $HOME/.popbull */
    int count = 0;
	
    sprintf(dot_pb_name, "%s/.popbull", p->homedir);
    strcpy(p->drop_name, temp_name);
#endif /* POPMOTD */

    /* Get an array for storing info about messages in folder */
    get_e_array(fld_msg, FLD_ENTRY_BLOCK);
    if (fld_msg == NULL)
	fail(FAIL_OUT_OF_MEMORY, 0);
    mp = &fld_msg[0];
    /* Load messages from mailbox folder to temporary folder */
#ifdef POPMOTD
    while(1) { 
    /*  This while(1) is a wrapper placed around the while(fgetl...) which
        allows for popmotd.  The first time through, the original inbox
        will be read.  After it exits, the program checks for
        popmotd files. If there are any, we go through and process those
        files in the same way as the inbox.
    */
        count++;
#endif
	while (fgetl(svr_buf,SVR_BUFSIZ,infp) != -1) {
	    fputs(svr_buf, outfp);
		if (ferror(outfp))
			return -1;
		if (isfromsp_start(svr_buf)) {
#ifdef PINE_IMAP
		    	if ((imap_done == 0) && (i == 0)) {
/*			    fprintf (stderr, "Saving header From \n"); */
		    	    mp->header_lines = (char *)malloc(strlen(svr_buf));
			    strcpy(mp->header_lines, svr_buf);
			}
#endif
			/* Make sure there is room in array for this entry */
			chk_e_size(fld_msg, FLD_ENTRY_BLOCK, i);
			if (fld_msg == NULL)
				fail(FAIL_OUT_OF_MEMORY, 0);
			/* Reset stats for this message */
			mp = &fld_msg[i];
			mp->fmsg_entry = ftell(outfp);
			mp->status = 0;
			sprintf(flash_buf,"%s %s@%s\r\n",POP3_RCPT_HDR,
					cli_user,svr_hostname);
			mp->pop_hdr = (char *)malloc(strlen(flash_buf)+1);

			if (mp->pop_hdr == NULL)
				fail(FAIL_OUT_OF_MEMORY, 0);
			strcpy(mp->pop_hdr,flash_buf);
			mp->bcount = strlen(mp->pop_hdr);
#ifdef UIDL_OKAY
			mp->msg_id = NULL;
#endif

			++i;
		} else {
#ifdef PINE_IMAP
		    	if ((imap_done == 0) && (i == 1)) {
/*			    fprintf (stderr, "imap_done == 0, i == 1\n"); */
			    if (strncmp ("Subject: ", svr_buf, 9) == 0) {
/*				fprintf (stderr, "Got subject, %s", svr_buf);
				fprintf (stderr, "%s", mp->header_lines);
*/
				if ((strstr (svr_buf, "FOLDER INTERNAL DATA")
					!= NULL) && (strncmp (mp->header_lines, 
					"From MAILER-DAEMON", 18) == 0)) {
/*				    fprintf (stderr, "Found the imap msg\n"); */
				    imap_done = 1;
				}
				else {
				    imap_done = -1;
				}
			    }
			}
#endif /* PINE_IMAP */
			mp->bcount += ((long)strlen(svr_buf) + 1L);
#ifdef UIDL_OKAY
			/* Gather Message-ID for UIDL command [1.010] */
                        if ( ( mp->msg_id == NULL ) &&
                             ( strncasecmp( svr_buf, MESSAGE_ID_HDR,
                                            strlen( MESSAGE_ID_HDR ) ) == 0 ) ){
			    mp->msg_id = (char *)malloc(strlen( svr_buf ) );
			    if ( mp->msg_id == NULL )
				fail(FAIL_OUT_OF_MEMORY, 0);
			    idp = svr_buf + strlen( MESSAGE_ID_HDR );
			    while ( *idp == SPACE_CHAR)
			    	++idp;
			    if ((*idp == '\n') || (*idp == '\r')) {
				if (find_msg_id(infp, mp) == 0) {
				    free (mp->msg_id);
				    mp->msg_id = 0;
				}
			    }
			    else {
			    	strcpy( mp->msg_id, idp );
			    }
			    if (mp->msg_id != NULL) {
			    	idp = strchr( mp->msg_id, LF_CHAR );
			    	if ( idp != NULL )
				    *idp = NULL_CHAR;
			    	if ( (int)strlen( mp->msg_id ) > 70 ) {
				    idp = mp->msg_id + 70;
				    *idp = NULL_CHAR;
				}
			    }
                        }
#endif
		}
	}
	if (ferror(infp))
		return -1;
#ifdef POPMOTD
        if(p->bullfiles[0] == -1) { /* If no bulletins to retrieve */
            break;  /* Break out of while(1) */
        }
        else {      /* We have bulletins to send */
            if (file_counter == 0) { /* If we're just starting to append. */
                /* Make FILE *infp = NULL.  If we simply close the 
                    file, we lose the lock on it, and bad things could
                    happen.  Instead, change the value, don't close the 
                    file, and don't lose the lock.  This is a local copy
                    of infp anyway, so it won't be changed once this 
                    function exits.
                */
                infp = NULL;
            }
            else {
                fprintf(outfp, "\n");
                mp->bcount += 2;
                fclose(infp);
            }
            if(p->bullfiles[file_counter] == -1) { /* at end of array */
                break;
            }

            /* get the next popmotd that has 'From ' as the first 5 chars */
            file_res = check_file_for_fromsp(&infp,&file_counter,p);

            if(file_res == 1) { /* No more motds */
                break;      /* Break out of the while(1) */
            }
        }   
    }   /* END while(1) */

    if (p->bullfiles[0] != -1) {
    	if ((dot_popbull = fopen(dot_pb_name, "w")) == NULL) {
#ifdef DEBUG
            fprintf(logfp, "%s: Couldn't open .popbull for writing\n",cli_user);
#endif /* DEBUG */
            return -1;
        }
        else {
            fprintf(dot_popbull,"%ld\n",p->bullfiles[file_counter - 1]);
            fclose(dot_popbull);
        }
    }
#endif /* POPMOTD */
    if (i == 0)
	free((char *)fld_msg);
    return(i);
}

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


/*
   This function will check a popmotd file to see if it starts with 'From '.  If
   not, the file will simply be skipped over.  Assigns a new file to infp.
*/
#ifdef POPMOTD

int check_file_for_fromsp(FILE **infp, int *file_counter, POP *p) {
    char Bullfile[100];
    char buffer[MAXMSGLINELEN+1];
    int count = 0;

    do {
        count++;
        sprintf(Bullfile,"%s/%ld",p->bulldir,p->bullfiles[*file_counter]);
        if (*infp != NULL) {
            fclose(*infp);
        }
        while (((*infp = fopen(Bullfile, "r")) == NULL) && 
        (p->bullfiles[*file_counter] != -1)) {
#ifdef DEBUG
            if (infp == NULL) {
                fprintf(logfp, 
		    "%s:Couldn't open bulletin file %ld for reading\n",
                    cli_user, p->bullfiles[*file_counter]);
            }
#endif /* DEBUG */
            (*file_counter)++;
            sprintf(Bullfile,"%s/%ld",p->bulldir,p->bullfiles[*file_counter]);
        }

        if (p->bullfiles[*file_counter] == -1) /* No more motds to append */
            return (1);
        fgets(buffer, MAXMSGLINELEN, *infp);
        (*file_counter)++;
    } while(strncmp(buffer,"From ",5) != 0);

    rewind(*infp);
    is_popmotd = 1;
    return 0;

}

#endif /* POPMOTD */


/************************************************/
#ifdef HOST_EXT /* [1.010] */

/* Open a BSMTP wrapped mailbox */
int
#ifdef ANSIC
fld_bsmtp(char *hostname)
#else /* !ANSIC */
fld_bsmtp(hostname)
char *hostname;
#endif /* ANSIC */
{
	int cnt;
#ifdef POPMOTD
	struct POP *p = NULL;
#endif
		
	p = NULL;
	/* Release previously opened mailbox */
	if (fld_fp != NULL)
		fld_release();
	/* Construct filename for new mailbox */
	cli_mbox = (char *)malloc(strlen(hostname)+strlen(DEF_POP3_DIR)+1);
	if (cli_mbox == NULL)
		fail(FAIL_OUT_OF_MEMORY, 0);
	strcpy(cli_mbox,DEF_POP3_DIR);
	strcat(cli_mbox,hostname);
	/* Open mailbox */
#ifdef POPMOTD
        /* Open mailbox */ /* pass p in added by BC */
        if ((cnt = fld_select(cli_mbox,1, p)) == -1) {
#else /* !POPMOTD */
        if ((cnt = fld_select(cli_mbox,1)) == -1) {
#endif /* POPMOTD */

#ifdef SVR4
		sprintf(svr_buf,"-ERR cannot open mailbox %s: %s\r\n",
			cli_mbox, strerror(errno));
#else
		sprintf(svr_buf,"-ERR cannot open mailbox %s: %s\r\n",
			cli_mbox,
			(errno<sys_nerr ? sys_errlist[errno]:"Unknown error" ));
#endif
		free(cli_mbox);
		cli_mbox = NULL;
		return(SVR_FOLD_STATE);
	} else {
#ifdef PINE_IMAP
	    if (imap_done == 1) {
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
			cnt-1,cli_user,cli_mbox);
	    } else {
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
			cnt,cli_user,cli_mbox);
	    }
#else
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
			cnt,cli_user,cli_mbox);
#endif
		return(SVR_TRANS_STATE);
	}
}

/* Send a BSMTP wrapped message to the POP3 client */
static void
#ifdef ANSIC
retr_bsmtp(int msgnum, int linecnt)
#else /* !ANSIC */
retr_bsmtp(msgnum,linecnt)
int msgnum;
int linecnt;
#endif /* ANSIC */
{
	char *tp;
	int msgbody = 0;

	/* Locate start of message in mailbox file */
	if (fseek(fld_fp, fld_msg[msgnum].fmsg_entry, 0) == -1)
		return;
	/* Display message text for the client */
	if (fld_msg[msgnum].pop_hdr != NULL)
		svr_data_out(fld_msg[msgnum].pop_hdr);
	while (fgetl(svr_buf,SVR_BUFSIZ,fld_fp) != -1) {
		if (isbsmtp_end(svr_buf))
			break;
		/* Use CR-LF line terminator */
		tp = strchr(svr_buf,LF_CHAR);
		if (tp != NULL)
			strcpy(tp,"\r\n");
		svr_data_out(svr_buf);
		if ((msgbody)&&(--linecnt == 0)) {
			break;
		} else {
			if (*svr_buf == CR_CHAR)
				msgbody = 1;
		}
	}
}

/* Load messages from a mailbox wrapped in BSMTP format */
/* Assume BSMTP mailbox starts with a HELO command.     */
/* Assume BSMTP mailbox doesnt end with a QUIT command. */
static int
#ifdef ANSIC
msg_bsmtp(FILE *infp, FILE *outfp)
#else /* !ANSIC */
msg_bsmtp(infp, outfp)
FILE *infp;
FILE *outfp;
#endif /* ANSIC */
{
	register struct fld_item *mp;
	int i = 0;
	int mbox_state = BSMTP_HELO_STATE;

	/* Get an array for storing info about messages in folder */
	get_e_array(fld_msg, FLD_ENTRY_BLOCK);
	if (fld_msg == NULL)
		fail(FAIL_OUT_OF_MEMORY, 0);
	mp = &fld_msg[0];
	mp->pop_hdr = NULL;
	/* Load messages from mailbox folder to temporary folder */
	while (fgetl(svr_buf,SVR_BUFSIZ,infp) != -1) {
		fputs(svr_buf, outfp);
		if (ferror(outfp))
			return -1;
		switch(mbox_state) {
		case BSMTP_HELO_STATE:		/* Look for HELO command */
			cmd_prepare(svr_buf);
			if (strncmp(svr_buf,"helo",4) == 0)
				mbox_state = BSMTP_MAIL_STATE;
			break;
		case BSMTP_MAIL_STATE:		/* Process MAIL command */
			cmd_prepare(svr_buf);
			if (strncmp(svr_buf,"mail",4) == 0)
				mbox_state = BSMTP_RCPT_STATE;
			break;
		case BSMTP_RCPT_STATE:		/* Process RCPT command(s) */
			cmd_prepare(svr_buf);
			if (strncmp(svr_buf,"rcpt",4) == 0) {
				/* Save recipient for POP3 client */
				sprintf(flash_buf,"%s %s\r\n",
					POP3_RCPT_HDR,bsmtp_rcpt(svr_buf));
				if (mp->pop_hdr == NULL) {
					mp->bcount = 0L;
					mp->status = 0;
					mp->pop_hdr = (char *)malloc(strlen(flash_buf)+1);
					if (mp->pop_hdr == NULL)
						fail(FAIL_OUT_OF_MEMORY, 0);
					strcpy(mp->pop_hdr,flash_buf);
				} else {
					mp->pop_hdr = realloc(mp->pop_hdr,
						(strlen(mp->pop_hdr)+strlen(flash_buf)+1));
					if (mp->pop_hdr == NULL)
						fail(FAIL_OUT_OF_MEMORY, 0);
					strcat(mp->pop_hdr,flash_buf);
				}
				mp->bcount += (long)strlen(flash_buf);
			} else if (strncmp(svr_buf,"data",4) == 0) {
				mbox_state = BSMTP_DATA_STATE;
				/* Save entry point of message text */
				mp->fmsg_entry = ftell(outfp);
			}
			break;
		case BSMTP_DATA_STATE:		/* Reading mail message */
			if (isbsmtp_end(svr_buf)) {
				/* Prepare for next message in mailbox */
				mbox_state = BSMTP_MAIL_STATE;
				++i;
				/* Resize message array, if needed */
				chk_e_size(fld_msg, FLD_ENTRY_BLOCK, i);
				if (fld_msg == NULL)
					fail(FAIL_OUT_OF_MEMORY, 0);
				mp = &fld_msg[i];
				mp->pop_hdr = NULL;
			} else {
				mp->bcount += ((long)strlen(svr_buf) + 1L);
				if (svr_buf[0] == DOT_CHAR)
					--mp->bcount;
			}
			break;
		default:			/* Shouldnt happen */
			fail(FAIL_CONFUSION, 0);
			break;
		}
	}
	if (ferror(infp))
		return -1;
	if (i == 0)
		free((char *)fld_msg);
	return(i);
}

/* Isolate a recipient address in a BSMTP   RCPT TO:<addr>   command */
static char *
#ifdef ANSIC
bsmtp_rcpt(char *inbuf)
#else /* !ANSIC */
bsmtp_rcpt(inbuf)
char *inbuf;
#endif /* ANSIC */
{
	char *cp;

	cp = strchr(inbuf,RANKLE_CHAR);
	if (cp == NULL)
		return("postmaster");
	*cp = NULL_CHAR;
	cp = strchr(inbuf,LANKLE_CHAR);
	if (cp == NULL)
		return("postmaster");
	return(cp+1);
}
#endif
