/*
 *	FOLDER.C  --  this C file contains the routines to load
 *		      and store a POP2 mail folder.
 *
 *      (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.
 *
 *	REVISIONS:
 *			 3-88	[ks]	original implementation
 *		1.000	 5-88	[ks]
 *		1.001	 2-89	[ks]    multiple RCPTS send as one msg
 *
 */

#include "globdefs.h"
#include "faildefs.h"
#include "svrdefs.h"
#include "svrvars.h"

#ifdef LINUX
# include <unistd.h>
#endif

extern char *pars_rfcname();

/******************* FOLDER UTILITY ROUTINES ********************************/

ismsg_start(str)
    char *str;				/* Ptr to string to test */
	/* This routine determines if a string starts with the   */
	/*   mail message delimiter string for FOLD folders. A   */
	/*   ptr to the string to test is passed in as str. If   */
	/*   str does start with the delim string, the routine   */
	/*   returns non-zero; otherwise, the routine returns 0. */
{
    return(!strncmp(str,DEF_MSGDELIM,strlen(DEF_MSGDELIM)));
}

isdot(str)
    char *str;				/* Ptr to string to test */
	/* This routine determines if a string starts with the   */
	/*   mail message delimiter string for HOST folders. A   */
	/*   ptr to the string to test is passed in as str. If   */
	/*   str does start with the delim string, the routine   */
	/*   returns non-zero; otherwise, the routine returns 0. */
{
    if (str == NULL) return(0);
    return( ((*str == DOT_CHAR) && (strlen(str) == 2)) );
}

chk_privs(fname)
    char *fname;			/* Name of file to check for privs */
	/* This routine checks if this process (i.e. this user) */
	/*   has write privileges for a file. A pointer to the  */
	/*   name of the file to check is passed in as fname.   */
	/*   If the user has write privs for the file, the      */
	/*   routine returns non-zero; otherwise, the routine   */
	/*   returns zero.					*/
{
    if (access(fname,W_OK) == -1) {	/* User can write file? */
	return(0);			/* No, return no privs */
    } else {
	return(1);			/* Yes, return write is ok */
    }
}

/************************** MESSAGE LOADING ***********************************/

msg_fromsp(in_fp,out_fp)
    FILE  *in_fp,			/* Mailbox file to load msgs from */
	  *out_fp;			/* Working file to load msgs to */
	/* This routine attempts to load a FOLD type message folder. */
	/*   FOLD folders are expected to consist of RFC822 mail     */
	/*   messages delimited by UNIX-style FromSPACE lines.       */
{
    int i;					/* Temp counter */

	/* Attempt to find the first mail message in the folder */
    while (fgetl(rfc_buf,POP2_BUFSIZ,in_fp) != NULL) {
	if (ismsg_start(rfc_buf)) break;	/* Break out at msg start */
    }
    if (ferror(in_fp)) fail(FAIL_FILE_IO_ERROR);
    if (feof(in_fp)) return(0);

	/* The start of the first mail message was located, load it      */
	/*   and any other mail messages into a message structure array. */
    get_e_array(fld_msg,DEF_MSG_HOLD);		/* Alloc the array structure */
    if (fld_msg == NULL) fail(FAIL_OUT_OF_MEMORY);

    fputs(rfc_buf,out_fp);			/* Transfer msg delimiter */
    if (ferror(out_fp)) fail(FAIL_FILE_IO_ERROR);

    i = 0;					/* Init the message counter */
    fld_msg[i].fmsg_entry = ftell(out_fp);	/* Save entry point of msg */
    fld_msg[i].bcount = 0;			/* Init msg byte counter */
    fld_msg[i].status = 0;			/* Status=just loaded */

	/* Construct an extra RFC822 header for the message. */
	/*   This header can be used by the POP2 client to   */
	/*   determine who that msg was delivered to.        */
    sprintf(flash_buf,"%s %s@%s\r\n",DEF_F_POP2,user_name,host_i_am);
    fld_msg[i].pop_hdr = malloc(strlen(flash_buf) + 1);
    if (fld_msg[i].pop_hdr == NULL) fail (FAIL_OUT_OF_MEMORY);
    strcpy(fld_msg[i].pop_hdr,flash_buf);
    fld_msg[i].bcount += (strlen(flash_buf));	/* Add POP2 hdr into count */


	/* Transfer the rest of the mailbox to the temp disk file. */
	/*   Load and count any additional mail messages as they   */
	/*   are encountered.					   */
    while (fgetl(rfc_buf,POP2_BUFSIZ,in_fp) != NULL) {
	fputs(rfc_buf,out_fp);			/* Transfer to temp file */
	if (ferror(out_fp)) fail(FAIL_FILE_IO_ERROR);

	if (ismsg_start(rfc_buf)) {		/* Start of next message? */
						/* Yes, found another msg */
	    chk_e_size(fld_msg,DEF_MSG_HOLD,i);	/* Resize array, if needed */
	    if (fld_msg == NULL) fail(FAIL_OUT_OF_MEMORY);
	    ++i;				/* Increment message counter */
						/* Save entry point of msg */
	    fld_msg[i].fmsg_entry = ftell(out_fp);
	    fld_msg[i].bcount = 0;		/* Init msg byte counter */
	    fld_msg[i].status = 0;		/* Status=just loaded */

						/* Extra hdr for POP2 client */
	    sprintf(flash_buf,"%s %s@%s\r\n",DEF_F_POP2,user_name,host_i_am);
	    fld_msg[i].pop_hdr = malloc(strlen(flash_buf) + 1);
	    if (fld_msg[i].pop_hdr == NULL) fail (FAIL_OUT_OF_MEMORY);
	    strcpy(fld_msg[i].pop_hdr,flash_buf);
	    fld_msg[i].bcount += (strlen(flash_buf));
	} else {				/* No, continuing current msg */
						/* Incr msg byte counter */
						/* Add imaginary CR each line */
	    fld_msg[i].bcount += (strlen(rfc_buf) + 1);
	}
    }
    if (ferror(in_fp)) fail(FAIL_FILE_IO_ERROR);

	/* All msgs have been transferred from original mailbox to */
	/*   the working mailbox.				   */
    ++i;					/* Make msg counter 1-based */
    return(i);
}

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

char *
get_host(str)
    char *str;				/* String containing HELO command */
	/* This routine interprets a BSMTP HELO command. If a valid */
	/*   HELO command verb is found, the routine returns a ptr  */
	/*   to the string following the HELO. If the HELO command  */
	/*   is not valid, the routine returns NULL.		    */
{
    char *host;					/* Temp pointer */

    if (strn_nocase(str,"HELO",4)) {		/* Matches expected cmd? */
	return(NULL);				/* No, return NULL to caller */
    }

    str += 4;					/* Skip past HELO verb */
    while (isspace(*str)) { ++str; }		/* Eat any LWSP */
    if (*str == NULL_CHAR) {			/* Anymore chars left? */
	return(NULL);				/* No, no host given */
    }

    strip_nl(str);				/* Strip LF from cmd line */
    host = malloc(strlen(str) + 1);		/* Get memory for host name */
    if (host == NULL) fail(FAIL_OUT_OF_MEMORY);
    strcpy(host,str);				/* Load host name */
    return(host);				/* Return host to caller */
}

char *
get_sender(str)
    char *str;				/* String containing MAIL command */
	/* This routine interprets a BSMTP MAIL command. If a valid */
	/*   MAIL command verb is found, the routine returns a ptr  */
	/*   to the string following the MAIL. If the MAIL command  */
	/*   is not valid, the routine returns NULL.		    */
{
    int i;					/* Temp index counter */
    char *rfc_str;				/* Temp pointer */

    if (strn_nocase(str,"MAIL",4)) {		/* Matchs expected command? */
	return(NULL);				/* No, return NULL to caller */
    }

    str += 4;					/* Skip past MAIL verb */
    while (isspace(*str)) { ++str; }		/* Eat any LWSP */
    if (*str == NULL_CHAR) {			/* Anymore chars left? */
	return(NULL);				/* No, return NULL to caller */
    }

    if (strn_nocase(str,"FROM:",5)) {		/* Expected syntax found? */
	return(NULL);				/* No, return NULL to caller */
    }
    str += 5;					/* Skip past FROM: string */
    if (*str == NULL_CHAR) {			/* Anymore chars left? */
	return(NULL);				/* No, return NULL to caller */
    }
						/* Get memory for name */
    rfc_str = pars_rfcname(str);		/* Strip comments, etc. */
    return(rfc_str);				/* Return ptr to sender name */
}

char *get_rcpt(str)
    char *str;				/* String containing RCPT command */
	/* This routine interprets a BSMTP RCPT command. If a valid */
	/*   RCPT command verb is found, the routine returns a ptr  */
	/*   to the string following the RCPT. If the RCPT command  */
	/*   is not valid, the routine returns NULL.		    */
{
    int i;					/* Temp index counter */
    char *rfc_str;				/* Temp pointer */

    if (strn_nocase(str,"RCPT",4)) {		/* Matches expected command? */
	return(NULL);				/* No, return NULL to caller */
    }

    str += 4;					/* Skip past RCPT verb */
    while (isspace(*str)) { ++str; }		/* Eat any LWSP */
    if (*str == NULL_CHAR) {			/* Anymore chars left? */
	return(NULL);				/* No, return NULL to caller */
    }

    if (strn_nocase(str,"TO:",3)) {		/* Expected syntax found? */
	return(NULL);				/* No, return NULL to caller */
    }
    str += 3;					/* Skip past TO: string */
    if (*str == NULL_CHAR) {			/* Anymore chars left? */
	return(NULL);				/* No, return NULL to caller */
    }
						/* Get memory for this RCPT */
    rfc_str = pars_rfcname(str);		/* Strip comments, etc. */
    return(rfc_str);				/* Return ptr to rcvr name */
}

msg_bsmtp(in_fp, out_fp)
    FILE *in_fp,			/* Mailbox file to load msgs from */
	 *out_fp;			/* Working file to load msgs to */
	/* This routine attempts to load a HOST type message folder. */
	/*   FOLD folders are expected to consist of RFC822 mail     */
	/*   messages delimited by BSMTP commands.		     */
{
    int i;					/* Temp index counters */
    int r;					/* Temp integer storage */
    int bcount;					/* Temp integer counter */
    char *pt;					/* Temp pointer */


	/* Prepare for loading a HOST folder. */
    if (smtp_host != NULL) free(smtp_host);	/* Clear last value, if any */
    smtp_host = NULL;				/* HELO cmd not parsed yet */

    get_e_array(fld_msg,DEF_MSG_HOLD);		/* Array for loaded msgs */
    if (fld_msg == NULL) fail(FAIL_OUT_OF_MEMORY);
    i = 0;					/* Init index counter */


	/* Attempt to load messages one-by-one. Each message is */
	/*   wrapped in BSMTP commands.				*/
    while (fgetl(rfc_buf,POP2_BUFSIZ,in_fp) != NULL) {

	    /* Attempt to parse HELO, QUIT or MAIL command */
        pt = get_host(rfc_buf);			/* Attempt to parse HELO */
        if (pt == NULL) {			/* Was it a HELO command? */
						/* No, not a HELO */
	    if (smtp_host == NULL) {		/* Was there a HELO before? */
	        continue;			/* No, keep looking */
	    }
						/* Was it a QUIT command? */
	    if (strn_nocase(rfc_buf,"QUIT",4) == 0) {
	        break;				/* Yes, tell this to caller */
	    }
						/* No, not QUIT must be MAIL */
        } else {
	    smtp_host = pt;
        }

        if (pt != NULL) {			/* Already got buffer? */
						/* No, used it, get another */
	    if (fgetl(rfc_buf,POP2_BUFSIZ,in_fp) == NULL) break;
        }


	    /* Found another BSMTP message transaction in this folder */
	chk_e_size(fld_msg,DEF_MSG_HOLD,i);	/* Resize array, if needed */
	if (fld_msg == NULL) fail(FAIL_OUT_OF_MEMORY);

	    /* Save entry point in working file of BMSTP */
	    /*    commands for this transaction		 */
        fld_msg[i].fhdr_entry = ftell(out_fp);

        fputs(rfc_buf,out_fp);			/* Write MAIL cmd to new file */
        if (ferror(out_fp)) fail(FAIL_FILE_IO_ERROR);

	    /* Attempt to parse MAIL command */
        pt = get_sender(rfc_buf);		/* Attempt to parse MAIL cmd */
        if (pt == NULL) break;			/* Must get MAIL cmd here */
	free(pt);				/* Sender not significant */

	    /* Attempt to parse RCPT command(s) */
	fld_msg[i].pop_hdr = malloc(1);
	fld_msg[i].pop_hdr[0] = NULL_CHAR;
	fld_msg[i].bcount = 0;			/* Init msg byte counter */
	fld_msg[i].status = 0;			/* Status=just loaded */
	for ( ; ; ) {				/* Get all RCPTs for this msg */
						/* Read next input line */
	    if (fgetl(rfc_buf,POP2_BUFSIZ,in_fp) == NULL) break;
						/* Break if BSMTP DATA cmd */
	    if (strn_nocase(rfc_buf,"DATA",4) == 0) break;

	    fputs(rfc_buf,out_fp);		/* Write RCPT cmd to new file */
	    if (ferror(out_fp)) fail(FAIL_FILE_IO_ERROR);

	    pt = get_rcpt(rfc_buf);		/* Attempt to parse RCPT name */
	    if (pt == NULL) break;


		/* Construct an extra RFC822 header for the message. */
		/*   Since messages for all users at the POP2 host   */	
		/*   can be stored in a HOST folder, this header can */
		/*   be used by a POP2 client to determine who a     */
		/*   msg is intended for. 			     */
	    if (strchr(pt,AT_CHAR)) {
		sprintf(flash_buf,"%s %s\r\n",DEF_F_POP2,pt);
	    } else {
		sprintf(flash_buf,"%s %s@%s\r\n",DEF_F_POP2,pt,host_client);
	    }
	    free(pt);				/* Release local memory */
	    fld_msg[i].pop_hdr = realloc(fld_msg[i].pop_hdr,
					 strlen(fld_msg[i].pop_hdr) +
					          strlen(flash_buf) + 1);
	    if (fld_msg[i].pop_hdr == NULL) fail(FAIL_OUT_OF_MEMORY);
	    strcat(fld_msg[i].pop_hdr,flash_buf);
						/* Include hdr in byte count */
	    fld_msg[i].bcount += (strlen(flash_buf));
	}
						/* Break if no RCPT found */
	if (fld_msg[i].pop_hdr[0] == NULL_CHAR) break;


	    /* Attempt to parse DATA command */
        if (strn_nocase(rfc_buf,"DATA",4) != 0) break;

        fputs(rfc_buf,out_fp);			/* Echo DATA cmd to new file */
        if (ferror(out_fp)) fail(FAIL_FILE_IO_ERROR);

	    /* Save the entry point of the actual RFC822 message */
        fld_msg[i].fmsg_entry = ftell(out_fp);

	    /* Transfer the RFC822 message to the working file.    */
	    /*   Count number of bytes in the message during xfer. */
        bcount = 0;				/* Init byte counter */
        while (fgetl(rfc_buf,POP2_BUFSIZ,in_fp) != NULL) {
	    fputs(rfc_buf,out_fp);		/* Write to working file */
	    if (ferror(out_fp)) fail(FAIL_FILE_IO_ERROR);

	    if (isdot(rfc_buf)) break;		/* Check for BSMTP msg end */

	    bcount += (strlen(rfc_buf) + 1);	/* Count number of bytes */
						/* Add one for ghost CR */
						/* Won't send escape chars */
	    if (rfc_buf[0] == DOT_CHAR) --bcount;
        }
        if (ferror(in_fp)) fail(FAIL_FILE_IO_ERROR);

	    /* Add the byte count of the message to the count already */
	    /*   established for all RCPTs of this message	      */
	fld_msg[i].bcount += bcount;
	++i;					/* Update index counter */
    }

	/* All msgs have been transferred from original mailbox to */
	/*   the working mailbox.				   */
    return(i);					/* Return actual # of msgs */
}

/************************* FOLDER OPEN/CLOSE **********************************/

fld_select(mbox)
    char *mbox;				/* Name of mailbox to load */
	/* This routine attempts to load a mail folder from disk. The */
	/*   name of the folder to load is passed in as mbox. The     */
	/*   routine returns the number of messages actually loaded.  */
{
    int i;					/* Temp counter */
    int r;				 	/* Temp integer storage */
    int lock;					/* Temp file descriptor */
    char temp_fname[32];			/* Temp char buffer */
    FILE *temp_fp,*mbox_fp;			/* Ptr for file read/write */
    struct stat stat_buf;			/* Struct for file inquiry */

    fld_current = UNDEFINED;			/* Reset current msg pointer */
    fld_fname = NULL;				/* Reset working folder name */
    fld_fp = NULL;				/* Reset working folder file */
    fld_write_ok = FALSE;			/* System mbox write privs */

						/* Does the mailbox exist? */
    if (stat(mbox,&stat_buf) == UNDEFINED) {
						/* No, nothing to load */
	return(0);				/* Return zero msgs loaded */
    }
					    
    if (stat_buf.st_size == 0) {		/* Mbox exists, is it empty? */
						/* Yes, nothing to load */
	return(0);				/* Return zero msgs loaded */
    }

	/* Transfer the original mailbox to a temporary working file. */
	/*   Do this to prevent holding the mailbox during the entire */
	/*   server session. Record the msg entry points and lengths  */
	/*   while transferring the messages.			      */
					    
    mbox_fp = fopen(mbox, "r");			/* Open mbox for reading */
    if (mbox_fp == NULL) fail(FAIL_FILE_NOT_FOUND);
					    
    lock = dup(fileno(mbox_fp));		/* Lock the original mailbox */
    if (lock == UNDEFINED) fail(FAIL_FILE_CANT_LOCK);
    r = flock(lock, LOCK_EX);
    if (r == UNDEFINED) fail(FAIL_FILE_CANT_LOCK);

    strcpy(temp_fname, TMPFILE);		/* Get a temp file name */
    if (mktemp(temp_fname) == NULL) fail(FAIL_FILE_SETUP);

    temp_fp = fopen(temp_fname, "w");		/* Open working for writing */
    if (temp_fp == NULL) fail(FAIL_FILE_CREATE);

    fld_fname = malloc(strlen(temp_fname) + 1);	/* Save the temp file name */
    if (fld_fname == NULL) fail(FAIL_OUT_OF_MEMORY);
    strcpy(fld_fname,temp_fname);

    if (host_client == NULL) {			/* Loading a HOST folder? */
	i = msg_fromsp(mbox_fp, temp_fp);	/* No, FromSPACE folder */
    } else {
	i = msg_bsmtp(mbox_fp, temp_fp);	/* Yes, BSMTP folder */
    }

    r = fclose(mbox_fp);			/* Close mbox (reading) */
    if (r == EOF) fail(FAIL_FILE_IO_ERROR);
    r = fclose(temp_fp);			/* Close working (writing) */
    if (r == EOF) fail(FAIL_FILE_IO_ERROR);

	/* Check now if the user has write privs on the original mailbox. */
	/*   If so, the user will be allowed to delete msgs from the      */
	/*   orginal mailbox. If not, the original mailbox will be left   */
	/*   untouched when the working mailbox is released.              */
	/*   NOTE: if no msgs were loaded, don't reset mailbox.		  */
					    /* Can write on original mbox? */
    if ((i > 0) && (fld_write_ok = chk_privs(mbox))) {
					    /* Yes, user can write on file */
	    /* Zero out the original mbox file. This allows other processes */
	    /*   to use the mailbox while this process is working on the    */
	    /*   working mailbox file.					    */
	mbox_fp = fopen(mbox, "w");
	if (mbox_fp == NULL) fail(FAIL_FILE_CREATE);
	r = fclose(mbox_fp);
	if (r == EOF) fail(FAIL_FILE_IO_ERROR);
    }

    flock(lock, LOCK_UN);		    /* Unlock the original mbox file */
    close(lock);

	/* The POP2 server will now continue with the working copy */
	/*   mailbox file. Open the working mailbox for reading.   */
    if (i != 0) {				/* Any msgs loaded? */
						/* Yes, open working for read */
        fld_fp = fopen(fld_fname,"r");
        if (fld_fp == NULL) fail(FAIL_FILE_NOT_FOUND);
    } else {
						/* No, no msgs found */
	    /* If zero messages in folder, server will never try */
	    /*   to read a message.				 */
	unlink(fld_fname);			/* Delete ghost working file */
	free(fld_fname);			/* Free alloced memory */
	fld_fname = NULL;			/* Reset vars */
	fld_fp = NULL;
    }

    return(i);					/* Return # actually loaded */
}

fld_release()
	/* This routine releases the current folder (if any) back to */
	/*   the original mailbox. If the user has write permissions */
	/*   for the mailbox, deleted msgs are removed from the      */
	/*   mailbox. After re-spooling (if any), the temp file      */
	/*   created by fld_select() is removed from disk.           */
{
    int i;					/* Temp counter */
    int r;					/* Temp integer storage */
    int lock;					/* Temp file descriptor */
    int write_it;				/* Delete status of a msg */
    int host_folder;				/* Releasing BSMTP folder */
    char temp_fname[32];			/* Buffer for temp filename */
    FILE *temp_fp,*mbox_fp;			/* Temp file pointers */

    if (fld_cnt == 0) {				/* Folder with msgs open? */
						/* No, no msgs in folder */
	free(fld_orig);				/* Free alloced memory */
	if (host_client != NULL) {		/* Reset HOST folder flag */
	    free(host_client);
	    host_client = NULL;
	}
	return;					/* Return to caller */
    }

    if (fld_write_ok && (fld_cnt > 0)) {	/* User has write privs? */
						/* Yes, spool only un-deleted */
						/*   msgs back to mailbox     */

	if (host_client == NULL) {		/* Was this a HOST folder? */
	    host_folder = FALSE;		/* No, do FOLD handling */
	} else {
	    host_folder = TRUE;			/* Yes, do HOST handling */
	}

	    /* Check if ALL msgs were deleted */
	for (i=0; i<fld_cnt; ++i) {		/* Check each message */
						/* Break out if loop if a  */
						/*   non-deleted msg found */
	    if ((fld_msg[i].status & STAT_DELETED) == 0) break;
	}
	    
	if (i >= fld_cnt) {			/* All msgs deleted? */
						/* Yes, discard temp file */
	    fclose(fld_fp);			/* Close msg file */
	    unlink(fld_fname);			/* Discard disk file */
	    if (host_folder) {			/* HOST folder? */
		unlink(fld_orig);		/* Yes, don't leave ghost */
	    }
	    free(fld_fname);
	    free(fld_orig);
	    fld_cnt = 0;			/* Reset folder msg count */
	    return;				/* Return to caller */
	}
	    /* At least one message was left undeleted */

	    /* Move any msgs added to the original mailbox between the */
	    /*   fld_select() and now to a second temp file.           */
	if (host_client == NULL) {		/* Was this a HOST folder? */
	    host_folder = FALSE;		/* No, do FOLD handling */
	} else {
	    host_folder = TRUE;			/* Yes, do HOST handling */
	}
						
	mbox_fp = fopen(fld_orig,"r");		/* Open original for read */
	if (mbox_fp == NULL) fail(FAIL_FILE_NOT_FOUND);
						
	lock = dup(fileno(mbox_fp));		/* Lock original mailbox */
	if (lock == UNDEFINED) fail(FAIL_FILE_CANT_LOCK);
	r = flock(lock, LOCK_EX);
	if (r == UNDEFINED) fail(FAIL_FILE_CANT_LOCK);
						
	strcpy(temp_fname, TMPFILE);		/* Get a temporary file */
	if (mktemp(temp_fname) == NULL) fail(FAIL_FILE_SETUP);
	temp_fp = fopen(temp_fname,"w");
	if (temp_fp == NULL) fail(FAIL_FILE_CREATE);

						/* Xfer new stuff from mbox */
	r = TRUE;				/* Flag for HOST folders */
						/* Transfer each line */
	while (fgetl(rfc_buf,POP2_BUFSIZ,mbox_fp) != NULL) {
	    if ((host_folder) && (r == TRUE)) {	/* First line of HOST mbox? */
						/* Yes, it is a HELO */
		r = FALSE;			/* Reset flag */
		continue;			/* Dont use keep HELO */
	    }

	    fputs(rfc_buf,temp_fp);		/* Write line to temp file */
	    if (ferror(temp_fp)) fail(FAIL_FILE_IO_ERROR);
	}
	if (ferror(mbox_fp)) fail(FAIL_FILE_IO_ERROR);
	r = fclose(temp_fp);			/* Close new file (write) */
	if (r == EOF) fail(FAIL_FILE_IO_ERROR);
	r = fclose(mbox_fp);			/* Close system mbox (read) */
	if (r == EOF) fail(FAIL_FILE_IO_ERROR);


	    /* Transfer all non-deleted msgs from the working mailbox */
	    /*   back to the original mailbox.			      */
						
	mbox_fp = fopen(fld_orig,"w");		/* Open mbox for output */
	if (mbox_fp == NULL) fail(FAIL_FILE_CREATE);
						
#ifdef LINUX
	rewind(fld_fp);
	r = ferror(fld_fp);
#else
	r = rewind(fld_fp);			/* Rewind working mailbox */
#endif
	if (r == UNDEFINED) fail(FAIL_FILE_IO_ERROR);

	if (host_folder) {			/* Restoring HOST folder? */
						/* Yes, writing a HOST folder */
						/* Start with HELO <hostname> */
	    sprintf(flash_buf,"HELO %s\n",smtp_host);
	    fputs(flash_buf, mbox_fp);
	    if (ferror(mbox_fp)) fail(FAIL_FILE_IO_ERROR);
	    free(smtp_host);			/* Reset HELO host storage */
	    smtp_host = NULL;

		/* Only write back one copy of messages with multiple */
		/*   RCPTs. If one/some of the copies of a msg with   */	
		/*   multiple RCPTs is deleted, but not all, the msg  */
		/*   is not deleted and will be available to same     */
		/*   multiple RCPTs next time the msg is loaded.      */
	    for (i=0; i<(fld_cnt-1); ++i) {	/* Check entire msg list */
						/* Was this msg deleted? */
	        if ((fld_msg[i].status & STAT_DELETED) == 0) {
						/* No, msg not deleted */
			/* Mark any further multiple RCPTs of this */
			/*   message as deleted. This will prevent */
			/*   multiple copies of the msg from being */
			/*   written back to the system mailbox.   */
		    for (r=(i+1); r<fld_cnt; ++r) {
						/* Same RFC822 msg? */
		        if (fld_msg[r].fhdr_entry == fld_msg[i].fhdr_entry) {
						/* Yes, prevent duplication */
			    fld_msg[r].status |= STAT_DELETED;
		        } else {
			    break;		/* No, no more multiple RCPTs */
			}
		    }
		}
	    }
	} else {

						/* No, writing a FOLD folder */
						/* Locate start of first msg */
	    while (fgetl(rfc_buf,POP2_BUFSIZ,fld_fp) != NULL) {
		if (ismsg_start(rfc_buf)) break;
	    }
	}

	    /* As each msg is encountered, check if the message */
	    /*   was deleted. If not deleted, transfer each     */
	    /*   text line back to the original mailbox.        */
	for (i=0; i<fld_cnt; ++i) {		/* Check loaded msg */
						/* Was msg deleted? */
	    if (fld_msg[i].status & STAT_DELETED) {
		write_it = FALSE;		/* Yes, don't transfer msg */
	    } else {
		write_it = TRUE;		/* No, transfer msg */
	    }

	    if (write_it) {			/* Transfer this msg? */
						/* Yes, xfer msg delimiter */
		if (host_folder) {		/* Is this a HOST folder? */
						/* Yes, seek start directly */
		    r = fseek(fld_fp, fld_msg[i].fhdr_entry, FSEEK_BEGIN);
		    if (r == UNDEFINED) fail(FAIL_FILE_IO_ERROR);
						/* Transfer BSMTP commands */
		    while (fgetl(rfc_buf,POP2_BUFSIZ,fld_fp) != NULL) {
			fputs(rfc_buf,mbox_fp);
			if (ferror(mbox_fp)) fail(FAIL_FILE_IO_ERROR);

			if (!strn_nocase(rfc_buf,"DATA",4)) break;
		    }
		    if (ferror(fld_fp)) fail(FAIL_FILE_IO_ERROR);
		} else {
						/* No, this is a FOLD folder */
						/* Already read msg delimiter */
		    fputs(rfc_buf,mbox_fp);	/* Output FromSPACE line */
		    if (ferror(mbox_fp)) fail(FAIL_FILE_IO_ERROR);
		}
	    }

						/* Continue reading this msg */
	    while (fgetl(rfc_buf,POP2_BUFSIZ,fld_fp) != NULL) {
						/* Start of next FOLD msg? */
		if ((!host_folder) && ismsg_start(rfc_buf)) {
		    break;			/* Yes, break out of loop */
		}
		if (write_it) {			/* Transfer this msg? */
		    fputs(rfc_buf,mbox_fp);	/* Yes, transfer text line */
		    if (ferror(mbox_fp)) fail(FAIL_FILE_IO_ERROR);
		} else {
		    if (host_folder) break;
		}
						/* End of this HOST msg? */
		if (host_folder && isdot(rfc_buf)) {
		    break;			/* Yes, break out of loop */
		}
	    }
	    if (ferror(fld_fp)) fail(FAIL_FILE_IO_ERROR);
	}



	    /* New temp file contains all text added to the system    */
	    /*   mailbox after fld_select() was called. Transfer this */
	    /*   text to the end of the original mailbox too. The     */
	    /*   result in the original mailbox is all non-deleted    */
	    /*   msgs from the working mailbox followed by all text   */
	    /*   added while the user was working on the mailbox.     */
						
	temp_fp = fopen(temp_fname,"r");	/* Open new file for reading */
	if (temp_fp == NULL) fail(FAIL_FILE_NOT_FOUND);
						/* Transfer all text */
	while (fgetl(rfc_buf,POP2_BUFSIZ,temp_fp) != NULL) {
	    fputs(rfc_buf,mbox_fp);
	    if (ferror(mbox_fp)) fail(FAIL_FILE_IO_ERROR);
	}
	if (ferror(temp_fp)) fail(FAIL_FILE_IO_ERROR);

	r = fclose(mbox_fp);			/* Close mailbox files */
	if (r == EOF) fail(FAIL_FILE_IO_ERROR);
	fclose(temp_fp);
	unlink(temp_fname);			/* Discard new temp disk file */

	flock(lock, LOCK_UN);			/* Remove lock on system mbox */
	close(lock);
    }

	/* The original mailbox has been restored to its proper state. */
	/*   cleanup and prepare for next call to fld_select().        */
	/* Clean up temp working mailbox */
    fclose(fld_fp);				/* No longer reading a folder */
    unlink(fld_fname);				/* Discard temp disk file */
	/* Reset alloced variables */
    free(fld_fname);				/* Free alloced memory */
    free(fld_orig);
    for (i=0; i<fld_cnt; ++i) {
	free(fld_msg[i].pop_hdr);
    }
    free(fld_msg);				/* Free msgs struct array */
    fld_cnt = 0;				/* Reset folder open var */
    if (host_client != NULL) {			/* Reset HOST folder flag */
	free(host_client);
	host_client = NULL;
    }
    return;
}
