static char rcsid[] = "@(#)$Id: localmbx.c,v 1.14 2007/08/21 16:44:02 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.14 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
 *      or  Kari Hurtta <elm@elmme-mailer.org>
 *****************************************************************************
 * Based on code ../src/newmbox.c, ../src/lock.c and ../src/string2.c. 
 * That code was following copyright:
 *
 *  The Elm Mail System 
 *
 *			Copyright (c) 1988-1992 USENET Community Trust
 *			Copyright (c) 1986,1987 Dave Taylor
 *****************************************************************************/


#include "def_mbox.h"
#include "s_me.h"
#include "s_elm.h"

DEBUG_VAR(Debug,__FILE__,"file");

#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif

static unsigned char * s2us P_((char *str));
static unsigned char * s2us(str)
     char *str;
{
    return (unsigned char *)str;
}

static char *us2s P_((unsigned char *str));
static char *us2s(str) 
     unsigned char *str;
{
    return (char *)str;
}

#ifdef I_UTIME
#  include <utime.h>
#endif
#ifdef I_SYSUTIME
#  include <sys/utime.h>
#endif

/* Locking primites ------------------------------------------------------- */

#ifdef SYSCALL_LOCKING
#  if (defined(BSD_TYPE) || !defined(apollo))
#    include <sys/file.h>
#  endif
#endif

#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif

static int GrabRead_the_file P_((int flock_fd));

static int GrabRead_the_file(flock_fd)
     int flock_fd;
{

#ifdef USE_FCNTL_LOCKING
    struct flock lock_info;
#endif

    errno = 0;

#ifdef   USE_FCNTL_LOCKING
    lock_info.l_type = F_RDLCK;
    lock_info.l_whence = 0;
    lock_info.l_start = 0;
    lock_info.l_len = 0;
    
    if (fcntl(flock_fd, F_SETLK, &lock_info) != 0) {
	int err = errno;
	DPRINT(Debug,12,(&Debug, 
		    "GrabRead_the_file: fcntl: %s (errno %d)\n",
		    error_description(err),err));
	return ((err == EACCES) || (err == EAGAIN))
	    ? FLOCKING_RETRY
	    : FLOCKING_FAIL ;
    }
#endif
    
#ifdef	USE_FLOCK_LOCKING
    if (flock (flock_fd, LOCK_NB | LOCK_SH)) {
	int err = errno;
	int retcode;
	DPRINT(Debug,12,(&Debug,
			 "GrabRead_the_file: flock: %s (errno %s)\n",
			 error_description(err),err));
	retcode = ((err == EWOULDBLOCK) || (err == EAGAIN))
	    ? FLOCKING_RETRY
	    : FLOCKING_FAIL ;
	
#ifdef USE_FCNTL_LOCKING
	lock_info.l_type = F_UNLCK;
	lock_info.l_whence = 0;
	lock_info.l_start = 0;
	lock_info.l_len = 0;
	
	/*
	 *  Just unlock it because we did not succeed with the
	 *  flock()-style locking. Never mind the return value.
	 *  It was our own lock anyway if we ever got this far.
	 */
	fcntl (flock_fd, F_SETLK, &lock_info);
#endif
	return retcode;
    }
#endif

    DPRINT(Debug,12,(&Debug,
		     "GrabRead_the_file=FLOCKING_OK\n"));
    return FLOCKING_OK;
}

int Grab_the_file(flock_fd)
     int flock_fd;
{
#ifdef USE_FCNTL_LOCKING
    struct flock lock_info;
#endif

    errno = 0;

#ifdef   USE_FCNTL_LOCKING
    lock_info.l_type = F_WRLCK;
    lock_info.l_whence = 0;
    lock_info.l_start = 0;
    lock_info.l_len = 0;
    
    if (fcntl(flock_fd, F_SETLK, &lock_info) != 0) {
	int err = errno;
	DPRINT(Debug,12,(&Debug,
			 "Grab_the_file: fcntl: %s (errno %d)\n",
			 error_description(err),err));
	return ((err == EACCES) || (err == EAGAIN))
	    ? FLOCKING_RETRY
	    : FLOCKING_FAIL ;
    }
#endif
    
#ifdef	USE_FLOCK_LOCKING
    if (flock (flock_fd, LOCK_NB | LOCK_EX)) {
	int err = errno;
	int retcode;
	DPRINT(Debug,12,(&Debug,
			 "Grab_the_file: flock: %s (errno %d)\n",
			 error_description(err),err));
	retcode = ((err == EWOULDBLOCK) || (err == EAGAIN))
	    ? FLOCKING_RETRY
	    : FLOCKING_FAIL ;
	
#ifdef USE_FCNTL_LOCKING
	lock_info.l_type = F_UNLCK;
	lock_info.l_whence = 0;
	lock_info.l_start = 0;
	lock_info.l_len = 0;
	
	/*
	 *  Just unlock it because we did not succeed with the
	 *  flock()-style locking. Never mind the return value.
	 *  It was our own lock anyway if we ever got this far.
	 */
	fcntl (flock_fd, F_SETLK, &lock_info);
#endif
	return retcode;
    }
#endif

    DPRINT(Debug,12,(&Debug,
		     "Grab_the_file=FLOCKING_OK\n"));
    return FLOCKING_OK;
}

int Release_the_file(flock_fd)
     int flock_fd;
{
#ifdef USE_FCNTL_LOCKING
    struct flock lock_info;
#endif

    int	fcntlret = 0,
	flockret = 0,
	fcntlerr = 0,
	flockerr = 0;
    
#ifdef	USE_FLOCK_LOCKING
    errno = 0;
    flockret = flock (flock_fd, LOCK_UN);
    flockerr = errno;
#endif

#ifdef	USE_FCNTL_LOCKING
    lock_info.l_type = F_UNLCK;
    lock_info.l_whence = 0;
    lock_info.l_start = 0;
    lock_info.l_len = 0;

    errno = 0;
    fcntlret = fcntl (flock_fd, F_SETLK, &lock_info);
    fcntlerr = errno;
#endif

    if (fcntlret) {
	errno = fcntlerr;
	DPRINT(Debug,12,(&Debug,
			 "Release_the_file=%d\n",fcntlret));
	return fcntlret;
    } else if (flockret) {
	errno = flockerr;
	DPRINT(Debug,12,(&Debug,
			 "Release_the_file=%d\n",flockret));
	return flockret;
    }
    DPRINT(Debug,12,(&Debug,
		     "Release_the_file=%d\n",0));
    return 0;
}

/* ------------------------------------------------------------------------  */

/* LOCAL browser */

#ifdef DIROPS

static void browser_zero_local P_((struct folder_browser *dir));
static void browser_zero_local(dir)
     struct folder_browser *dir;
{
    DPRINT(Debug,11,(&Debug,"browser_zero_local: dir=%p\n", dir));

    dir->a.local_browser.handle = NULL;
}

static void browser_free_local P_((struct folder_browser *dir));

static void browser_free_local(dir)
     struct folder_browser *dir;
{
    DPRINT(Debug,11,(&Debug,
		     "browser_free_local: dir=%p (%s)\n", 
		     dir,dir->sys_dir ? dir->sys_dir : "<NULL>"));

    if (dir->a.local_browser.handle) {
	closedir(dir->a.local_browser.handle);
	dir->a.local_browser.handle = NULL;
    }
}


static void browser_local_do_stat P_((struct folder_browser *dir,
				      int idx));
static void browser_local_do_stat(dir,idx)
     struct folder_browser *dir;
     int idx;
{
    char * pathname;
    struct stat buf;

    char * entryname;
    int flags;
    int l1 = strlen(dir->sys_dir);

    DPRINT(Debug,13,(&Debug,
		     "browser_local_do_stat: dir=%p, idx=%d\n", 
		     dir,idx));

    if (idx < 0 || idx >= dir->vector_len)
	panic("MBX PANIC",__FILE__,__LINE__,"browser_local_do_stat",
	      "Bad index",0);

    flags     = dir->vector[idx].flags;
    entryname = dir->vector[idx].sys_name;

    flags &= ~BROWSER_NEEDSTAT;

    pathname = safe_strdup(dir->sys_dir);
    if (l1 > 0 && '/' != dir->sys_dir[l1-1])
	pathname = strmcat(pathname,"/");
    pathname = strmcat(pathname,entryname);
    
    DPRINT(Debug,20,(&Debug,
		     "browser_local_do_stat: %s -> %s\n", 
		     entryname,pathname));
    
    if (0 != stat(pathname,&buf)) {
	int err = errno;
	DPRINT(Debug,13,(&Debug,
			 "browser_local_do_stat: %s: (errno=%d) %s\n",
			 pathname,err,error_description(err)));
	flags = BROWSER_NOFOLDER|BROWSER_NODIR;
    } else {
	dir->vector[idx].mtime   = buf.st_mtime;
	
	if (
#ifdef S_ISDIR
	    !S_ISDIR(buf.st_mode)
#else
	    S_IFDIR != (buf.st_mode & S_IFMT)
#endif
	    ) {
	    flags |= BROWSER_NODIR;
	}

	if (
#ifdef S_ISREG
	    !S_ISREG(buf.st_mode)
#else
	    S_IFREG != (buf.st_mode & S_IFMT)
#endif
	    ) {
	    flags |= BROWSER_NOFOLDER;
	} else
	    if (buf.st_mtime > buf.st_atime) {
		DPRINT(Debug,13,(&Debug,
				 "browser_local_do_stat: %s: mtime=%d > atime=%d -- new mail?\n",
				 pathname,buf.st_mtime,buf.st_atime));
		flags |= BROWSER_MARKED;
	    }
	
	if ((BROWSER_NOFOLDER|BROWSER_NODIR) == flags) {
	    DPRINT(Debug,13,(&Debug,
			     "browser_local_do_stat: %s: Not a directory or folder (file)\n",
			     pathname));
	}
    }

    DPRINT(Debug,13,(&Debug,
		     "browser_local_do_stat: changing flags %X -> %X\n",
		     dir->vector[idx].flags,flags));

    dir->vector[idx].flags = flags;

    free(pathname);		    
}

static void browser_fill_local P_((struct folder_browser *dir));
static void browser_fill_local(dir)
     struct folder_browser *dir;
{
#if DIROPS == USE_DIRENT
    struct dirent * Xptr;
#endif /* DIROPS == USE_DIRENT */
#if DIROPS == USE_SYSDIR
    struct direct * Xptr;
#endif /* DIROPS == USE_SYSDIR */
    int l1 = strlen(dir->sys_dir);

    DPRINT(Debug,13,(&Debug,"browser_fill_local: dir=%p\n", dir));
    
    clear_dir_vector(dir);

    while (NULL != (Xptr = readdir(dir->a.local_browser.handle))) {
	if ('.' != Xptr->d_name[0]) {
	    int flags = 0;

#if DIROPS == USE_DIRENT
	    char * entryname = safe_strdup(Xptr->d_name);
#endif /* DIROPS == USE_DIRENT */
#if DIROPS == USE_SYSDIR
	    char * entryname = safe_malloc(Xptr->d_namlen+1);
	    
	    strncpy(entryname,Xptr->d_name,Xptr->d_namlen);
	    entryname[Xptr->d_namlen] = '\0';
#endif /* DIROPS == USE_SYSDIR */
	    
	    flags |= BROWSER_NEEDSTAT;


	    /* WARNING: add_dir_vector does not allocate strings -- 
	     *          it just assign pointers!	    
	     */
	    add_dir_vector(dir,
                           entryname,new_string2(local_fs_charset,
						 s2us(entryname)),
			   flags);

	    /* Do not free 'entryname' --  pointer is stored by add_dir_vector 
	     */
	}
    }
}

/* Returns name relative to directory of browser */
static struct string * browser_descend_local P_((struct folder_browser *dir,
						 const struct string *rel_name1));
static struct string * browser_descend_local(dir,rel_name1)
     struct folder_browser *dir;
     CONST struct string *rel_name1;
{
    int L, idx;
    static struct string * ret = NULL;
    struct string *rel_name = NULL;
    int is_ascii = 0;

    int last_idx_ok = -1;

    DPRINT(Debug,12,(&Debug,"browser_descend_local: dir=%p\n", dir));

    if (!rel_name1) {
	DPRINT(Debug,12,(&Debug,"browser_descend_local=NULL\n"));
	return NULL;
    }

    rel_name = ascify_string(rel_name1);
    DPRINT(Debug,12,(&Debug,"browser_descend_local: rel_name=%S\n",rel_name));

    L = string_len(rel_name);

    if (rel_name->string_type->MIME_name &&
	0 == istrcmp(rel_name->string_type->MIME_name,"US-ASCII")) {
	is_ascii++;

	DPRINT(Debug,12,(&Debug,
			 "browser_descend_local: relname is ASCII only...\n"));
    }

    for (idx = 0; idx < L ; idx++) {
	uint16 code = give_unicode_from_string(rel_name,idx);
       
	if (0x002F /* '/' */ == code) {
	    int X1 = 0;
	    struct string * A1 = NULL;

	    if (local_fast_lookup || is_ascii) {
		int idx2;
		DPRINT(Debug,12,(&Debug,
				 "browser_descend_local:%s%s: Going to last directory on path\n",
				 local_fast_lookup ? " local_fast_lookup" : "",
				 is_ascii ? " is_ascii" : ""));
		
		for (idx2 = idx+1; idx2 < L; idx2++) {
		    uint16 code2 = give_unicode_from_string(rel_name,idx2);
		    if (0x002F /* '/' */ == code2)
			idx = idx2;
		}
		DPRINT(Debug,12,(&Debug,
				 "browser_descend_local: last found idx=%d\n",idx));
	    } 
		
	    /* 1) First check is current path have same prefix ... */
	    A1 = clip_from_string(rel_name,&X1,idx+1);	    
	    if (dir->dirname) {
		int X2 = 0;
		struct string * A2 = clip_from_string(dir->dirname,&X2,idx+1); 

		if (X1 == X2 &&
		    0 == string_cmp(A1,A2,-99 /* Unknown indicator */ )) {

		    DPRINT(Debug,12,(&Debug,
				     "browser_descend_local: sep idx=%d -- so far ok\n",
				     idx));

		    last_idx_ok = idx;
		    free_string(&A1);
		    free_string(&A2);
		    continue;
		}
		
		free_string(&A2);
	    }

	    /* 2) Then check if current path have prefix of wanted */
	    if (!dir->dirname || 
		0 != string_cmp(A1,dir->dirname,
				-99 /* unknown indicator */)) {
		struct string * Lstr =  NULL;
		char * str           =  NULL;
		struct stat buf;

		DPRINT(Debug,12,(&Debug,
				 "browser_descend_local: sep idx=%d -- need change of directory\n",
				 idx));
		
		if (dir->dirname && 
		    string_len(dir->dirname) == last_idx_ok+1) {
		    int Z1 = last_idx_ok+1;

		    /* NOTE: A1 includes terminal /  --
		             however we do NOT want it when comparing
			     path component agaist directory listing
		    */

		    int  wanted_len = string_len(A1);

		    struct string * Z2;

		    int i;

		    if (wanted_len > 0  &&
			0x002F /* '/' */ == 
			give_unicode_from_string(A1,wanted_len-1)) {
			wanted_len--;
			wanted_len -= Z1;
		    } else {
			DPRINT(Debug,12,(&Debug,
					 "browser_descend_local: OOPS -- Not removing / from end of %S\n",
					 A1));
		    }

		    if (wanted_len < 1)
			goto no_way;

		    Z2 = clip_from_string(A1,&Z1,wanted_len);

		    /* Update cache ... */
		    browser_vector_len(dir);

		    for (i = 0; i < dir->vector_len; i++)
			if (0 == (string_cmp(Z2,
					     dir->vector[i].disp_name,
					     -99 /* Unknown indicator */)))
			    break;

		    if (i >= dir->vector_len) {
			DPRINT(Debug,1,(&Debug,
					"browser_descend_local: Name %S do NOT found from directory listing of %S\n",
					Z2,dir->dirname));
		    }
		    
		    free_string(&Z2);


		    if (i < dir->vector_len) {
			int l1 = strlen(dir->sys_dir);
			int add_slash = 0;
			
			if (l1 > 0 && '/' != dir->sys_dir[l1-1]) {
			    fill_ascii_to_string(dir->dirname,1,'/');
			    add_slash = 1;
			}

			Lstr = cat_strings(dir->dirname,
					   dir->vector[i].disp_name,
					   0);

			str = safe_strdup(dir->sys_dir);
			if (add_slash) {
			    str = strmcat(str,"/");
			}
			str = strmcat(str,dir->vector[i].sys_name);

			DPRINT(Debug,12,(&Debug,
					 "browser_descend_local: Using name %s (%S) from listing\n",
					 str,Lstr));

		    } else
			goto no_way;

		} else {
		no_way:
		    Lstr = convert_string(local_fs_charset,A1,0);
		    str  =  us2s(stream_from_string(Lstr,0,NULL));
		    DPRINT(Debug,12,(&Debug,
				     "browser_descend_local: Using name %s (%S)\n",
				     str,Lstr));
		}

		if (0 != stat(str,&buf) 
#ifdef S_ISDIR
		    || !S_ISDIR(buf.st_mode)
#endif
		    ) {
		    DPRINT(Debug,12,(&Debug,
				     "browser_descend_local: Failed -- bailing out\n"));

		    
		    free_string(&A1);
		    free_string(&Lstr);
		    free(str);
		    break;
		} 

		if (dir->a.local_browser.handle) 
		    closedir(dir->a.local_browser.handle);
		dir->a.local_browser.handle = NULL;

		/* Make empty selection folder */
		clear_dir_vector(dir);

		if (dir->dirname)
		    free_string(&dir->dirname);
		dir->dirname = Lstr;
		Lstr = NULL;
		
		if (dir->sys_dir) {
		    free(dir->sys_dir);
		    dir->sys_dir = NULL;
		}
		dir->sys_dir = str;
		str = NULL;
		if (0 != access(dir->sys_dir,READ_ACCESS)) {
		    DPRINT(Debug,12,(&Debug,
				     " -- No read access for %s\n",
				     dir->sys_dir));
		    dir->a.local_browser.handle = NULL;
		} else
		    dir->a.local_browser.handle = opendir(dir->sys_dir);

		if (dir->a.local_browser.handle) {
		    clear_dir_vector(dir);
		    DPRINT(Debug,12,(&Debug,
				     "browser_descend_local: Delaying reading of directory\n"));
		    dir->vector_len = -1;
		} else {
		    DPRINT(Debug,12,(&Debug, 
				     "browser_descend_local: No dir listing for %s (%S)\n",
				     dir->sys_dir,dir->dirname));
		}
	    }

	    DPRINT(Debug,12,(&Debug,
			     "browser_descend_local: sep idx=%d -- ok\n",
			idx));
	    last_idx_ok = idx;		
	    free_string(&A1);
	}
    }

    if (dir->dirname &&
	last_idx_ok < string_len(dir->dirname)) {

	DPRINT(Debug,12,(&Debug,
			 "browser_descend_local:  last_idx_ok = %d < len of dirname %S\n",
			 last_idx_ok,
			 dir->dirname));
			 

	if (last_idx_ok >= 0) {	    
	    struct string * Lstr =  NULL;
	    unsigned char * str  =  NULL;
	    int X = 0;
	    struct string * A1   = NULL;

	    DPRINT(Debug,12,(&Debug,
			     "browser_descend_local:  Target directory is substring of current!\n"));


	    A1 = 
		clip_from_string(dir->dirname,&X,
				 last_idx_ok > 0 ? last_idx_ok : 1);
	    
	    
	    Lstr = convert_string(local_fs_charset,A1,0);
	    str  =  stream_from_string(Lstr,0,NULL);
	    
	    /* We assume that directory name is OK without checking ... */
	    
	    DPRINT(Debug,12,(&Debug,
			     "... using directory name %s (%S)\n",
			     str,Lstr));
	    
	    if (dir->a.local_browser.handle) 
		closedir(dir->a.local_browser.handle);
	    dir->a.local_browser.handle = NULL;

	    /* Make empty selection folder */
	    clear_dir_vector(dir);
	    
	    if (dir->dirname)
		free_string(&dir->dirname);
	    dir->dirname = Lstr;
	    Lstr = NULL;
	    
	    if (dir->sys_dir) {
		free(dir->sys_dir);
		dir->sys_dir = NULL;
	    }
	    dir->sys_dir = us2s(str);
	    str = NULL;
	    if (0 != access(dir->sys_dir,READ_ACCESS)) {
		DPRINT(Debug,12,(&Debug,
				 " -- No read access for %s\n",
				 dir->sys_dir));
		dir->a.local_browser.handle = NULL;
	    } else
		dir->a.local_browser.handle = opendir(dir->sys_dir);
	    
	    if (dir->a.local_browser.handle) {
		clear_dir_vector(dir);
		DPRINT(Debug,12,(&Debug,
				 "browser_descend_local: Delaying reading of directory\n"));
		dir->vector_len = -1;
	    } else {
		DPRINT(Debug,12,(&Debug,
				 "browser_descend_local: No dir listing for %s\n",
				 dir->sys_dir));
	    }
	    
	    free_string(&A1);
	} else {
	    DPRINT(Debug,12,(&Debug,
			     "browser_descend_local: No directory name on rel_name: %S\n",
			     rel_name));

	    if (dir->a.local_browser.handle) 
		closedir(dir->a.local_browser.handle);
	    dir->a.local_browser.handle = NULL;

	    /* Make empty selection folder */
	    clear_dir_vector(dir);

	    if (dir->dirname)
		free_string(&dir->dirname);

	    if (dir->sys_dir) {
		free(dir->sys_dir);
		dir->sys_dir = NULL;
	    }
	}
    } 

    DPRINT(Debug,12,(&Debug,
		     "browser_descend_local: Up to %d OK\n",last_idx_ok));

    last_idx_ok++;

    ret = clip_from_string(rel_name,&last_idx_ok,string_len(rel_name));

    if (dir->dirname)
	DPRINT(Debug,12,(&Debug,"*** %S as relative to %S is %S\n",
			 rel_name,dir->dirname,ret));

    free_string(&rel_name);
    
    DPRINT(Debug,12,(&Debug,
		"browser_descend_local=%S   -- consumed to %d\n",
		ret,last_idx_ok));
    return ret;
}
				 
/* rel_dirname is relative to type -- (not include user@hostname) */
static int browser_change_local P_((struct folder_browser *dir,
				    struct string *rel_dirname,
				    struct string **dispname));
static int browser_change_local(dir,rel_dirname,dispname)
     struct folder_browser *dir;
     struct string *rel_dirname;
     struct string **dispname;
{
    int ret = 0;
    struct string * relative = NULL;
    struct string * Lstr = NULL;
    char          * str  = NULL;
   
    DPRINT(Debug,11,(&Debug,"browser_change_local: dir=%p\n", dir));

    relative = browser_descend_local(dir,rel_dirname);

    /* browser_select_generic uses 'rel_dirname' if
       'relative' is null 
    */
    browser_select_generic(dir,dir->dirname,
			   rel_dirname,relative,&Lstr,&str,'/',
			   local_fs_charset);	
    
    if (dir->a.local_browser.handle) 
	closedir(dir->a.local_browser.handle);

    if (0 != access(str,READ_ACCESS)) {
	dir->a.local_browser.handle = NULL;
    } else
	dir->a.local_browser.handle = opendir(str);
    
    if (!dir->a.local_browser.handle) {
	int err = errno;
	lib_error(CATGETS(elm_msg_cat, MeSet, MeDirError,
			  "Directory %S: %s"),
		  Lstr, error_description(err));
	goto fail;
    }

    ret = 1;
		
    if (dir->dirname)
	free_string(&dir->dirname);
    /* Copy just from edit buffer */
    dir->dirname = dup_string(*dispname);
    
    if (dir->sys_dir) {
	free(dir->sys_dir);
	dir->sys_dir = NULL;
    }

    dir->sys_dir = str;
    str = NULL;
    
    clear_dir_vector(dir);
    DPRINT(Debug,12,(&Debug,
		     "browser_change_local: Delaying reading of directory\n"));
    dir->vector_len = -1;
       
 fail:
    if (Lstr)
	free_string(&Lstr);    
    if (str)
	free(str);

    if (relative)
	free_string(&relative);

    DPRINT(Debug,11,(&Debug,"browser_change_local=%d\n", ret));
    return ret;
}

static int browser_change_v_local P_((struct folder_browser *dir,
				      struct name_vector *X,
				      struct string **dispname));
static int browser_change_v_local(dir,X,dispname)
     struct folder_browser *dir;
     struct name_vector *X;
     struct string **dispname;
{
    int ret = 0;

    DPRINT(Debug,11,(&Debug,"browser_change_v_local: dir=%p\n", dir));

    if (dir->dirname && dir->sys_dir) {
	struct string * Lstr = NULL;
	char          * str  = NULL;
	int l1 = strlen(dir->sys_dir);
	int add_slash = 0;

	if (l1 > 0 && '/' != dir->sys_dir[l1-1]) {
	    fill_ascii_to_string(dir->dirname,1,'/');
	    add_slash = 1;
	}

	Lstr = cat_strings(dir->dirname,
			   X->disp_name,
			   0);
	
	str = safe_strdup(dir->sys_dir);
	if (add_slash) {
	    str = strmcat(str,"/");
	}
	str = strmcat(str,X->sys_name);
	
	DPRINT(Debug,12,(&Debug,
			 "browser_change_v_local: Using name %s (%S) from listing\n",
			 str,Lstr));

	if (dir->a.local_browser.handle) 
	    closedir(dir->a.local_browser.handle);

	if (0 != access(str,READ_ACCESS)) {
	    dir->a.local_browser.handle = NULL;
	} else
	    dir->a.local_browser.handle = opendir(str);
    
	if (!dir->a.local_browser.handle) {
	    int err = errno;
	    lib_error(CATGETS(elm_msg_cat, MeSet, MeDirError,
			      "Directory %S: %s"),
		      Lstr, error_description(err));
	    goto fail;
	}
	
	ret = 1;
	
	/* Make empty selection folder */
	clear_dir_vector(dir);
	
	if (dir->dirname)
	    free_string(&dir->dirname);
	dir->dirname = Lstr;
	Lstr = NULL;
	
	/* Copy name to edit buffer */
	*dispname = dup_string(dir->dirname);
	
	if (dir->sys_dir) {
	    free(dir->sys_dir);
	    dir->sys_dir = NULL;
	}
	dir->sys_dir = str;
	str = NULL;
	
	clear_dir_vector(dir);
	DPRINT(Debug,12,(&Debug,
			 "browser_change_v_local: Delaying reading of directory\n"));
	dir->vector_len = -1;
	
    fail:
	if (Lstr)
	    free_string(&Lstr);    
	if (str)
	    free(str);
    }

    DPRINT(Debug,11,(&Debug,"browser_change_v_local=%d\n", ret));

    return ret;   
}


static int browser_change_up_local P_((struct folder_browser *dir,
				      struct string **dispname));
static int browser_change_up_local(dir,dispname)
     struct folder_browser *dir;
     struct string **dispname;
{
    int ret = 0;
    
    int L   = string_len(dir->dirname);
    int L1  = -1;
    int idx;
    
    DPRINT(Debug,11,(&Debug,"browser_change_up_local: dir=%p\n", dir));
    
    for (idx = 0; idx < L ; idx++) {
	uint16 code = give_unicode_from_string(dir->dirname,idx);
	
	if (0x002F /* '/' */ == code) 
	    L1 = idx;
    }

    if (L1 >= 0) {
	struct string * A1;

	int X = 0;
	    
	if (L1 < L-1)
	    L1++;
	
	A1 = clip_from_string(dir->dirname,&X,L1);

	/* Need not generate actual directory listing */
	
	if (*dispname)
	    free_string(dispname);	    
	*dispname = A1;
	
	ret = 1;
    } else
	ret = -1;   /* Signals caller to generate default menu */

    DPRINT(Debug,11,(&Debug,
		     "browser_change_up_local=%d\n", 
		     ret));
    return ret;   
}



/* rel_itemname is relative to type -- (not include user@hostname) */
static int browser_select_local P_((struct folder_browser *dir,
				    const struct string *rel_itemname,
				    struct string **dispname));
static int browser_select_local(dir,rel_itemname,dispname)
     struct folder_browser *dir;
     CONST struct string *rel_itemname;
     struct string **dispname;
{
    int ret = 0;

    struct string * relative = NULL;

    DPRINT(Debug,11,(&Debug,"browser_select_local: dir=%p\n", dir));

    if (rel_itemname) {
	DPRINT(Debug,11,(&Debug,"browser_select_local: rel_itemname=%S\n", 
		    rel_itemname));
    } else {
	DPRINT(Debug,11,(&Debug,"browser_select_local: rel_itemname=NULL\n"));
    }

    relative = browser_descend_local(dir,rel_itemname);

    if (relative) {
	ret = real_select_local(dir,rel_itemname,relative);
	free_string(&relative);
    }

    DPRINT(Debug,11,(&Debug,"browser_select_local=%d\n", ret));
    return ret;
}

static struct string * browser_give_title_local P_((struct folder_browser *dir));
static struct string * browser_give_title_local(dir)
     struct folder_browser *dir;
{
    static struct string *ret;
    
    DPRINT(Debug,11,(&Debug,"browser_give_title_local: dir=%p\n", dir));
    
    if (!dir->sys_dir)
	dir->sys_dir = safe_strdup("");
      
    if (!dir->dirname)
	dir->dirname = new_string2(local_fs_charset,s2us(dir->sys_dir));

    if (dir->filter)
	ret = format_string(CATGETS(elm_msg_cat, MeSet,MeLocalDirFilter,
				    "Local directory %S with filter %S"),
			    dir->dirname,dir->filter);
    else
	ret = format_string(CATGETS(elm_msg_cat, MeSet,MeLocalDir,
				    "Local directory %S"),
			    dir->dirname);
        
    DPRINT(Debug,11,(&Debug,"browser_give_title_local=%S\n", ret));

    return ret;
}

static char browser_separator_local P_((struct folder_browser *dir));
static char browser_separator_local(dir)
     struct folder_browser *dir;
{
    return '/';
}

static struct string * browser_name_local P_((struct folder_browser *dir));
static struct string * browser_name_local(dir)
     struct folder_browser *dir;
{
    static struct string *ret;

    DPRINT(Debug,11,(&Debug,
		     "browser_name_local: dir=%p\n", 
		     dir));

    if (!dir->sys_dir)
	dir->sys_dir = safe_strdup("");
    
    if (!dir->dirname)
	dir->dirname = new_string2(local_fs_charset,s2us(dir->sys_dir));

    ret = format_string(CATGETS(elm_msg_cat, MeSet,MeLocalDir,
				"Local directory %S"),
			dir->dirname);

    DPRINT(Debug,11,(&Debug,"browser_name_local=%S\n", ret));

    return ret;
}

static struct string * browser_cat_local P_((struct folder_browser *dir,
					     struct string * item));
static struct string * browser_cat_local(dir,item)
     struct folder_browser *dir;
     struct string * item;
{
    struct string * ret = NULL;
    int L = 0;

    DPRINT(Debug,11,(&Debug,"browser_cat_local: dir=%p\n", 
		     dir));
   
    if (dir->dirname &&
	(L = string_len(dir->dirname)) > 0) {
	
	ret = dup_string(dir->dirname);
	if (L > 0 && 
	    0x002F /* '/' */  !=  give_unicode_from_string(dir->dirname,
							   L-1))
	    fill_ascii_to_string(ret,1,'/');
	
	/* Some local directory! */
	if (item) {
	    struct string * XX = ret;
	    ret = cat_strings(XX,item,0);
	    free_string(&XX);
	}
    } else {
	/* Default MENU  -- also default directory ! */

	if (item)
	    ret = dup_string(item);
	else
	    ret = new_string(system_charset);
    }
    
    DPRINT(Debug,11,(&Debug,"browser_cat_local=%S\n",ret));
    return ret;
}

static struct folder_info * 
browser_folder_from_local P_((struct folder_browser *dir));

static struct folder_info * browser_folder_from_local(dir)
     struct folder_browser *dir;
{
    struct folder_info * res = NULL;

    DPRINT(Debug,11,(&Debug,"browser_folder_from_local: dir=%p\n", 
		     dir));

    res = real_folder_from_local(dir);

    if (res) {
	DPRINT(Debug,11,(&Debug,"browser_folder_from_local=%p\n",res));
    } else {
	DPRINT(Debug,11,(&Debug,"browser_folder_from_local=NULL\n"));
    }
    return res;
}

static int browser_create_selection_local P_((struct folder_browser *dir));

static int browser_create_selection_local(dir)
     struct folder_browser *dir;
{
    int ret = 0;
    char * name = NULL;

    DPRINT(Debug,11,(&Debug,"browser_create_selection_local: dir=%p\n", 
		     dir));

    if (dir->sys_dir && dir->sys_dir[0])
	name = elm_message(FRM("%s/%s"),
			   dir->sys_dir,
			   dir->selection->sys_name);
    else
	name = safe_strdup(dir->selection->sys_name);
    
    ret = create_as_user(name);
	
    free(name);

    DPRINT(Debug,11,(&Debug,"browser_create_selection_local=%d\n", ret));
    
    return ret;
}


static int browser_prepare_write_local P_((struct folder_browser *dir,
				  WRITE_STATE ptr));
static int browser_prepare_write_local(dir,ptr)
     struct folder_browser *dir;
     WRITE_STATE ptr;
{
    int ret = 0;
    char * name = NULL;

    DPRINT(Debug,11,(&Debug,"browser_prepare_write_local: dir=%p\n", dir));

    if (dir->sys_dir && dir->sys_dir[0])
	name = elm_message(FRM("%s/%s"),
			   dir->sys_dir,
			   dir->selection->sys_name);
    else
	name = safe_strdup(dir->selection->sys_name);
    
    ret = real_prepare_write_local(dir,ptr,name);
    
    free(name);

    DPRINT(Debug,11,(&Debug,"browser_prepare_write_local=%d\n", ret));

    return ret;
}

static int browser_sync_write_local P_((struct folder_browser *dir,
					WRITE_STATE ptr));
static int browser_sync_write_local(dir,ptr)
     struct folder_browser *dir;
     WRITE_STATE ptr;
{
    int ret = 0;
    char * name = NULL;

    DPRINT(Debug,11,(&Debug,"browser_sync_write_local: dir=%p\n", dir));

    if (dir->sys_dir && dir->sys_dir[0])
	name = elm_message(FRM("%s/%s"),
			   dir->sys_dir,
			   dir->selection->sys_name);
    else
	name = safe_strdup(dir->selection->sys_name);
    
    ret = real_sync_write_local(dir,ptr,name);
    
    free(name);
    
    DPRINT(Debug,11,(&Debug,"browser_sync_write_local=%d\n", ret));
    
    return ret;
}


static int browser_end_write_local P_((struct folder_browser *dir,
			      WRITE_STATE ptr));
static int browser_end_write_local(dir,ptr)
     struct folder_browser *dir;
     WRITE_STATE ptr;
{
    int ret = 0;
    char * name = NULL;

    DPRINT(Debug,11,(&Debug,"browser_end_write_local: dir=%p\n", dir));

    if (dir->sys_dir && dir->sys_dir[0])
	name = elm_message(FRM("%s/%s"),
			   dir->sys_dir,
			   dir->selection->sys_name);
    else
	name = safe_strdup(dir->selection->sys_name);
    
    ret = real_end_write_local(dir,ptr,name);
    
    free(name);
    
    DPRINT(Debug,11,(&Debug,"browser_end_write_local=%d\n", ret));
    
    return ret;
}

static long browser_tell_local_ws P_((struct folder_browser *dir,
				      WRITE_STATE write_state_ptr));
static long browser_tell_local_ws(dir,write_state_ptr)
     struct folder_browser *dir;
     WRITE_STATE write_state_ptr;
{
    long ret = -1L;

    DPRINT(Debug,11,(&Debug,"browser_tell_local_ws: dir=%p\n", 
		     dir));

    ret = real_browser_tell_ws(dir,write_state_ptr);
    
    DPRINT(Debug,11,(&Debug,"browser_tell_local_ws=%ld\n",ret));
    return ret;
}

/* Returns 0 on failure */
static int browser_seek_local_ws P_((struct folder_browser *dir,
				      WRITE_STATE write_state_ptr,
				      long pos));
static int browser_seek_local_ws(dir,write_state_ptr,pos)
     struct folder_browser *dir;
     WRITE_STATE write_state_ptr;
     long pos;
{
    int ret = 0;

    DPRINT(Debug,11,(&Debug,"browser_seek_local_ws: dir=%p\n", 
		     dir));

    ret = real_browser_seek_ws(dir,write_state_ptr,pos);
    
    DPRINT(Debug,11,(&Debug,"browser_seek_local_ws=%ld\n",ret));
    return ret;
}

static int browser_write_local_ws P_((struct folder_browser *dir,
				      WRITE_STATE ptr,
				      int l, const char *buffer));
static int browser_write_local_ws(dir,ptr,l,buffer)
     struct folder_browser *dir;
     WRITE_STATE ptr;
     int l; 
     CONST char *buffer;
{
    int ret = 0;

    DPRINT(Debug,11,(&Debug,"browser_write_local_ws: dir=%p\n", 
		     dir));

    ret = real_browser_write_ws(dir,ptr,l,buffer);
    
    DPRINT(Debug,11,(&Debug,"browser_write_local_ws=%d\n",ret));
    return ret;
}


static int browser_start_we_local P_((struct folder_browser *dir,
				      WRITE_STATE write_state_ptr,
				      int write_envelope,
				      struct header_rec *current_header,
				      int *env_flags));
static int browser_start_we_local(dir,write_state_ptr,
				  write_envelope,current_header,
				  env_flags)
     struct folder_browser *dir;
     WRITE_STATE write_state_ptr;
     int write_envelope;
     struct header_rec *current_header;
     int *env_flags;
{
    int ret = 1;

    DPRINT(Debug,11,(&Debug,"browser_start_we_local: dir=%p\n", 
		     dir));

    *env_flags = 0;
    if (write_envelope)
	ret = real_start_we_local(dir,write_state_ptr,current_header,
				  env_flags);
	    
    DPRINT(Debug,11,(&Debug,"browser_start_we_local=%d\n",ret));
    return ret;
}


static int browser_end_we_local P_((struct folder_browser *dir,
				  WRITE_STATE write_state_ptr,
				  int write_envelope,
				  struct header_rec *current_header));
static int browser_end_we_local(dir,write_state_ptr,
			      write_envelope,current_header)
     struct folder_browser *dir;
     WRITE_STATE write_state_ptr;
     int write_envelope;
     struct header_rec *current_header;
{
    int ret = 1;
    DPRINT(Debug,11,(&Debug,"browser_end_we_local: dir=%p\n", 
		     dir));

    if (write_envelope)
	ret = real_end_we_local(dir,write_state_ptr,current_header);

    DPRINT(Debug,11,(&Debug,"browser_end_we_local=%d\n",ret));
    return ret;
}

static int browser_selection_is_local P_((struct folder_browser *dir,
					  struct folder_info *folder));
static int browser_selection_is_local(dir,folder)
     struct folder_browser *dir;
     struct folder_info *folder;
{
    int ret = 0;
    DPRINT(Debug,11,(&Debug,"browser_selection_is_local: dir=%p\n", 
		     dir));
    
    ret = real_selection_is_local(dir,folder);
    
    DPRINT(Debug,11,(&Debug,"browser_selection_is_local=%d\n",ret));
    return ret;
}

static int browser_make_ref_local P_((struct folder_browser *dir,
				      char **refname, int *iscopy,
				      int is_text));
static int browser_make_ref_local(dir,refname,iscopy,is_text)
     struct folder_browser *dir;
     char **refname; 
     int *iscopy;
     int is_text;
{
    int ret = 0;

    DPRINT(Debug,11,(&Debug,"browser_make_ref_local: dir=%p\n", 
		     dir));

    ret = real_make_ref_local(dir,refname,iscopy,is_text); 

    DPRINT(Debug,11,(&Debug,"browser_make_ref_local=%d\n",ret));
    
    return ret;
}

static void browser_update_local P_((struct folder_browser *dir));
static void browser_update_local(dir)
     struct folder_browser *dir;
{
    clear_dir_vector(dir);

    if (dir->a.local_browser.handle) {
	DPRINT(Debug,10,(&Debug, 
			 "browser_fill_local: Reading directory of %s\n",
			 dir->sys_dir ? dir->sys_dir : "<NULL>"));

	browser_fill_local(dir);
    } else {
	DPRINT(Debug,11,(&Debug, 
			 "browser_fill_local: NO directory handle\n"));
    }
}

static int sort_by_name P_((const void *A, const void *B));
static int sort_by_name(A,B)
     CONST void *A; 
     CONST void *B;
{
    CONST struct name_vector * A1 = A;
    CONST struct name_vector * B1 = B;

    int r = string_cmp(A1->disp_name,
		       B1->disp_name,
		       0  /* compare fialure */);

    if (0 == r)
	r = strcmp(A1->sys_name,B1->sys_name);
   
    return r;
}

static int sort_by_revname P_((const void *A, const void *B));
static int sort_by_revname(A,B)
     CONST void *A; 
     CONST void *B;
{
    return -sort_by_name(A,B);
}

static int sort_by_mtime P_((const void *A, const void *B));
static int sort_by_mtime(A,B)
     CONST void *A; 
     CONST void *B;
{
    CONST struct name_vector * A1 = A;
    CONST struct name_vector * B1 = B;

    int r = A1->mtime - B1->mtime;

    if (0 == r)
	r = strcmp(A1->sys_name,B1->sys_name);
    
    return r;

}
static int sort_by_revmtime P_((const void *A, const void *B));
static int sort_by_revmtime(A,B)
     CONST void *A; 
     CONST void *B;
{
    return -sort_by_mtime(A,B);
}


S_(browser_folder_sort_dir browser_folder_sort_local)
static void browser_folder_sort_local P_((struct folder_browser *dir,
					  print_sort_message * print));
static void browser_folder_sort_local(dir,print)
     struct folder_browser *dir;
     print_sort_message * print;
{
    struct string * msg = NULL;
    int i;

    if (dir->vector_len < 2)
	return;

    switch (give_dt_sort_as_int(&local_dir_sortby)) {
    case LD_NONE:                 return;
    case LD_NAME_SORT:
	
	if (dir->vector_len < 10) {
	    msg = format_string(CATGETS(elm_msg_cat, MeSet, MeSortingDirByName, 
					"Sorting directory %S by Name"),
				dir->dirname);
	    print(msg);
	}
	qsort(dir->vector,dir->vector_len,sizeof (dir->vector[0]),
	      sort_by_name);
	break;
    case REVERSE LD_NAME_SORT:
	
	if (dir->vector_len > 10) {
	    msg = format_string(CATGETS(elm_msg_cat, MeSet, MeSortingDirByRevName, 
					"Sorting directory %S by Reverse Name"),
				dir->dirname);
	    print(msg);
	}
	qsort(dir->vector,dir->vector_len,sizeof (dir->vector[0]),
	      sort_by_revname);
	break;
    case LD_MTIME_SORT:

	if (dir->vector_len < 10) {
	    msg = format_string(CATGETS(elm_msg_cat, MeSet, MeSortingDirByMtime, 
					"Sorting directory %S by Modify Time"),
				dir->dirname);
	    print(msg);
	}
	for (i = 0; i < dir->vector_len; i++)
	    if (dir->vector[i].flags & BROWSER_NEEDSTAT)
		browser_local_do_stat(dir,i);


	qsort(dir->vector,dir->vector_len,sizeof (dir->vector[0]),
	      sort_by_mtime);
	break;
    case REVERSE LD_MTIME_SORT:

	if (dir->vector_len > 10) {
	    msg = format_string(CATGETS(elm_msg_cat, MeSet, MeSortingDirByRevMtime, 
					"Sorting directory %S by Reverse Modify Time"),
				dir->dirname);
	    print(msg);
	}

	for (i = 0; i < dir->vector_len; i++)
	    if (dir->vector[i].flags & BROWSER_NEEDSTAT)
		browser_local_do_stat(dir,i);

	qsort(dir->vector,dir->vector_len,sizeof (dir->vector[0]),
	      sort_by_revmtime);
	break;

    }

    if (msg) {
	print(NULL);
	free_string(&msg);
    }
}



struct browser_type local_browser = {  browser_zero_local,
				       browser_free_local,
				       browser_change_local,
				       browser_give_title_local,
				       browser_separator_local,
				       browser_name_local,
				       browser_cat_local,
				       browser_select_local,
				       browser_folder_from_local,
				       browser_change_v_local,
				       browser_change_up_local,
				       browser_create_selection_local,
				       zero_ws_fields_local,
				       free_ws_fields_local,
				       browser_prepare_write_local,
				       browser_end_write_local,
				       browser_tell_local_ws,
				       browser_seek_local_ws,
				       browser_write_local_ws,
				       browser_start_we_local,
				       browser_end_we_local,
				       browser_selection_is_local,
				       browser_make_ref_local,
				       browser_update_local,
				       browser_local_do_stat,
				       browser_sync_write_local,
				       browser_folder_sort_local
};

#endif  /* DIROPS */


/* ------------------------------------------------------------------------- */

/* LOCAL mailbox */


static void mbx_close_non_spool P_((struct folder_info *folder,
				    enum close_mode mode));
static void mbx_close_non_spool(folder,mode) 
     struct folder_info *folder;
     enum close_mode mode;
{
    DPRINT(Debug,11,(&Debug, 					 
		     "mbx_close_non_spool: folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));

    /* normal folder */

    if (folder -> p->fh_folder) {
	switch (mode) {
	case CLOSE_NORMAL:
	    if (lockfolders)
		Release_the_file(fileno(folder -> p->fh_folder));      
	    break;
	case CLOSE_LEAVE_LOCKED:
	    break;
	}
    }

    return;
}


static void mbx_close_spool P_((struct folder_info *folder,
				enum close_mode mode));
static void mbx_close_spool(folder,mode) 
     struct folder_info *folder;
     enum close_mode mode;
{    
    DPRINT(Debug,11,(&Debug, 
		     "mbx_close_spool: folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));

    switch (mode) {
    case CLOSE_NORMAL:

	if (folder -> p->a.spool.lock_state == ON)
	    unlock_folder(0,folder);
    
	/* falltru */
    case CLOSE_LEAVE_LOCKED:
	if (!folder -> p->fh_temp) {
	    DPRINT(Debug,1,(&Debug, 
			    "mbx_close_spool: tempfile (%s) not open -- will not unlink\n",
			    folder -> cur_tempfolder));
	} else if (unlink(folder -> cur_tempfolder) != 0) {
	    if (errno != ENOENT) {
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSorryCantUnlinkTemp,
				  "Sorry, can't unlink the temp file %s [%s]!\n\r"),
			  folder -> cur_tempfolder, error_description(errno));
	    }
	} else {
	    DPRINT(Debug,1,(&Debug, 
			    "close_folder: Unlinking tempfile (%s).\n",
			    folder -> cur_tempfolder));
	}      
    }
}


static int  mbx_lock_non_spool P_((int direction,
				    struct folder_info *folder));
static int  mbx_lock_non_spool(direction,folder)
     int direction;
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug, 
		     "mbx_lock_non_spool=1 (dummy): folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));    	     
    return 1;
}


#ifdef	USE_DOTLOCK_LOCKING		

static int  mbx_dotlock_file P_((int direction,
				 struct folder_info *folder));
static int  mbx_dotlock_file(direction,folder)
     int direction;
     struct folder_info *folder;
{
    int status = 0;
    int create_iteration = 0;
    char pid_buffer[SHORT];

    struct stat    buf;		/* stat command  */
    int stat_code = -1;

    int err       = 0;
    int temp_fd = -1;
    int create_fd = -1;	/* file descriptor for creating lock file */

    gid_t oldgid = getegid();

    if (have_saved_ids) {
	/* reset id so that we can get at lock file */
	if (setgid(mailgroupid) < 0) {
	    int err = errno;
	    lib_error(FRM("Lock: setgid(%d) FAILED: %s"),
		      mailgroupid,error_description(err));	    
	}
    }

    if(folder->p->a.spool.lock_state == ON) {
	DPRINT(Debug,1,(&Debug, 
			"mbx_dotlock_file: Folder %s already locked.\n", 
			folder->cur_folder_sys));
	if (direction == INCOMING)
	    DPRINT(Debug,1,(&Debug, 
			    "mbx_dotlock_file: ERROR: ... And direction INCOMING! Software error!\n"));
	else {
	    status = 1;
	    goto clean;
	}		   
    }
    
#ifdef PIDCHECK
    /** first, try to read the lock file, and if possible, check the pid.
	If we can validate that the pid is no longer active, then remove
	the lock file.
    **/

    if((temp_fd=open(folder->p->a.spool.lockfile,O_RDONLY)) != -1) {
	if (read(temp_fd, pid_buffer, SHORT) > 0) {
	    int pid_value = atoi(pid_buffer);
	    if (pid_value) {
		int kill_status = kill(pid_value, 0);
		if (kill_status != 0 && errno != EPERM) {
		    if (unlink(folder->p->a.spool.lockfile) != 0) {
			DPRINT(Debug,1,(&Debug, 
					"Error %s\n\ttrying to unlink file %s (%s)\n", 
					error_description(errno), 
					folder->p->a.spool.lockfile, "lock"));
			lib_error(CATGETS(elm_msg_cat, ElmSet, 
					  ElmLeaveCouldntRemoveCurLock,
					  "\nCouldn't remove the current lock file %s\n"), 
				  folder->p->a.spool.lockfile);
			lib_error(FRM("** %s **\n"), 
				  error_description(errno));
			close(temp_fd);
			status = 0;
			goto clean;
		    }
		}
	    }
	}
	close(temp_fd);
    }
#endif
	      
    /* try to assert create lock file MAX_ATTEMPTS times */
    do {
	err = 0;
	if((create_fd=open(folder->p->a.spool.lockfile,
				   O_WRONLY | O_CREAT | 
				   O_EXCL,0444)) != -1)
	    break;
	else {
	    err = errno;

	    DPRINT(Debug,9,(&Debug,
			    "open (creating) %s: %s (errno %d) --  try %d\n",
			    folder->p->a.spool.lockfile,
			    error_description(err),err,
			    create_iteration));

	    stat_code = stat(folder->p->a.spool.lockfile,&buf);

	    if (0 == stat) {
		DPRINT(Debug,9,(&Debug,
				"stat %d  succeed!\n",
				folder->p->a.spool.lockfile));				
	    }



	    /* Creation of lock failed NOT because it already exists!!! */

	    if (err != EEXIST && stat_code < 0) {		    

		DPRINT(Debug,1,(&Debug, 
				"Error encountered attempting to create lock %s\n", 
				folder->p->a.spool.lockfile));
		DPRINT(Debug,1,(&Debug, 
				"** %s **\n", error_description(err)));


		/* If /var/mail nfs mounted on Solaris 2.3 at least you can */
		/* get EACCES.  Treat it like EEXIST.                       */
		
		if (err != EACCES ||
		    /* Stat buffer argument is NULL because stat failed */
		    ! in_directory(NULL,folder->p->a.spool.lockfile,
				   mailhome)) {
		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
				      ElmLeaveErrorCreatingLock,
				      "\nError encountered while attempting to create lock file %s;\n"),
			      folder->p->a.spool.lockfile);
		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
				      ElmErrorAccess,
				      "%.45s: %.33s"),
			      folder->p->a.spool.lockfile,
			      error_description(err));
		} else {	
		    lib_error(CATGETS(elm_msg_cat, ElmSet, 
				      ElmLeaveCantCreateLock,
				      "Can't create lock file! Need write permission in \"%s\".\n"),
			      mailhome);
		}
		status = 0;
		goto clean;
	    }
	}
	DPRINT(Debug,2,(&Debug, 
			"File '%s' already exists!  Waiting...(lock)\n", 
			folder->p->a.spool.lockfile));
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveWaitingToRead,
			  "Waiting to read mailbox while mail is being received: attempt #%d"),
		  create_iteration);
#if POLL_METHOD	  
	wait_for_timeout(5);
#else
	sleep(5);
#endif
    } while (create_iteration++ < MAX_ATTEMPTS);

    if(create_fd == -1) {	
	struct stat    buf2;	/* stat command  */
	int stat2_code = stat(folder->cur_folder_sys,&buf2);
	time_t now = time(NULL);
	int can_remove = 0;

	DPRINT(Debug,2,(&Debug, 
			"mbx_dotlock_file: now       = %d \n",
			now)); 
	if (stat_code == 0) {
	    DPRINT(Debug,1,(&Debug, 
			    "mbx_dotlock_file: lock time = %d (%s)\n",
			    buf.st_mtime,folder->p->a.spool.lockfile));
	    can_remove = buf.st_mtime < now - 10 * 60;
	    DPRINT(Debug,1,(&Debug, 
			    "                  (modified %1.1f minutes ago)\n",
			    (double)(now - buf.st_mtime) / 60.0));
	}
	if (stat2_code == 0) {
	    DPRINT(Debug,1,(&Debug, 
			    "mbx_dotlock_file: read time = %d (%s)\n",
			    buf2.st_atime,folder->cur_folder_sys));
	    if (buf2.st_atime > now - 10 * 60)
		can_remove = 0;
	    DPRINT(Debug,1,(&Debug, 
			    "                  (read %1.1f minutes ago)\n",
			    (double)(now - buf2.st_atime) / 60.0));
	}
	DPRINT(Debug,2,(&Debug, 
			"mbx_dotlock_file: can remove = %d \n",
			can_remove)); 

	/* we weren't able to create the lock file */
	
	if (can_remove) {
	    /** time to waste the lock file!  Must be there in error! **/
	    DPRINT(Debug,2,(&Debug, 
			    "Warning: I'm giving up waiting - removing lock file(lock)\n"));
	    if (direction == INCOMING)
		lib_error(CATGETS(elm_msg_cat, ElmSet, 
				  ElmLeaveTimedOutRemoving,
				  "\nTimed out - removing current lock file..."));
	    else
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveThrowingAwayLock,
				  "Throwing away the current lock file!"));

	    if (unlink(folder->p->a.spool.lockfile) != 0) {
		DPRINT(Debug,1,(&Debug, 
				"Error %s\n\ttrying to unlink file %s (%s)\n", 
				error_description(errno), folder->p->a.spool.lockfile, "lock"));
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveCouldntRemoveCurLock,
				  "\nCouldn't remove the current lock file %s\n"), 
			  folder->p->a.spool.lockfile);	     
		lib_error(FRM("** %s **\n"), 
			  error_description(errno));
		status = 0;
		goto clean;
	    }

	    /* we've removed the bad lock, let's try to assert lock once more */
	    if((create_fd=open(folder->p->a.spool.lockfile,
			       O_WRONLY | O_CREAT | O_EXCL,0444)) == -1){
		int err=errno;

		/* still can't lock it - just give up */
		DPRINT(Debug,1,(&Debug, 
			   "Error encountered attempting to create lock %s\n", 
			   folder->p->a.spool.lockfile));
		DPRINT(Debug,1,(&Debug, "%s (errno %d)\n",
				error_description(err), err));

		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveErrorCreatingLock,
				  "\nError encountered while attempting to create lock file %s;\n"),
			  folder->p->a.spool.lockfile);	    
		lib_error(FRM("** %s. **\n\n"), 
			  error_description(err));
		status = 0;
		goto clean;
	    }
	}
	else {
	    /* Okay...we die and leave, not updating the mailfile mbox or
	       any of those! */

	    if (direction == INCOMING) {
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveGivingUp,
				  "\n\nGiving up after %d iterations.\n"), 
			  create_iteration);		
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeavePleaseTryAgain,
				  "\nPlease try to read your mail again in a few minutes.\n\n"));
		DPRINT(Debug,1,(&Debug, 
			   "Warning: bailing out after %d iterations...(lock)\n",
			   create_iteration));
		status = 0;
		goto clean;
		
	    } else {
		DPRINT(Debug,1,(&Debug, 
				"Warning: after %d iterations, timed out! (lock)\n",
				create_iteration));
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveErrorTimedOutLock,
				  "Timed out on locking mailbox.  Leaving program.\n"));
		status = 0;
		goto clean;
	    }
	}
    }

    status = 1;
    /* If we're here we successfully created the lock file */
    DPRINT(Debug,55,(&Debug, 
		     "Lock %s %s for file %s on.\n", 
		     folder->p->a.spool.lockfile,
		     (direction == INCOMING ? "incoming" : "outgoing"), 
		     folder->cur_folder_sys));
    
    /* Place the pid of Elm into the lock file for SVR3.2 and its ilk */
    elm_sfprintf(pid_buffer, sizeof pid_buffer,
		 FRM("%d"), 
		 getpid());
    write(create_fd, pid_buffer, strlen(pid_buffer));
    
 clean:
    if (create_fd != -1)
	close(create_fd);

    if (have_saved_ids) {
	if (setgid(oldgid) <0) {
    	    int err = errno;
	    lib_error(FRM("Lock: setgid(%d) FAILED: %s"),
		      oldgid,error_description(err));
	}
    }

    DPRINT(Debug,2,(&Debug, 
		    "mbx_dotlock_file = %d \n",
		    status));

    return status;
}
#endif

#ifdef SYSCALL_LOCKING
static int  mbx_syscall_lock_file P_((int direction,
				      struct folder_info *folder));
static int  mbx_syscall_lock_file(direction,folder)
     int direction;
     struct folder_info *folder;
{
    int status = 0;
    int stat = FLOCKING_FAIL;
    int flock_iteration = 0;

    /* try to assert lock MAX_ATTEMPTS times */
    do {
	stat = Grab_the_file (fileno(folder->p->fh_folder));
	if (FLOCKING_OK == stat)
	    break;

	switch (stat) {	    
	case	FLOCKING_FAIL:
	    /*
	     *	Creation of lock failed
	     *	NOT because it already exists!!!
	     */
	    
	    DPRINT(Debug,1,(&Debug, 
			    "Error encountered attempting to flock %s\n",
			    folder->cur_folder_sys));
	    DPRINT(Debug,1,(&Debug, 
			    "** %s **\n", 
			    error_description(errno)));
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveErrorFlockMailbox,
			      "Error encountered while attempting to flock mailbox %S: %s"), 
		      folder->cur_folder_disp,
		      error_description(errno));
	    
	    status = 0;
	    goto clean;

	case	FLOCKING_RETRY:
	default:
	    DPRINT(Debug,2,(&Debug, 
			    "Mailbox '%s' already locked!  Waiting...(lock)\n", 
			    folder->cur_folder_sys));
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveWaitingToRead,
			      "Waiting to read mailbox while mail is being received: attempt #%d"),
		      flock_iteration);
#if POLL_METHOD	  
	    wait_for_timeout(5);
#else
	    sleep(5);
#endif
	}
      } while (flock_iteration++ < MAX_ATTEMPTS);

      lib_transient(FRM(""));

      if (stat != FLOCKING_OK) {
	  /* We couldn't lock the file. We die and leave not updating
	   * the mailfile mbox or any of those! */
	  
	  if (direction == INCOMING) {
	      lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveGivingUp,
				"\n\nGiving up after %d iterations.\n"), 
			flock_iteration);	    
	      lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeavePleaseTryAgain,
				"\nPlease try to read your mail again in a few minutes.\n\n"));
	      DPRINT(Debug,1,(&Debug, 
			      "Warning: bailing out after %d iterations...(lock)\n",
			      flock_iteration));
	  } else {
	      DPRINT(Debug,1,(&Debug, 
			      "Warning: after %d iterations, timed out! (lock)\n",
			      flock_iteration));
	  }
	  lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveErrorTimedOutLock,
			    "Timed out on locking mailbox.  Leaving program.\n"));
	  status = 0;
	  goto clean;
      }

      /* We locked the file */
      DPRINT(Debug,5,(&Debug, 					 
		      "Lock %s on file %s on.\n",
		      (direction == INCOMING ? "incoming" : "outgoing"), 
		      folder->cur_folder_sys));
      status = 1;

 clean:
      DPRINT(Debug,2,(&Debug, 
		      "mbx_syscall_lock_file = %d \n",
		      status));
      return status;
}
#endif

static int  mbx_lock_spool P_((int direction,
			       struct folder_info *folder));
static int  mbx_lock_spool(direction,folder)
     int direction;
     struct folder_info *folder;
{
     /** Create lock file to ensure that we don't get any mail 
	 while altering the folder contents!
	 If it already exists sit and spin until 
	 either the lock file is removed...indicating new mail
	 or
	 we have iterated MAX_ATTEMPTS times, in which case we
	 either fail or remove it and make our own (determined
	 by if REMOVE_AT_LAST is defined in header file
	 If direction == INCOMING then DON'T remove the lock file
	 on the way out!  (It'd mess up whatever created it!).
	 
	 But if that succeeds and if we are also locking by flock(),
	 follow a similar algorithm. Now if we can't lock by flock(),
	 we DO need to remove the lock file, since if we got this far,
	 we DID create it, not another process.
      **/
    
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_lock_spool: folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));

#ifdef	USE_DOTLOCK_LOCKING	
    if (!mbx_dotlock_file(direction,folder)) {
	status = 0;
	goto clean;
    }
#endif	

#ifdef SYSCALL_LOCKING
      /* Now we also need to lock the file with flock(2) */

    if(!folder->p->fh_folder) {
	DPRINT(Debug,11,(&Debug, 
			 "mbx_lock_spool: non-existent -- no syscall locking.\n"));
    } else if (!mbx_syscall_lock_file(direction,folder)) {
#ifdef	USE_DOTLOCK_LOCKING
	(void)unlink(folder->p->a.spool.lockfile);
#endif /* USE_DOTLOCK_LOCKING */
	status = 0;
	goto clean;
    }
#endif

    DPRINT(Debug,5,(&Debug, 
		    "Lock %s for file %s on successfully.\n",
		    (direction == INCOMING ? "incoming" : "outgoing"), 
		    folder->cur_folder_sys));

    folder->p->a.spool.lock_state = ON;
    status = 1;
    
 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_lock_spool=%d\n", status));

    return status;
}


static int mbx_unlock_non_spool P_((int interrupt, 
				    struct folder_info *folder));
static int mbx_unlock_non_spool(interrupt,folder) 
     int interrupt;
     struct folder_info *folder;
{
    SIGDPRINT(Debug,11,(&Debug, 
		     "mbx_unlock_non_spool=1 (dummy): folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));
    return 1;
}

#ifdef SYSCALL_LOCKING

static int mbx_syscall_unlock_file P_((int interrupt, 
				       struct folder_info *folder));

static int mbx_syscall_unlock_file(interrupt,folder)
     int interrupt; 
     struct folder_info *folder;
{
    int status = 0;

    if (0 != Release_the_file (fileno(folder->p->fh_folder))) { 
	SIGDPRINT(Debug,1,(&Debug, 
			   "Error %s\n\ttrying to unlock file %s (%s)\n", 
			   error_description(errno), 
			   folder->cur_folder_sys, "unlock"));
    } else
	status = 1;

    return status;
}
#endif

#ifdef USE_DOTLOCK_LOCKING

static int mbx_dotunlock_file P_((int interrupt, 
				  struct folder_info *folder));

static int mbx_dotunlock_file(interrupt,folder)
     int interrupt; 
     struct folder_info *folder;
{
    int status = 0;
    gid_t oldgid = getegid();

    if (have_saved_ids) {
	/* reset id so that we can get at lock file */
	
	if (setgid(mailgroupid) < 0) {
    	    int err = errno;
	    SIGDPRINT(Debug,1,(&Debug,
			       "mbx_dotunlock_file: setgid(%d) FAILED: %s\n",
			       mailgroupid,error_description(err)));
	    if (!interrupt)
		lib_error(FRM("Unlock: setgid(%d) FAILED: %s"),
			  mailgroupid,error_description(err));
	}
    }

    if(unlink(folder->p->a.spool.lockfile) == 0) {	/* remove lock file */
	status = 1;
    } else {
	SIGDPRINT(Debug,1,(&Debug, 
			"Error %s\n\ttrying to unlink file %s (%s)\n", 
			error_description(errno), 
			folder->p->a.spool.lockfile,
			"unlock"));
	if (!interrupt)
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmLeaveCouldntRemoveOwnLock,
			      "Couldn't remove my own lock file %s!"), 
		      folder->p->a.spool.lockfile);
    }

    if (have_saved_ids) {
	if (setgid(oldgid) < 0) {
    	    int err = errno;
	    SIGDPRINT(Debug,1,(&Debug, 
			       "mbx_dotunlock_file: setgid(%d) FAILED: %s\n",
			       oldgid,error_description(err)));
	    if (!interrupt)
		lib_error(FRM("Unlock: setgid(%d) FAILED: %s"),
			  oldgid,error_description(err));
	}
    }

    return status;
}
#endif


static int mbx_unlock_spool P_((int interrupt, struct folder_info *folder));

static int mbx_unlock_spool(interrupt,folder)
     int interrupt; 
     struct folder_info *folder;
{
    /** Remove the lock file!    This must be part of the interrupt
	processing routine to ensure that the lock file is NEVER
	left sitting in the mailhome directory!
	
	If also using flock(), remove the file lock as well.
    **/

    int status = 1;

    SIGDPRINT(Debug,11,(&Debug, 
		     "mbx_unlock_spool: folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));

#ifndef USE_DOTLOCK_LOCKING
    SIGDPRINT(Debug,5,(&Debug, 
		       "Lock (no .lock) for file %s %s off.\n",
		       folder->cur_folder_sys, 
		       (folder-> p->a.spool.lock_state == ON ? 
			"going" : "already")));
#else   /* USE_DOTLOCK_LOCKING */
    SIGDPRINT(Debug,5,(&Debug, 
			"Lock %s for file %s %s off.\n",
			(folder->p->a.spool.lockfile ? 
			 folder->p->a.spool.lockfile : "none"),
			folder->cur_folder_sys,
			(folder->p->a.spool.lock_state == ON ? 
			 "going" : "already")));
#endif  /* USE_DOTLOCK_LOCKING */

    if(folder->p->a.spool.lock_state == ON) {
#ifdef SYSCALL_LOCKING
	if(!folder->p->fh_folder) {
	    SIGDPRINT(Debug,11,(&Debug, 
			"mbx_unlock_spool: non-existent -- no syscall locking.\n"));
	} else  if (!mbx_syscall_unlock_file(interrupt,folder))
	    status = 0;
#endif

#ifdef USE_DOTLOCK_LOCKING
	if (!mbx_dotunlock_file(interrupt,folder))
	    status = 0;    
#endif
    
	if (status)
	    folder->p->a.spool.lock_state = OFF; /* indicate we don't have a lock on */
    
    }
    SIGDPRINT(Debug,11,(&Debug, 
			"mbx_unlock_non_spool=%d\n",
			status));
    return status;
}

static void mk_temp_mail_fn P_((char *tempfn, char *mbox,
				int tempfn_size));


static void mbx_init_non_spool P_((struct folder_info *folder));
static void mbx_init_non_spool(folder) 
     struct folder_info *folder;
{	
    DPRINT(Debug,11,(&Debug, 
		     "mbx_init_non_spool: folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));

    folder -> p = safe_malloc(sizeof (struct private_data));
    /* defined in hdrs/defs.h */
    bzero((void *)folder -> p,sizeof( struct private_data));   
    
    folder ->p->fh_temp     = NULL;
    folder ->p->fh_folder   = NULL;
    folder ->p->flags1      = 0;
    
}

static void mbx_init_spool P_((struct folder_info *folder));
static void mbx_init_spool(folder) 
     struct folder_info *folder;
{	
    DPRINT(Debug,11,(&Debug, 
		     "mbx_init_spool: folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));

    mk_temp_mail_fn(folder-> cur_tempfolder, 
		    folder->cur_folder_sys, 
		    sizeof folder -> cur_tempfolder);

    folder -> p = safe_malloc(sizeof (struct private_data));
    /* defined in hdrs/defs.h */
    bzero((void *)folder -> p,sizeof (struct private_data));   
    folder ->p->fh_temp     = NULL;
    folder ->p->fh_folder   = NULL;
    folder ->p->flags1      = 0;

    folder -> p -> a.spool.lock_state = OFF;
#ifdef  USE_DOTLOCK_LOCKING
    folder -> p -> a.spool.lockfile=
	safe_strdup(mk_lockname(folder->cur_folder_sys));
#endif  /* USE_DOTLOCK_LOCKING */

}

static void mk_temp_mail_fn(tempfn, mbox, tempfn_size)
     char *tempfn, *mbox;
     int tempfn_size;
{
    /** create in tempfn the name of the temp file corresponding to
	mailfile mbox. Used to session lock also.
    **/
  
    char *cp,*ptr;
    struct stat    buf;		/* stat command  */
    int in_spool = 0;
    char *Y = NULL, *Y1 = "";

    char * prefix = "mbox.";
    char * tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
    int    ls  = give_dt_enumerate_as_int(&local_sessionlock_use_home);

    int L;


    if (stat(mbox,&buf) < 0) {
	DPRINT(Debug,8,(&Debug, 
			"mk_temp_mail_fn: stat %s failed\n",
			mbox));
	in_spool = in_directory(NULL,mbox,mailhome);
    } else 
	in_spool = in_directory(&buf,mbox,mailhome);
	    
    DPRINT(Debug,11,(&Debug, 
		     "mk_temp_mail_fn: in_spool=%d, mbox=%s, local_sessionlock_use_home=%d\n",
		     in_spool,mbox,ls));

    /* We need not use default_temp or local_sessionlock_dir
       if file is not on spool area 
    */
    
    switch (ls) {
    case 0: /* newer */
    default:
	Y = in_spool || !tmp ? local_sessionlock_dir : tmp;
	break;
    case 1: /* spool */
	Y       = in_spool || !tmp ? home     : tmp;
	prefix  = in_spool || !tmp ? ".mbox." : "mbox.";
	break;
    case 2: /* always */
	Y      = home;
	prefix = ".mbox.";
	break;
    case 3: /* non-spool */
	Y      = in_spool ? local_sessionlock_dir : home;
	prefix = in_spool ? "mbox."               : ".mbox.";
	break;
    }

    L = strlen(Y);

    DPRINT(Debug,11,(&Debug, 
		     "     => temp dir=%s prefix=%s\n",Y,prefix));

    if (strlen(Y) + strlen(prefix) > tempfn_size-2) {
	DPRINT(Debug,1,(&Debug,
			"mk_temp_mail_fn: Too long path!\n"));
	strfcpy(tempfn,"TEMP_MBOX", tempfn_size);
	return;
    }
  
    if (L < 1) {
	DPRINT(Debug,1,(&Debug,
			"mk_temp_mail_fn: Dir empty!!\n"));
	strfcpy(tempfn,"TEMP_MBOX", tempfn_size);
	return;
    }

    if (Y[L-1] != '/')
	Y1 = "/";

    elm_sfprintf(tempfn, tempfn_size,
		 FRM("%s%s%s"), Y, Y1, prefix);


    if((cp = rindex(mbox, '/')) != NULL) {    
	cp++;
	if (strcmp(cp, "mbox") == 0 || strcmp(cp, "mailbox") == 0 ||
	    strcmp(cp, "inbox") == 0 || *cp == '.') {
	    ptr = username;
	}
	else {
	    ptr = cp;
	}
    } else {
	ptr = mbox;
    }
    
    if (strlen(tempfn) + strlen(ptr) > tempfn_size-1) {
	DPRINT(Debug,1,(&Debug, 
		  "mk_temp_mail_fn: Too long path or mailbox!\n"));
    } else
	strfcat(tempfn, ptr, tempfn_size);

    if (!in_spool) {
	/* Assume that this is user's incoming mail area */
	if (strlen(tempfn) + strlen(username) > tempfn_size-2) {
	    DPRINT(Debug,1,(&Debug, 
			    "mk_temp_mail_fn: Too long path or username!\n"));
	} else {
	    strfcat(tempfn, "-", tempfn_size);
	    strfcat(tempfn, username, tempfn_size);
	}
    }
    DPRINT(Debug,8,(&Debug, 
	      "mk_temp_mail_fn: tempfname=%s\n",tempfn));
}


static void mbx_free_non_spool P_((struct folder_info *folder));
static void mbx_free_non_spool(folder)
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug, 
		"mbx_free_non_spool: folder=%X (%s)\n",
		folder,folder->cur_folder_sys));    
    
    if (folder -> p -> fh_temp) {
	fclose( folder -> p -> fh_temp);
	folder -> p -> fh_temp = NULL;
    }
    if (folder -> p -> fh_folder) {
	fclose(folder -> p -> fh_folder);	
	folder -> p -> fh_folder = NULL;
    }
    free(folder -> p);
    folder -> p = NULL;
}


static void mbx_free_spool P_((struct folder_info *folder));
static void mbx_free_spool(folder)
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug, 
		     "mbx_free_non_spool: folder=%X (%s)\n",
		     folder,folder->cur_folder_sys));    

    if (folder -> p->fh_temp) {
	fclose(folder -> p->fh_temp);
	folder -> p -> fh_temp = NULL;
    }
    if (folder -> p -> fh_folder) {
	fclose(folder -> p -> fh_folder);	
	folder -> p -> fh_folder = NULL;
    }
#ifdef	USE_DOTLOCK_LOCKING
    if (folder -> p -> a.spool.lockfile) {
	free(folder -> p -> a.spool.lockfile);
	folder -> p -> a.spool.lockfile = NULL;
    }
#endif
    free(folder -> p);
    folder -> p = NULL;
}


static int mbx_sessionlock_filehandle P_((struct folder_info *folder,
					  enum sessionlock_mode mode));

static int mbx_sessionlock_filehandle(folder,mode)
     struct folder_info *folder;
     enum sessionlock_mode mode;
{
    int status = 0;

    if (mode == SESSIONLOCK_CHECK) {
	int code = 0;
	if ((code = can_open(folder->cur_folder_sys, "r+")) != 0 && 
	    code != ENOENT) {
	    DPRINT(Debug,1,(&Debug, 
			    "Error: given file %s as folder - unreadable (%s)!\n", 
			    folder->cur_folder_sys, 
			    error_description(code)));
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantOpenFolderRead,
			      "Can't open folder '%S' for reading: %s"), 
		      folder->cur_folder_disp,
		      error_description(code));
	    status = 0;
	    goto clean;
	}
	DPRINT(Debug,12,(&Debug, 
			 "mbx_sessionlock_filehandle: %s SESSIONLOCK_CHECK OK %s\n",
			 folder->cur_folder_sys,
			 code ? error_description(code) : ""));
    }

    if (mode == SESSIONLOCK_REOPEN && folder->p->fh_folder) {
	fclose(folder->p->fh_folder);
	folder->p->fh_folder = NULL;
    }

    status = 1;

 clean:
    return status;
}     

static int mbx_sessionlock_read_only P_((struct folder_info *folder,
				       enum sessionlock_mode mode));

static int mbx_sessionlock_read_only(folder,mode)
     struct folder_info *folder;
     enum sessionlock_mode mode;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_sessionlock_read_only: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (mode == SESSIONLOCK_CHECK) {
	if ((errno = can_open(folder->cur_folder_sys, 
			      "r")) != 0) {
	    int err1 = errno;
	    DPRINT(Debug,1,(&Debug, 
			    "Error: given file %s as folder - unreadable (%s)!\n", 
			    folder->cur_folder_sys, 
			    error_description(err1)));
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantOpenFolderRead,
			      "Can't open folder '%S' for reading: %s"), 
		      folder->cur_folder_disp,
		      error_description(err1));
	    status = 0;
	    goto clean;
	}
    }
    
    if (mode == SESSIONLOCK_REOPEN && folder->p->fh_folder) {
	fclose(folder->p->fh_folder);
	folder->p->fh_folder = NULL;
    }

    if (mode == SESSIONLOCK_TRUNCATE) {
	DPRINT(Debug,10,(&Debug,  
			 "mbx_sessionlock_read_only: mode == SESSIONLOCK_TRUNCATE (ignored) : %s\n",
			 folder->cur_folder_sys));
    }

    if (!folder->p->fh_folder) {	
	folder->p->fh_folder = fopen(folder->cur_folder_sys,"r");
	
	if (!folder->p->fh_folder) {
	    int err = errno;
	    
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailOnOpenNewmbox,
			      "Mailbox %S open failed: %s"),
		      folder->cur_folder_disp,
		      error_description(err));
	    DPRINT(Debug,1,(&Debug, 
			    "fail on open in mbx_sessionlock_non_spool, file %s!!\n",
			    folder->cur_folder_sys));
	    status = 0;
	    goto clean;
	}
	DPRINT(Debug,10,(&Debug, 
			 "Mailfile (folder) opened: %s\n",
			 folder->cur_folder_sys));
    } else
	rewind(folder->p->fh_folder);

    if (mode == SESSIONLOCK_NONE) {
	status = 1;
	goto clean;
    }

    if (lockfolders) {
	switch (GrabRead_the_file(fileno(folder -> p->fh_folder))) {
	case FLOCKING_OK:
	    DPRINT(Debug,1,(&Debug,  
			    "Folder locked (%s).\n",
			    folder -> cur_folder_sys));
	    break;
	case FLOCKING_RETRY:
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmAlreadyRW,
			      "You seem to have ELM already reading (read-write) this mail!"));	
	    status = 0;
	    goto clean;	    

	case	FLOCKING_FAIL:
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveErrorLockFolder,
			      "Error encountered while attempting to lock folder %S: %s"), 
		      folder->cur_folder_disp,
		      error_description(errno));

	    status = 0;
	    goto clean;
	}
    }

    status = 1;

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_sessionlock_read_only=%d\n",status));
    return status;
}

static void set_closeonexec_folder P_((struct folder_info *folder));
static void set_closeonexec_folder(folder)
     struct folder_info *folder;
{
    int r;

#ifdef FD_CLOEXEC
    r = fcntl(fileno(folder -> p->fh_folder), F_SETFD, FD_CLOEXEC);
#else
    r = fcntl(fileno(folder -> p->fh_folder), F_SETFD, 1);
#endif    

    if (-1 == r) {
	int err = errno;

	DPRINT(Debug,1,(&Debug, 
			"Failed to set close-on-exec flag for %s: %s\n",
			folder->cur_folder_sys,
			error_description(err)));
    } else {
	DPRINT(Debug,11,(&Debug, 
			"Set close-on-exec flag for %s\n",
			 folder->cur_folder_sys));
    }
}


static int mbx_sessionlock_non_spool P_((struct folder_info *folder,
				       enum sessionlock_mode mode));

static int mbx_sessionlock_non_spool(folder,mode)
     struct folder_info *folder;
     enum sessionlock_mode mode;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_sessionlock_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (!mbx_sessionlock_filehandle(folder,mode)) {
	status = 0;
	goto clean;
    }

    if (mode == SESSIONLOCK_TRUNCATE) {
	DPRINT(Debug,11,(&Debug, 
			 "mbx_sessionlock_non_spool: mode == SESSIONLOCK_TRUNCATE (ignored) : %s\n",
			 folder->cur_folder_sys));
    }

    if (!folder->p->fh_folder) {	
	folder->p->fh_folder = fopen(folder->cur_folder_sys,"r+");

	if (!folder->p->fh_folder) {
	    int err = errno;
	    
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailOnOpenNewmbox,
			      "Mailbox %S open failed: %s"),
		      folder->cur_folder_disp,
		      error_description(err));
	    DPRINT(Debug,1,(&Debug, 
			    "fail on open in mbx_sessionlock_non_spool, file %s!!\n",
			    folder->cur_folder_sys));
	    status = 0;
	    goto clean;
	}
	DPRINT(Debug,10,(&Debug, 
			 "Mailfile (folder) opened: %s\n",
			 folder->cur_folder_sys));
	set_closeonexec_folder(folder);
    } else
	rewind(folder->p->fh_folder);

    if (mode == SESSIONLOCK_NONE) {
	status = 1;
	goto clean;
    }

    if (lockfolders) {
	switch (Grab_the_file(fileno(folder -> p->fh_folder))) {
	case FLOCKING_OK:
	    DPRINT(Debug,1,(&Debug, 
			    "Folder locked (%s).\n",
			    folder -> cur_folder_sys));
	    break;
	case FLOCKING_RETRY:
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmAlreadyRunning1,
			      "You seem to have ELM already reading this mail!"));	
	    status = 0;
	    goto clean;	    

	case	FLOCKING_FAIL:
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveErrorLockFolder,
			      "Error encountered while attempting to lock folder %S: %s"), 
		      folder->cur_folder_sys,
		      error_description(errno));

	    status = 0;
	    goto clean;
	}
    }

    status = 1;

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_sessionlock_non_spool=%d\n",status));
    return status;
}


static int mbx_sessionlock_spool P_((struct folder_info *folder,
				       enum sessionlock_mode mode));

static int mbx_sessionlock_spool(folder,mode)
     struct folder_info *folder;
     enum sessionlock_mode mode;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_sessionlock_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (!mbx_sessionlock_filehandle(folder,mode)) {
	status = 0;
	goto clean;
    }

    if (!folder->p->fh_folder) {
	folder->p->fh_folder = fopen(folder->cur_folder_sys,"r+");
	if (!folder->p->fh_folder) {
	    if (errno != ENOENT) {
		int err = errno;
	    
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailOnOpenNewmbox,
				  "Mailbox %S open failed: %s"),
			  folder->cur_folder_disp,
			  error_description(err));
		DPRINT(Debug,1,(&Debug, 
				"fail on open in mbx_sessionlock_non_spool, file %s!!\n",
				folder->cur_folder_sys));
		status = 0;
		goto clean;
	    } else {
		folder->mailfile_size = 0;    
		/* must non-existant folder */
	    }
	}
	DPRINT(Debug,10,(&Debug, 
			 "Mailfile (folder) opened: %s %s\n",
			 folder->cur_folder_sys,
			 folder->p->fh_folder ? "" : " (non existant)"));
	if (folder->p->fh_folder)
	    set_closeonexec_folder(folder);
    } else {
	rewind(folder->p->fh_folder);
    }

    switch(mode) {
	int need_reopen;
    case SESSIONLOCK_NONE:
	status = 1;
	goto clean;
    case SESSIONLOCK_TRUNCATE:
	need_reopen = 1;
#ifdef FTRUNCATE  
	if (folder->p->fh_temp) {
	    rewind(folder->p->fh_temp);
	    if (0 == ftruncate(fileno(folder->p->fh_temp),0)) {
		need_reopen = 0;
		DPRINT(Debug,10,(&Debug, 
				 "truncate_tempfolder: tempfile %s truncated (not recreated)\n",
				 folder->cur_tempfolder));
	    }
	    else 
		lib_error(CATGETS(elm_msg_cat, ElmSet, 
				  ElmSorryCantTruncateTemp,
				  "Sorry, can't truncate the temp file %s [%s]!"),
			  folder -> cur_tempfolder, error_description(errno));
	    /* IF FAIL REOPEN IT INSTEAD */
	}
#endif
	if (!need_reopen)
	    break;  /* DONE */
	if (folder->p->fh_temp) {
	    fclose (folder->p->fh_temp);
	    folder->p->fh_temp = NULL;
	}

	if (0 != unlink(folder -> cur_tempfolder)) {
	    int err = errno;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSorryCantTruncateTemp,
			      "Sorry, can't truncate the temp file %s [%s]!"),
		      folder -> cur_tempfolder, error_description(err));    
	    status = 0;
	    goto clean;
	}
	goto create_it;
    case   SESSIONLOCK_REOPEN:
	if (folder -> p->fh_temp) {
	    int temp_handle;
	    fclose(folder -> p->fh_temp);
	    folder -> p->fh_temp = NULL;

	    if ( (temp_handle = open(folder-> cur_tempfolder, 
				     O_RDWR,
				     0600)) == -1 ||
		 NULL == (folder -> p->fh_temp = fdopen(temp_handle,"w+"))) {
		int err = errno;
		
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSorryCantReopenTemp,
				  "Sorry, can't reopen the temp file %s [%s]!"),
			  folder -> cur_tempfolder, error_description(err));  
		
		if (-1 != temp_handle)
		    close(temp_handle);
  
		status = 0;
		goto clean;
	    }

	    break;
	}
	/* FALLTHRU */
    case SESSIONLOCK_NORMAL:
    case SESSIONLOCK_CHECK:
    create_it:
	if (!folder -> p->fh_temp) {
	    int temp_handle;

	    /* If we are changing files and we are changing to a spool file,
	     * make sure there isn't a temp file for it, because if
	     * there is, someone else is using ELM to read the new file,
	     * and we don't want to be reading it at the same time.
	     */
    
	    if ( (temp_handle = open(folder-> cur_tempfolder, 
				     O_RDWR|O_CREAT|O_EXCL,
				     0600)) == -1) {
		int err = errno;
		
		if (err == EEXIST) {
		    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmAlreadyRunningX,
				      "You seem to have ELM already reading this mail!You may not have two copies of\n\
ELM running simultaneously. If this is in error, then you'll need to remove \n\
the following file: %s"),
			      folder -> cur_tempfolder);
#if POLL_METHOD	  
		    wait_for_timeout(2 + sleepmsg);
#else
		    sleep(2 + sleepmsg);
#endif		    
		    status = 0;
		    goto clean;	    
		}
	    }
	    if (-1 == temp_handle || 
		NULL == (folder -> p->fh_temp = fdopen(temp_handle,"w+"))) {
		int err = errno;
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailedCreateTmpFolder,
				  "Failed to create %.50s: %.60s"),
			  folder -> cur_tempfolder,
			  error_description(err));
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmIGiveUp,
				  "Ahhhh... I give up."));
		
		if (-1 != temp_handle)
		    close(temp_handle);
		
		status = 0;
		goto clean;	    
	    }
	    
	    DPRINT(Debug,1,(&Debug, 
			    "Creating tempfile (%s).\n",
			    folder -> cur_tempfolder));
	    
	    elm_chown(folder->cur_tempfolder, userid, groupid);
	    chmod(folder -> cur_tempfolder, 0700);	
	    /* shut off file for other people! */	    
	}
	break;
    }
    status = 1;

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_sessionlock_spool=%d\n",status));
    return status;
}

void mbx_flush_temp(folder) 
     struct folder_info *folder;
{
    DPRINT(Debug,12,(&Debug, 
		     "mbx_flush_temp: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    
    if (!folder->p->fh_temp)
	return;
    
#ifdef ultrix
    /** Ultrix returns an error if fflush is called on a file opened
	for read only, so we have to account for this.
    **/
    
    if (folder->p->fh_temp->_flag & (_IOREAD|_IORW) == _IOREAD)
	return;
#endif
    fflush(folder->p->fh_temp);
    return;    
}

static void mbx_flush_read_only P_((struct folder_info *folder));
static void mbx_flush_read_only(folder) 
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug, 
		     "mbx_flush_read_only (dummy): folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

}

static void mbx_flush_non_spool P_((struct folder_info *folder));
static void mbx_flush_non_spool(folder) 
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug, 
		     "mbx_flush_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (!folder->p->fh_folder)
	return;

#ifdef ultrix
	/** Ultrix returns an error if fflush is called on a file opened
	    for read only, so we have to account for this.
	**/

	if (folder->p->fh_folder->_flag & (_IOREAD|_IORW) == _IOREAD)
	    return;
#endif
	fflush(folder->p->fh_folder);
	return;

}

static void mbx_flush_spool P_((struct folder_info *folder));
static void mbx_flush_spool(folder) 
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug, 
		     "mbx_flush_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    mbx_flush_temp(folder);
    mbx_flush_non_spool(folder);    
}


static int mbx_ferror_non_spool P_((struct folder_info *folder, int clean));
static int mbx_ferror_non_spool(folder,clean) 
     struct folder_info *folder; 
     int clean; 
{
    int status;
    DPRINT(Debug,11,(&Debug, 
		     "mbx_ferror_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    status = ferror(folder->p->fh_folder);
    if (clean)
	clearerr(folder->p->fh_folder);

    DPRINT(Debug,11,(&Debug, 
		     "mbx_ferror_non_spool=%d\n",status));
    return status;
}


static int mbx_ferror_spool P_((struct folder_info *folder, int clean));
static int mbx_ferror_spool(folder,clean) 
     struct folder_info *folder; 
     int clean; 
{
    int status;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_ferror_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if(!folder->p->fh_folder) {
	DPRINT(Debug,11,(&Debug, 
			 "mbx_ferror_spool: non-existent -- no error.\n"));
	status = 0;
    } else {
	status = ferror(folder->p->fh_folder);
	if (clean)
	    clearerr(folder->p->fh_folder);
    }

    if (folder->p->fh_temp) {
	if (ferror(folder->p->fh_temp))
	    status = 1;
	if (clean)
	    clearerr(folder->p->fh_temp);
    }

    DPRINT(Debug,11,(&Debug, 
		     "mbx_ferror_spool=%d\n",status));
    return status;
}

static void mbx_zero_rs_fields_file P_((struct read_folder_state *rs));
static void mbx_zero_rs_fields_file(rs)
     struct read_folder_state *rs;
{
    DPRINT(Debug,11,(&Debug, 
		     "mbx_zero_rs_fields_file: rs=%p\n",
		     rs));

    rs -> a.file.next_line     = NULL;
    rs -> a.file.next_line_len = 0;    
}

static void mbx_free_rs_fields_file P_((struct read_folder_state *rs));
static void mbx_free_rs_fields_file(rs)
     struct read_folder_state *rs;
{
    DPRINT(Debug,11,(&Debug, 
		     "mbx_free_rs_fields_file: rs=%p\n",
		     rs));

    if (rs -> a.file.next_line) {
	free(rs -> a.file.next_line);
	rs -> a.file.next_line = NULL;
    }
    rs -> a.file.next_line_len = 0;        
}


static int mbx_prepare_seek_folder P_((struct folder_info *folder,
				       int add_new_only,
				       READ_STATE read_state_ptr));
static int mbx_prepare_seek_folder(folder,add_new_only,read_state_ptr)
     struct folder_info *folder;
     int add_new_only;
     READ_STATE read_state_ptr;
{
    int status = 0;
    long result;

    if (add_new_only) {
	if (fseek(folder -> p->fh_folder, 
		  folder -> mailfile_size, SEEK_SET) == -1) {
	    int err = errno;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntSeekEndFolder,
				"Couldn't seek to %ld (end of folder) in %S: %s"),
		      folder-> mailfile_size, 
		      folder-> cur_folder_disp,   
		      error_description(err));
	    DPRINT(Debug,1,(&Debug, 
			    "Error: Couldn't seek to end of folder %s: (offset %ld) Errno %s (%s)\n",
			    folder -> cur_folder_sys, 
			    folder -> mailfile_size, 
			    error_description(err), 
			    "mbx_prepare_seek_folder"));
	    status = 0;
	    goto clean;
	}
	/* read_state_ptr->count  = message_count; */	  /* next available  */
	read_state_ptr->fbytes = folder-> mailfile_size;  /* start correctly */
    }

    result = file_bytes(folder->cur_folder_sys);
    if (-1L == result) {
	status = 0;
	goto clean;
    }
    folder -> mailfile_size = result;

    status = 1;

 clean:
    return status;
}

static int mbx_prepare_read_non_spool P_((struct folder_info *folder,
					  enum prepare_mode mode,
					  READ_STATE read_state_ptr));
static int mbx_prepare_read_non_spool(folder,mode,read_state_ptr)
     struct folder_info *folder;
     enum prepare_mode mode;
     READ_STATE read_state_ptr;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_prepare_read_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                          : read_state_ptr=%p\n",
		     read_state_ptr));

    
    if (PREPARE_ACCESS          == mode)
	panic("MBX PANIC",__FILE__,__LINE__,"mbx_prepare_read_non_spool",
	      "mode == PREPARE_ACCESS",0);

    if (!mbx_prepare_seek_folder(folder, 
				 PREPARE_NEW_ONLY        == mode ||
				 PREPARE_NEW_ONLY_NOLOCK == mode ||
				 PREPARE_ACCESS          == mode,
				 read_state_ptr)) {
	status = 0;
	goto clean;
    }
    status = 1;

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_prepare_read_non_spool=%d\n",status));
    return status;
}

static int mbx_prepare_read_spool P_((struct folder_info *folder,
				      enum prepare_mode mode,
				      READ_STATE read_state_ptr));
static int mbx_prepare_read_spool(folder,mode,read_state_ptr)
     struct folder_info *folder;
     enum prepare_mode mode;
     READ_STATE read_state_ptr;
{
    int status = 0;
    int add_new_only =  PREPARE_NEW_ONLY == mode ||
	                PREPARE_NEW_ONLY_NOLOCK == mode ||
	                PREPARE_ACCESS  == mode;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_prepare_read_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                      : read_state_ptr=%p\n",
		     read_state_ptr));

    if (PREPARE_ACCESS          == mode)
	panic("MBX PANIC",__FILE__,__LINE__,"mbx_prepare_read_spool",
	      "mode == PREPARE_ACCESS",0);
    
    if (PREPARE_NOLOCK == mode || 
	PREPARE_NEW_ONLY_NOLOCK == mode ||
	PREPARE_ACCESS == mode) {
	DPRINT(Debug,11,(&Debug, 
			 "mbx_prepare_read_spool: mode == PREPARE_NOLOCK (or PREPARE_ACCESS)\n"));
    } else if (folder -> p->a.spool.lock_state == ON) {
	DPRINT(Debug,1,(&Debug, 
			"mbx_prepare_read_spool: %s already locked.\n",
			folder->cur_folder_sys));
    } else {
	/* ensure no mail arrives while we do this! */
	if (!lock_folder(INCOMING, folder)) {
	    status = 0;
	    goto clean;
	}
    }

    if (add_new_only) {
	if (!folder->p->fh_temp) {
	    DPRINT(Debug,11,(&Debug, 
			     "mbx_prepare_read_spool -- NO temp file %s\n",
			     folder->cur_tempfolder));
	} else if (fseek(folder -> p->fh_temp, 
		  folder -> mailfile_size, SEEK_SET) == -1) {
	    int err = errno;
	    
	    unlock_folder(0,folder);	/* remove lock file! */
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntSeekTempEnd,
			      "\nCouldn't fseek to end of temp mbox.\n"));
	    lib_error(FRM("** %s. **\n"), error_description(err));
	    DPRINT(Debug,1,(&Debug, 
			    "Error: Couldn't fseek to end of reopened temp mbox.  errno %s (%s)\n",
			    error_description(err), "mbx_prepare_read_spool"));
	    status = 0;
	    goto clean;	    
	}
    }

    if (!mbx_prepare_seek_folder(folder,add_new_only,read_state_ptr)) {
	status = 0;
	goto clean;
    }
    status = 1;

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_prepare_read_spool=%d\n",status));
    return status;
}



static int mbx_end_read_non_spool P_((struct folder_info *folder,
				      READ_STATE read_state_ptr,
				      int silent));

static int mbx_end_read_non_spool(folder,read_state_ptr,silent)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     int silent;
{
    int status = 0;
    DPRINT(Debug,11,(&Debug, 
		     "mbx_end_read_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                  : read_state_ptr=%p\n",
		     read_state_ptr));

    rewind(folder->p->fh_folder);
    status = 1;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_end_read_non_spool=%d\n",status));
    return status;
}


static int mbx_end_read_spool P_((struct folder_info *folder,
				  READ_STATE read_state_ptr,
				  int silent));

static int mbx_end_read_spool(folder,read_state_ptr,silent)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     int silent;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_end_read_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                  : read_state_ptr=%p\n",
		     read_state_ptr));

    if (PREPARE_NOLOCK == read_state_ptr->mode ||
	PREPARE_NEW_ONLY_NOLOCK == read_state_ptr->mode ||
	PREPARE_ACCESS == read_state_ptr->mode) {
	DPRINT(Debug,11,(&Debug, 
			 "mbx_end_read_spool: PREPARE_NOLOCK == mode (or PREPARE_ACCESS)\n"));
    } else 
	unlock_folder(0, folder);

    if (!folder->p->fh_temp) {
	DPRINT(Debug,11,(&Debug, 
			 "mbx_end_read_spool=1 -- NO temp file %s\n",
			 folder->cur_tempfolder));
	return 1;
    }

    if ((ferror(folder->p->fh_temp)) || 
	(fflush(folder->p->fh_temp) == EOF)) {
	if (!silent) {
	    int err = errno;
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFlushOnTempFailed,
			      "Flush on temp file %s failed: %s"), 
		      folder -> cur_tempfolder,
		      error_description(err));
	}
	DPRINT(Debug,1,(&Debug, 
		   "Can't flush on temp file %s!!\n",
		   folder -> cur_tempfolder));
	status = 0;
	goto clean;
    }
	 
    /* sanity check on append - is resulting temp file longer??? */
    if ( file_bytes(folder-> cur_tempfolder) != 
	 folder-> mailfile_size) {
	if (!silent) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLengthNESpool,
			      "\nnewmbox - length of mbox. != spool mailbox length!!\n"));
	}
	DPRINT(Debug,1,(&Debug,  
			"newmbox - mbox. != spool mail length"));
	
    }
	  
    rewind(folder->p->fh_temp);
    status = 1;
    
 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_end_read_spool=%d\n",status));
    return status;
}


static int read_line P_((FILE *fh,char **buffer, int *len, int max_read));
static int read_line(fh,buffer,len,max_read)
     FILE *fh;
     char **buffer; 
     int *len; 
     int max_read;
{
    int       LEN = 0;
    char * BUFFER = NULL;
    int alloced = 1024;
    int ch;

    *buffer = NULL;
    *len    = 0;

    if (max_read < 1)
	return 0;

    if (alloced > max_read+1) 
	alloced = max_read+1;

    BUFFER = safe_malloc(alloced);
    
    while (LEN < max_read) {
	ch = getc(fh); /* Macro, faster than  fgetc() ! */

	if (ch == EOF) {

	    if (0 == LEN) {
		DPRINT(Debug,65,(&Debug, 
				 "read_line=0: EOF\n"));

		free(BUFFER);
		return 0;
	    }

	    break;
	}

	if (LEN+1 > alloced) {
	    int n = alloced + 1024;

	    if (n > max_read+1)
		n = max_read+1;

	    BUFFER = safe_realloc(BUFFER,n);
	    alloced = n;
	}
	BUFFER[LEN++] = ch;

	if (ch == '\n')
	    break;
    }

    BUFFER = safe_realloc(BUFFER,LEN+1);
    BUFFER[LEN] = '\0';
    
    *len    = LEN;
    *buffer = BUFFER;


    DPRINT(Debug,65,(&Debug, 
		     "read_line=1: len=%d, buffer=%.*s",
		     *len,*len,(*buffer) ? (*buffer) : ""));
    if (*len < 1 || !(*buffer) || (*buffer)[*len -1] != '\n') {
	DPRINT(Debug,65,(&Debug, 
			 "\nread_line: NO NEWLINE\n"));
    } 
    return 1;
}

static int mbx_read_buffered_line P_((struct folder_info *folder,
				      READ_STATE read_state_ptr,
				      char **buffer, int *len));
static int mbx_read_buffered_line(folder,read_state_ptr,buffer,len)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
{
    if(read_state_ptr ->a.file.next_line) {
	*buffer = read_state_ptr -> a.file.next_line;
	*len    = read_state_ptr -> a.file.next_line_len;
    } else {
	
	if (!read_line(folder->p->fh_folder,buffer,len,
		       folder->mailfile_size-read_state_ptr->fbytes))
	    return 0;

	read_state_ptr -> a.file.next_line      = *buffer;
	read_state_ptr -> a.file.next_line_len  = *len;
	
    }
    
    DPRINT(Debug,60,(&Debug, 
		     "mbx_read_buffered_line: len=%d, buffer=%.*s",
		     *len,*len,(*buffer) ? (*buffer) : ""));
    if (*len < 1 || !(*buffer) || (*buffer)[*len -1] != '\n') {
	DPRINT(Debug,60,(&Debug, 
			 "\nmbx_read_buffered_line: NO NEWLINE\n"));
    } 

    return 1;
}

static void mbx_accept_buffered_line P_((struct folder_info *folder,
					 READ_STATE read_state_ptr,
					 char **buffer, int *len));
static void mbx_accept_buffered_line(folder,read_state_ptr,buffer,len)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
{
    if (*buffer != read_state_ptr -> a.file.next_line)
       	panic("MBX PANIC",__FILE__,__LINE__,"mbx_accept_buffered_line",
	      "Bad buffer!",0);

    if (!*buffer)
	return;

    if (*len < 1 || (*buffer)[*len -1] != '\n') {
    } else {
	read_state_ptr -> linecounter++;
    }
    read_state_ptr -> a.file.next_line     = NULL;
    read_state_ptr -> fbytes       += read_state_ptr -> a.file.next_line_len;
    read_state_ptr -> a.file.next_line_len = 0;

    free(*buffer);
    *buffer = NULL;
    *len    = 0;
}

#ifdef MMDF
static int mbx_copy_envelope_check_MMDF P_((char *buffer,int len));
static int mbx_copy_envelope_check_MMDF(buffer,len)
     char *buffer;
     int len; 
{
    if (strcmp(buffer, MSG_SEPARATOR) == 0)
	return 1;
    return 0;
}
#endif


static int mbx_copy_envelope_non_spool P_((struct folder_info *folder,
					   READ_STATE read_state_ptr,
					   struct header_rec *entry,
					   int force));
static int mbx_copy_envelope_non_spool(folder,read_state_ptr,entry,force)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     struct header_rec *entry;
     int force;
{
    char * buffer = NULL;
    int  len;

    /* NO COPY */
    int status = 0;
    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                           : read_state_ptr=%p\n",
		     read_state_ptr));

    /* !!! */
    if (PREPARE_ACCESS == read_state_ptr->mode) 
	panic("MBX PANIC",__FILE__,__LINE__,"mbx_copy_envelope_non_spool",
	      "Skipping not supported!!",0);


    read_state_ptr -> linecounter   = 0;      /* Linecounter of current
					         message */
    entry->offset = read_state_ptr -> fbytes; /* Offset of current message */


    if ( FLAG1_CHECKNEW & folder -> p -> flags1 ) {
	/* Really treat as mailbox and not as folder ... */
	entry->status  = VISIBLE | NEW | UNREAD; /* Default status of message    */

    } else {
	int de = give_dt_enumerate_as_int(&def_folder_status);

	entry->status = VISIBLE | UNREAD;         /* Default status of message */

	switch(de) {
	case FOLDER_STATUS_READ: 
	    entry->status = VISIBLE; 
	    break;
	case FOLDER_STATUS_OLD:
	    entry->status = VISIBLE | UNREAD;
	    break;
	case FOLDER_STATUS_NEW:
	    entry->status = VISIBLE | NEW | UNREAD;
	    break;
	default:
	    DPRINT(Debug,1,(&Debug,
			    "default-folder-status=%d BAD\n",
			    de));
	}
	DPRINT(Debug,11,(&Debug, "           status=%x -- def_folder_status=%d\n",
			 entry->status,entry->status));
    }

    if (!mbx_read_buffered_line(folder,read_state_ptr,
				     &buffer,&len)) {
	status = 0;
	goto clean;
    }
    if (0 == len) {
	status = 0;
	goto clean;
    }

#ifdef MMDF    
    if (mbx_copy_envelope_check_MMDF(buffer,len)) {
	mbx_accept_buffered_line(folder,read_state_ptr,
				 &buffer,&len);
	if (!mbx_read_buffered_line(folder,read_state_ptr,
					 &buffer,&len)) {
	    status = 0;
	    goto clean;
	}	
	status = 1;
    } else {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFolderCorrupt,
			  "Folder is corrupt!!  I can't read it!!"));
	status = -1;
	goto clean;
    }
#endif

    if (real_from(buffer,entry)) {
	mbx_accept_buffered_line(folder,read_state_ptr,
				      &buffer,&len);
	status = 1;

	while (mbx_read_buffered_line(folder,read_state_ptr,
					   &buffer,&len) &&
	       first_word_nc(buffer,">From ")) {
	    forwarded(buffer+6, entry); /* return address */
	    mbx_accept_buffered_line(folder,read_state_ptr,
					  &buffer,&len);	    
	}

    } else if (0 == status) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFolderCorrupt,
			  "Folder is corrupt!!  I can't read it!!"));
	status = -1;
    }

 clean:

    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_non_spool=%d\n",
		     status));

#if 0
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"mbx_copy_envelope_non_spool",
	      "Bad magic number (read state)",0);
#endif

    return status;
}


int mbx_copy_line_to_temp(folder,buffer,len)
     struct folder_info *folder;
     char *buffer; 
     int len;
{
    if (!folder->p->fh_temp) {
	DPRINT(Debug,15,(&Debug, 
			 "mbx_copy_line_to_temp=1 -- NO temp file %s\n",
			 folder->cur_tempfolder));
	return 1;
    }

    if (fwrite(buffer, 1, len, folder->p->fh_temp) != len) {
	int err = errno;

	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmWriteToTempFailed,
			  "\nWrite to temp file %s failed!!\n"),
		  folder->cur_tempfolder);       
	lib_error(FRM("** %s. **\n"), error_description(err));

	DPRINT(Debug,1,(&Debug, 
		   "Can't write to temp file %s!!\n",
		   folder->cur_tempfolder));
	return 0;
    }
    DPRINT(Debug,15,(&Debug, 
		     "mbx_copy_line_to_temp=1 -> %.*s",
		     len,buffer));
    if (len < 1 || buffer[len-1] != '\n') {
	DPRINT(Debug,15,(&Debug, 
			 "\nmbx_copy_line_to_temp <-- NO NEWLINE\n"));
    }

    return 1;
}



static int mbx_copy_envelope_spool P_((struct folder_info *folder,
				       READ_STATE read_state_ptr,
				       struct header_rec *entry,
				       int force));
static int mbx_copy_envelope_spool(folder,read_state_ptr,entry,force)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     struct header_rec *entry;
     int force;
{
    char * buffer = NULL;
    int  len;

    /* COPY */
    int status = 0;
    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                       : read_state_ptr=%p\n",
		     read_state_ptr));

    /* !!! */
    if (PREPARE_ACCESS == read_state_ptr->mode) 
	panic("MBX PANIC",__FILE__,__LINE__,"mbx_copy_envelope_spool",
	      "Skipping not supported!!",0);

    read_state_ptr -> linecounter   = 0;   /* Linecounter of current message */
    entry->status  = VISIBLE | NEW | UNREAD; /* Default status of message    */

    
    if (!folder->p->fh_folder) {
	DPRINT(Debug,11,(&Debug, 
			 "                      : folder not open...\n"));
	status = 0;
	goto clean;
    } 

    do {
	entry->offset = read_state_ptr -> fbytes; 
	/* Offset of current message */

	if (!mbx_read_buffered_line(folder,read_state_ptr,
					 &buffer,&len)) {
	    status = 0;
	    goto clean;
	}
	if (0 == len) {
	    status = 0;
	    goto clean;
	}
		
	if ((len == 1 && 0 == memcmp(buffer,"\n",len)) ||
	    (len == 2 && 0 == memcmp(buffer,"\r\n",len))) {
	    if (!mbx_copy_line_to_temp(folder,buffer,len)) {
		status = 0;
		goto clean;
	    }

	    mbx_accept_buffered_line(folder,read_state_ptr,
					  &buffer,&len);
	} else
	    break;
    } while (1); 

#ifdef MMDF
    if (mbx_copy_envelope_check_MMDF(buffer,len)) {
	if (!mbx_copy_line_to_temp(folder,buffer,len)) {
	    status = 0;
	    goto clean;
	}
	mbx_accept_buffered_line(folder,read_state_ptr,
				      &buffer,&len);
	if (!mbx_read_buffered_line(folder,read_state_ptr,
					 &buffer,&len)) {
	    status = 0;
	    goto clean;
	}	
	status = 1;
    } else {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFolderCorrupt,
			  "Folder is corrupt!!  I can't read it!!"));
	status = -1;
	goto clean;
    }
#endif

    if (real_from(buffer,entry)) {
	if (!mbx_copy_line_to_temp(folder,buffer,len)) {
	    status = 0;
	    goto clean;
	}

	mbx_accept_buffered_line(folder,read_state_ptr,
				      &buffer,&len);
	status = 1;

	while (mbx_read_buffered_line(folder,read_state_ptr,
					   &buffer,&len) &&
	       first_word_nc(buffer,">From ")) {
	    forwarded(buffer+6, entry); /* return address */

	    if (!mbx_copy_line_to_temp(folder,buffer,len)) {
		status = 0;
		goto clean;
	    }
	    mbx_accept_buffered_line(folder,read_state_ptr,
					  &buffer,&len);	    
	}

    } else if (0 == status) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFolderCorrupt,
			  "Folder is corrupt!!  I can't read it!!"));
	status = -1;
    }


 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_spool=%d\n",
		     status));
    return status;
}



static CONST char * mbx_is_forwarded_spool P_((struct folder_info *folder,
					      READ_STATE read_state_ptr));
static CONST char * mbx_is_forwarded_spool(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    char * buffer = NULL;
    CONST char * status = NULL; 
    int  len;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_is_forwarded_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                      : read_state_ptr=%p\n",
		     read_state_ptr));
    

    if (!folder->p->fh_folder) {
	DPRINT(Debug,11,(&Debug, 
			 "                      : folder not open...\n"));
    } else {
	if (!mbx_read_buffered_line(folder,read_state_ptr,
				    &buffer,&len)) {
	    status = NULL;
	    goto clean;
	}

	if (len > 11 && first_word_nc(buffer, "forward to "))
	    status = buffer + 11;
    }

 clean:

    DPRINT(Debug,11,(&Debug, 
		     "mbx_is_forwarded_spool=%s\n",
		     status ? status : "NULL"));
    return status;
}

void append_buffer(buffer,len,buffer1,len1)
     char **buffer; 
     int *len;
     char *buffer1; 
     int len1;
{
    int res = *len + len1 + 1;

    *buffer = safe_realloc(*buffer,res);

    /* bcopy is defined on hdrs/defs.h */
    bcopy(buffer1,(*buffer)+(*len),len1); 
    (*buffer)[(*len) + len1] = '\0';
    (*len) += len1;
}

static int mbx_copy_header_non_spool P_((struct folder_info *folder,
				       READ_STATE read_state_ptr,
				       char **buffer, int *len));
static int mbx_copy_header_non_spool(folder,read_state_ptr,buffer,len)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
{
    char *buffer1 = NULL;
    int len1;
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_header_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                         : read_state_ptr=%p\n",
		     read_state_ptr));


    if (!mbx_read_buffered_line(folder,read_state_ptr,
				     &buffer1,&len1)) {
	status = 0;
	goto clean;
    }

    if ((len1 == 1 && 0 == memcmp(buffer1,"\n",len1)) ||
	(len1 == 2 && 0 == memcmp(buffer1,"\r\n",len1))) {
	/* End of headers */
	mbx_accept_buffered_line(folder,read_state_ptr,
				      &buffer1,&len1);
	status = 0;
	goto clean;
    }
    
    if (NULL == memchr(buffer1,':',len1) ||
#ifdef MMDF
	mbx_copy_envelope_check_MMDF(buffer1,len1) ||
#endif
	0 == memcmp(buffer1,"From ",5)) {
	/* End of headers -- bad header */
	status = 0;
	goto clean;
    }

    do {
	append_buffer(buffer,len,buffer1,len1);
	mbx_accept_buffered_line(folder,read_state_ptr,
				 &buffer1,&len1);
	if (!mbx_read_buffered_line(folder,read_state_ptr,
					 &buffer1,&len1)) {
	    break;
	}
    } while (len1 > 0 && whitespace(buffer1[0]));
    status = 1;

 clean:
    /* Not need to free() -- buffer1 is same than next_line -buffer */

    if (!status) {
	if (*buffer) {
	    free(*buffer);
	    *buffer = NULL;
	}
    }

    DPRINT(Debug,50,(&Debug, 
		"mbx_copy_header_non_spool=%d | len=%d, buffer=%s",
		status,*len,
		*buffer ? *buffer : "NULL"));
    if (*len < 1 || !*buffer || (*buffer)[*len -1] != '\n') {
	DPRINT(Debug,50,(&Debug, 
		    "\nmbx_copy_header_non_spool <- NO NEWLINE\n"));
    }
    return status;
}

static int mbx_copy_header_spool P_((struct folder_info *folder,
				     READ_STATE read_state_ptr,
				     char **buffer, int *len));
static int mbx_copy_header_spool(folder,read_state_ptr,buffer,len)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
{
    char *buffer1 = NULL;
    int len1;

    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_header_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                     : read_state_ptr=%p\n",
		     read_state_ptr));

    if (!mbx_read_buffered_line(folder,read_state_ptr,
				     &buffer1,&len1)) {
	status = 0;
	goto clean;
    }

    if ((len1 == 1 && 0 == memcmp(buffer1,"\n",len1)) ||
	(len1 == 2 && 0 == memcmp(buffer1,"\r\n",len1))) {
	/* End of headers */
	if (!mbx_copy_line_to_temp(folder,buffer1,len1)) {
	    status = 0;
	    goto clean;
	}
	mbx_accept_buffered_line(folder,read_state_ptr,
				      &buffer1,&len1);
	status = 0;
	goto clean;
    }
    
    if (NULL == memchr(buffer1,':',len1) ||
#ifdef MMDF
	mbx_copy_envelope_check_MMDF(buffer1,len1) ||
#endif
	0 == memcmp(buffer1,"From ",5)) {
	/* End of headers -- bad header */
	status = 0;
	goto clean;
    }

    do {
	append_buffer(buffer,len,buffer1,len1);
	if (!mbx_copy_line_to_temp(folder,buffer1,len1)) {
	    status = 0;
	    goto clean;
	}
	mbx_accept_buffered_line(folder,read_state_ptr,
				      &buffer1,&len1);
	if (!mbx_read_buffered_line(folder,read_state_ptr,
					 &buffer1,&len1)) {
	    break;
	}
    } while (len1 > 0 && whitespace(buffer1[0]));
    status = 1;

 clean:
    /* Not need to free() -- buffer1 is same than next_line -buffer */

    if (!status) {
	if (*buffer) {
	    free(*buffer);
	    *buffer = NULL;
	}
    }

    DPRINT(Debug,50,(&Debug, 
		     "mbx_copy_header_spool=%d | len=%d, buffer=%s",
		     status,*len,
		     *buffer ? *buffer : "NULL"));
    if (*len < 1 || !*buffer || (*buffer)[*len -1] != '\n') {
	DPRINT(Debug,50,(&Debug, 
			 "\nmbx_copy_header_spool <- NO NEWLINE\n"));
    }
    return status;
}

static int copy_body_common P_((struct folder_info *folder,
				READ_STATE read_state_ptr,
				char **buf, int *len,
				long *content_remaining));
static int copy_body_common(folder,read_state_ptr,buf,len,
			    content_remaining)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buf; 
     int *len;
     long *content_remaining;
{
    char *buffer1 = *buf;
    int len1 = *len;
    int r = 0;

    if (!mbx_read_buffered_line(folder,read_state_ptr,
				     &buffer1,&len1)) {
	r = 0;
	goto clean;
    }

    if (*content_remaining < 1 && 
#ifdef MMDF
	mbx_copy_envelope_check_MMDF(buffer1,len1)
#else
	len1 > 5 && 'F' == buffer1[0] &&
	0 == memcmp(buffer1,"From ",5) &&
	real_from(buffer1,NULL)
#endif
	) {
	r = 0;
	goto clean;
    }

    r = 1;

 clean:
    *buf = buffer1;
    *len = len1;
    return r;
}

static int mbx_copy_body_non_spool P_((struct folder_info *folder,
				       READ_STATE read_state_ptr,
				       char **buffer, int *len,
				       long *content_remaining));


static int mbx_copy_body_non_spool(folder,read_state_ptr,buffer,len,
				   content_remaining)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
     long *content_remaining;
{
    char *buffer1;
    int len1;

    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_body_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                       : read_state_ptr=%p\n",
		     read_state_ptr));


    if (!copy_body_common(folder,read_state_ptr,
			  &buffer1,&len1,content_remaining)) {
	status = 0;
	goto clean;
    }


    append_buffer(buffer,len,buffer1,len1);
    mbx_accept_buffered_line(folder,read_state_ptr,
			     &buffer1,&len1);
    
    if (*content_remaining > *len)
	*content_remaining -= *len;
    else if (*content_remaining >= 0)
	*content_remaining = 0;
    status = 1;
    
 clean:
    /* buffer1 is same then next_line -buffer -- not need free() */

    if (!status) {
	if (*buffer) {
	    free(*buffer);
	    *buffer = NULL;
	}
    }

    DPRINT(Debug,50,(&Debug, 
		     "mbx_copy_body_non_spool=%d | len=%d, buffer=%s",
		     status,*len,
		     *buffer ? *buffer : "NULL"));
    if (*len < 1 || !*buffer || (*buffer)[*len -1] != '\n') {
	DPRINT(Debug,50,(&Debug, 
			 "\nmbx_copy_body_non_spool <- NO NEWLINE\n"));
    }
    return status;
}

static int mbx_copy_body_spool P_((struct folder_info *folder,
				   READ_STATE read_state_ptr,
				   char **buffer, int *len,
				   long *content_remaining));

static int mbx_copy_body_spool(folder,read_state_ptr,buffer,len,
				   content_remaining)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
     long *content_remaining;
{
    char *buffer1;
    int len1;
 
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_body_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                   : read_state_ptr=%p\n",
		     read_state_ptr));

    if (!copy_body_common(folder,read_state_ptr,
			  &buffer1,&len1,content_remaining)) {
	status = 0;
	goto clean;
    }

    append_buffer(buffer,len,buffer1,len1);
    if (!mbx_copy_line_to_temp(folder,buffer1,len1)) {
	status = 0;
	goto clean;
    }
    mbx_accept_buffered_line(folder,read_state_ptr,
			     &buffer1,&len1);
    
    if (*content_remaining > *len)
	*content_remaining -= *len;
    else if (*content_remaining >= 0)
	*content_remaining = 0;
    status = 1;

 clean:
    /* buffer1 is same then next_line -buffer -- not need free() */

    if (!status) {
	if (*buffer) {
	    free(*buffer);
	    *buffer = NULL;
	}
    }

    DPRINT(Debug,50,(&Debug, 
		     "mbx_copy_body_spool=%d | len=%d, buffer=%s",
		     status,*len,
		     *buffer ? *buffer : "NULL"));
    if (*len < 1 || !*buffer || (*buffer)[*len -1] != '\n') {
	DPRINT(Debug,50,(&Debug, 
			 "\nmbx_copy_body_spool <- NO NEWLINE\n"));
    }
    return status;
}


#ifndef MMDF
static int mbx_copy_envelope_end_from P_((struct folder_info *folder,
					  READ_STATE read_state_ptr));

static int mbx_copy_envelope_end_from(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    char *buffer1;
    int len1;
    int status = 0;

    /* Will be re-handled on copy_envelope_folder() */
    if (!mbx_read_buffered_line(folder,read_state_ptr,
				     &buffer1,&len1)) {
	status = 1;
	goto clean;
    }
    if (real_from(buffer1,NULL))
	status = 1;
    else
	status = 0;
 clean:
    DPRINT(Debug,12,(&Debug, 
		     "mbx_copy_envelope_end_from=%d\n",
		     status));
    return status;
}
#endif


static int mbx_copy_envelope_end_non_spool P_((struct folder_info *folder,
					       READ_STATE read_state_ptr));

static int mbx_copy_envelope_end_non_spool(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    char *buffer1;
    int len1;

    int status = 0;
    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_end_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                               : read_state_ptr=%p\n",
		     read_state_ptr));


    if (!mbx_read_buffered_line(folder,read_state_ptr,
				     &buffer1,&len1)) {
	status = 1;
	goto clean;
    }

    if (
#ifdef MMDF
	mbx_copy_envelope_check_MMDF(buffer1,len1) 
#else
	(len1 == 1 && 0 == memcmp(buffer1,"\n",len1)) ||
	(len1 == 2 && 0 == memcmp(buffer1,"\r\n",len1))
#endif
	) {
	mbx_accept_buffered_line(folder,read_state_ptr,
				      &buffer1,&len1);
	status = 1;
    }

#ifndef MMDF
    /* Will be re-handled on copy_envelope_folder() */
    if (mbx_copy_envelope_end_from(folder,read_state_ptr))
	status = 1;
    else
	status = 0;
#endif
 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_end_non_spool=%d\n",
		     status));
    return status; 
}

static int mbx_copy_envelope_end_spool P_((struct folder_info *folder,
					   READ_STATE read_state_ptr));

static int mbx_copy_envelope_end_spool(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    char *buffer1;
    int len1;

    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		"mbx_copy_envelope_end_spool: folder=%p (%s)\n",
		folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                           : read_state_ptr=%p\n",
		     read_state_ptr));


    if (!mbx_read_buffered_line(folder,read_state_ptr,
				     &buffer1,&len1)) {
	status = 1;
	goto clean;
    }

    if (
#ifdef MMDF
	mbx_copy_envelope_check_MMDF(buffer1,len1) 
#else
	(len1 == 1 && 0 == memcmp(buffer1,"\n",len1)) ||
	(len1 == 2 && 0 == memcmp(buffer1,"\r\n",len1))
#endif
	) {
	if (!mbx_copy_line_to_temp(folder,buffer1,len1)) {
	    status = 0;
	    goto clean;
	}
	mbx_accept_buffered_line(folder,read_state_ptr,
				      &buffer1,&len1);
	status = 1;
    }

#ifndef MMDF
    /* Will be re-handled on copy_envelope_folder() */
    if (mbx_copy_envelope_end_from(folder,read_state_ptr))
	status = 1;
    else
	status = 0;
#endif

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_end_spool=%d\n",
		     status));
    return status; 
}


static int mbx_reset_folder P_((struct folder_info *folder,
				READ_STATE read_state_ptr));

static int mbx_reset_folder(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    int status = 0;
    if (fseek(folder->p->fh_folder, read_state_ptr -> fbytes_body , 
	      SEEK_SET) == -1) {
	int err = errno;

	lib_error(CATGETS(elm_msg_cat, ElmSet, 
			  ElmCouldntSeekBytesIntoFolder,
			  "\nCouldn't seek %ld bytes into folder.\n"),
		  read_state_ptr -> fbytes_body);		
	lib_error(FRM("** %s. **\n"), error_description(err));

	DPRINT(Debug,1,(&Debug, 
		   "Error: Couldn't seek folder %s: (offset %ld) Errno %s (%s)\n",
		   folder->cur_folder_sys, read_state_ptr -> fbytes_body, 
		   error_description(err), "mbx_reset_folder"));
	status = 0;

	goto clean;
    }
    read_state_ptr -> fbytes = read_state_ptr -> fbytes_body;
    mbx_free_rs_fields_file(read_state_ptr);
    status = 1;

 clean:
    DPRINT(Debug,12,(&Debug, 
		     "mbx_reset_folder=%d\n",
		     status));
    return status;
}

static int mbx_copy_envelope_reset_body_non_spool P_((struct folder_info 
						      *folder,
						      READ_STATE
						      read_state_ptr));
static int mbx_copy_envelope_reset_body_non_spool(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_reset_body_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                                      : read_state_ptr=%p\n",
		     read_state_ptr));

    status = mbx_reset_folder(folder,read_state_ptr);

    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_reset_body_non_spool=%d\n",status));
    return status;
}

static int mbx_copy_envelope_reset_body_spool P_((struct folder_info 
						  *folder,
						  READ_STATE
						  read_state_ptr));
static int mbx_copy_envelope_reset_body_spool(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    int status = 0;
    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_reset_body_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug, 
		     "                                  : read_state_ptr=%p\n",
		     read_state_ptr));

    
    if (!folder->p->fh_temp) {
	DPRINT(Debug,11,(&Debug, 
			 "mbx_copy_envelope_reset_body_spool -- NO temp file %s\n",
			 folder->cur_tempfolder));
    } else if (fseek(folder->p->fh_temp, read_state_ptr -> fbytes_body , 
	      SEEK_SET) == -1) {
	int err = errno;

	lib_error(CATGETS(elm_msg_cat, ElmSet, 
			  ElmCouldntSeekBytesIntoFolder,
			  "\nCouldn't seek %ld bytes into folder.\n"),
		  read_state_ptr -> fbytes_body);		
	lib_error(FRM("** %s. **\n"), error_description(err));

	DPRINT(Debug,1,(&Debug, 
			"Error: Couldn't seek folder %s: (offset %ld) Errno %s (%s)\n",
			folder->cur_tempfolder, read_state_ptr -> fbytes_body, 
			error_description(err), 
			"mbx_copy_envelope_reset_body_spool"));
	status = 0;

	goto clean;
    }

    status = mbx_reset_folder(folder,read_state_ptr);

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_copy_envelope_reset_body_spool=%d\n",status));
    return status;
}


static FILE * mbx_non_spool_to_fd P_((struct folder_info *folder,long offset));
static FILE * mbx_non_spool_to_fd(folder,offset)
     struct folder_info *folder;
     long offset;
{
    FILE * status = NULL;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_non_spool_to_fd: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    if (offset != -1L &&
	fseek(folder->p->fh_folder, offset , 
	      SEEK_SET) == -1) {
	int err = errno;

	lib_error(CATGETS(elm_msg_cat, ElmSet, 
			  ElmCouldntSeekBytesIntoFolder,
			  "\nCouldn't seek %ld bytes into folder.\n"),
		  offset);		
	lib_error(FRM("** %s. **\n"), error_description(err));

	DPRINT(Debug,1,(&Debug, 
			"Error: Couldn't seek folder %s: (offset %ld) Errno %s (%s)\n",
			folder->cur_folder_sys, offset, 
			error_description(err), "mbx_non_spool_to_fd"));
	status = NULL;
	goto clean;
    }
    status = folder->p->fh_folder;

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_non_spool_to_fd=%s (%p)\n",
		     status ? "NON-NULL" : "NULL",
		     status));
    return status;
}

static FILE * mbx_spool_to_fd P_((struct folder_info *folder,long offset));
static FILE * mbx_spool_to_fd(folder,offset)
     struct folder_info *folder;
     long offset;
{
    FILE * status = NULL;

    DPRINT(Debug,11,(&Debug, 
		     "mbx_spool_to_fd: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    if (offset != -1L &&
	fseek(folder->p->fh_temp, offset , 
	      SEEK_SET) == -1) {
	int err = errno;
	lib_error(CATGETS(elm_msg_cat, ElmSet, 
			  ElmCouldntSeekBytesIntoFolder,
			  "\nCouldn't seek %ld bytes into folder.\n"),
		  offset);		
	lib_error(FRM("** %s. **\n"), error_description(err));

	DPRINT(Debug,1,(&Debug, 
			"Error: Couldn't seek folder %s: (offset %ld) Errno %s (%s)\n",
			folder->cur_tempfolder, offset, 
			error_description(err), "mbx_spool_to_fd"));
	status = NULL;
	goto clean;
    }
    status = folder->p->fh_temp;

 clean:
    DPRINT(Debug,11,(&Debug, 
		     "mbx_spool_to_fd=%s (%p)\n",
		     status ? "NON-NULL" : "NULL",
		     status));
    return status;
}


static int mbx_new_mail_on_normal P_((struct folder_info *folder,
					 int *bytes));
static int mbx_new_mail_on_normal(folder,bytes)
     struct folder_info *folder;
     int *bytes;
{
    int status = 0;
    long size = 0L;

    DPRINT(Debug,11,(&Debug,
		     "mbx_new_mail_on_normal: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    size = file_bytes(folder->cur_folder_sys);
    if (size > folder->mailfile_size)
	status = 1;
    *bytes = size - folder->mailfile_size;

    DPRINT(Debug,11,(&Debug,
		     "mbx_new_mail_on_normal=%d (*bytes=%d)\n",
		     status,*bytes));
    return status;
}


static int mbx_consider_remove_non_spool P_((struct folder_info *folder));
static int mbx_consider_remove_non_spool(folder)
     struct folder_info *folder;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug,
		     "mbx_consider_remove_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (0L == file_bytes(folder->cur_folder_sys)) {
	folder->mailfile_size = 0;
	if (0 == unlink(folder->cur_folder_sys))
	    status = 1;
	else {
	    int err = errno;
	    DPRINT(Debug,11,(&Debug,
			     "mbx_consider_remove_non_spool: unlink(%s) failed: %s (errno=%d)\n",
			     folder->cur_folder_sys,
			     error_description(err),err));
	}
    }
    DPRINT(Debug,11,(&Debug,
		     "mbx_consider_remove_non_spool=%d\n",
		     status));
    return status;
}

static void mbx_zero_ks_fields_file P_((struct keep_folder_state *rs));
static void mbx_zero_ks_fields_file(rs)
     struct keep_folder_state *rs;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_zero_ks_fields_file: rs=%p\n",
		     rs));

    rs -> a.file.temp_keep_file       = NULL;
    rs -> a.file.keep_file            = NULL;
}


static void mbx_free_ks_fields_file P_((struct keep_folder_state *rs));
static void mbx_free_ks_fields_file(rs)
     struct keep_folder_state *rs;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_free_ks_fields_file: rs=%p\n",
		     rs));

    if (rs -> a.file.temp_keep_file) {
	free(rs -> a.file.temp_keep_file);
	rs -> a.file.temp_keep_file = NULL;
    }

    if (rs -> a.file.keep_file) {
	fclose(rs -> a.file.keep_file);
	rs -> a.file.keep_file = NULL;
    }
}


static int mbx_open_temp_file P_((struct folder_info *folder,
				  KEEP_STATE keep_state_ptr));
static int mbx_open_temp_file(folder,keep_state_ptr)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
{
    int status = 0,err;
    char * tmp;

    tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
    if (!tmp)
	tmp = "/tmp/";

    keep_state_ptr -> a.file.temp_keep_file = 
	elm_message(FRM("%s%s%d"),tmp, temp_file, getpid());

    if ((err = can_open(keep_state_ptr -> a.file.temp_keep_file, "sw"))) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveTempFileDenied,
			  "Permission to create temp file %s for writing denied! Leaving folder intact."),
		  keep_state_ptr -> a.file.temp_keep_file);

	DPRINT(Debug,1,(&Debug,
			"Error: Permission to create temp file %s denied!! (%s)\n",
			keep_state_ptr -> a.file.temp_keep_file, 
			"mbx_open_temp_file"));
	DPRINT(Debug,1,(&Debug,
			"** %s ** (errno %d)\n", 
			error_description(err),err));
	status = 0;
	goto clean;
    }

    if ((keep_state_ptr -> a.file.keep_file = 
	 fopen(keep_state_ptr -> a.file.temp_keep_file,"w+")) == NULL) {
	err = errno;
	
	DPRINT(Debug,1,(&Debug,
			"Error: could not create file %s\n", 
			keep_state_ptr ->a.file.temp_keep_file));
	DPRINT(Debug,1,(&Debug,
			"** %s **\n", error_description(err)));
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveCouldNotCreate,
			  "Could not create temp file %s!"), 
		  keep_state_ptr -> a.file.temp_keep_file);

	status = 0;
	goto clean;
    }
    status = 1;

 clean:	
    return status;
}

static int mbx_prepare_keep_read_only P_((struct folder_info *folder,
				       KEEP_STATE keep_state_ptr));
static int mbx_prepare_keep_read_only(folder,keep_state_ptr)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_prepare_keep_read_only=0 (dummy): folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    return 0;
}

static int mbx_prepare_keep_normal P_((struct folder_info *folder,
				       KEEP_STATE keep_state_ptr));
static int mbx_prepare_keep_normal(folder,keep_state_ptr)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
{
    int status = 0;
    DPRINT(Debug,11,(&Debug,
		     "mbx_prepare_keep_normal: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (!mbx_open_temp_file(folder,keep_state_ptr)) {
	status = 0;
	goto clean;
    }
    status = 1;

 clean:
    DPRINT(Debug,11,(&Debug,
		     "mbx_prepare_keep_normal=%d\n",
		     status));
    return status;
}


static int copy_to_folder P_((FILE * from, struct folder_info *to));
static int copy_to_folder(from, to) 
     FILE * from;
     struct folder_info *to;
{
    int need_reopen = 1;
    int truncate_fh = -1;
    int code;
    
    DPRINT(Debug,10,(&Debug,
		     "copy_to_folder: folder=%p (%s)\n",
		     to,to->cur_folder_sys));
    
    rewind(to->p->fh_folder);
#ifdef FTRUNCATE  
    if (0 == ftruncate(fileno(to->p->fh_folder),0)) {
	DPRINT(Debug,10,(&Debug,
			 "copy_to_folder: truncated (ftruncate)\n"));
	need_reopen = 0;
    } else {
	int err = errno;
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSorryCantTruncateFolder,
			  "Sorry, can't truncate the folder %S [%s]!"),
		  to -> cur_folder_disp, error_description(err));    
    }
#endif
  if (need_reopen) {
      truncate_fh = open(to->cur_folder_sys,O_RDWR|O_TRUNC,0600);
      if (truncate_fh == -1) {
	  int err = errno;
	  
	  lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSorryCantTruncateFolder,
			    "Sorry, can't truncate the folder %S [%s]!"),
		    to -> cur_folder_disp, error_description(err));    
	  return 1;
      }
      DPRINT(Debug,10,(&Debug,
		       "copy_to_folder- truncated (reopened)\n"));
  }
  code = copy_to_fh(from,to->p->fh_folder);
  
  /* In this point we may lost locks,
     but copy is already done */
  if (truncate_fh != -1)
      close(truncate_fh);

  DPRINT(Debug,10,(&Debug,
		   "copy_to_folder=%d\n",code));
  return code;
}


static int mbx_move_temp_file P_((struct folder_info *folder,
				  KEEP_STATE keep_state_ptr,
				  int need_to_copy));
static int mbx_move_temp_file(folder,keep_state_ptr,need_to_copy)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
     int need_to_copy;
{
    int status = 0;
    int was_symlink = FALSE;

    struct stat    buf;		/* stat command  */
#ifdef SYMLINK
    struct stat    lbuf;		/* lstat command  */
#endif
#if defined(BSD_TYPE) && !defined(UTIMBUF)
    time_t utime_buffer[2];		/* utime command */
#else
    struct utimbuf utime_buffer;	/* utime command */
#endif

    if (fflush(keep_state_ptr->a.file.keep_file) == EOF ) {
	int err = errno;
	
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveFlushFailedTemp,
			  "Flush failed in leavembox: %s: %s"),
		  keep_state_ptr->a.file.temp_keep_file,
		  error_description(err));
	DPRINT(Debug,2,(&Debug,
			"\n\rfflush err on temp_keep_file - mbx_move_temp_file\n\r"));
	unlink(keep_state_ptr->a.file.temp_keep_file);
	status = 0;
	goto clean;
    }

    if (ferror(folder->p->fh_folder)) {
	DPRINT(Debug,1,(&Debug,
			"Failed to read mailfile!"));

	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReadMailfile,
			  "Error when reading mailfile %S"),
		  folder->cur_folder_disp);

	clearerr(folder->p->fh_folder);
	unlink(keep_state_ptr->a.file.temp_keep_file);
	status = 0;
	goto clean;
    }
    
    DPRINT(Debug,10,(&Debug,
		     "!! Need copy (or link) from %s to %s\n",
		     keep_state_ptr->a.file.temp_keep_file, 
		     folder->cur_folder_sys));	    

    /* Get original permissions and access time of the original
     * mail folder before we remove it.
     */
    if(save_file_stats(folder->cur_folder_sys) != 0) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveProblemsSavingPerms,
			  "Problems saving permissions of folder %s!"), 
		  folder->cur_folder_sys);	
    }

    if (stat(folder->cur_folder_sys, &buf) != 0) {
	int err = errno;
	DPRINT(Debug,1,(&Debug,
			"Error: errno %d (%s) attempting to stat file %s\n", 
			err,error_description(err), 
			folder->cur_folder_sys));

	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveErrorStat,
			  "Error stat %S: %s"), 
		  folder->cur_folder_disp,
		  error_description(err)); 		  
    }

#ifdef SYMLINK
    if (lstat(folder->cur_folder_sys, &lbuf) != 0) {
	int err = errno;
	DPRINT(Debug,1,(&Debug,
			"Error: errno %d (%s) attempting to stat file %s\n", 
			err,error_description(err), 
			folder->cur_folder_sys));
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveErrorStat,
			  "Error stat %S: %s"), 
		  folder->cur_folder_disp,
		  error_description(err));
    }
#endif

    flush_folder(folder);

    if (buf.st_nlink > 1) {
	DPRINT(Debug,10,(&Debug,
			 "* several links\n"));
	need_to_copy = TRUE;
    }
    if (buf.st_mode & 07000) { /* copy if special modes set */
	DPRINT(Debug,10,(&Debug,
			 "* special modes\n"));
	need_to_copy = TRUE;    /* such as enforcement lock */
    }
#ifdef SYMLINK
    if (
#ifdef S_ISLNK
	S_ISLNK(lbuf.st_mode)
#else
	(lbuf.st_mode & S_IFMT) == S_IFLNK
#endif
	) {
	DPRINT(Debug,10,(&Debug,
			 "* symlink\n"));
	need_to_copy = TRUE;
	was_symlink = TRUE;
    }
#endif

#ifdef _PC_CHOWN_RESTRICTED
    if (!need_to_copy) {
/*
 * Chown may or may not be restricted to root in SVR4, if it is,
 *	then need to copy must be true, and no restore of permissions
 *	should be performed.
 */
	if (pathconf(folder->cur_folder_sys, 
		     _PC_CHOWN_RESTRICTED)) {
	    DPRINT(Debug,10,(&Debug,
			     "* _PC_CHOWN_RESTRICTED\n"));
	    
	    need_to_copy = TRUE;
	}
    }
#endif  /* _PC_CHOWN_RESTRICTED */

    DPRINT(Debug,10,(&Debug,
		     "-- need_to_copy=%d\n",
		     need_to_copy));

    if(!need_to_copy) {
	if (0 == unlink(folder->cur_folder_sys)) {
	    DPRINT(Debug,10,(&Debug,
			     "!! unlinked folder: %s\n",
			     folder->cur_folder_sys));
	}

	if (link(keep_state_ptr->a.file.temp_keep_file, 
		 folder->cur_folder_sys) != 0) {
	    if(errno == EXDEV || errno == EEXIST) {
		int err = errno;
		/* oops - can't link across file systems - 
		   use copy instead */
		
		DPRINT(Debug,10,(&Debug,
				 "link(%s, %s) failed: %s (errno %d)\n", 
				 keep_state_ptr->a.file.temp_keep_file, 
				 folder->cur_folder_sys,
				 error_description(err),err));		
		need_to_copy = TRUE;
	    } else {
		int err = errno;
		DPRINT(Debug,1,(&Debug,
				"link(%s, %s) failed (leavembox)\n", 
				keep_state_ptr->a.file.temp_keep_file, 
				folder->cur_folder_sys));
		DPRINT(Debug,1,(&Debug, 
				"** %s ** (errno %d)\n", 
				error_description(err),err));
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveLinkFailed,
				  "Link failed! %s.\n"), 
			  error_description(err));
		need_to_copy = TRUE;
	    }
	} else {
	    DPRINT(Debug,19,(&Debug,
			     "!! linked %s to %s\n", 
			     keep_state_ptr->a.file.temp_keep_file, 
			     folder->cur_folder_sys));
	    status = 1;
	}

	if (folder->p->fh_folder)
	    fclose(folder->p->fh_folder);	
	folder->p->fh_folder = NULL;
	
	folder->p->fh_folder = open_or_create(folder->cur_folder_sys);
	    
	if (NULL == folder->p->fh_folder) {
	    goto PANIC_copy_failed;
	}
	DPRINT(Debug,10,(&Debug,
			 "!! reopened (created) current folder after unlink: %s\n",
			 folder->cur_folder_sys));	        
    }

    if(need_to_copy) {
	char new_cur_folder[100];

	rewind(keep_state_ptr->a.file.keep_file);
	if (copy_to_folder(keep_state_ptr->a.file.keep_file, folder) != 0) {
	    /* copy to cur_folder failed - try to copy to special file */
	    {
		int err = errno;
		DPRINT(Debug,1,(&Debug,
				"leavembox: copy(%s, %s) failed;",
				keep_state_ptr->a.file.temp_keep_file, 
				folder->cur_folder_sys));
		DPRINT(Debug,1,(&Debug,
			   "** %s ** (errno %d)\n", 
				error_description(err),err));
		lib_error(CATGETS(elm_msg_cat, ElmSet, 
				  ElmLeaveCouldntModifyFolder,
				  "Couldn't modify folder!"));
	    }
	PANIC_copy_failed:

	    if (sleepmsg > 0) {
#if POLL_METHOD	  
		wait_for_timeout((sleepmsg + 1) / 2);
#else
		sleep((sleepmsg + 1) / 2);
#endif
	    }

	    elm_sfprintf(new_cur_folder,sizeof new_cur_folder,
			 FRM("%s/%s"), home, unedited_mail);

	    if (copy1(keep_state_ptr->a.file.keep_file, 
		      new_cur_folder,FALSE) != 0) {

		/* couldn't copy to special file either */
		int err = errno;
		DPRINT(Debug,1,(&Debug,
				"leavembox: couldn't copy to %s either!!  Help;", 
				new_cur_folder));
		DPRINT(Debug,1,(&Debug,
				"** %s ** (errno %d)\n", 
				error_description(err), err));
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveCantCopyMailbox,
				  "Can't copy folder, system trouble : contents preserved in %s\n"),
			  keep_state_ptr->a.file.temp_keep_file);
		
		fclose(keep_state_ptr->a.file.keep_file);
		keep_state_ptr->a.file.keep_file = NULL;
		status = 0;
		goto clean;
	    } else {
		DPRINT(Debug,1,(&Debug,
				"\nWoah! Confused - Saved mail in %s (leavembox)\n", 
				new_cur_folder));
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveSavedMailIn,
				  "Saved mail in %s."), 
			  new_cur_folder);
	    }
	} else
	    status = 1;
    }

    /* link or copy complete - remove temp keep file */
    unlink(keep_state_ptr->a.file.temp_keep_file);
    fclose(keep_state_ptr->a.file.keep_file);
    keep_state_ptr->a.file.keep_file = NULL;

    /*
     * restore permissions and access times of folder only if not
     * a symlink, as symlinks have no permissions, and not worth
     * tracking down what it points to.
     */

    if (!was_symlink) {
	if(restore_file_stats(folder->cur_folder_sys) != 1) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveProblemsRestoringPerms,
			      "Problems restoring permissions of folder %S"),
		      folder->cur_folder_disp);
	}
    }

#if defined(BSD_TYPE) && !defined(UTIMBUF)
    utime_buffer[0]     = buf.st_atime;
    utime_buffer[1]     = buf.st_mtime;
#else
    utime_buffer.actime = buf.st_atime;
    utime_buffer.modtime= buf.st_mtime;
#endif

    if (utime(folder->cur_folder_sys,
#if defined(BSD_TYPE) && !defined(UTIMBUF)
	      utime_buffer
#else
	      &utime_buffer
#endif
	      ) != 0) {
	int err = errno;

	DPRINT(Debug,1,(&Debug,
		   "Error: encountered error doing utime (leavmbox)\n"));
	DPRINT(Debug,1,(&Debug,
		   "** %s ** (errno %d)\n", error_description(err), err));

	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLeaveChangingAccessTime,
			  "Error %s trying to change file %S access time."), 
		  error_description(err), 
		  folder->cur_folder_disp);
    }
    
 clean:
    DPRINT(Debug,12,(&Debug,
		     "mbx_move_temp_file=%d\n",
		     status));
    return status;
}

static int mbx_end_keep_read_only P_((struct folder_info *folder,
				    KEEP_STATE keep_state_ptr));
static int mbx_end_keep_read_only(folder,keep_state_ptr)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_end_keep_read_only=1 (dummy): folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    return 1;
}


static int mbx_end_keep_non_spool P_((struct folder_info *folder,
				    KEEP_STATE keep_state_ptr));
static int mbx_end_keep_non_spool(folder,keep_state_ptr)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
{
    int need_to_copy = FALSE;
    int status = 0;

    DPRINT(Debug,11,(&Debug,
		     "mbx_end_keep_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (lockfolders) {
	DPRINT(Debug,10,(&Debug,
			 "* lockfolders\n"));
	need_to_copy = TRUE;
    }

    if (!mbx_move_temp_file(folder,keep_state_ptr,need_to_copy)) {
	status = 0;
	goto clean;
    }
    folder->mailfile_size = file_bytes(folder->cur_folder_sys);
    status = 1;

 clean:
    DPRINT(Debug,11,(&Debug,
		     "mbx_end_keep_non_spool=%d\n",
		     status));
    return status;
}

static int mbx_end_keep_spool P_((struct folder_info *folder,
				    KEEP_STATE keep_state_ptr));
static int mbx_end_keep_spool(folder,keep_state_ptr)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
{
    int status = 0;
    int need_to_copy = FALSE;

    gid_t oldgid = getegid();

    if (have_saved_ids) {
	if (setgid(mailgroupid) < 0) {
    	    int err = errno;
	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
		      mailgroupid,error_description(err));
	}
    }

    DPRINT(Debug,11,(&Debug,
		     "mbx_end_keep_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

#ifdef SYSCALL_LOCKING
    DPRINT(Debug,10,(&Debug,
		     "* SYSCALL_LOCKING (SPOOL)\n"));
    need_to_copy = TRUE;
#endif /* SYSCALL_LOCKING */

    if (!mbx_move_temp_file(folder,keep_state_ptr,need_to_copy)) {
	status = 0;
	goto clean;
    }
    folder->mailfile_size = file_bytes(folder->cur_folder_sys);
    status = 1;

 clean:

    if (have_saved_ids) {
	if (setgid(oldgid) < 0) {
    	    int err = errno;
	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
		      oldgid,error_description(err));
	}
    }

    DPRINT(Debug,11,(&Debug,
		     "mbx_end_keep_spool=%d\n",
		     status));
    return status;
}


static void mbx_mark_keep_read_only P_((struct folder_info *folder,
				      KEEP_STATE keep_state_ptr,
				      struct header_rec *entry,
				      int keep));
static void mbx_mark_keep_read_only(folder,keep_state_ptr,entry,keep)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
     struct header_rec *entry;
     int keep;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_mark_keep_read_only: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
}


static void mbx_mark_keep_normal P_((struct folder_info *folder,
				     KEEP_STATE keep_state_ptr,
				     struct header_rec *entry,
				     int keep));
static void mbx_mark_keep_normal(folder,keep_state_ptr,entry,keep)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
     struct header_rec *entry;
     int keep;
{
    int count;
    FILE * fh;
    int status_written = 0;

    /*  FIXME:
     *
     *  This should probably use real_start_we_local()
     *                           real_end_we_local()
     *   on savefolder.c
     *
     *  there is too many similar routines
     */

    DPRINT(Debug,11,(&Debug,
		     "mbx_mark_keep_normal: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (keep) {
	int ch = '\0';

	fh = folder_to_fd(folder,entry->offset);
	if (!fh)
	    return;
    
	DPRINT(Debug,11,(&Debug,
			 "mbx_mark_keep_normal: envelope + header %ld - %ld\n",
			 entry->offset,entry->mime_rec.offset));

	count = 0;
	while (ftell(fh) < entry->mime_rec.offset) {
	    char * buffer = NULL;
	    int len,i;

	    if (!read_line(fh,&buffer,&len,
			   entry->mime_rec.offset - ftell(fh)))
		return;
	    
	    /* End of headers ? */
	    if ((len == 1 && 0 == memcmp(buffer,"\n",len)) ||
		(len == 2 && 0 == memcmp(buffer,"\r\n",len))) {
		if (!status_written) {
		    char buffer1[WLEN+10];   /* Enough space for status letters */
		    
		    count += fprintf(keep_state_ptr->a.file.keep_file,
				     "Status: ");

		    if (status_2_mailbox(entry,buffer1,sizeof buffer1) > 0)
			count += fprintf(keep_state_ptr->a.file.keep_file,
					 "%s",buffer1);

		    /* Write EOLN */
		    for (i = 0; i < len; i++) {
			putc(buffer[i],keep_state_ptr->a.file.keep_file);
			count++;
		    }
		    status_written = 1;
		}
	    }

	    if (NULL != header_cmp(buffer, "Status", NULL)) {
		/* SKIP */
	    } else {
		for (i = 0; i < len; i++) {
		    putc(buffer[i],keep_state_ptr->a.file.keep_file);
		    count++;
		}
	    }
	    free(buffer);
	}
	if (!status_written) {
	    DPRINT(Debug,1,(&Debug,
			    "mbx_mark_keep_normal: ERROR : Status: not written!\n"));
	}

	DPRINT(Debug,11,(&Debug,
			 "mbx_mark_keep_normal: wrote %d bytes of header\n",
			 count));
	DPRINT(Debug,11,(&Debug,
			 "mbx_mark_keep_normal: content length %ld\n",
			 entry->content_length));
	
	count = 0;
	while (count < entry->content_length) {
	    ch = getc(fh);
	    
	    if (EOF == ch) {
		DPRINT(Debug,11,(&Debug,
				 "mbx_mark_keep_normal: Got EOF when reading\n"));
		break;
	    }

	    if (EOF == putc(ch,keep_state_ptr->a.file.keep_file)) {
		DPRINT(Debug,11,(&Debug,
				 "mbx_mark_keep_normal: Got EOF (error) when writing\n"));
		break;
	    }
	    count++;
	}
	DPRINT(Debug,11,(&Debug,
			 "mbx_mark_keep_normal: wrote %d bytes of body\n",
			 count));
	
	/*
	 * parse_body_routine() excludes ending empty line from
	 * content_length, so add empty line always to mail 
	 */

	if (ch != '\n') {
	    DPRINT(Debug,1,(&Debug,
			     "mbx_mark_keep_normal: Last character was not NL !!\n"));
	    if (EOF != putc('\n',keep_state_ptr->a.file.keep_file)) {
		DPRINT(Debug,11,(&Debug,
				 "mbx_mark_keep_normal: Added extra NL\n"));
	    }
	}

#ifndef MMDF

	/* blank line to keep mailx happy *sigh* */      
	if (fprintf(keep_state_ptr->a.file.keep_file, "\n") == EOF) {
	    DPRINT(Debug,5,(&Debug,
			    "mbx_mark_keep_normal: Failed to add second NL to end of mail\n"));
	} else {
	    DPRINT(Debug,11,(&Debug,
			     "mbx_mark_keep_normal: Added NL for empty line.\n"));
	}

#else
	/* FIXME --- What is correct? */

#endif
	
    }
}

CONST char * mbx_non_spool_type P_((struct folder_info *folder));
CONST char * mbx_non_spool_type(folder)
     struct folder_info *folder;
{
    static char *FOLDER = NULL;
    if (!FOLDER)
	FOLDER = catgets(elm_msg_cat, ElmSet, ElmFolder, "Folder");

    DPRINT(Debug,11,(&Debug,
		     "mbx_non_spool_type: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug,
		     "mbx_non_spool_type=%s\n",
		     FOLDER));
    return FOLDER;
}

CONST char * mbx_read_only_type P_((struct folder_info *folder));
CONST char * mbx_read_only_type(folder)
     struct folder_info *folder;
{
    static char *FOLDER = NULL;
    if (!FOLDER)
	FOLDER = catgets(elm_msg_cat, ElmSet, ElmReadOnlyFolder, 
			 "Read-only folder");

    DPRINT(Debug,11,(&Debug,
		     "mbx_read_only_type: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug,
		     "mbx_read_only_type=%s\n",
		     FOLDER));
    return FOLDER;
}

CONST char * mbx_spool_type P_((struct folder_info *folder));
CONST char * mbx_spool_type(folder)
     struct folder_info *folder;
{
    static char *mailbox = NULL;
    if (!mailbox)
	mailbox = catgets(elm_msg_cat, ElmSet, ElmMailbox, "Mailbox");

    DPRINT(Debug,11,(&Debug,
		     "mbx_spool_type: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug,
		     "mbx_spool_type=%s\n",
		     mailbox));
    return mailbox;
}

static int mbx_start_edit_non_spool P_((struct folder_info *folder, 
				     CONST char **buffer));
static int mbx_start_edit_non_spool(folder,buffer)
     struct folder_info *folder;
     CONST char **buffer;
{
    int status = 0;
    DPRINT(Debug,11,(&Debug,
		     "mbx_start_edit_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    *buffer = folder->cur_folder_sys;
    status = 1;

    DPRINT(Debug,50,(&Debug,
		     "mbx_start_edit_non_spool=%d | *buffer=%s\n",
		     status,
		     *buffer ? *buffer : "NULL"));
    return status;
}

static int mbx_start_edit_spool P_((struct folder_info *folder, 
				     CONST char **buffer));
static int mbx_start_edit_spool(folder,buffer)
     struct folder_info *folder;
     CONST char **buffer;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug,
		     "mbx_start_edit_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    *buffer = NULL;

    if(save_file_stats(folder->cur_folder_sys) != 0) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmPermFolder,
			  "Problems saving permissions of folder %S!"), 
		  folder->cur_folder_disp);
	status = 0;
	goto clean;
    }

    *buffer = folder->cur_tempfolder;
    status = 1;

 clean:
    DPRINT(Debug,50,(&Debug,
		     "mbx_start_edit_spool=%d | *buffer=%s\n",
		     status,
		     *buffer ? *buffer : "NULL"));
    return status;
}

static int mbx_end_edit_non_spool P_((struct folder_info *folder));
static int mbx_end_edit_non_spool(folder)
     struct folder_info *folder;
{
    int status = 0;

    DPRINT(Debug,11,(&Debug,
		     "mbx_end_edit_non_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (!sessionlock_folder(folder,SESSIONLOCK_REOPEN)) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntOpenFolder,
			  "Couldn't open %s for reading!  Edit LOST!"), 
		  folder->cur_folder_sys);
	status = 0;
	goto clean;
    }

    lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmResyncingNewVersion,
		      "Resynchronizing with new version of folder..."));
    status = 1;

 clean:
    DPRINT(Debug,11,(&Debug,
		     "mbx_end_edit_non_spool=%d\n",
		     status));
    return status;
}

static int mbx_end_edit_spool P_((struct folder_info *folder));
static int mbx_end_edit_spool(folder)
     struct folder_info *folder;
{
    int status = 0;
    gid_t oldgid = getegid();
    
    DPRINT(Debug,11,(&Debug,
		     "mbx_end_edit_spool: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));

    if (!sessionlock_folder(folder,SESSIONLOCK_REOPEN)) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntOpenFolder,
			  "Couldn't open %s for reading!  Edit LOST!"), 
		  folder->cur_folder_sys);
	status = 0;
	goto clean;
    }
    
    if (!lock_folder(OUTGOING,folder)) {
	status = 0;
	goto clean;
    }
    
    if (file_bytes(folder->cur_folder_sys) != 
	folder->mailfile_size) {
	char buffer[1000];
	int len;
	
	/* SIGH.  We've received mail since we invoked the editor
	   on the folder.  We'll have to do some strange stuff to
	   remedy the problem... */
	
	lib_transient(CATGETS(elm_msg_cat, ElmSet, 
			  ElmWarnNewMailRecv,
			  "Warning: new mail received..."));

	if (0 != fseek(folder->p->fh_temp,0,SEEK_END)) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntSeekTemp,
			      "Couldn't seek to end of temp file. Edit LOST!"));
	    status = 0;
	    goto clean;
	}
	
	if (fseek(folder->p->fh_folder, 
		  folder->mailfile_size, 0) == -1) {
	    DPRINT(Debug,1,(&Debug,
			    "Couldn't seek to end of cur_folder (offset %ld) (%s)\n",
			    folder->mailfile_size, "mbx_end_edit_non_spool"));
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntSeekEnd,
			      "Couldn't seek to end of folder.  Edit LOST!"));
	    
	    unlock_folder(0,folder);
	    status = 0;
	    goto clean;
	}

	/** Now we can finally stream the new mail into the tempfile **/

	while ((len = mail_gets(buffer, SLEN, 
				folder ->p->fh_folder)) != 0)
	    if (fwrite(buffer, 1, len, folder ->p->fh_temp) != len) {
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntCopyMailfile,
				  "Couldn't copy %S to mail file %s!"),
			  folder->cur_folder_disp, 
			  folder->cur_tempfolder);
		unlock_folder(0,folder);
		status = -1;
		goto clean;
	    }

	if (0 != fflush(folder->p->fh_temp)) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldntCopyMailfile,
			      "Couldn't copy %S to mail file %s!"),
		      folder->cur_folder_disp, 
		      folder->cur_tempfolder);
	    unlock_folder(0,folder);
	    status = -1;
	    goto clean;
	}


	lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmChangesIncorporated,
			      "Changes incorporated into new mail..."));
    } else 
	lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmResyncingNewVersion,
			      "Resynchronizing with new version of folder..."));

    
    if (have_saved_ids) {
	if (setgid(mailgroupid) < 0) {
    	    int err = errno;
	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
		      mailgroupid,error_description(err));
	}
    }

    /* remove real mail_file and then
     * link or copy the edited mailfile to real mail_file */

    if (copy_to_folder(folder->p->fh_temp,folder) != 0) {
	unlock_folder(0,folder);
	status = -1;
	goto clean;
    }
    
    /* restore file permissions before removing lock */
	
    if(restore_file_stats(folder->cur_folder_sys) != 1) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmProblemsRestoringPerms,
			  "Problems restoring permissions of folder %S"),
		  folder->cur_folder_disp);
	lib_error(FRM(""));
    }

    unlock_folder(0,folder);
    status = 1;

 clean:

    if (have_saved_ids) {
	if (setgid(oldgid) < 0) {
    	    int err = errno;
	    lib_error(FRM("Mailbox: setgid(%d) FAILED: %s"),
		      oldgid,error_description(err));
	}
    }

    DPRINT(Debug,11,(&Debug,
		     "mbx_end_edit_spool=%d\n",
		     status));
    return status;
}

static int mbx_get_spool_mode P_((struct folder_info *folder));
static int mbx_get_spool_mode(folder)
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_get_spool_mode=FOLDER_MBOX|FOLDER_FILE: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    return FOLDER_MBOX | FOLDER_FILE;
}

static int mbx_get_non_spool_mode P_((struct folder_info *folder));
static int mbx_get_non_spool_mode(folder)
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_get_spool_mode=FOLDER_FILE: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    return FOLDER_FILE;
}

static int mbx_get_read_only_mode P_((struct folder_info *folder));
static int mbx_get_read_only_mode(folder)
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_get_read_only_mode=FOLDER_RDONLY|FOLDER_FILE: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    return FOLDER_RDONLY |FOLDER_FILE;
}

static CONST char * mbx_is_forwarded_normal P_((struct folder_info *folder,
					      READ_STATE read_state_ptr));
static CONST char * mbx_is_forwarded_normal(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_is_forwarded_normal: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug,
		     "                     : read_state_ptr=%p\n",
		     read_state_ptr));

    DPRINT(Debug,11,(&Debug,
		     "mbx_is_forwarded_normal=NULL\n"));
    return NULL;
}

static int mbx_consider_remove_normal P_((struct folder_info *folder));
static int mbx_consider_remove_normal(folder)
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_consider_remove_normal: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug,
		     "mbx_consider_remove_normal=0\n"));
    return 0;
}


static int mbx_start_edit_read_only P_((struct folder_info *folder, 
				     CONST char **buffer));
static int mbx_start_edit_read_only(folder,buffer)
     struct folder_info *folder;
     CONST char **buffer;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_start_edit_read_only: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug,
		     "mbx_start_edit_read_only=0\n"));
    return 0;
}


static int mbx_end_edit_read_only P_((struct folder_info *folder));
static int mbx_end_edit_read_only(folder)
     struct folder_info *folder;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_end_edit_read_only: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug,
		     "mbx_end_edit_read_only=0\n"));
    return 0;
}


struct folder_type read_only = { "FOLDER",
                                 mbx_close_non_spool,
				 mbx_lock_non_spool,
				 mbx_init_non_spool,
				 mbx_sessionlock_read_only,
				 mbx_unlock_non_spool,
				 mbx_flush_read_only,
				 mbx_ferror_non_spool,
				 mbx_prepare_read_non_spool,
				 mbx_end_read_non_spool,
				 mbx_copy_envelope_non_spool,
				 mbx_is_forwarded_normal,
				 mbx_copy_header_non_spool,
				 mbx_copy_body_non_spool,
				 mbx_copy_envelope_end_non_spool,
				 mbx_copy_envelope_reset_body_non_spool,
				 mbx_non_spool_to_fd,
				 mbx_new_mail_on_normal,
				 mbx_consider_remove_normal,
				 mbx_prepare_keep_read_only,
				 mbx_end_keep_read_only,
				 mbx_mark_keep_read_only,
				 mbx_read_only_type,
				 mbx_start_edit_read_only,
				 mbx_end_edit_read_only,
				 mbx_free_non_spool,
				 mbx_zero_rs_fields_file,
				 mbx_free_rs_fields_file,
				 mbx_zero_ks_fields_file,
				 mbx_free_ks_fields_file,
				 mbx_get_read_only_mode };

struct folder_type non_spool = { "FOLDER",
                                 mbx_close_non_spool,
				 mbx_lock_non_spool,
				 mbx_init_non_spool,
				 mbx_sessionlock_non_spool,
				 mbx_unlock_non_spool,
				 mbx_flush_non_spool,
				 mbx_ferror_non_spool,
				 mbx_prepare_read_non_spool,
				 mbx_end_read_non_spool,
				 mbx_copy_envelope_non_spool,
				 mbx_is_forwarded_normal,
				 mbx_copy_header_non_spool,
				 mbx_copy_body_non_spool,
				 mbx_copy_envelope_end_non_spool,
				 mbx_copy_envelope_reset_body_non_spool,
				 mbx_non_spool_to_fd,
				 mbx_new_mail_on_normal,
				 mbx_consider_remove_non_spool,
				 mbx_prepare_keep_normal,
				 mbx_end_keep_non_spool,
				 mbx_mark_keep_normal,
				 mbx_non_spool_type,
				 mbx_start_edit_non_spool,
				 mbx_end_edit_non_spool,
				 mbx_free_non_spool,
				 mbx_zero_rs_fields_file,
				 mbx_free_rs_fields_file,
				 mbx_zero_ks_fields_file,
				 mbx_free_ks_fields_file,
				 mbx_get_non_spool_mode };
struct folder_type spool     = { "MAILBOX",
                                 mbx_close_spool,
				 mbx_lock_spool,
				 mbx_init_spool,
				 mbx_sessionlock_spool,
				 mbx_unlock_spool,
				 mbx_flush_spool,
				 mbx_ferror_spool,
				 mbx_prepare_read_spool,
				 mbx_end_read_spool,
				 mbx_copy_envelope_spool,
				 mbx_is_forwarded_spool,
				 mbx_copy_header_spool,
				 mbx_copy_body_spool,
				 mbx_copy_envelope_end_spool,
				 mbx_copy_envelope_reset_body_spool,
				 mbx_spool_to_fd,
				 mbx_new_mail_on_normal,
				 mbx_consider_remove_normal,
				 mbx_prepare_keep_normal,
				 mbx_end_keep_spool,
				 mbx_mark_keep_normal,
				 mbx_spool_type,
				 mbx_start_edit_spool,
				 mbx_end_edit_spool,
				 mbx_free_spool,
				 mbx_zero_rs_fields_file,
				 mbx_free_rs_fields_file,
				 mbx_zero_ks_fields_file,
				 mbx_free_ks_fields_file,
				 mbx_get_spool_mode };

void mailbox_2_status(status,entry)
     char * status; 
     struct header_rec *entry;
{

    strfcpy(entry->mailx_status, status, WLEN);

    remove_possible_trailing_spaces(entry->mailx_status);
	
    /* Okay readjust the status. If there's an 'R', message
     * is read; if there is no 'R' but there is an 'O', message
     * is unread. In any case it isn't new because a new 
     * message wouldn't have a Status: header. 
     * -- if message is re$ynced there may now be 
     * Status: -header
     */
    if (index(status, 'R') != NULL)
	entry->status &= ~(NEW | UNREAD);

    else if (index(status,'O') != NULL) {
	entry->status &= ~NEW;
	entry->status |= UNREAD;
    }

    if (index(status, 'r') != NULL)
	entry->status  |= REPLIED;
    if (index(status, 'F') != NULL)
	entry->status1 |= S1_FLAGGED;

}

int status_2_mailbox(entry,buffer,size)
     struct header_rec *entry;
     char *buffer;
     int size;
{
    int count = 0;
    int i;

    size--;    /* For trailing \0' */

#define ADD(x)   do { if (count < size) { buffer[count++] = (x); } else { goto fail; } } while(0)

    if (!ison(entry->status, UNREAD)) 
	ADD('R');
	    
    if (ison(entry->status, NEW)) 
	ADD('N');
    else 
	ADD('O');

    if (ison(entry->status, REPLIED)) 
	ADD('r');


    if (ison(entry->status1, S1_FLAGGED)) 
	ADD('F');

    /* Write unknown flags */
    for (i=0; entry->mailx_status[i] != '\0'; i++)
	switch(entry->mailx_status[i]) {
	case 'R':
	case 'O':
	case 'r':
	case 'N':
	case 'F':
	    break;
	default:
	    ADD(entry->mailx_status[i]);
	}

 fail:
    buffer[count] = '\0';

#undef ADD

    return count;
}

void remove_possible_trailing_spaces(string)
     char *string;
{
	/** an incredibly simple routine that will read backwards through
	    a string and remove all trailing whitespace.
	**/

	int i, j;

	for ( j = i = strlen(string); --i >= 0 && whitespace(string[i]); )
		/** spin backwards, semicolon intented **/ ;

	if (i > 0 && string[i-1] == '\\') /* allow for line to end with \blank  */
	  i++;

	if (i < j)
	  string[i+1] = '\0';	/* note that even in the worst case when there
				   are no trailing spaces at all, we'll simply
				   end up replacing the existing '\0' with
				   another one!  No worries, as M.G. would say
				*/
}


/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */







syntax highlighted by Code2HTML, v. 0.9.1