ftp.nice.ch/pub/next/unix/mail/Pop3d-RnA.1.0.NI.bs.tar.gz#/pop3d/folder.c

This is folder.c in view mode; [Download] [Up]

/*
 *	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 -- Campus Access Point
 *	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)
 */

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include "pop3.h"

#ifdef LINUX
# include <unistd.h>
#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];		/* 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 */
static int fld_write_ok = -1;		/* -1=client doesnt have write privs */
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))

static int fld_select();
static void retr_fromsp();
static void retr_bsmtp();
static int msg_fromsp();
static int msg_bsmtp();
static char *bsmtp_rcpt();

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

/* Open a BSMTP wrapped mailbox */
int
fld_bsmtp(hostname)
char *hostname;
{
	int cnt;

	/* Release previously opened mailbox */
	if (fld_fp != NULL)
		fld_release();
	/* Construct filename for new mailbox */
	cli_mbox = malloc(strlen(hostname)+strlen(DEF_POP3_DIR)+1);
	if (cli_mbox == NULL)
		fail(FAIL_OUT_OF_MEMORY);
	strcpy(cli_mbox,DEF_POP3_DIR);
	strcat(cli_mbox,hostname);
	/* Open mailbox */
	if ((cnt = fld_select(cli_mbox,1)) == -1) {
		sprintf(svr_buf,"-ERR cannot open mailbox %s\r\n",
			cli_mbox);
		free(cli_mbox);
		cli_mbox = NULL;
		return(SVR_FOLD_STATE);
	} else {
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
			cnt,cli_user,cli_mbox);
		return(SVR_TRANS_STATE);
	}
}

/* Open a FromSpace delimited mailbox */
int
fld_fromsp(fname)
char *fname;
{
	int cnt;

	/* Release previously opened mailbox */
	if (fld_fp != NULL)
		fld_release();
	/* Construct filename for new mailbox */
	cli_mbox = malloc(strlen(fname)+1);
	if (cli_mbox == NULL)
		fail(FAIL_OUT_OF_MEMORY);
	strcpy(cli_mbox,fname);
	/* Open mailbox */
	if ((cnt = fld_select(cli_mbox,0)) == -1) {
		sprintf(svr_buf,"-ERR cannot open mailbox %s\r\n",
			cli_mbox);
		free(cli_mbox);
		cli_mbox = NULL;
		return(SVR_FOLD_STATE);
	} else {
		sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
			cnt,cli_user,cli_mbox);
		return(SVR_TRANS_STATE);
	}
}

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

/* Mark a message for deletion */
void
fld_delete(msgnum)
int msgnum;
{
	if (fld_fp == NULL) {
		strcpy(svr_buf, svr_nomsg);
		return;
	}

	if ((msgnum < 1)||(msgnum > fld_max)) {
		sprintf(svr_buf,"-ERR invalid message; number out of range\r\n");
	} else {
		fld_msg[msgnum-1].status |= MSG_DELETED;
		sprintf(svr_buf,"+OK message %d marked for deletion\r\n",
			msgnum);
		if ((msgnum-1) > fld_highest)
			fld_highest =(msgnum-1);
	}
}

/* Report the highest access number for this mailbox */
void
fld_last()
{
	sprintf(svr_buf,"+OK %d\r\n",(fld_highest+1));
}

/* Give information about messages in mailbox folder */
void
fld_list(msgnum)
int msgnum;
{
	int i;

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

	if (msgnum == -1) {
		sprintf(svr_buf,"+OK %d messages; msg# and size (in octets) for undeleted messages:\r\n",fld_max);
		svr_data_out(svr_buf);
		for (i=0; i<fld_max; ++i) {
			if ((fld_msg[i].status & MSG_DELETED) == 0) {
				sprintf(svr_buf,"%d %ld\r\n",
					(i+1),fld_msg[i].bcount);
				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-1].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-1].bcount);
	}
}

/* Reset deleted messages and highest access number */
void
fld_reset()
{
	int i;

	if (fld_fp == NULL) {
		strcpy(svr_buf, svr_nomsg);
		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;
	sprintf(svr_buf,"+OK %d messages ready for %s in %s\r\n",
		fld_max,cli_user,cli_mbox);
}

/* Retrieve a message from mailbox */
void
fld_retr(msgnum,linecnt)
int msgnum;
int linecnt;
{
	if (fld_fp == NULL) {
		strcpy(svr_buf, svr_nomsg);
		return;
	}

	if ((msgnum < 1)||(msgnum > fld_max)) {
		sprintf(svr_buf,"-ERR invalid message; number out of range\r\n");
	} else if (fld_msg[msgnum-1].status & MSG_DELETED) {
		sprintf(svr_buf,"-ERR message %d has been marked for deletion\r\n",
			msgnum);
	} else {
		sprintf(svr_buf,"+OK message %d (%ld octets):\r\n",
			msgnum,fld_msg[msgnum-1].bcount);
		svr_data_out(svr_buf);
		if (fld_hostmbox == 0)
			retr_fromsp(--msgnum,linecnt);
		else
			retr_bsmtp(--msgnum,linecnt);
		sprintf(svr_buf,".\r\n");
		if ((linecnt != -1)&&(msgnum > fld_highest))
			fld_highest = msgnum;
	}
}

/* Give message count and total size (in octets) of a mailbox folder */
void
fld_stat()
{
	int i;
	long total_cnt = 0L;

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

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

/* Attempt to load a mailbox folder */
static int
fld_select(mbox,host_fld)
char *mbox;
int host_fld;
{
	struct stat stat_buf;
	FILE *mboxfp;
	int lock;

	/* Reset folder variables */
	fld_hostmbox = host_fld;
	fld_fp = NULL;
	fld_write_ok = -1;
	fld_highest = -1;

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

	/* 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;
	
	/* Secure mailbox for POP3 session; copy to temporary file */
	if ((mboxfp = fopen(mbox, "r")) == NULL)
		return -1;
	if ((lock = dup(fileno(mboxfp))) == -1) {
		fclose(mboxfp);
		return -1;
	}
	if (flock(lock, LOCK_EX) == -1) {
		fclose(mboxfp);
		close(lock);
		return -1;
	}
	if ((fld_fp = fopen(fld_fname,"w")) == NULL) {
		fclose(mboxfp);
		flock(lock, LOCK_UN);
		close(lock);
		return -1;
	}

	/* Load messages from folder */
	if (fld_hostmbox == 0)
		fld_max = msg_fromsp(mboxfp, fld_fp);
	else
		fld_max = msg_bsmtp(mboxfp, fld_fp);
	if (fclose(mboxfp) == EOF)
		fld_max = -1;
	if (fclose(fld_fp) == EOF)
		fld_max = -1;

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

	/* Unlock mailbox */
	flock(lock, LOCK_UN);
	close(lock);

	/* Prepare to use temporary file for POP3 session */
	if (fld_max > 0) {
		if ((fld_fp = fopen(fld_fname,"r")) == 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
fld_release()
{
	char temp_fname[32];
	FILE *mboxfp;
	FILE *tempfp;
	int lock;
	int i = 0;
	int savemsg = 1;
	int zap_orig_mbox;
	int bsmtp_helo = 0;
	struct stat stat_buf;

	/* 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;
	}

	/* If user doesnt have write permission for this */
	/* mailbox, just delete the working mailbox.     */
	if (fld_write_ok = 0)
		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;
	
				/* If no messages were deleted, just remove */
				/* 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 cleanup;
			} 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);
	} else {
		/* Save parts of this mailbox */
		if ((mboxfp = fopen(cli_mbox, "r")) == NULL)
			fail(FAIL_FILE_ERROR);
	}
	/* Lock original mailbox folder */
	if ((lock = dup(fileno(mboxfp))) == -1)
		fail(FAIL_FILE_ERROR);
	if (flock(lock, LOCK_EX) == -1)
		fail(FAIL_FILE_ERROR);

	/* 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);
	} 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) != NULL) {
			cmd_prepare(svr_buf);
			if (isbsmtp_helo(svr_buf)) {
				break;
			}
		}
		if (ferror(mboxfp))
			fail(FAIL_FILE_ERROR);
	}

	/* 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);
		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);
		if ((tempfp = fopen(temp_fname,"w")) == NULL)
			fail(FAIL_FILE_ERROR);

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

	/* 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;

	/* Transfer undeleted messages from the working mailbox */
	rewind(fld_fp);
	i = 0;				/* [1.002] reset index counter */
	if (fld_hostmbox != 0) {
		/* BSMTP: Transfer all text upto and including HELO */
		while (fgetl(svr_buf,SVR_BUFSIZ,fld_fp) != NULL) {
			fputs(svr_buf,mboxfp);
			if (ferror(mboxfp))
				fail(FAIL_FILE_ERROR);
			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);
	}
	while (fgetl(svr_buf,SVR_BUFSIZ,fld_fp) != NULL) {
		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);
		}
		if ((fld_hostmbox != 0) && (isbsmtp_end(svr_buf))) { 
			/* BSMTP mailbox */
			/* Transfer next msg, unless deleted */
			savemsg = !(fld_msg[i++].status & MSG_DELETED);
		}
	}
	if (ferror(fld_fp))
		fail(FAIL_FILE_ERROR);

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

addnew:
	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.
		 */
		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) != NULL) {
				fputs(svr_buf,mboxfp);
				if (ferror(mboxfp))
					fail(FAIL_FILE_ERROR);
				cmd_prepare(svr_buf);
				if (isbsmtp_helo(svr_buf)) {
					bsmtp_helo = 1;
					break;
				}
			}
			if (ferror(fld_fp))
				fail(FAIL_FILE_ERROR);
		}
		/* 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);
		while (fgets(svr_buf,SVR_BUFSIZ,tempfp) != NULL) {
			fputs(svr_buf,mboxfp);
			if (ferror(mboxfp))
				fail(FAIL_FILE_ERROR);
		}
		if (ferror(tempfp))
			fail(FAIL_FILE_ERROR);
		if (fclose(tempfp) == EOF)
			fail(FAIL_FILE_ERROR);
		unlink(temp_fname);
		if (fclose(mboxfp) == EOF)
			fail(FAIL_FILE_ERROR);
	}

	/* Unlock original mailbox folder */
	flock(lock, LOCK_UN);
	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);
	}
	free( (char *)fld_msg );
	free(cli_mbox);
	cli_mbox = NULL;
}

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

/* Send a BSMTP wrapped message to the POP3 client */
static void
retr_bsmtp(msgnum,linecnt)
int msgnum;
int linecnt;
{
	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) != NULL) {
		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;
		}
	}
}

/* Send a FromSP delimited message to the POP3 client */
static void
retr_fromsp(msgnum,linecnt)
int msgnum;
int linecnt;
{
	char *cp, *tp;
	int msgbody = 0;

	/* 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);
	while (fgetl(cp,SVR_BUFSIZ,fld_fp) != NULL) {
		if (isfromsp_start(cp))
			break;
		/* 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 ((msgbody)&&(--linecnt == 0)) {
			break;
		} else {
			if (*cp == 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
msg_bsmtp(infp, outfp)
FILE *infp;
FILE *outfp;
{
	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);
	mp = &fld_msg[0];
	mp->pop_hdr = NULL;
	/* Load messages from mailbox folder to temporary folder */
	while (fgetl(svr_buf,SVR_BUFSIZ,infp) != NULL) {
		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 = malloc(strlen(flash_buf)+1);
					if (mp->pop_hdr == NULL)
						fail(FAIL_OUT_OF_MEMORY);
					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);
					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);
				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);
			break;
		}
	}
	if (ferror(infp))
		return -1;
	if (i == 0)
		free((char *)fld_msg);
	return(i);
}

/* Load messages from a mailbox delimited by FromSPACE */
static int
msg_fromsp(infp, outfp)
FILE *infp;
FILE *outfp;
{
	int i = 0;
	register struct fld_item *mp;

	/* 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);
	mp = &fld_msg[0];
	/* Load messages from mailbox folder to temporary folder */
	while (fgetl(svr_buf,SVR_BUFSIZ,infp) != NULL) {
		fputs(svr_buf, outfp);
		if (ferror(outfp))
			return -1;
		if (isfromsp_start(svr_buf)) {
			/* 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);
			/* 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 = malloc(strlen(flash_buf)+1);
			if (mp->pop_hdr == NULL)
				fail(FAIL_OUT_OF_MEMORY);
			strcpy(mp->pop_hdr,flash_buf);
			mp->bcount = strlen(mp->pop_hdr);

			++i;
		} else {
			mp->bcount += ((long)strlen(svr_buf) + 1L);
		}
	}
	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 *
bsmtp_rcpt(inbuf)
char *inbuf;
{
	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);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.