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

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

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

DEBUG_VAR(Debug,__FILE__,"messages");

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

struct mv_storage {
    struct current_storage  ** the_mailbox;
    int                       mailbox_count;
    
};

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


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

static void mt_init_storage(mbx)
     struct MailboxView *mbx;
{

    mbx->u.storage = safe_malloc(sizeof (* (mbx->u.storage)));
		
    /* bzero is defined hdrs/defs.h */
    bzero((void *)mbx->u.storage, sizeof (* (mbx->u.storage)));

    mbx->u.storage->the_mailbox   = NULL;
    mbx->u.storage->mailbox_count = 0;

}

S_(mt_free_mailbox mt_free_storage)
static void mt_free_storage P_((struct MailboxView *mbx));
static void mt_free_storage(mbx)
     struct MailboxView *mbx;
{
    if (mbx->u.storage->the_mailbox) {
	int i;

	for (i = 0; i < mbx->u.storage->mailbox_count; i++) {
	    if (mbx->u.storage->the_mailbox[i])
		free_storage (& (mbx->u.storage->the_mailbox[i]));
	}

	free(mbx->u.storage->the_mailbox);
	mbx->u.storage->the_mailbox = NULL;
    }
    mbx->u.storage->mailbox_count = 0;

    free(mbx->u.storage);
    mbx->u.storage = NULL;
}

S_(mt_add_mailbox_storage mt_add_storage_storage)
static void mt_add_storage_storage P_((struct MailboxView *mailbox,
					struct current_storage *storage));
static void mt_add_storage_storage(mailbox,storage)
     struct MailboxView *mailbox;
     struct current_storage *storage;
{
    mailbox->u.storage->the_mailbox    = 
	safe_realloc(mailbox->u.storage->the_mailbox,
		     sizeof ( mailbox->u.storage->the_mailbox[0]) *
		     ( mailbox->u.storage->mailbox_count + 1));
    
    mailbox->u.storage->the_mailbox[mailbox->u.storage->mailbox_count] = storage;
    mailbox->u.storage->mailbox_count++;
}

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

    for (i = 0; i < mailbox->u.storage->mailbox_count; i++) {
	int j;

	count += mailbox->u.storage->the_mailbox[i]->message_count;

	/* Count how many messages are hided */
	for (j =  0; j < mailbox->u.storage->the_mailbox[i]->message_count; 
	     j++) {
	    if (mailbox->u.storage->the_mailbox[i]->headers &&
		mailbox->u.storage->the_mailbox[i]->headers[j] &&
		mailbox->u.storage->the_mailbox[i]->headers[j]->
		exit_disposition == HIDE) {
		DPRINT(Debug,7,(&Debug,"mt_update_view_storage: ... mailbox %d message %d hidden\n",
				i,j));
		hide++;
	    }
	}
    }

    DPRINT(Debug,7,(&Debug,
		    "mt_update_view_storage: mailbox=%x %d storages, %d mails ( %d hidden) , current view len %d\n",
		    mailbox,mailbox->u.storage->mailbox_count, count, hide,
		    mailbox->view_len));
	   
    if (count - hide != mailbox->view_len) {
	mt_make_storage_view(mailbox);
	DPRINT(Debug,7,(&Debug,
			"mt_update_view_storage=1 (view len=%d)\n",mailbox->view_len));
	return 1;
    }

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

S_(mt_get_main_mailbox_folder mt_get_main_storage_folder)
static struct folder_info * mt_get_main_storage_folder P_((struct MailboxView *mailbox));
static struct folder_info * mt_get_main_storage_folder(mailbox)
     struct MailboxView *mailbox;
{
    if (mailbox->u.storage->mailbox_count < 1)
	return NULL;

    if (! mailbox->u.storage->the_mailbox ||
	! mailbox->u.storage->the_mailbox[0]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_get_main_storage_folder",
	      "Mailbox count positive, but no pointer",0);
	return NULL;
    }

    return mailbox->u.storage->the_mailbox[0]->current_folder;
}


/* Can be called from signal handler */
S_(mt_get_mailbox_storage mt_get_storage_storage)
/* Can be called from signal handler */
static struct current_storage * mt_get_storage_storage P_((struct MailboxView *mailbox,
							    int i));
/* Can be called from signal handler */
static struct current_storage * mt_get_storage_storage(mailbox,i) 
     struct MailboxView *mailbox;
     int i;
{
    if (i < 0 || i >= mailbox->u.storage->mailbox_count ||
	! mailbox->u.storage->the_mailbox[i]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_get_storage_storage",
	      "Bad index",1);
	return NULL;
    }

    return mailbox->u.storage->the_mailbox[i];    
}

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

/* Can be called from signal handler */
static int mt_get_storage_storage_count(mailbox) 
     struct MailboxView *mailbox;
{
    return mailbox->u.storage->mailbox_count;
}

S_(mt_give_header_mailbox mt_give_header_storage)
static struct header_rec * mt_give_header_storage P_((struct MailboxView *mailbox,
						      int index,
						      struct folder_view *v));
static struct header_rec * mt_give_header_storage(mailbox,index,v)
     struct MailboxView *mailbox;
     int index;
     struct folder_view *v;
{

    int mbx,idx;

    mbx = v->mailbox_number;

    if (mbx < 0 || mbx >= mailbox->u.storage->mailbox_count ||
	! mailbox->u.storage->the_mailbox || 
	! mailbox->u.storage->the_mailbox[mbx]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_give_header_storage",
	      "bad mailbox number",0);
	return NULL;
    }
    idx = v->index;

    if (idx < 0 || 
	idx >= mailbox->u.storage->the_mailbox[mbx]->message_count ||
	! mailbox->u.storage->the_mailbox[mbx]->headers ||
	! mailbox->u.storage->the_mailbox[mbx]->headers[idx]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_give_header_storage",
	      "bad internal index",0);
	return NULL;
    }

    return mailbox->u.storage->the_mailbox[mbx]->headers[idx];
}

S_(sdt_give_header_s sdt_give_header_mbx)
static struct header_rec * sdt_give_header_mbx P_((struct sort_data *s,
						   struct folder_view *v));
static struct header_rec * sdt_give_header_mbx(s,v)
     struct sort_data *s;
     struct folder_view *v;
{
    return s->u.mbx->headers[v->index];
}


static struct sort_data_type mbx_sort = {
    SORTDATATYPE_magic,
    sdt_give_header_mbx
};


S_(mt_sort_mailbox_view mt_sort_storage_view)
     static void mt_sort_storage_view P_((struct MailboxView *mailbox,
				     hdr_compare_func   *func));
static void mt_sort_storage_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 = &mbx_sort;
	array[i].u.mbx = mailbox->u.storage->the_mailbox[mbx];
    }

    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);
}

S_(mt_give_message_data_mailbox mt_give_message_data_storage)
static int mt_give_message_data_storage 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_storage(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 || mbx >= mailbox->u.storage->mailbox_count ||
	! mailbox->u.storage->the_mailbox || 
	! mailbox->u.storage->the_mailbox[mbx]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "mt_give_message_data_storage",
	      "bad mailbox number",0);
	return 0;
    }
    idx = v->index;

    if (idx < 0 || 
	idx >= mailbox->u.storage->the_mailbox[mbx]->message_count ||
	! mailbox->u.storage->the_mailbox[mbx]->headers ||
	! mailbox->u.storage->the_mailbox[mbx]->headers[idx]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "mt_give_message_data_storage",
	      "bad internal index",0);
	return 0;
    }

    if (! mailbox->u.storage->the_mailbox[mbx]->current_folder)
	return 0;

    hdr = mailbox->u.storage->the_mailbox[mbx]->headers[idx];

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

    if (!prepare_message_access(mailbox->u.storage->the_mailbox[mbx]->
				current_folder,
				hdr,parse_header_routine,parse_body_routine,
				counter,parse_mime))
	return 0;
			   
    if (ret_F) {
	*ret_F = folder_to_fd(mailbox->u.storage->the_mailbox[mbx]->
			      current_folder,
			      hdr->offset);

	if (!*ret_F)
	    return 0;
    }
   
    return 1;
}

S_(mt_write_mailbox_info mt_write_storage_info)
static void mt_write_storage_info P_((FILE *fp, struct MailboxView *mailbox,
				      int s, int cur_idx));
static void mt_write_storage_info(fp,mailbox,s, cur_idx)
     FILE *fp; 
     struct MailboxView *mailbox;
     int s;
     int cur_idx;
{
    int i;

    struct current_storage *storage;


    if (s < 0 || s >= mailbox->u.storage->mailbox_count)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "mt_write_storage_info",
	      "bad storage index",0);
	
    storage = mailbox->u.storage->the_mailbox[s]; 

    if (!storage)
	return;

    /* write out the pathname of the folder */    
    write_folder_info(fp,storage->current_folder);

    /* write out the folder size and message indices */
    fprintf(fp, "N%d\n", storage->message_count);
    for (i = 0 ; i < storage->message_count ; ++i) {
	if (storage->headers[i] &&
	    -1 == storage->headers[i]->offset) {
	    /* Try download tagged messages */
	    if (((storage->headers[i]->status & TAGGED) ||
		 ( /* OR message is current */
		  
		  cur_idx == i
		  )
		 ) && storage->current_folder)
		prepare_message_access(storage->current_folder,
				       storage->headers[i],
				       parse_header_routine,
				       parse_body_routine,
				       NULL,
				       NO_mime_parse);
	}
	
	if (! storage->headers[i] || 
	    -1 == storage->headers[i]->offset)
	    fprintf(fp, "I*\n");
	else {
	    fprintf(fp, "I%ld", 
		    storage->headers[i]->offset);
	    if (-1 !=  storage->headers[i]->content_length)
		fprintf(fp, " %ld", 
			storage->headers[i]->content_length);
	    putc('\n',fp);

	}
    }
}

S_(mt_mailbox_title mt_storage_title)
static struct string * mt_storage_title P_((struct MailboxView *mailbox));
static struct string * mt_storage_title(mailbox)
     struct MailboxView *mailbox;
{
    int count    = 0;
    int mbxcount = 0;
    int i;
    struct current_storage * s = NULL;

    for (i = 0; i < mailbox->u.storage->mailbox_count; i++)
	if (mailbox->u.storage->the_mailbox[i] &&
	    mailbox->u.storage->the_mailbox[i]->current_folder) {
	    count++;
	    s = mailbox->u.storage->the_mailbox[i];

	    if (0 != (FOLDER_MBOX & get_folder_mode(s->current_folder)))
		mbxcount++;
	}

    if (1 == count && s->current_folder) {

	struct string * folder_string = NULL;
	struct string *s1;

	if (*hostname && menu_display_host) 
	    folder_string = format_string(FRM("%s:%S"), hostname, 
					  s->current_folder->
					  cur_folder_disp);
	else
	    folder_string = dup_string(s->current_folder->
				       cur_folder_disp);

	s1 = format_string(CATGETS(elm_msg_cat, ElmSet, 
				     ElmShownMbxTitle1,
				  "%s is '%S'"),
			  folder_type(s->current_folder),
			  folder_string);

	free_string(&folder_string);
	return s1;				     
    }

    
    if (mbxcount > 0 && *hostname && menu_display_host) 
	return format_string(CATGETS(elm_msg_cat, ElmSet, 
				     ElmShownMbxTitleMbxOn,
				     "%d mailboxes on %s"),
			     count,hostname);
    if (mbxcount > 0) 
	return format_string(CATGETS(elm_msg_cat, ElmSet, 
				     ElmShownMbxTitleMbx,
				     "%d mailboxes"),
			     count);
			     
    if (*hostname && menu_display_host) 
	return format_string(CATGETS(elm_msg_cat, ElmSet, 
				     ElmShownMbxTitleFolderOn,
				     "%d folders on %s"),
			     count,hostname);

    return format_string(CATGETS(elm_msg_cat, ElmSet, 
				 ElmShownMbxTitleFolder,
				 "%d folders"),
			 count);

}

S_(mt_make_mailbox_view mt_make_storage_view)
static void mt_make_storage_view (mailbox)
     struct MailboxView *mailbox;
{
    int count = 0;
    int i,x;

    for (i = 0; i < mailbox->u.storage->mailbox_count; i++)
	count += mailbox->u.storage->the_mailbox[i]->message_count;

    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 (i = 0, x = 0; i < mailbox->u.storage->mailbox_count; i++) {
	int j;

	for (j =  0; j < mailbox->u.storage->the_mailbox[i]->message_count; 
	     j++) {
	    if (x >= count)
		panic("MBX VIEW PANIC",__FILE__,__LINE__,
		      "mt_make_storage_view",
		      "overflow",0);
	    if (mailbox->u.storage->the_mailbox[i]->headers &&
		mailbox->u.storage->the_mailbox[i]->headers[j] &&
		mailbox->u.storage->the_mailbox[i]->headers[j]->
		exit_disposition == HIDE) {
		DPRINT(Debug,7,(&Debug,"mt_make_storage_view: ... mailbox %d message %d hidden\n",
				i,j));
	    } else {
		zero_folder_view(& (mailbox->view[x]));

		mailbox->view[x].mailbox_number = i;
		mailbox->view[x].index          = j;
		x++;
	    }
	}
    }
    mailbox->view_len = x;
}

S_(mt_add_mailbox_digest mt_add_storage_digest)
static void mt_add_storage_digest P_((struct MailboxView *mailbox,
				      mime_t *list,
				      time_t received_time,
				      char *env_from,
				      FILE *F,
				      charset_t defcharset
				      ));
static void mt_add_storage_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_storage_digest",
	  "mt_add_storage_digest called",0);
}

static struct mailbox_type mt_storage = {
    MAILBOXTYPE_magic,
    mt_init_storage,
    mt_free_storage,
    mt_add_storage_storage,
    mt_update_view_storage,
    mt_get_main_storage_folder,
    mt_get_storage_storage,
    mt_get_storage_storage_count,
    mt_give_header_storage,
    mt_sort_storage_view,
    mt_give_message_data_storage,
    mt_write_storage_info,
    mt_storage_title,
    mt_make_storage_view,
    mt_add_storage_digest
};

void free_storage(storage) 
     struct current_storage **storage;
{
    
    if ((*storage)->current_folder) {
	/* FREE current_folder */
	leave_old_folder(& (*storage)->current_folder,CLOSE_NORMAL);   
	
    }
    
    if ((*storage)->headers) {
	int i;
	
	for (i = 0; i < (*storage)->max_headers; i++) {
	    if ((*storage)->headers[i])
		header_free( & ((*storage)->headers[i]));
	}
	free((*storage)->headers);
	(*storage)->headers  = NULL;
    }
    
    free(*storage);
    *storage = NULL;

}

struct current_storage *new_storage(new_folder) 
     struct folder_info *new_folder;
{
    struct current_storage *result = NULL;
    
    result  = safe_malloc( sizeof (*result));
    
    result->current_folder = new_folder;
    result->message_count  = 0;
    
    result->max_headers    = 0;
    result->headers        = NULL;
        
    return result;
}

struct MailboxView * malloc_mailbox_view(storage)
     struct current_storage *storage;
{
    struct MailboxView *ret = malloc_view(&mt_storage);

    if (storage) {
	ret->mailbox_type->mt_add_it_storage(ret,storage);	
	ret->mailbox_type->mt_make_it_view(ret);
    }

    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