static char rcsid[] = "@(#)$Id: canceled_mail.c,v 1.16 2006/07/23 08:47:23 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.16 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
 *****************************************************************************/

#include "def_messages.h"
#include "s_elm.h"
#include "s_me.h"

DEBUG_VAR(Debug,__FILE__,"messages");

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

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

static struct MailboxView *canceled_mail_view = NULL;

struct mv_canceldir {
    char * dirname;
    char * indexname;

    FILE * index_F;
    charset_t   cs;

    time_t      last_scan;
    time_t      last_mtime;

    struct message_list {
	char              * filename;
	struct header_rec REC;
    } * message_list;
    int message_list_len;

    int    last_open_index;
    FILE * last_open_file;
};

S_(mt_init_mailbox mt_init_canceldir)
static void mt_init_canceldir P_((struct MailboxView *mbx));

static void mt_init_canceldir(mbx)
     struct MailboxView *mbx;
{
    mbx->u.canceldir = safe_malloc(sizeof (* (mbx->u.canceldir)));
		
    /* bzero is defined hdrs/defs.h */
    bzero((void *)mbx->u.canceldir, sizeof (* (mbx->u.canceldir)));

    mbx->u.canceldir->dirname       = NULL;
    mbx->u.canceldir->indexname     = NULL;
    mbx->u.canceldir->index_F       = NULL;
    mbx->u.canceldir->cs            = NULL;

    mbx->u.canceldir->last_scan     = 0; 
    mbx->u.canceldir->last_mtime    = 0;

    mbx->u.canceldir->message_list      = NULL;
    mbx->u.canceldir->message_list_len  = 0;

    mbx->u.canceldir->last_open_index   = -1;
    mbx->u.canceldir->last_open_file    = NULL;

}

S_(mt_free_mailbox mt_free_canceldir)
static void mt_free_canceldir P_((struct MailboxView *mbx));
static void mt_free_canceldir(mbx)
     struct MailboxView *mbx;
{

    if (mbx->u.canceldir->dirname) {
	free(mbx->u.canceldir->dirname);
	mbx->u.canceldir->dirname = NULL;
    }

    if (mbx->u.canceldir->indexname) {
	free(mbx->u.canceldir->indexname);
	mbx->u.canceldir->indexname = NULL;
    }

    if (mbx->u.canceldir->index_F) {

	fflush(mbx->u.canceldir->index_F);

	Release_the_file(fileno(mbx->u.canceldir->index_F));

	fclose(mbx->u.canceldir->index_F);
	mbx->u.canceldir->index_F = NULL;
    }

    mbx->u.canceldir->cs            = NULL;

    if (mbx->u.canceldir->message_list) {
	int i;

	for (i = 0; i < mbx->u.canceldir->message_list_len; i++) {
	    if (mbx->u.canceldir->message_list[i].filename) {
		free (mbx->u.canceldir->message_list[i].filename);
		mbx->u.canceldir->message_list[i].filename = NULL;
	    }

	    header_clear ( & ( mbx->u.canceldir->message_list[i].REC) );
	}
	free(mbx->u.canceldir->message_list);
	mbx->u.canceldir->message_list = NULL;
    }
    mbx->u.canceldir->message_list_len = 0;


    mbx->u.canceldir->last_open_index   = -1;
    if (mbx->u.canceldir->last_open_file) {
	fclose(mbx->u.canceldir->last_open_file);
	mbx->u.canceldir->last_open_file    = NULL;
    }

    free(mbx->u.canceldir);
    mbx->u.canceldir = NULL;

    /* Reset canceled_mail_view -pointer if we are going erase it */
    if (canceled_mail_view == mbx)
	canceled_mail_view = NULL;
}

static void mt_make_canceldir_view P_((struct MailboxView *mailbox));


S_(mt_add_mailbox_storage mt_add_canceldir_storage)
static void mt_add_canceldir_storage P_((struct MailboxView *mailbox,
				      struct current_storage *storage));
static void mt_add_canceldir_storage(mailbox,storage)
     struct MailboxView *mailbox;
     struct current_storage *storage;
{
    panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_add_canceldir_storage",
	  "mt_add_canceldir_storage called",0);
}

static int process_index P_((struct MailboxView *view));

static void unlock_index P_((struct MailboxView *view));
static void unlock_index(view)
     struct MailboxView *view;
{

    if (!view->u.canceldir->index_F)
	return;

    fflush(view->u.canceldir->index_F);

    Release_the_file(fileno(view->u.canceldir->index_F));

    fclose(view->u.canceldir->index_F);
    view->u.canceldir->index_F = NULL;   /* Mark -- no locked */
}

static void update_index P_((struct MailboxView *v));
static void add_canceled_mail1 P_((char *filename,
			     struct mailing_headers * headers,
			     struct MailboxView *view,
			     time_t X,
			     int lines,
			     header_list_ptr h,
			     long body_offset));	      

static void move_olds P_((struct MailboxView *v));

#ifdef DIROPS

#if DIROPS == USE_DIRENT
#include <dirent.h>
#endif /* DIROPS == USE_DIRENT */
#if DIROPS == USE_SYSDIR
#include <sys/dir.h>
#endif /* DIROPS == USE_SYSDIR */

static void update_index(v)
     struct MailboxView *v;
{
    DIR *   handle;
    struct stat dstat;
    time_t  now   = time(NULL);
   
    int unlock_it = 0;

#if DIROPS == USE_DIRENT
    struct dirent * Xptr;
#endif /* DIROPS == USE_DIRENT */
#if DIROPS == USE_SYSDIR
    struct direct * Xptr;
#endif /* DIROPS == USE_SYSDIR */

    if (0 != stat(v->u.canceldir->dirname,&dstat)) {
	DPRINT(Debug,1,(&Debug,"stat %s failed!\n",
			v->u.canceldir->dirname));
	dstat.st_mtime = now;
    }

    if (dstat.st_mtime == v->u.canceldir->last_mtime &&
	now < v->u.canceldir->last_scan + 60) {
	DPRINT(Debug,7,(&Debug,"scan %s skipped\n",
			v->u.canceldir->dirname));
	return;
    }

    if (!v->u.canceldir->index_F) {
	if (! process_index(v))
	    return;

	unlock_it++;
    }

    v->u.canceldir->last_mtime = dstat.st_mtime;
    v->u.canceldir->last_scan  = now;

    handle = opendir(v->u.canceldir->dirname);
    if (!handle)
	goto fail2;

    while (NULL != (Xptr = readdir(handle))) {
	if ('.' != Xptr->d_name[0]) {
	    struct stat X;
	    char *fullname;
	    int fd;
	    FILE *f1 = NULL;
	    header_list_ptr h = NULL;
	    long b;
	    int lines = 0;
	    int i,c;

#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 */
	    
	    fullname = safe_strdup(v->u.canceldir->dirname);
	    fullname = strmcat(fullname,"/");
	    fullname = strmcat(fullname,entryname);

	    for (i = 0; i < v->u.canceldir->message_list_len; i++)
		if ( 0 == strcmp(entryname,
				 v->u.canceldir->message_list[i].filename))
		    goto found;

	    fd = open(fullname,O_RDONLY);
	    if (fd < 0)
		goto fail1;
	    
	    
	    if (-1 == fstat(fd,&X)) {
		close(fd);
		goto fail1;
	    }

	    if (X.st_uid != userid) {
		/* Wrong owner */
		close(fd);
		goto fail1;
	    }

	    f1 = fdopen(fd,"r");
	    if (!f1) {
		close(fd);
		goto fail1;
	    }
	    

	    h = file_read_headers(f1,RHL_CHECK_HEADER);
	    b = ftell(f1);

	    while (EOF != (c = getc(f1))) {
		if ('\n' == c)
		    lines++;
	    }

	    add_canceled_mail1(entryname,
			      NULL,v,X.st_mtime,lines,h,b);


	fail1:
	    if (h)
		delete_headers(&h);

	    if (f1)
		fclose(f1);;


	found:
	    free(entryname);
	    free(fullname);
	}
    }

    closedir(handle);

    if (v == canceled_mail_view)
	move_olds(v);

 fail2:
    if (unlock_it)
	unlock_index(v);
}


#else
static void update_index(v)
     struct MailboxView *v;
{
    /* EMPTY */
}
#endif

/* Return 1 if redraw required */
S_(mt_update_view_mailbox mt_update_view_canceldir)
/* Return 1 if redraw required */
static int mt_update_view_canceldir P_((struct MailboxView *mailbox));
static int mt_update_view_canceldir(mailbox)
     struct MailboxView *mailbox;
{
    int count;
    int i,x;

    update_index(mailbox);
      
    count = mailbox->u.canceldir->message_list_len;

    if (count != mailbox->view_len) {

	mt_make_canceldir_view(mailbox);

	DPRINT(Debug,7,(&Debug,
			    "mt_update_view_canceldir=1 (%d messages)\n",
			mailbox->view_len));
	
	return 1;
    }

    DPRINT(Debug,7,(&Debug,
		    "mt_update_view_canceldir=0\n"));
    return 0;
}

S_(mt_get_main_mailbox_folder mt_get_main_canceldir_folder)
static struct folder_info * mt_get_main_canceldir_folder P_((struct MailboxView *mailbox));
static struct folder_info * mt_get_main_canceldir_folder(mailbox)
     struct MailboxView *mailbox;
{
    return NULL;
}

/* Can be called from signal handler */
S_(mt_get_mailbox_storage mt_get_canceldir_storage)
/* Can be called from signal handler */
static struct current_storage * mt_get_canceldir_storage P_((struct MailboxView *mailbox,
							    int i));
/* Can be called from signal handler */
static struct current_storage * mt_get_canceldir_storage(mailbox,i) 
     struct MailboxView *mailbox;
     int i;
{

    return NULL;
}

/* Can be called from signal handler */
S_(mt_get_mailbox_storage_count mt_get_canceldir_storage_count)
/* Can be called from signal handler */
static int mt_get_canceldir_storage_count P_((struct MailboxView *mailbox));

/* Can be called from signal handler */
static int mt_get_canceldir_storage_count(mailbox) 
     struct MailboxView *mailbox;
{
    return 1;
}

static int update_open P_((struct mv_canceldir *d, int idx));
static int update_open(d,idx)
     struct mv_canceldir *d; 
     int idx;
{
    if (d->last_open_index != idx &&
	d->last_open_file) {

	fclose(d->last_open_file);
	d->last_open_file = NULL;
    }

    if (!d->last_open_file) {
	char * filename = elm_message(FRM("%s/%s"),
				      d->dirname,
				      d->message_list[idx].
				      filename);
	    
	int err  = can_open(filename,"r");
	if (err) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
			      "Can't open %s!"),
		      filename);
	    free(filename);
	    return 0;
	}
	
	d->last_open_file = fopen(filename,"r"); 
	if (!d->last_open_file) {
	    lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
			      "Can't open %s!"),
		      filename);
	    free(filename);
	    return 0;
	}
	d->last_open_index = idx;
	free(filename);
	
    } else
	rewind(d->last_open_file);
    
    return 1;
}

static int update_header P_((struct mv_canceldir *d, int idx));
static int update_header(d,idx)
     struct mv_canceldir *d; 
     int idx;
{
    struct header_rec *hdr = & (d->message_list[idx].REC);

    if (!update_open(d,idx)) {
	DPRINT(Debug,10,(&Debug,"update_header: %d -- failed\n",
			 idx));

	return 0;
    }
    if (! hdr->body_parsed) {
	header_list_ptr parsed_headers = 
	    file_read_headers(d->last_open_file,0);
	long content_start;
	
	
	if (!parsed_headers) {
	    DPRINT(Debug,3,(&Debug,
			    "update_header:  No headers parsed! \n"));
	}
	
	read_folder_headers_helper(hdr,parsed_headers);
	header_parse_helper(hdr,parsed_headers);
	
	content_start = ftell(d->last_open_file);
	start_body_helper(hdr,
			  content_start,parsed_headers);
	
	delete_headers(&parsed_headers);
	
	/* start_body_helper is called */
	hdr->body_parsed = 1;
	
    }

    DPRINT(Debug,10,(&Debug,"update_header: %d -- OK\n",
			 idx));


    return 1;
}


S_(mt_give_header_mailbox mt_give_header_canceldir)
static struct header_rec * mt_give_header_canceldir P_((struct MailboxView *mailbox,
						     int index,
						     struct folder_view *v));
static struct header_rec * mt_give_header_canceldir(mailbox,index,v)
     struct MailboxView *mailbox;
     int index;
     struct folder_view *v;
{
    int mbx,idx;
    
    mbx = v->mailbox_number;
    if (mbx != 0)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "mt_give_header_canceldir",
	      "Bad mailbox number",0);

    idx = v->index;
    if (idx < 0 || idx >= mailbox->u.canceldir->message_list_len)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "mt_give_header_canceldir",
	      "Bad internal index",0);
	

    if (-1 == mailbox->u.canceldir->message_list[idx].
	REC.mime_rec.begin_offset)
	update_header(mailbox->u.canceldir,idx);
   
    return & (mailbox->u.canceldir->message_list[idx].REC);
    
}

S_(sdt_give_header_s sdt_give_header_cm)
static struct header_rec * sdt_give_header_cm P_((struct sort_data *s,
						   struct folder_view *v));
static struct header_rec * sdt_give_header_cm(s,v)
     struct sort_data *s;
     struct folder_view *v;
{
    return & (s->u.canceldir->message_list[v->index].REC);
}

static struct sort_data_type cm_sort = {
    SORTDATATYPE_magic,
    sdt_give_header_cm
};


S_(mt_sort_mailbox_view mt_sort_canceldir_view)
     static void mt_sort_canceldir_view P_((struct MailboxView *mailbox,
				     hdr_compare_func   *func));
static void mt_sort_canceldir_view(mailbox,func)
     struct MailboxView *mailbox;
     hdr_compare_func   *func;
{
    int i;
    struct sort_data * array;

    /* Little dirty ... */
    typedef int (*compar) P_((const void *, const void *));
    compar X = (compar) func;
    
    array = safe_malloc(mailbox->view_len * sizeof (array[0]));

    for (i = 0; i < mailbox->view_len; i++) {
	int mbx = mailbox->view[i].mailbox_number;

	array[i].w              = mailbox->view[i];
	array[i].t              = mailbox->thread_view;   /* For thread sorting */
	array[i].sort_data_type = &cm_sort;
	array[i].u.canceldir    = mailbox->u.canceldir;

    }

    qsort(array,mailbox->view_len,sizeof (array[0]), X);
   
    for (i = 0; i < mailbox->view_len; i++) {
	mailbox->view[i] = array[i].w;
    }

    free(array);
}

/* XXX not good .... */

S_(mt_give_message_data_mailbox mt_give_message_data_canceldir)
static int mt_give_message_data_canceldir P_((struct MailboxView *mailbox,
					   int index,
					   struct header_rec **ret_header,
					   FILE              **ret_F,
					   struct counter_data *counter,
					   parse_mime_callback *parse_mime,
					   struct folder_view *v));
static int mt_give_message_data_canceldir(mailbox,index,ret_header,ret_F,
					  counter,parse_mime,v)
     struct MailboxView *mailbox;
     int index;
     struct header_rec **ret_header;
     FILE              **ret_F;
     struct counter_data *counter;
     parse_mime_callback *parse_mime;
     struct folder_view *v;
{
    struct header_rec *hdr;
    
    int mbx,idx;
    
    mbx = v->mailbox_number;
    if (mbx != 0) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "mt_give_message_data_canceldir",
	      "Bad mailbox number",0);
	return 0;
    }

    idx = v->index;
    if (idx < 0 || idx >= mailbox->u.canceldir->message_list_len) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "mt_give_message_data_canceldir",
	      "Bad internal index",0);
	return 0;
    }

    hdr = & (mailbox->u.canceldir->message_list[idx].REC);

    /* hdr is also needed on error messages ... */
    if (ret_header) {

	if (-1 == hdr->mime_rec.begin_offset) 
	    update_header(mailbox->u.canceldir,idx);  
        *ret_header = hdr;

	DPRINT(Debug,10,(&Debug,"mt_give_message_data_canceldir: %d -- giving header\n",
			 idx));

    }

    if (ret_F) {

	if (!update_header(mailbox->u.canceldir,idx)) {
	    DPRINT(Debug,6,(&Debug,"mt_give_message_data_canceldir: %d failed\n",
			    idx));
	    return 0;
	}


	/* Simulate prepare_message_access */

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

	    int status;


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

	    if (0 != fseek(mailbox->u.canceldir->last_open_file,
			   hdr->offset,
			   SEEK_SET)) {
		
		DPRINT(Debug,10,(&Debug,
				 "mt_give_message_data_canceldir: seek to %ld failed\n",
				 hdr->offset));
		return 0;		
	    }

	    status = parse_mime(NULL,hdr,
				mailbox->u.canceldir->last_open_file);
	    if (status <= 0) {
		DPRINT(Debug,10,(&Debug,
				 "mt_give_message_data_canceldir: parse_mime callback failed (%d)\n",
				 status));
	    }



	}

	rewind(mailbox->u.canceldir->last_open_file);	
	*ret_F = mailbox->u.canceldir->last_open_file;

	DPRINT(Debug,10,(&Debug,"mt_give_message_data_canceldir: %d -- giving file\n",
			 idx));

    }

    DPRINT(Debug,10,(&Debug,"mt_give_message_data_canceldir: %d -- succeed\n",
		     idx));
    
    return 1;
}



S_(mt_write_mailbox_info mt_write_canceldir_info)
static void mt_write_canceldir_info P_((FILE *fp, struct MailboxView *mailbox,
				     int s, int cur_idx));
static void mt_write_canceldir_info(fp,mailbox,s, cur_idx)
     FILE *fp; 
     struct MailboxView *mailbox;
     int s;
     int cur_idx;
{
    /* EMPTY */
}

S_(mt_mailbox_title mt_canceldir_title)
static struct string * mt_canceldir_title P_((struct MailboxView *mailbox));
static struct string * mt_canceldir_title(mailbox)
     struct MailboxView *mailbox;
{

    if (canceled_mail_view == mailbox) {
	if (*hostname && menu_display_host) 
	    return format_string(CATGETS(elm_msg_cat, ElmSet, 
					 ElmCanceledMailsOn,
					 "Canceled mails on %s"),
				 hostname);
				 
	return format_string(CATGETS(elm_msg_cat, ElmSet, 
				     ElmCanceledMails,
				     "Canceled mails"));

    }

    /* These two should not really be used ... */

    if (*hostname && menu_display_host) 
	return format_string(CATGETS(elm_msg_cat, ElmSet, 
				     ElmMDirectoryOn,
				     "Message directory %s on %s"),
			     mailbox->u.canceldir->dirname,
			     hostname);

    return format_string(CATGETS(elm_msg_cat, ElmSet, 
				 ElmMDirectory,
				     "Message directory %s"),
			 mailbox->u.canceldir->dirname);

}

S_(mt_make_mailbox_view mt_make_canceldir_view)
static void mt_make_canceldir_view (mailbox)
     struct MailboxView *mailbox;
{
    int count = mailbox->u.canceldir->message_list_len;
    int i,x;


    if (count < 1) {
	if (mailbox->view)
	    free(mailbox->view);
	mailbox->view     = NULL;
	mailbox->view_len = 0;

	return;
    }

    mailbox->view = 
	safe_realloc(mailbox->view,
		     count * (sizeof ( mailbox->view[0])));

    
    for (x = 0; x < count; x++) {
	zero_folder_view(& (mailbox->view[x]));

	mailbox->view[x].mailbox_number = 0;
	mailbox->view[x].index          = x;
    }
    mailbox->view_len = count;
}


S_(mt_add_mailbox_digest mt_add_canceldir_digest)
static void mt_add_canceldir_digest P_((struct MailboxView *mailbox,
				      mime_t *list,
				      time_t received_time,
				      char *env_from,
				      FILE *F,
				      charset_t defcharset
				      ));
static void mt_add_canceldir_digest(mailbox, list, received_time, env_from, F,
				    defcharset
				    )
     struct MailboxView *mailbox;
     mime_t *list;
     time_t received_time;
     char *env_from;
     FILE *F;
     charset_t defcharset;
{
    panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_add_canceldir_digest",
	  "mt_add_canceldir_digest called",0);
}

static struct mailbox_type mt_canceldir = {
    MAILBOXTYPE_magic,
    mt_init_canceldir,
    mt_free_canceldir,
    mt_add_canceldir_storage,
    mt_update_view_canceldir,
    mt_get_main_canceldir_folder,
    mt_get_canceldir_storage,
    mt_get_canceldir_storage_count,
    mt_give_header_canceldir,
    mt_sort_canceldir_view,
    mt_give_message_data_canceldir,
    mt_write_canceldir_info,
    mt_canceldir_title,
    mt_make_canceldir_view,
    mt_add_canceldir_digest
};

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

static void index_initialize P_((struct MailboxView *view));

/* 1 == readed and locked, 0 = failure */
static int process_index(view)
     struct MailboxView *view;
{

    int count = 0;

    int err = can_open(view->u.canceldir->indexname, "a");
    int ret;
    char buffer[20];

    if (err) {
	lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
			  "Can't open %s!"),
		  view->u.canceldir->indexname);
	return 0;
    }

    view->u.canceldir->index_F = 
	open_or_create(view->u.canceldir->indexname);
    if (!view->u.canceldir->index_F) {
	lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
			  "Can't open %s!"),
		  view->u.canceldir->indexname);
	return 0;
    }


    ret = Grab_the_file(fileno(view->u.canceldir->index_F));
    if (FLOCKING_RETRY == ret) {
	lib_transient(CATGETS(elm_msg_cat, MeSet, MeLockingFile,
			      "Locking %s..."),
		      view->u.canceldir->indexname);
	while (FLOCKING_RETRY == ret && count++ < 3) {
#if POLL_METHOD
	    wait_for_timeout(1);
#else
	    sleep(1);
#endif
	    ret = Grab_the_file(fileno(view->u.canceldir->index_F));
	}
	
	if (FLOCKING_OK == ret) 
	    lib_transient(CATGETS(elm_msg_cat, MeSet, MeLockingFileOK,
				  "Locking %s... OK."),
			  view->u.canceldir->indexname);
	
	if (FLOCKING_RETRY == ret) {
	    fclose(view->u.canceldir->index_F);
	    view->u.canceldir->index_F = NULL;
	    return 0;
	}	    	    
    }
    
    if (FLOCKING_FAIL == ret) {
	lib_error(CATGETS(elm_msg_cat, MeSet, MeLockingFileFAIL,
			  "Locking %s... Failed."),
		  view->u.canceldir->indexname);
	
	fclose(view->u.canceldir->index_F);
	view->u.canceldir->index_F = NULL;
	return 0;
    }
    
    if ((ret = mail_gets(buffer, sizeof buffer,
			 view->u.canceldir->index_F)) > 0) {
	
	struct message_list * current = NULL;   /* current index */
	
	if (ret != 12 || 0 != memcmp(buffer,"ELMME+ MIDX\n",12)) {

	    DPRINT(Debug,7,(&Debug,
			    "process_index: Bad bagic (len %d): %.*s\n",
			    ret,ret,buffer));

	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
			      "File %s is corrupted."),
		      view->u.canceldir->indexname);
	    
	    Release_the_file(fileno(view->u.canceldir->index_F));

	    fclose(view->u.canceldir->index_F);
	    view->u.canceldir->index_F = NULL;
	    
	    return 0;
	}
	
	/* malloc_gets reallocates buffer1 and do not return \n.
	   It returns -1 if line is longer than given limit (32000)
	   and -2 is returned on error  (buffer may still be alloced)
	*/
	while (!feof(view->u.canceldir->index_F) &&
	       !ferror(view->u.canceldir->index_F) &&
	       ret >= 0) {
	    char * buffer1 = NULL;
	    
	    ret = malloc_gets(&buffer1, 32000, view->u.canceldir->index_F);
	    if (ret < 0 || !buffer1)
		goto fail;
	    
	    if (ret >= 2) {

		if (strcmp("--END",buffer1) == 0) {
		    /* Temporary terminator */
		    
		    ret = -2;
		    goto fail;
		}


		if (0 == strncmp(buffer1,"C ",2)) {
		    view->u.canceldir->cs = 
			    MIME_name_to_charset(buffer1+2,0);
		    goto next_line;
		}		    
		
		if (!view->u.canceldir->cs ||
		    ' ' != buffer1[1]) {

		    DPRINT(Debug,7,(&Debug,
				    "process_index: Bad line (len %d): %.*s\n",
				    ret,ret,buffer1));

		    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
				      "File %s is corrupted."),
			      view->u.canceldir->indexname);
		    ret = -1;
		    goto fail;
		}
		
		switch (buffer1[0]) {
		case 'F': {
		    char * fname = buffer1+2;
		    int i;

		    current = NULL;

		    for (i = 0; i < view->u.canceldir->message_list_len; i++)
			if (0 == strcmp(view->u.canceldir->message_list[i].
					filename,fname)) {
			    current = & (view->u.canceldir->
					 message_list[i]);
			    DPRINT(Debug,7,(&Debug,
					    "process_index: File %s already on index (%d)\n",
					    fname,i));
			}

		    if (!current) {		    
			DPRINT(Debug,7,(&Debug,
					"process_index: Adding file %s  to index\n",
					fname));
			
			view->u.canceldir->message_list =
			    safe_realloc(view->u.canceldir->message_list,
					 (view->u.canceldir->message_list_len+1) *
					 sizeof (view->u.canceldir->message_list[0]));
			
			current = & (view->u.canceldir->
				     message_list[view->u.canceldir->message_list_len++]);
			
			header_zero( & (current->REC));
			
			current->filename = safe_strdup(buffer1+2);


			/* Charset used by index writing code... */
			current->REC.header_charset = view->u.canceldir->cs;
			
			current->REC.offset         = 0;

			/* Default envelope sender */
			if (view == canceled_mail_view) 
			    strfcpy(current->REC.env_from,username,
				    sizeof (current->REC.env_from));
		    }
		}
		    break;
		    
		case 'L':
		    if (!current)  goto bad0;
		    current->REC.lines = atoi(buffer1+2);
			break;
			
		case 'T':
		    if (!current)  goto bad0;
		    current->REC.received_time = atol(buffer1+2);
		    break;
		    
		case 'E':
		    if (!current)  goto bad0;
		    strfcpy(current->REC.env_from,buffer1+2,
			    sizeof (current->REC.env_from));
		    break;
		    
		case 'f':
		    if (!current)  goto bad0;
		    if (current->REC.from) 
			break;
		    current->REC.from = break_down_address(buffer1+2,0,view->u.canceldir->cs);
		    break;
		    
		case 't':
		    if (!current)  goto bad0;
		    if (current->REC.to) 
			break;
		    current->REC.to = break_down_address(buffer1+2,0,view->u.canceldir->cs);
		    break;
		    
		case 'c':
		    if (!current)  goto bad0;
		    if (current->REC.cc)
			break;
		    current->REC.cc = break_down_address(buffer1+2,0,view->u.canceldir->cs);
		    break;
		    
		case 'M':
		    if (!current)  goto bad0;
		    strfcpy(current->REC.messageid,buffer1+2,
			    sizeof (current->REC.messageid));
		    break;
		    
		case 'd':
		    if (!current)  goto bad0;
		    current->REC.time_sent     = atol(buffer1+2);
		    break;
		    
		case 'S':
		    if (!current)  goto bad0;
		    if (current->REC.subject)
			break;
		    current->REC.subject = hdr_to_string(HDR_TEXT,
							 buffer1+2,
							 view->u.canceldir->cs,
							 0);
		    break;

		default:
		bad0:
		    
		    DPRINT(Debug,7,(&Debug,
				    "process_index: Bad line or token (len %d): %.*s\n",
				    ret,ret,buffer1));

		    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
				      "File %s is corrupted."),
			      view->u.canceldir->indexname);
		    ret = -1;
		    goto fail;
		    
		}
		
	    } else if (0 != ret) {

		DPRINT(Debug,7,(&Debug,
				"process_index: short line (len %d): %.*s\n",
				ret,ret,buffer1));
		
		lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
				  "File %s is corrupted."),
			  view->u.canceldir->indexname);
		ret = -1;
	    } else
		current = NULL;
	    
	    
	next_line:
	fail:
	    
	    if (buffer1) {
		free(buffer1);
		buffer1 = NULL;
	    }
	    
	}
	
	
	
    } else {
	/* Initialize file */

	index_initialize(view);
    }
    
    return 1;  

}


static void setup_canceldir P_((struct MailboxView *view, char *dir));
static void setup_canceldir(view,dir)
     struct MailboxView *view; 
     char *dir;
{
    if (&mt_canceldir!= view->mailbox_type)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"setup_canceldir",
	      "Bad type for canceldir view",0);

    if (view->u.canceldir->dirname ||
	view->u.canceldir->indexname ||
	view->u.canceldir->index_F)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"setup_canceldir",
	      "canceldir view already set up",0);

    DPRINT(Debug,8,(&Debug,
		    "setup_canceldir(view=%p,dir=%s)\n",
		    view,dir));

    if (dir[0]) {
	int err,ret;
	char buffer[30];

	view->u.canceldir->dirname = safe_strdup(dir);
        
	view->u.canceldir->indexname = 
	    elm_message(FRM("%s/.index"),dir);

	/* Is directory created yet ? */
	if (access(dir, WRITE_ACCESS) < 0) {
	    int err = errno;

	    if (ENOENT == err)
		return;

	    lib_error(CATGETS(elm_msg_cat, ElmSet,ElmErrorAccess,
			      "%.45s: %.33s"),
		      dir,error_description(err));

	    return;
	}

	process_index(view);
    }	   
}

static struct addr_item *dup_addr_list P_((struct addr_item *list));
static struct addr_item *dup_addr_list(list) 
     struct addr_item *list;
{
    int L = 0;
    struct addr_item *ptr;
    int i;

    for (ptr=list; ptr->addr && ptr->fullname; ptr++)
	L++;


    ptr = safe_malloc((L+1) * sizeof (ptr[0]));

    for (i = 0; i < L; i++) {
	ptr[i].addr     = safe_strdup(list[i].addr);
	ptr[i].fullname = dup_string(list[i].fullname);
	ptr[i].comment = NULL;
	if (list[i].comment)
	    ptr[i].comment = dup_string(list[i].comment);
    }

    ptr[i].addr     = NULL;
    ptr[i].fullname = NULL;
    ptr[i].comment = NULL;

    return ptr;
}

static void write_addr_list P_((FILE *F, struct addr_item *list,
				charset_t cs, int letter));
static void write_addr_list(F,list,cs,letter)
     FILE *F; 
     struct addr_item *list;
     charset_t cs; 
     int letter;
{
    struct addr_item *ptr;
    
    putc(letter,F);
    putc(' ',F);

    for (ptr=list; ptr->addr && ptr->fullname; ptr++) {
	char * buffer;

	if (ptr != list) {
	    putc(',',F);
	    putc(' ',F);
	}

	buffer  = string_to_hdr(HDR_PHRASE, ptr->fullname,
				      cs, 0, NULL);

	if (buffer) {
	    fputs(buffer,F);
	    putc(' ',F);
	    free(buffer);
	}

	putc('<',F);
	fputs(ptr->addr,F);
	putc('>',F);

	if (ptr->comment) {
	    buffer = string_to_hdr(HDR_COMMENT, ptr->comment,
				   cs, 0, NULL);

	    if (buffer) {
		putc(' ',F);
		putc('(',F);
		fputs(buffer,F);
		putc(')',F);
		
		free(buffer);
	    }
	}
    }
    putc('\n',F);
}

static void write_index_rec P_((struct MailboxView *view,
				struct message_list * current));

static void write_index_rec(view,current)
     struct MailboxView *view;
     struct message_list * current;
{
    fprintf(view->u.canceldir->index_F,
	    "F %s\n",
	    current->filename);

    if (current->REC.lines >= 0) {	    
	fprintf(view->u.canceldir->index_F,"L %d\n",
		current->REC.lines);
    }

    fprintf(view->u.canceldir->index_F,
	    "T %ld\n",
	    (long int) current->REC.received_time);

    fprintf(view->u.canceldir->index_F,
	    "d %ld\n",
	    (long int) current->REC.time_sent);

    if (current->REC.env_from[0]) {
	fprintf(view->u.canceldir->index_F,
		"E %s\n",
		current->REC.env_from);	
    }

    if (current->REC.from) {
	write_addr_list(view->u.canceldir->index_F,
			    current->REC.from,
			view->u.canceldir->cs,'f');
    }

    if (current->REC.to) {
	write_addr_list(view->u.canceldir->index_F,
			current->REC.to,
			view->u.canceldir->cs,'t');
    }

    if (current->REC.cc) {
	write_addr_list(view->u.canceldir->index_F,
			current->REC.cc,
			view->u.canceldir->cs,'c');
    }

    if (current->REC.messageid[0]) {
	fprintf(view->u.canceldir->index_F,
		"M %s\n",
		current->REC.messageid);	
    }

    if (current->REC.subject) {
	char * s = string_to_hdr(HDR_TEXT,current->REC.subject,
				 view->u.canceldir->cs,0, NULL);
	fprintf(view->u.canceldir->index_F,
		"S %s\n",
		s);
	free(s);	    
    }    
}

static void add_canceled_mail1(filename,headers,view,X,lines,h,
			      body_offset)
     char *filename;
     struct mailing_headers * headers;
     struct MailboxView *view;
     time_t X;
     int lines;
     header_list_ptr h;
     long body_offset;	      
{
    struct message_list * current = NULL;   /* current index */

    view->u.canceldir->message_list =
	safe_realloc(view->u.canceldir->message_list,
		     (view->u.canceldir->message_list_len+1) *
		     sizeof (view->u.canceldir->message_list[0]));
    
    current = & (view->u.canceldir->
		 message_list[view->u.canceldir->message_list_len++]);
    

    current->filename = safe_strdup(filename);
    header_zero( & (current->REC));
    
    /* Dummy default ... */
    current->REC.header_charset = view->u.canceldir->cs; 
    /* read_folder_headers_helper() will re-set header_charset
       if it sees X-ELM-OSV header with parameter
       hdr-charset
    */
    
    /* Start of headers */
    current->REC.offset         = 0;
    current->REC.mime_rec.begin_offset   = 0;
    
    /* Start of body */
    if (body_offset >= 0L)
	current->REC.mime_rec.begin_offset  =  body_offset;

    if (lines >= 0) 
	current->REC.lines = lines;
    current->REC.received_time = X;
    current->REC.time_sent = X;
    
    if (h) {
	
	/* Parses Return-Path, Message-Id, Content-Length,
	   Date, MIME-Version, X-ELM-OSV
	*/
	read_folder_headers_helper(& (current->REC), h);
	
	/* Parses Sensitivity, Importance, Priority,
	   Action, Content-Type, Status, 
	   Subject, From, To, Cc
	   
	   And X-IMAP is used on message-hide-hack
	*/
	header_parse_helper(& (current->REC), h);
    }
       
    if (headers && headers->env_from &&
	! current->REC.env_from[0]) {
	int x;
	CONST char * t = mailer_env_from_value(headers->env_from,&x);

	/* Assurance */
	if (t)
	    strfcpy(current->REC.env_from,t,
		    sizeof (current->REC.env_from));
    } 
    
    /* Adds env_from, if not set */
    if (view == canceled_mail_view &&
	!current->REC.env_from[0]) {

	strfcpy(current->REC.env_from,username,
		sizeof (current->REC.env_from));
    }

    if (headers && headers->from.addrs &&
	! current->REC.from) {
	current->REC.from = dup_addr_list(headers->from.addrs);
    }
    
    if (headers && headers->to.addrs &&
	! current->REC.to) {
	current->REC.to = dup_addr_list(headers->to.addrs);
    }
            
    if (headers && headers->cc.addrs &&
	! current->REC.cc) {
	current->REC.cc = dup_addr_list(headers->cc.addrs);
    }
        
    if (headers && headers->subject &&
	! current->REC.subject)
	current->REC.subject = dup_string(headers->subject);
    
    write_index_rec(view,current);
}

void delete_marked_canceled_mails(view)
     struct MailboxView *view;
{
    int i;
    struct mv_canceldir *d; 

    if (&mt_canceldir!= view->mailbox_type)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "delete_marked_canceled_mails",
	      "Bad type for canceldir view",0);

    d = view->u.canceldir;

    /* DO not remove data from index on here!
       because it confuses canceled mail selection
    */

    if (! d->dirname)
	return;

    for (i = 0; i < d->message_list_len; i++) {
	if (ison(d->message_list[i].REC.status,
		 DELETED)) {
	    char * filename = elm_message(FRM("%s/%s"),
					  d->dirname,
					  d->message_list[i].
					  filename);


	    if (0 == unlink(filename)) {
		DPRINT(Debug,7,(&Debug,
				"Removed canceled mail [%d]: %s\n",
				i,filename));

	    }

	    free(filename);
	}
    }
}

static void index_initialize(view)
     struct MailboxView *view;
{
    /* Initialize file */

    rewind(view->u.canceldir->index_F);
    
#ifdef FTRUNCATE
    ftruncate(fileno(view->u.canceldir->index_F),0);
#endif

    fprintf(view->u.canceldir->index_F,
	    "ELMME+ MIDX\n");
    
    view->u.canceldir->cs = 
	MIME_name_to_charset("UTF-8",0);
    if (view->u.canceldir->cs && 
	view->u.canceldir->cs->MIME_name)
	fprintf(view->u.canceldir->index_F,
		"C %s\n",
		view->u.canceldir->cs->MIME_name);
    
    fflush(view->u.canceldir->index_F);
}



void sync_canceled_mails(view) 
    struct MailboxView *view;
{
    /* Rewrites index if needed */

    int i,X;
    int unlock_it = 0;
    struct mv_canceldir *d; 
    

    if (&mt_canceldir!= view->mailbox_type)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "sync_canceled_mails",
	      "Bad type for canceldir view",0);

    d = view->u.canceldir;

    if (! d->dirname ||
	! d->indexname) {
	return;
    }

    if (!view->u.canceldir->index_F) {
	if (! process_index(view))
	    return;

	unlock_it++;
    }


    for (i = 0, X=0; i < d->message_list_len; i++) {

	char * filename = elm_message(FRM("%s/%s"),
				      d->dirname,
				      d->message_list[i].
				      filename);
	
	if (0 != access(filename,ACCESS_EXISTS)) {
	    DPRINT(Debug,7,(&Debug,
			    "[%d] not exists, removing from index: %s\n",
			    i,filename));


	    header_clear(& (d->message_list[i].REC));
	    free(d->message_list[i].filename);
	    d->message_list[i].filename = NULL;

	} else {
	    if (X < i) {
		d->message_list[X] = d->message_list[i];
	
		/* Avoid double pintters */
		header_zero(& (d->message_list[i].REC));
		d->message_list[i].filename = NULL;
	    }
	    X++;
	}

	free(filename);
    }

    if (X < d->message_list_len) {

	long pos;

	
	DPRINT(Debug,7,(&Debug,
			"Canceled mails reduced %d => %d\n",
			d->message_list_len,X));
				      
	d->message_list_len = X;

	index_initialize(view);
	
	/* Write records */

	for (i = 0; i < d->message_list_len; i++) {

	    write_index_rec(view,& (d->message_list[i]));

	}

	mt_make_canceldir_view(view);

	pos = ftell(view->u.canceldir->index_F);

	/* Temporary terminator */
	fprintf(view->u.canceldir->index_F,"--END\n");  

	/* Set position so that next appended index overwrites this */
	fseek(view->u.canceldir->index_F,pos,SEEK_SET);
       
    }

    if (unlock_it)
	unlock_index(view);   
}


FILE * add_canceled_mail P_((char **outfile,
			     struct mailing_headers * headers,
			     struct MailboxView *view,
			     time_t X,
			     int lines,
			     header_list_ptr h,
			     long body_offset));
FILE * add_canceled_mail(outfile,headers,view, X, lines,h,body_offset)
     char **outfile;
     struct mailing_headers * headers;
     struct MailboxView *view;
     time_t X;
     int lines;
     long body_offset;
     header_list_ptr h;
{
    int i;
    FILE *ret = NULL;
 
    int unlock_it = 0;

    if (&mt_canceldir!= view->mailbox_type)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"add_canceled_mail",
	      "Bad type for canceldir view",0);


    if (!view->u.canceldir->dirname ||
	!view->u.canceldir->indexname ||
	!view->u.canceldir->cs){

	DPRINT(Debug,7,(&Debug,
			"add_canceled_mail=NULL -- not setup\n"));

	return NULL;
    }

    if (!view->u.canceldir->index_F) {
	if (! process_index(view))
	    return NULL;

	unlock_it++;
    }

    for (i = view->u.canceldir->message_list_len;
	 i < view->u.canceldir->message_list_len+100;
	 i++) {
	int fd;

	if (*outfile)
	    free(*outfile);

	*outfile = elm_message(FRM("%s/%05d-%02d.%s"),
			       view->u.canceldir->dirname,
			       (int)(X/(24*60*60)),
			       i,
			       dead_letter);;
	
	fd = open(*outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
	if (fd < 0) {
	    DPRINT(Debug,7,(&Debug,
			    "add_canceled_mail: %d -- %s creation failed\n",
			    i,*outfile));
	    continue;
	}
	ret = fdopen(fd, "w");

	if (!ret) {
	    
	    close(fd);
	    goto fail;
	}
	DPRINT(Debug,7,(&Debug,
			"add_canceled_mail: Created %s\n",
			*outfile));
	break;
    }

    if (ret) {
	char *x = strrchr(*outfile,'/');
	
	if (!x)
	    panic("MBX VIEW PANIC",__FILE__,__LINE__,"add_canceled_mail",
		  "NO / on generated name",0);

	add_canceled_mail1(x+1,headers,view,X,lines,h,body_offset);

    } else {
	DPRINT(Debug,7,(&Debug,
			"add_canceled_mail: failed to create mail\n"));

    }

 fail:
    if (!ret) {
	if (*outfile)
	    free(*outfile);
	*outfile = NULL;
    }

    if (unlock_it)
	unlock_index(view);


    DPRINT(Debug,7,(&Debug,
		    "add_canceled_mail=%p\n",ret));

    return ret;
}			     

static void move_olds(view)
     struct MailboxView *view;
{
    int i;

    for (i = 0; i < 100; i++) {
	char *lbuf1;
	long b;
	int fd;
	struct stat stat_buf;
	FILE *f1,*f2;
	header_list_ptr h = NULL;
	int lines = 0,c;
	char *newname = NULL;
	
	if (0 == i) 
	    lbuf1 = elm_message(FRM("%s/%s"),
				    home,dead_letter);	    
	else
	    lbuf1 = elm_message(FRM("%s/%02d.%s"),
				home,i,dead_letter);
	

	fd = open(lbuf1,O_RDONLY);
	
	if (fd < 0) {
	    DPRINT(Debug,7,(&Debug,
			    "move_olds - copy %d: no file %s\n",
			    i,lbuf1));
	    
	    free(lbuf1);
	    if (i > 1)
		break;
	    continue;
	}
	
	if (-1 == fstat(fd,&stat_buf)) {
	    close(fd);
	    free(lbuf1);
	    continue;
	    
	}
	
	if (stat_buf.st_uid != userid) {
	    /* Wrong owner */
	    close(fd);
	    free(lbuf1);
	    continue;
	}

	if (
#ifdef S_ISREG
	    ! S_ISREG(stat_buf.st_mode)
#else
	    S_IFREG != (stat_buf.st_mode & S_IFMT)
#endif
	    ) {
	    /* Wrong type */
	    close(fd);
	    free(lbuf1);
	    continue;
	}

	f1 = fdopen(fd,"r");
	if (!f1) {
	    close(fd);
	    free(lbuf1);
	    continue;
	}
	
	h = file_read_headers(f1,RHL_CHECK_HEADER);
	
	b = ftell(f1);
	
	while (EOF != (c = getc(f1))) {
	    if ('\n' == c)
		lines++;
	}
	
	f2 = add_canceled_mail(&newname,NULL,
			       view,
			       stat_buf.st_mtime,lines,h,b);
	if (f2) {
	    
	    rewind(f1);
	    
	    if (0 != rename(lbuf1,newname)) {
		while (EOF != (c = getc(f1))) {
		    putc(c,f2);
		}
		
		if (0 == fflush(f2) &&
		    !ferror(f1) && 
		    !ferror(f1)) {
		    
		    DPRINT(Debug,7,(&Debug,
				    "give_canceled_mail - copy %d: copied %s to %s\n",
				    i,lbuf1,newname));
		    
		    
		    unlink(lbuf1);
		}
	    } else {
		DPRINT(Debug,7,(&Debug,
				"give_canceled_mail - copy %d: renamed %s to %s\n",
				i,lbuf1,newname));
	    }
	    fclose(f2);
	}
	
	if (h)
	    delete_headers(&h);
	
	if (newname)
	    free(newname);
	
	
	fclose(f1);
	free(lbuf1);
	
    }		  

}


struct MailboxView *give_canceled_mail()
{

    char *t = give_dt_estr_as_str(&dead_letter_dir_e,"dead-letter-dir");
           
    if (!canceled_mail_view) {
	
	if (!t) {
	    DPRINT(Debug,7,(&Debug,
			    "give_canceled_mail=NULL: no dead-letter-dir\n"));
	    return NULL;
	}
	canceled_mail_view =  give_canceldir();

	setup_canceldir(canceled_mail_view,t);
    }

    if (&mt_canceldir!= canceled_mail_view->mailbox_type)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"give_canceled_mail",
	      "Bad type for canceled_mail_view",0);



    if (t && 0 == mkdir(t,0700)) {
	int i;

	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmDeadLetterDirCreated,
			  "\"dead-letter-dir\" %s created."),
		  t);

	/* Try again create index file ....           */
	if (canceled_mail_view->u.canceldir->indexname &&
	    ! canceled_mail_view->u.canceldir->index_F) {
	    if (!process_index(canceled_mail_view))
		goto XX;
	}

	move_olds(canceled_mail_view);

    } else if (EEXIST == errno) {
	    DPRINT(Debug,7,(&Debug,
			    "give_canceled_mail: %s exists already\n",
			    t));

	move_olds(canceled_mail_view);
    }

    update_index(canceled_mail_view);
  
 XX:

    mt_make_canceldir_view(canceled_mail_view);

    unlock_index(canceled_mail_view);

    DPRINT(Debug,7,(&Debug,
		    "give_canceled_mail=%p\n",
		    canceled_mail_view));

    return canceled_mail_view;
}

void close_canceled_mail()
{

    if (canceled_mail_view) {	
	/* NOTE: Can not call 
	         free_mailbox(& (canceled_mail_view)));
	   because
	          mt_free_canceldir
           will reset canceled_mail_view
	*/

	struct MailboxView *a =  canceled_mail_view;

	sync_canceled_mails(a);

	free_mailbox (&a);

	if (canceled_mail_view)
	    panic("MBX VIEW PANIC",__FILE__,__LINE__,
		  "close_canceled_mail",
		  "canceled_mail_view not resetted",0);

    }	
}

/* HACK -- return 1 on succeed, 0 on failure */
int cancel_set_current(cancel_view,last_canceled_mail)
     struct MailboxView * cancel_view;
     char *last_canceled_mail;
{
    int x;
    char * D = last_canceled_mail;

    if (&mt_canceldir!= cancel_view->mailbox_type)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"cancel_set_current",
	      "Bad type for cancel_view",0);

    if (cancel_view->u.canceldir->dirname) {
	int L = strlen(cancel_view->u.canceldir->dirname);

	if (0 == strncmp(D,cancel_view->u.canceldir->dirname,L) &&
	    '/' == D[L]) {

	    DPRINT(Debug,7,(&Debug,
			    "cancel_set_current: Filename %s have dirname as prefix, good ",
			    D));

	    D += L+1;
	    DPRINT(Debug,7,(&Debug,"=> %s\n",
			    D));
	}

    }

    for (x = 0; x < cancel_view->view_len; x++) {
	int n;

	if (0 != cancel_view->view[x].mailbox_number)
	    panic("MBX VIEW PANIC",__FILE__,__LINE__,"cancel_set_current",
		  "Bad internal mailbox number",0);
	n = cancel_view->view[x].index;
	if (n < 0 || n >= cancel_view->u.canceldir->message_list_len) 
	    panic("MBX VIEW PANIC",__FILE__,__LINE__,"cancel_set_current",
		  "Bad internal index",0);

	if (0 == strcmp(cancel_view->u.canceldir->message_list[n].filename,
			D)) {
	    DPRINT(Debug,7,(&Debug," Found filename %s internal index %d view index %d\n",
			    D,n,x));
	    
	    /* NOTE: Caller uses current == view_index +1 */
	    cancel_view->current = x+1;
	    return 1;
	}

    }


    DPRINT(Debug,7,(&Debug,"cancel_set_current: Filename %s not found\n",
		    D));
    return 0;
}

/* HACK -- delete curently open file */

void  delete_current_cancel(cancel_view,ref_file)
     struct MailboxView * cancel_view;
     FILE *ref_file;
{
    int idx;
    char *filename = NULL;

    if (&mt_canceldir!= cancel_view->mailbox_type)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"cancel_set_current",
	      "delete_current_cancel",0);

    if (! cancel_view->u.canceldir->last_open_file
	|| ref_file != cancel_view->u.canceldir->last_open_file) {
	DPRINT(Debug,3,(&Debug,
			"delete_current_cancel: referenced file not currently open\n"));
	return;
    }
    idx = cancel_view->u.canceldir->last_open_index;

    if (idx < 0 || idx >= cancel_view->u.canceldir->message_list_len)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "delete_current_cancel",
	      "Bad internal index",0);
    
    filename = elm_message(FRM("%s/%s"),
			   cancel_view->u.canceldir->dirname,
			   cancel_view->u.canceldir->message_list[idx].
			   filename);
    if (0 == unlink(filename)) {
		DPRINT(Debug,3,(&Debug,
				"delete_current_cancel: [%d] %s deleted\n",
				idx,filename));
    }
    free(filename);
}


struct MailboxView *give_canceldir() 
{
    struct MailboxView *ret = malloc_view(&mt_canceldir);

    return ret;
}

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


syntax highlighted by Code2HTML, v. 0.9.1