static char rcsid[] = "@(#)$Id: mbox.c,v 1.6 2006/05/01 09:18:57 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.6 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
 *****************************************************************************
 * Based on code ../src/newmbox.c and ../src/lock.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"
#ifdef USE_DLOPEN
#include "shared_imp.h"
#endif
#include "s_me.h"
#include "s_elm.h"

DEBUG_VAR(Debug,__FILE__,"mbox");

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


CONST static unsigned char *cs2us P_((const char *str));
CONST static unsigned char *cs2us(str) 
     CONST char *str;
{
    return (CONST unsigned char *)str;
}

/* Folder type dependent routines ------------------------------------------ */


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

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

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

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

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

    folder -> cur_tempfolder[0] = '\0';
    folder -> p = NULL;
}

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


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

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


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


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

static void malloc_read_folder_state P_((struct read_folder_state **ptr));
static void malloc_read_folder_state(ptr)
     struct read_folder_state **ptr;
{
    *ptr = safe_malloc(sizeof (struct read_folder_state));

    DPRINT(Debug,11,(&Debug,
		     "malloc_read_folder_state: (*ptr)=%p\n",
		     *ptr));

    /* bzero is defined hdrs/defs.h */
    bzero((void *)*ptr,sizeof (struct read_folder_state));

    (*ptr) -> magic         = RF_magic;
    (*ptr) -> fbytes        = 0;
    /* (*ptr) -> count         = 0; */
    (*ptr) -> linecounter   = 0;

    (*ptr) -> fbytes_body   = 0;
    (*ptr) -> skipping      = -1; /*  0 == reading, 1 = skipping, -1 == end of message */
    (*ptr) -> skip_count    = 0;
    (*ptr) -> skip_bytes    = 0;
}

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

    /* bzero is defined hdrs/defs.h */
    bzero((void *)*ptr,sizeof (struct read_folder_state));

    free(*ptr);
    *ptr = NULL;
}


static int mbx_prepare_read_no_name P_((struct folder_info *folder,
				       enum prepare_mode mode,
				       READ_STATE read_state_ptr));
static int mbx_prepare_read_no_name(folder,mode,read_state_ptr)
     struct folder_info *folder;
     enum prepare_mode mode;
     READ_STATE read_state_ptr;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_prepare_read_no_name: 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_prepare_read_no_name=0\n"));
    return 0;
}

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

static int mbx_end_read_null(folder,read_state_ptr,silent)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     int silent;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_end_read_null: 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_end_read_null=1\n"));
    return 1;
}

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

    entry->offset = 0;
    entry->status = VISIBLE;

    DPRINT(Debug,11,(&Debug,
		     "mbx_copy_envelope_no_name=0\n"));
    return 0;
}

static CONST char * mbx_is_forwarded_null P_((struct folder_info *folder,
					      READ_STATE read_state_ptr));
static CONST char * mbx_is_forwarded_null(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_is_forwarded_null: 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_null=NULL\n"));
    return NULL;
}

static int mbx_copy_header_no_name P_((struct folder_info *folder,
				       READ_STATE read_state_ptr,
				       char **buffer, int *len));
static int mbx_copy_header_no_name(folder,read_state_ptr,buffer,len)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_copy_header_no_name: 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_copy_header_no_name=0\n"));
    return 0;
}


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

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

{ 
    DPRINT(Debug,11,(&Debug,
		     "mbx_copy_body_no_name: 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_copy_body_no_name=0\n"));
    return 0;
}

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

static int mbx_copy_envelope_end_no_name(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_copy_envelope_end_no_name: 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_copy_envelope_end_no_name=1\n"));
    return 1; /* Always end of message */
}

static int mbx_copy_envelope_reset_body_no_name P_((struct folder_info *folder,
						    READ_STATE
						    read_state_ptr));
static int mbx_copy_envelope_reset_body_no_name(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_copy_envelope_reset_body_no_name: 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_copy_envelope_reset_body_no_name=0\n"));
    return 0;
}

static FILE * mbx_no_name_to_fd P_((struct folder_info *folder,long offset));
static FILE * mbx_no_name_to_fd(folder,offset)
     struct folder_info *folder;
     long offset;
{
    DPRINT(Debug,11,(&Debug,
		     "mbx_no_name_to_fd: folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
    DPRINT(Debug,11,(&Debug,
		     "mbx_no_name_to_fd=NULL\n"));
    return NULL;
}

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

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

static void malloc_keep_folder_state P_((struct keep_folder_state **ptr));
static void malloc_keep_folder_state(ptr)
     struct keep_folder_state **ptr;
{
    *ptr = safe_malloc(sizeof (struct keep_folder_state));
    bzero((void *)*ptr,sizeof (struct keep_folder_state));
    (*ptr)->magic = KS_magic;
}

static void free_keep_folder_state P_((struct keep_folder_state **ptr));
static void free_keep_folder_state(ptr)
     struct keep_folder_state **ptr;
{
    bzero((void *)*ptr,sizeof (struct keep_folder_state));
    free(*ptr);
    *ptr = NULL;
}

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

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

static void mbx_mark_keep_no_name P_((struct folder_info *folder,
				      KEEP_STATE keep_state_ptr,
				      struct header_rec *entry,
				      int keep));
static void mbx_mark_keep_no_name(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_no_name (dummy): folder=%p (%s)\n",
		     folder,folder->cur_folder_sys));
}


CONST char * mbx_no_name_type P_((struct folder_info *folder));
CONST char * mbx_no_name_type(folder)
     struct folder_info *folder;
{
    char * status = "NULL";

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


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


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

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


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

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

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

}

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

}



static struct folder_type no_name   = { "(none)",
                                        mbx_close_no_name,   
					mbx_lock_no_name,
                                        mbx_init_null,
					mbx_sessionlock_no_name,
					mbx_unlock_no_name,
					mbx_flush_null,
					mbx_ferror_no_name,
					mbx_prepare_read_no_name,
					mbx_end_read_null,
					mbx_copy_envelope_no_name,
					mbx_is_forwarded_null,
					mbx_copy_header_no_name,
					mbx_copy_body_no_name,
					mbx_copy_envelope_end_no_name,
					mbx_copy_envelope_reset_body_no_name,
					mbx_no_name_to_fd,
					mbx_new_mail_on_no_name,
					mbx_consider_remove_null,
					mbx_prepare_keep_no_name,
					mbx_end_keep_no_name,
					mbx_mark_keep_no_name,
					mbx_no_name_type,
					mbx_start_edit_no_name,
					mbx_end_edit_no_name,
					mbx_free_null,
					mbx_zero_rs_fields_null,
					mbx_free_rs_fields_null,
					mbx_zero_ks_fields_null,
					mbx_free_ks_fields_null,
					mbx_get_no_name_mode};

CONST folder_type_p NO_NAME   = &no_name;
CONST folder_type_p NON_SPOOL = &non_spool;	/* mailfile -- not mailbox */
CONST folder_type_p SPOOL     = &spool;		/* normal mailbox */
CONST folder_type_p READ_ONLY = &read_only;	/* read only mailfile */
#ifdef REMOTE_MBX
CONST folder_type_p POP_MBX   = &pop_mbx;	/* POP mailbox */
CONST folder_type_p IMAP_MBX  = &imap_mbx;	/* IMAP mailbox */
#endif


static int valid_magic P_((folder_type_p magic));
static int valid_magic(magic)
     folder_type_p magic;
{
    int i;

    if (magic == &no_name || 
        magic == &non_spool ||
	magic == &spool ||
#ifdef REMOTE_MBX
	magic == &pop_mbx ||
	magic == &imap_mbx ||
#endif
	magic == &read_only)
	return 1;

#ifdef USE_DLOPEN
    for (i = 0; i < shared_folder_type_count; i++)
	if (magic == shared_folder_types[i].T)
	    return 1;
#endif


    return 0;
}

/* General routines -------------------------------------------------------- */

folder_type_p get_folder_type(filename, in_mail)
     CONST char *filename;
     enum folder_place *in_mail;
{
    /** returns the type of mailfile filename is
	NO_NAME = no name
	SPOOL = consisting only of mailhome plus base file name
	(no intervening directory name)
	NON_SPOOL = a name that is not SPOOL type above
	READ_ONLY = open this read-only
    **/

    struct stat    bufX, *buf = NULL;		/* stat command  */
    char *mbx_dir = NULL;

    if (in_mail)
	*in_mail = in_none;

    /* if filename is null or is of zero length */
    if((filename == NULL) || (*filename == '\0')) {
	DPRINT(Debug,8,(&Debug, 
			"get_folder_type=NO_NAME: no filename\n"));
	return(NO_NAME);
    }
    
    DPRINT(Debug,8,(&Debug,
		    "get_folder_type: filename=%s\n",filename));
    
    if (stat(filename, &bufX) != 0) {
	int err = errno;
	DPRINT(Debug,8,(&Debug,
			"get_folder_type: errno %d (%s) attempting to stat file %s\n", 
			err, error_description(err), filename));
    } else 
	buf = &bufX;

    if (in_directory(buf,filename,mailhome)) {
	DPRINT(Debug,8,(&Debug,
			"get_folder_type=SPOOL\n"));
	return(SPOOL);
    }

    mbx_dir = give_dt_estr_as_str(&extra_mailbox_dir_e,
				  "extra-mailbox-dir");
    if (mbx_dir) {
	if (in_directory(buf,filename,mbx_dir)) {
	    DPRINT(Debug,8,(&Debug, 
			    "get_folder_type=SPOOL (is on %s)\n",
			    mbx_dir));
	    return(SPOOL);
	}
    }

    if (in_mail) {
	/* give_dt_estr_as_str adds / to end */
	char * str = give_dt_estr_as_str(&folders_e,"maildir");

	if (str) {
	    if (in_directory(buf,filename,str)) {
		DPRINT(Debug,8,(&Debug, 
				"get_folder_type: On folders directory: %s\n",
				str));
		*in_mail = in_folders;
	    }
	}
	if (home[0]) {
	    if (in_directory(buf,filename,home)) {
		DPRINT(Debug,8,(&Debug,
				"get_folder_type: On home directory: %s\n",
				home));
		*in_mail = in_home;
	    }
	}
    }

    /* if file name == default mailbox, its a spool file also
     * even if its not in the spool directory. (SVR4)
     */


    {
	char * default_val = give_dt_estr_as_str(&defaultfile_e,"incoming-mailbox");
	
	if (default_val &&
	    strcmp(filename, default_val) == 0) {
	    DPRINT(Debug,8,(&Debug,
			"get_folder_type=SPOOL\n"));
	    return(SPOOL);
	}
    }

    
    if (buf) {
	if (buf->st_mode & 07000) { 
	    /* is 'SPOOL' file if special modes set */
	    DPRINT(Debug,8,(&Debug,
			    "get_folder_type=SPOOL; mode=%05o\n",
			    buf->st_mode));
	    return(SPOOL);
	}
	/* If owner do not have write permission, open it read-only */
	if (0 == (buf->st_mode & 00200)) {
	    DPRINT(Debug,8,(&Debug,
			    "get_folder_type=READ_ONLY; mode=%05o\n",
			    buf->st_mode));
	    return(READ_ONLY);
	}
    }
    
    /* Open read only if we have no write access ... 
     * This also detects (at least on Linux) cases where filesystem is
     * mounted read-only
     */
    if (0 != access(filename,WRITE_ACCESS)) {
	int err = errno;

	DPRINT(Debug,8,(&Debug, 
			"get_folder_type=READ_ONLY; no write access: %s (errno %d)\n",
			error_description(err),err));
	return(READ_ONLY);
    }

    DPRINT(Debug,8,(&Debug,
		    "get_folder_type=NON_SPOOL\n"));
    return(NON_SPOOL);
}

int in_directory(buf1,name,dir)
     struct stat *buf1;
     CONST char *name;
     CONST char * dir;
{
    CONST char * ptr = strrchr(name,'/');
    CONST char * X = name;
    int l1   =  strlen(dir);    

    if (buf1) {
	DPRINT(Debug,8,(&Debug,
			"in_directory: buf1=%p ",buf1));
    } else {
	DPRINT(Debug,8,(&Debug,
			"in_directory: buf1=NULL "));
    }
    DPRINT(Debug,8,(&Debug,
		    "name=%s dir=%s\n",name,dir));

    if (l1 > 0 && '/' == dir[l1-1]) {
	l1--;
	DPRINT(Debug,8,(&Debug,
			"in_directory: Last char / on dir=%s (using len=%d)\n",
			dir,l1));
    }

    if (ptr) {
	int L   =  ptr-X;

	X = ptr+1;
	
	if (l1 == L &&
	    0 == strncmp(dir,name,L)) {
	    DPRINT(Debug,8,(&Debug,
			    "in_directory=1   same base=%.*s\n",
			    L,dir));
	    return 1;
	}
    }

    if (buf1) {
	char * cmp = elm_message(FRM("%.*s/%s"),l1,dir,X);
	struct stat buf2;

	if (stat(cmp, &buf2) != 0) {
	    int err = errno;
	    DPRINT(Debug,8,(&Debug,
			    "in_directory=1: %s (errno=%d) attempting to stat file %s\n", 
			    error_description(err), err, cmp));
	    free(cmp);
	    return 0;
	}

	if (buf1->st_ino == buf2.st_ino && buf1->st_dev == buf2.st_dev) {
	    DPRINT(Debug,8,(&Debug,
			     "in_directory=1  (same dev=%ld and ino=%d as %s)\n",
			     (long)buf1->st_dev,(long)buf1->st_ino,cmp)); 
	    free(cmp);
	    return 1;
	    
	}
	free(cmp);
    }
	
    DPRINT(Debug,8,(&Debug,
		    "in_directory=0\n"));
    return 0;
}

int same_file(name1,name2)
     char *name1, *name2;
{
    struct stat buf1, buf2;
    
    if (0 == strcmp(name1,name2)) {
	DPRINT(Debug,8,(&Debug,
			"same_file(%s,%s)=TRUE\n",name1,name2)); 
	return TRUE;
    }
    
    if (stat(name1, &buf1) != 0) {
	int err = errno;
	DPRINT(Debug,8,(&Debug, 
			"same_file(%s,%s)=FALSE: %s (errno=%d) attempting to stat file %s\n", 
			name1,name2,error_description(err), err, name1));
	return FALSE;
    }
    
    if (stat(name2, &buf2) != 0) {
	int err = errno;
	DPRINT(Debug,8,(&Debug,
			"same_file(%s,%s)=FALSE: %s (errno=%d) attempting to stat file %s\n", 
			name1,name2,error_description(err), err, name2));
	return FALSE;
    }
    
    if (buf1.st_ino == buf2.st_ino && buf1.st_dev == buf2.st_dev) {
	DPRINT(Debug,8,(&Debug,
			"same_file(%s,%s)=TRUE\n",name1,name2)); 
	return TRUE;
    }
    DPRINT(Debug,8,(&Debug, 
		    "same_file(%s,%s)=FALSE\n",name1,name2)); 
    return FALSE;
}

void close_folder(folder,mode) 
     struct folder_info *folder;
     enum close_mode mode;
{
    DPRINT(Debug,10,(&Debug,
		     "close_folder: folder=%p (%s), type=%p\n",
		     folder,folder->cur_folder_sys,folder -> folder_type));
    
    folder -> folder_type->close_it(folder,mode);

    if (folder -> p) {
	if (folder -> p->fh_folder != NULL)
	    fclose(folder -> p->fh_folder); 
	folder -> p->fh_folder = NULL;

	if (folder -> p->fh_temp != NULL)
	    fclose(folder -> p->fh_temp); 
	folder -> p->fh_temp = NULL;
    }
}

struct folder_info *mbx_new_folder() 
{
    struct folder_info *new_folder = NULL;

    new_folder = safe_malloc(sizeof (struct folder_info));

    /* defined in hdrs/defs.h */
    bzero((void *)new_folder,sizeof (struct folder_info));   
    
    new_folder -> p = NULL;
    new_folder -> cur_folder_sys  = NULL;
    new_folder -> cur_folder_disp = NULL;
    new_folder -> cur_tempfolder[0] = '\0';
    new_folder -> mailfile_size     = 0;

    return new_folder;
}


struct folder_info *enter_new_folder(new_file) 
     CONST char *new_file;
{
    struct folder_info *new_folder = NULL;

    DPRINT(Debug,10,(&Debug,
		     "enter_new_folder(%s)\n",
		     new_file));

    new_folder = mbx_new_folder();
    new_folder -> cur_folder_sys  = safe_strdup(new_file);
    new_folder -> cur_folder_disp = new_string2(display_charset,
						cs2us(new_file));

    /* determine type of new mailfile and calculate temp file name
       remote_folder_type calls folder's init_it routine if
       succees
    */
    if (!remote_folder_type(new_folder)) {
	new_folder -> folder_type = get_folder_type(new_file,NULL);
	new_folder -> folder_type->init_it(new_folder);
    }

    /* HACK */
    if (new_folder->p)	
	new_folder->p->flags1 = 0;

#if 0
    DPRINT(Debug,1,(&Debug,
		    "New folder %s type %s temp file %s (%s)\n", 
		    current_folder->cur_folder_sys, 
		    (current_folder -> folder_type == SPOOL ? 
		     "spool" : "non-spool"),
		    (*current_folder-> cur_tempfolder ? 
		     current_folder -> cur_tempfolder : "none"), "newmbox"));
#endif

    DPRINT(Debug,10,(&Debug,
		     "enter_new_folder=%p (%s), type=%p (%s)\n",
		     new_folder,new_folder->cur_folder_sys,
		     new_folder->folder_type,
		     new_folder->folder_type->type_name));

    return new_folder;
}

void leave_old_folder(folder,mode) 
     struct folder_info **folder;
     enum close_mode mode;
{    
    if (!valid_magic((*folder)->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"leave_old_folder",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "leave_old_folder: *folder=%p (%s), type=%p (%s)\n",
		     folder,
		     (*folder)->cur_folder_sys,
		     (*folder)->folder_type,
		     (*folder)->folder_type->type_name));

    close_folder(*folder, mode);    
    (*folder)->folder_type->free_it(*folder);

    if ((*folder) -> cur_folder_sys) {
	free((*folder) -> cur_folder_sys);
	(*folder) -> cur_folder_sys = NULL;
    }
    if ((*folder) -> cur_folder_disp)
	free_string(&((*folder) -> cur_folder_disp));

    free(*folder);
    *folder = NULL;
}

int lock_folder(direction, folder)
     int direction;
     struct folder_info *folder;
{   
    int ret;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"lock_folder",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "lock_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));
    
    ret = folder -> folder_type->lock_it(direction,folder);

    DPRINT(Debug,10,(&Debug,
		     "lock_folder=%d\n",
		     ret));

    return ret;
}

int unlock_folder(interrupt, folder)
     int interrupt;
     struct folder_info *folder;
{   
    int ret;

    /* If interrupt is set, avoid calling no-reentrant routines ... */
    
    /** Flush the mailfile buffer if necessary before removing the lock.
     **/

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"unlock_folder",
	      "Bad magic number (folder type)",interrupt);

    DPRINT(Debug,10,(&Debug,
		     "unlock_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    if (!interrupt)
	flush_folder(folder);

    ret = folder -> folder_type->unlock_it(interrupt,folder);

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


/* Return 1 on succeed */
int sessionlock_folder(folder,mode)
     struct folder_info *folder;
     enum sessionlock_mode mode;
{
    int ret;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"sessionlock_folder",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "sessionlock_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    /* HACK */

    if (folder->p)	
	folder->p->flags1 = 0;
    
    switch (mode) {
    case SESSIONLOCK_NONE_CHECKNEW:
    
	if (folder->p)	
	    folder->p->flags1   |=  FLAG1_CHECKNEW;
	else {
	    DPRINT(Debug,10,(&Debug,
			     "sessionlock_folder: SESSIONLOCK_NONE_CHECKNEW unsupported\n"));

	}

	mode = SESSIONLOCK_NONE;
	break;
    }

    ret = folder->folder_type->sessionlock_it(folder,mode);

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

void flush_folder(folder)
     struct folder_info *folder;
{

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"flush_folder",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "flush_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    folder->folder_type->flush_it(folder);
}

int ferror_folder(folder,clean)
     struct folder_info *folder; 
     int clean;
{
    int ret;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"ferror_folder",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		"ferror_folder: folder=%p (%s), type=%p (%s)\n",
		folder,folder->cur_folder_sys,folder -> folder_type,
		folder->folder_type->type_name));

    ret = folder->folder_type->ferror_it(folder,clean);

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

int prepare_read_folder(folder,mode,read_state_ptr)
     struct folder_info *folder;
     enum prepare_mode mode;
     READ_STATE * read_state_ptr;
{
    int status;
    READ_STATE ptr = NULL;
        
    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"prepare_read_folder",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "prepare_read_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    malloc_read_folder_state(&ptr);
    folder->folder_type->zero_rs_fields_it(ptr);
    ptr->mode = mode;

    status = folder->folder_type->prepare_read_it(folder,mode,ptr);
    if (!status) {
	folder->folder_type->free_rs_fields_it(ptr);
	free_read_folder_state(&ptr);
    }
    *read_state_ptr = ptr;

    DPRINT(Debug,10,(&Debug,
		     "prepare_read_folder=%d\n",
		     status));

    return status;
}

int end_read_folder(folder,read_state_ptr,silent)
     struct folder_info *folder;
     READ_STATE * read_state_ptr;
     int silent;
{
    int status;
    READ_STATE ptr = *read_state_ptr;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"end_read_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"end_read_folder",
	      "Bad magic number (read state)",0);
    
    DPRINT(Debug,10,(&Debug,
		     "end_read_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    status = folder->folder_type->end_read_it(folder,ptr,silent);

    folder->folder_type->free_rs_fields_it(ptr);
    free_read_folder_state(&ptr);
    *read_state_ptr = ptr;

    DPRINT(Debug,10,(&Debug,
		     "end_read_folder=%d\n",
		     status));

    return status;
}

void copy_skipcount_folder(folder,read_state_ptr,skipcount,skipbytes)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     int *skipcount;
     long *skipbytes;
{

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"copy_skipcount_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"copy_skipcount_folder",
	      "Bad magic number (read state)",0);


    *skipcount = read_state_ptr -> skip_count;
    *skipbytes = read_state_ptr -> skip_bytes;
}

/* Returns:  0 = End of folder
             1 = OK
	    -1 = format error
*/
int copy_envelope_folder(folder,read_state_ptr,entry,parse_header,parse_body,
			 counter)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     struct header_rec *entry;
     parse_header_callback *parse_header;
     parse_body_callback *parse_body;
     struct counter_data *counter;
{
    int status;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"copy_envelope_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"copy_envelope_folder",
	      "Bad magic number (read state)",0);

    DPRINT(Debug,10,(&Debug,
		     "copy_envelope_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));
    DPRINT(Debug,10,(&Debug,
		     "                     : entry=%p",entry));
    if (!entry->mbx_info) {
	DPRINT(Debug,10,(&Debug,
		    ", { mbx_info=NULL }\n"));
    } else {
	DPRINT(Debug,10,(&Debug,
			 ", { mbx_info=%p, type=%p }\n",
			 entry->mbx_info,entry->mbx_info->type_code));
    }

    read_state_ptr ->skipping     = 0; /*  0 == reading, 1 = skipping, -1 == end of message */
    entry->body_parsed            = 0;
    entry->mime_parsed            = 0;

    status = folder->folder_type->copy_envelope_it(folder,read_state_ptr,
						   entry,0);
    read_state_ptr -> fbytes_body = read_state_ptr -> fbytes;
    entry->mime_rec.begin_offset  = read_state_ptr -> fbytes;;

    DPRINT(Debug,12,(&Debug,
		     "copy_envelope_folder: {mime} begin_offset = %ld\n",
		     entry->mime_rec.begin_offset));

    /* TEMPORARY? */
    if (status > 0) {
	int s;
	header_list_ptr parsed_headers;

	DPRINT(Debug,12,(&Debug,
			 "copy_envelope_folder: hdr %ld body %ld\n",
			 entry->offset,read_state_ptr -> fbytes_body));


	entry->binary                 = TRUE;
	/* read_folder_headers() -- actually unfold_header()
	   resets binary flags if LF is seend without CR
	*/

	entry->header_charset         = display_charset; 
	/* read_folder_headers() will re-set header_charset
	   if it sees X-ELM-OSV header with parameter
	   hdr-charset
	*/

	entry->content_length   = -1; /* not found yet */
	/* read_folder_headers() will re-set content_length
	   if it sees Content-Length header 
	*/

	parsed_headers = 
	    read_folder_headers(read_state_ptr,folder,entry);
	if (entry->binary) {
	    DPRINT(Debug,10,(&Debug,
			     "copy_envelope_folder: binary flag was preserved\n"));
	}
	if (entry->header_charset != display_charset) {
	    DPRINT(Debug,10,(&Debug,
			     "copy_envelope_folder: header charset was modified: %s\n",
			     entry->header_charset->MIME_name ?
			     entry->header_charset->MIME_name :
			     "<no MIME name>"
			     ));
	
	}

	if (-1 != entry->content_length) {
	    DPRINT(Debug,10,(&Debug,
			     "copy_envelope_folder: content_length set: %ld\n",
			     entry->content_length
			     ));
	}


	s = parse_header(folder,read_state_ptr,entry,parsed_headers);

	if (s <= 0) {
	    DPRINT(Debug,10,(&Debug,
			     "copy_envelope_folder: parse_header callback failed (%d)\n",
			     s));
	    status = -1;
	} else {
	    if (read_state_ptr ->skipping) {
		DPRINT(Debug,10,(&Debug,
				 "copy_envelope_folder: Body skipped\n"));
	    } else {
		s = parse_body(folder,read_state_ptr,entry,parsed_headers,counter);
		if (s <= 0) {
		    DPRINT(Debug,10,(&Debug,
				     "copy_envelope_folder: parse_body callback failed (%d)\n",
				     s));
		    status = -1;
		}
	    }
	    delete_headers(&parsed_headers);
	}	
    }

    if (-1 != read_state_ptr ->skipping &&
	status > 0) {
	int s;
	DPRINT(Debug,10,(&Debug,
			 "copy_envelope_folder: copy_envelope_end_folder not called or succeed (skipping=%d)\n",
			 read_state_ptr ->skipping));

	s = folder->folder_type->copy_envelope_end_it(folder,read_state_ptr);
	if (s <= 0) {
	    DPRINT(Debug,10,(&Debug,
			     "copy_envelope_folder: copy_envelope_end_it failed (%d)\n",
			     s));
	    status = -1;
	} else
	    read_state_ptr ->skipping = -1;
    }

    DPRINT(Debug,10,(&Debug,
		     "copy_envelope_folder=%d\n",
		     status));

    return status;
}

#if ANSI_C
extern parse_mime_callback NO_mime_parse;
#endif
int NO_mime_parse(folder,entry,fp)
     struct folder_info *folder;
     struct header_rec *entry;
     FILE *fp;
{
    return 1;  /* OK, but not set parsed flag */
}

int prepare_message_access(folder,entry,parse_header,
			   parse_body,counter,parse_mime)
     struct folder_info *folder;
     struct header_rec *entry;
     parse_header_callback *parse_header;
     parse_body_callback *parse_body;
     struct counter_data *counter;
     parse_mime_callback *parse_mime;
{
    int status = 1;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"prepare_message_access",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "prepare_message_access: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));
    DPRINT(Debug,10,(&Debug,
		     "                     : entry=%p",entry));
    if (!entry->mbx_info) {
	DPRINT(Debug,10,(&Debug,
		    ", { mbx_info=NULL }\n"));
    } else {
	DPRINT(Debug,10,(&Debug,
			 ", { mbx_info=%p, type=%p }\n",
			 entry->mbx_info,entry->mbx_info->type_code));
    }


    if (! entry->body_parsed) {
	READ_STATE read_state_ptr;

	DPRINT(Debug,10,(&Debug,
			"prepare_message_access: Need read message\n",
			folder,folder->cur_folder_sys));

	malloc_read_folder_state(&read_state_ptr);
	folder->folder_type->zero_rs_fields_it(read_state_ptr);

	if (!folder->p->fh_temp) {
	    if (!valid_magic(folder->folder_type)) 
		panic("MBX PANIC",__FILE__,__LINE__,"folder_to_message",
		      "Internal error -- no temp file",0);
	}
       
	read_state_ptr->mode = PREPARE_ACCESS;   
	status = folder->folder_type->prepare_read_it(folder,PREPARE_ACCESS,
						      read_state_ptr);
	if (!status) 
	    goto fail2;

	/*  0 == reading, 1 = skipping, -1 == end of message */
	read_state_ptr ->skipping     = 0;

	status = folder->folder_type->copy_envelope_it(folder,read_state_ptr,
						       entry,1 /*force */);
	read_state_ptr -> fbytes_body = read_state_ptr -> fbytes;
	entry->mime_rec.begin_offset  = read_state_ptr -> fbytes;
	
	DPRINT(Debug,12,(&Debug,
			 "prepare_message_access: {mime} begin_offset = %ld\n",
			 entry->mime_rec.begin_offset));

	if (status > 0) {
	    header_list_ptr parsed_headers = NULL;

	    DPRINT(Debug,12,(&Debug,
			     "prepare_message_access: hdr %ld body %ld\n",
			     entry->offset,read_state_ptr -> fbytes_body));

	    parsed_headers = 
		read_folder_headers(read_state_ptr,folder,entry);
	    
	    status = parse_header(folder,read_state_ptr,entry,parsed_headers);
	    if (status <= 0) {
		DPRINT(Debug,10,(&Debug,
				 "prepare_message_access: parse_header callback failed (%d)\n",
				 status));
		goto fail3;
	    }

	    status = parse_body(folder,read_state_ptr,entry,parsed_headers,counter);
	    if (status <= 0) {
		DPRINT(Debug,10,(&Debug,
				 "prepare_message_access: parse_body callback failed (%d)\n",
				 status));
	    }
	fail3:
	    if (parsed_headers) {
		delete_headers(&parsed_headers);
	    }
	}
    fail2:

	folder->folder_type->end_read_it(folder,read_state_ptr,1);	
	folder->folder_type->free_rs_fields_it(read_state_ptr);
	free_read_folder_state(&read_state_ptr);
		
	if (!status)
	    goto fail;
	
    }

    if (! entry->mime_parsed && parse_mime == NO_mime_parse) {
	DPRINT(Debug,10,(&Debug,
			"prepare_message_access: mime structure not needed\n"));

    } else if (! entry->mime_parsed) {
	FILE * F;

	DPRINT(Debug,10,(&Debug,
			 "prepare_message_access: Need parsing of mime structure (offset %ld)\n",
			 entry->offset
			 ));

	/* Offset of current message */
	F = folder->folder_type->xxx_to_fd(folder,entry->offset);

	if (!F) {
	    status = 0;
	    goto fail;
	}

	status = parse_mime(folder,entry,F);
	if (status <= 0) {
	    DPRINT(Debug,10,(&Debug,
			     "prepare_message_access: parse_mime callback failed (%d)\n",
			     status));
	}
    }

 fail:

    DPRINT(Debug,10,(&Debug,
		     "prepare_message_access=%d\n",status));

    return status;
 }

CONST char * is_forwarded_folder(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    CONST char *ret;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"is_forwarded_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"is_forwarded_folder",
	      "Bad magic number (read state)",0);

    DPRINT(Debug,10,(&Debug,
		     "is_forwarded_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    ret=folder->folder_type->is_forwarded_it(folder,read_state_ptr);

    DPRINT(Debug,10,(&Debug,
		     "is_forwarded_folder=%s\n",
		     ret ? ret : "<NULL>"));
    return ret;
}

long copy_fbytes_folder(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"copy_fbytes_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"copy_fbytes_folder",
	      "Bad magic number (read state)",0);
    
    DPRINT(Debug,10,(&Debug,
		     "copy_fbytes_folder=%ld: folder=%p (%s), type=%p (%s)\n",
		     read_state_ptr->fbytes,
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    return read_state_ptr->fbytes;
}

int copy_lines_folder(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"copy_lines_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"copy_lines_folder",
	      "Bad magic number (read state)",0);

    DPRINT(Debug,10,(&Debug,
		     "copy_lines_folder=%d: folder=%p (%s), type=%p (%s)\n",
		     read_state_ptr -> linecounter,
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));
    
    return read_state_ptr -> linecounter;
}


/* Gives header including continuation lines */
int copy_header_folder(folder,read_state_ptr,buffer,len)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
{
    int status;
    *buffer = NULL;
    *len = 0;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"copy_header_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"copy_header_folder",
	      "Bad magic number (read state)",0);

    DPRINT(Debug,10,(&Debug,
		     "copy_header_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    status = folder->folder_type->copy_header_it(folder,read_state_ptr,
						 buffer,len);

    read_state_ptr -> fbytes_body = read_state_ptr -> fbytes;

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

int copy_body_folder(folder,read_state_ptr,buffer,len,content_remaining)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     char **buffer; 
     int *len;
     long *content_remaining;
{
    int ret;
    *buffer = NULL;
    *len = 0;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"copy_body_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"copy_body_folder",
	      "Bad magic number (read state)",0);

    DPRINT(Debug,10,(&Debug,
		     "copy_body_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    if (*content_remaining == 0L) {
	/* If content remining has gone 0, let
	   let routine copy_envelope_end_folder() 
	   check end of message
	   -1 indicates no content-length given;
	*/
	DPRINT(Debug,10,(&Debug,
			 "copy_body_folder=0 (*content_remaining == 0)\n"));

	return 0;
    }

    ret=folder->folder_type->copy_body_it(folder,read_state_ptr,
					  buffer,len, 
					  content_remaining);
    DPRINT(Debug,10,(&Debug,
		     "copy_body_folder=%d\n",
		     ret));
    return ret;
}

/* Returns 0 if not end of message (needs resync without content-length) */
int copy_envelope_end_folder(folder,read_state_ptr)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
{
    int ret;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"copy_envelope_end_folder",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"copy_envelope_end_folder",
	      "Bad magic number (read state)",0);

    DPRINT(Debug,10,(&Debug,
		     "copy_envelope_end_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    ret=folder->folder_type->copy_envelope_end_it(folder,read_state_ptr);

    if (ret) {
	/*  0 == reading, 1 = skipping, -1 == end of message */
	read_state_ptr ->skipping = -1;
    }

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

int copy_envelope_reset_body(folder,read_state_ptr,content_remaining)
     struct folder_info *folder;
     READ_STATE read_state_ptr;
     long *content_remaining;
{
    int ret;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"copy_envelope_reset_body",
	      "Bad magic number (folder type)",0);
    if (RF_magic != read_state_ptr -> magic)
	panic("MBX PANIC",__FILE__,__LINE__,"copy_envelope_reset_body",
	      "Bad magic number (read state)",0);

    DPRINT(Debug,10,(&Debug,
		     "copy_envelope_reset_body: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    if (*content_remaining < 0L) {
       	panic("MBX PANIC",__FILE__,__LINE__,"copy_envelope_reset_body",
	      "*content_remaining < 0",0);

    }
    *content_remaining = -1L;
    
    ret=folder->folder_type->copy_envelope_reset_it(folder,read_state_ptr);

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

FILE * folder_to_fd(folder,offset)
     struct folder_info *folder;
     long offset;  
{
    FILE *ret;
    DPRINT(Debug,10,(&Debug,
		     "folder_to_fd: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"folder_to_fd",
	      "Bad magic number (folder type)",0);
	
    ret=folder->folder_type->xxx_to_fd(folder,offset);

    DPRINT(Debug,10,(&Debug,
		     "folder_to_fd=%s (%p)\n",
		     ret ? "NON-NULL" : "NULL",
		ret));
    return ret;
}

int new_mail_on_folder(folder,bytes)
     struct folder_info *folder;
     int *bytes;
{
    int ret;
    DPRINT(Debug,10,(&Debug,
		     "new_mail_on_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));
    
    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"new_mail_on_folder",
	      "Bad magic number (folder type)",0);

    ret=folder->folder_type->new_mail_on_it(folder,bytes);

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

int consider_remove_folder(folder)
     struct folder_info *folder; 
{    
    DPRINT(Debug,10,(&Debug,
		     "consider_remove_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"consider_remove_folder",
	      "Bad magic number (folder type)",0);
    
    if (!keep_empty_files) {
	if(folder->folder_type->consider_remove_it(folder)) {
	    close_folder(folder,CLOSE_NORMAL);
	    DPRINT(Debug,10,(&Debug,
			     "consider_remove_folder=1\n"));
	    return 1;
	}
    }
    DPRINT(Debug,10,(&Debug,
		     "consider_remove_folder=0 (keep_empty_files=%d)\n",
		     keep_empty_files));
    return 0;
}

int prepare_keep_folder(folder,keep_state_ptr)
     struct folder_info *folder;
     KEEP_STATE * keep_state_ptr;
{
    int status;
    KEEP_STATE ptr = NULL;

    DPRINT(Debug,10,(&Debug,
		     "prepare_keep_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"prepare_keep_folder",
	      "Bad magic number (folder type)",0);

    malloc_keep_folder_state(&ptr);
    folder->folder_type->zero_ks_fields_it(ptr);

    status = folder->folder_type->prepare_keep_it(folder,ptr);
   
    if (!status) {
	folder->folder_type->free_ks_fields_it(ptr);
	free_keep_folder_state(&ptr);
    }

    *keep_state_ptr = ptr;

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

int end_keep_folder(folder,keep_state_ptr)
     struct folder_info *folder;
     KEEP_STATE * keep_state_ptr;
{
    int status = 0;
    KEEP_STATE ptr = *keep_state_ptr;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"end_keep_folder",
	      "Bad magic number (folder type)",0);
    if (KS_magic != ptr->magic)
	panic("MBX PANIC",__FILE__,__LINE__,"end_keep_folder",
	      "Bad magic number (keep state)",0);

    DPRINT(Debug,10,(&Debug,
		     "end_keep_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));	

    status = folder->folder_type->end_keep_it(folder,ptr);
    
    folder->folder_type->free_ks_fields_it(ptr);
    free_keep_folder_state(&ptr);
    *keep_state_ptr = ptr;

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

void mark_keep_folder(folder,keep_state_ptr,entry,keep)
     struct folder_info *folder;
     KEEP_STATE keep_state_ptr;
     struct header_rec *entry;
     int keep;
{
    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"mark_keep_folder",
	      "Bad magic number (folder type)",0);
    if (KS_magic != keep_state_ptr->magic)
	panic("MBX PANIC",__FILE__,__LINE__,"mark_keep_folder",
	      "Bad magic number (keep state)",0);
    
    DPRINT(Debug,10,(&Debug,
		     "mark_keep_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));
    DPRINT(Debug,10,(&Debug,
		     "                : entry=%p",entry));
    if (!entry->mbx_info) {
	DPRINT(Debug,10,(&Debug,
			 ", { mbx_info=NULL }\n"));
    } else {
	DPRINT(Debug,10,(&Debug,
			 ", { mbx_info=%p, type=%p }\n",
			 entry->mbx_info,entry->mbx_info->type_code));
    }
    
    folder->folder_type->mark_keep_it(folder,keep_state_ptr,entry,keep);
}

CONST char * folder_type(folder)
     struct folder_info *folder;
{
    CONST char *ret;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"folder_type",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "folder_type: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    ret=folder->folder_type->type(folder);

    DPRINT(Debug,10,(&Debug,
		     "folder_type=%s\n",
		     ret ? ret : "<NULL>"));
    return ret;
}

int get_folder_mode(folder) 
     struct folder_info *folder;
{
    int ret = 0;

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"get_folder_mode",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "get_folder_mode: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));
    
    ret = folder->folder_type->get_it_mode(folder);
    
    DPRINT(Debug,10,(&Debug,
		     "get_folder_mode=%d\n",ret));
    return ret;
}

int start_edit_folder(folder,buffer)
     struct folder_info *folder; 
     CONST char **buffer;
{
    int ret;
    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"start_edit_folder",
	      "Bad magic number (folder type)",0);

    DPRINT(Debug,10,(&Debug,
		     "start_edit_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    ret=folder->folder_type->start_edit_it(folder,buffer);

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

int end_edit_folder(folder)
     struct folder_info *folder;
{
    int ret;
    DPRINT(Debug,10,(&Debug,
		     "end_edit_folder: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"end_edit_folder",
	      "Bad magic number (folder type)",0);

    ret=folder->folder_type->end_edit_it(folder);

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

void write_folder_info(F,folder)
     FILE *F; 
     struct folder_info *folder;
{
    DPRINT(Debug,10,(&Debug,
		     "write_folder_info: folder=%p (%s), type=%p (%s)\n",
		     folder,folder->cur_folder_sys,folder -> folder_type,
		     folder->folder_type->type_name));

    if (!valid_magic(folder->folder_type)) 
	panic("MBX PANIC",__FILE__,__LINE__,"write_folder_info",
	      "Bad magic number (folder type)",0);

    fprintf(F, "F%s\n",
	    (folder->folder_type == NON_SPOOL ? 
	     folder->cur_folder_sys : 
	     folder->cur_tempfolder));
}

void change_rec_mbx_info(entry, t)
     struct header_rec *entry;
     info_type_t t;
{
    DPRINT(Debug,14,(&Debug,
		     "change_rec_mbx_info: entry=%p, (new)t=%p\n",
		     entry,t));
    /* Make new mbx_info */
    if (entry->mbx_info) {
	DPRINT(Debug,14,(&Debug,
			 "                 : mbx_info=%p, type=%p\n",
			 entry->mbx_info,entry->mbx_info->type_code));	
	DPRINT(Debug,14,(&Debug,
			 "change_rec_mbx_info: resetting current mbx_info...\n"));
	entry->mbx_info->type_code->free_it(entry->mbx_info);
    } else {
	DPRINT(Debug,14,(&Debug,
			 "                 : mbx_info=NULL\n"));
    }
    
    entry->mbx_info = safe_realloc(entry->mbx_info, 
				   sizeof (struct mbx_hdr_info));
    bzero((void *)entry->mbx_info,sizeof (struct mbx_hdr_info));
    entry->mbx_info->type_code = t;
    entry->mbx_info->type_code->zero_it(entry->mbx_info);
}

void mbx_status_hook(hdr,buffer)
     struct header_rec *hdr; 
     char *buffer;
{
    /* buffer[0]     interim status of the message 
       buffer[1]     permanent attributes of the message
    */
    if (hdr->mbx_info)
	hdr->mbx_info->type_code->it_status(hdr->mbx_info,
					    buffer);
}



void free_rec_mbx_info(entry)
     struct header_rec *entry;
{
    DPRINT(Debug,10,(&Debug,
		     "free_rec_mbx_info: entry=%p\n",
		     entry));

    if (!entry->mbx_info) {
	DPRINT(Debug,10,(&Debug,
			 "                 : mbx_info=NULL\n"));
	return;
    }
    if (entry->mbx_info) {
	DPRINT(Debug,10,(&Debug,
			 "                 : mbx_info=%p, type=%p\n",
			 entry->mbx_info,entry->mbx_info->type_code));
	entry->mbx_info->type_code->free_it(entry->mbx_info);
	free(entry->mbx_info);
	entry->mbx_info = NULL;
    }
}

void unfold_header(buffer,len,current_header)
     char *buffer; 
     int *len; 
     struct header_rec *current_header;
{
    char *c, *p;
    enum tag { t_NORMAL, t_CR, t_LF } tag = t_NORMAL;
    
    DPRINT(Debug,65,(&Debug,
		     "fold_header- len=%d,buffer=%.*s",*len,*len,buffer));
    if (*len < 1 || !(buffer) || (buffer)[*len -1] != '\n') {
	DPRINT(Debug,65,(&Debug,
			 "\nfold_header- NO NEWLINE\n"));
    } 

    /* Unfold and remove newline ... */
    for (c = buffer, p = buffer; c < buffer + *len; c++) {
	switch(*c) {
	case '\n':
	    if (tag != t_CR && current_header && current_header->binary) {
		current_header->binary = 0;
		DPRINT(Debug,12,(&Debug,
				 "-- Not a binary message\n"));
	    }			
	    tag = t_LF;
	    break;
	case '\r':
	    tag = t_CR;
	    break;
	case ' ':
	case '\t':
	    if (tag == t_LF) {
		*(p++) = ' ';
		tag = t_NORMAL;
		break;
	    }
	default:
	    *(p++) = *c;
	case '\0':
	    tag = t_NORMAL;
	}
    }
    *p = '\0';
    
    *len = p-buffer;
    DPRINT(Debug,65,(&Debug,
		     "fold_header: len=%d,buffer=%.*s\n",*len,*len,buffer));

}

/* result MALLOCED */
char * return_path_to_env_from_1(value)
     CONST char *value;
{
    char * temp = NULL;

    char ** tokens = rfc822_tokenize(value);

    remove_space_tokenized(tokens);

    if (tokens[0] && 0 == strcmp(tokens[0],"<")) {
	int start = 1,i;
	
	/* Strip source path */
	for (i = 1; tokens[i]; i++) {
	    if (0 == strcmp(":",tokens[i]))
		start = i+1;
	    if (0 == strcmp(">",tokens[i]))
		break;
	}

	if (!tokens[i]) {
	    DPRINT(Debug,20,(&Debug,
			     "Bad Return-Path: %s\n",value));
	} else {
	    int j;

	    temp = safe_strdup("");
		
	    if (0 != strcmp(tokens[1],"@"))
		start = 1;
	    else if (start > 1) {
		DPRINT(Debug,20,(&Debug,
				 "  (stripping source path)\n"));
	    }
	    
	    for (j = start; j < i; j++)
		temp = strmcat(temp,tokens[j]);
	}    
    } else {
	DPRINT(Debug,20,(&Debug,
			 "Bad Return-Path: %s\n",value));
    }
    free_rfc822tokenized(tokens);
    
    return temp;
}


void return_path_to_env_from(entry,value)
     struct header_rec *entry;
     CONST char *value;
{
    int ef = give_dt_enumerate_as_int(&env_from_source);

    DPRINT(Debug,20,(&Debug,
		     "return_path_to_env_from- value=%s\n",value));
    DPRINT(Debug,20,(&Debug,
		     "env_from_source=%d\n",ef));

    /* env_from_source:      
       0 == forward-from,
       1 == from,
       2 == return-path
    */
    
    if (ef <3) {
	char * temp = return_path_to_env_from_1(value);

	if (temp) {
	    strfcpy(entry->env_from, temp, sizeof(entry->env_from));
	    DPRINT(Debug,20,(&Debug,
			     "  user=%s\n", temp));
	    free(temp);
	}
    }    
}

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


syntax highlighted by Code2HTML, v. 0.9.1