static char rcsid[] = "@(#)$Id: partial.c,v 1.22 2006/05/07 08:35:31 hurtta Exp $";

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

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

DEBUG_VAR(Debug,__FILE__,"messages");

struct mv_partial {
    struct MailboxView       * parent_mailbox;
    
    struct composite_vector  * composite;
    int                      composite_len;
    
    FILE                    *F;
    char                    *fname;
    
};



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

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

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

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

    mbx->u.partial->parent_mailbox     = NULL;

    mbx->u.partial->composite          = NULL;
    mbx->u.partial->composite_len      = 0;

    mbx->u.partial->F                  = NULL;
    mbx->u.partial->fname              = NULL;
}

struct composite_vector {
    char     * id;
    int      total;

    struct header_rec *mss;

    struct folder_view * locate_ids      ;
    int                  locate_id_count ;
};

static struct header_rec * mt_give_header_partial P_((struct MailboxView 
						      *mailbox,
						      int index,
						      struct folder_view *v));


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

    if (mbx->u.partial->composite) {
	int i;

	for (i = 0; i < mbx->u.partial->composite_len; i++) {
	    struct header_rec *X = mbx->u.partial->composite[i].mss;
	    
	    /* MARK deleted on parent also deleted */
	    
	    if (X && ison(X->status,DELETED)) {
		int j;
		
		for (j = 0; 
		     j < mbx->u.partial->composite[i].locate_id_count;
		     j++) {
		    /* locate_ids are shifted so that 0 is our
		       composite mailbox
		    */
		    struct header_rec * H =
			mt_give_header_partial(mbx,-1,
					       &
					       mbx->u.partial->composite[i].
					       locate_ids[j] );
		    if (H)
			setit(H->status,DELETED);
		    
		}
	    }	    
	}

	for (i = 0; i < mbx->u.partial->composite_len; i++) {
	    
	    if (mbx->u.partial->composite[i].mss) {
		header_free( & (mbx->u.partial->composite[i].mss));
	    }
	    	   
	    if (mbx->u.partial->composite[i].id) {
		free(mbx->u.partial->composite[i].id);
		mbx->u.partial->composite[i].id = NULL;
	    }
	    
	    if (mbx->u.partial->composite[i].locate_ids) {				
		free (mbx->u.partial->composite[i].locate_ids);
		mbx->u.partial->composite[i].locate_ids = NULL;
	    }
	    mbx->u.partial->composite[i].locate_id_count = 0;
	}
	    
	free(mbx->u.partial->composite);
	mbx->u.partial->composite = NULL;
    }
    mbx->u.partial->composite_len = 0;

    if (mbx->u.partial->F) {
	fclose(mbx->u.partial->F);	
	mbx->u.partial->F = NULL;
    }

    if (mbx->u.partial->fname) {
	if (0 == unlink(mbx->u.partial->fname)) {
	    DPRINT(Debug,7,(&Debug,"%s unlinked\n",
			    mbx->u.partial->fname));
	}

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

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


S_(mt_add_mailbox_storage mt_add_partial_storage)
static void mt_add_partial_storage P_((struct MailboxView *mailbox,
				       struct current_storage *storage));

static void mt_add_partial_storage(mailbox,storage)
     struct MailboxView *mailbox;
     struct current_storage *storage;
{    
    add_storage(mailbox->u.partial->parent_mailbox,storage);
}

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

/* Return 1 if redraw required */
S_(mt_update_view_mailbox mt_update_view_partial)
/* Return 1 if redraw required */
static int mt_update_view_partial P_((struct MailboxView *mailbox));
static int mt_update_view_partial(mailbox)
     struct MailboxView *mailbox;
{
    struct MailboxView * Z = mailbox->u.partial->parent_mailbox;
    int count,i;

    int r = update_view(Z);

    int hidden = 0;


    /* check what parts need NOT be included ... */
    for (i = 0; i < Z->view_len; i++) {
	struct header_rec *X = give_header(Z,i);

	if (X) {
	    if (X->partial_len)
		hidden++;
	    else if ((X->status & MIME_MESSAGE) && 
		     (get_type_flags(X->mime_rec.TYPE) & MIME_PARTIAL)) {

		/* Try register partial ... */
		if (reg_partial(X, & ((X->mime_rec)))) {

		    DPRINT(Debug,7,(&Debug,
				    "mt_update_view_partial: Found new fragment\n"));

		    hidden++;
		    r = 1;
		}
	    }
	}
    }

    /* check collect messages also for partial */

    for (i = 0; i < mailbox->u.partial->composite_len; i++) {
	struct header_rec *X = mailbox->u.partial->composite[i].mss;
	if (X) {
	    if (X->partial_len)
		hidden++;
	    else if ((X->status & MIME_MESSAGE) && X->mime_rec.mime_flags &&
		     (get_type_flags(X->mime_rec.TYPE) & MIME_PARTIAL)) {

		/* Try register partial ... */
		if (reg_partial(X, & ((X->mime_rec)))) {

		    DPRINT(Debug,7,(&Debug,
				    "mt_update_view_partial: Found new fragment from reassembed message\n"));

		    hidden++;
		    r = 1;
		}
	    }
	}
    }



    DPRINT(Debug,7,(&Debug,
		    "mt_update_view_partial: %d parts hidden\n",hidden));

    count = Z->view_len + mailbox->u.partial->composite_len - hidden;

    if (r || count != mailbox->view_len) {
	  
	mt_make_partial_view(mailbox);

	DPRINT(Debug,7,(&Debug,
			"mt_update_view_partial=1 (view len=%d)\n",
			mailbox->view_len));
	return 1;
    }
    
    DPRINT(Debug,7,(&Debug,
		    "mt_update_view_partial=0\n"));
    return 0;
}

S_(mt_get_main_mailbox_folder mt_get_main_partial_folder)
static struct folder_info * mt_get_main_partial_folder P_((struct MailboxView *mailbox));
static struct folder_info * mt_get_main_partial_folder(mailbox)
     struct MailboxView *mailbox;
{
    return get_main_folder(mailbox->u.partial->parent_mailbox);
}


/* Can be called from signal handler */
S_(mt_get_mailbox_storage mt_get_partial_storage)
/* Can be called from signal handler */
static struct current_storage * mt_get_partial_storage P_((struct MailboxView *mailbox,
							    int i));
/* Can be called from signal handler */
static struct current_storage * mt_get_partial_storage(mailbox,i) 
     struct MailboxView *mailbox;
     int i;
{
 
    if (i == 0) 
	return NULL;           /* Not available */

    /* Shift by one */
    return get_storage(mailbox->u.partial->parent_mailbox,i-1);
}

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

/* Can be called from signal handler */
static int mt_get_partial_storage_count(mailbox) 
     struct MailboxView *mailbox;
{
    /* Storage number 0 is internal so add +1 */
    
    return 1 + get_storage_count(mailbox->u.partial->parent_mailbox);
}

static void generate_mail_header P_((struct MailboxView *mailbox,
				     int composite_index));


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

    if (0 == v->mailbox_number) {   /* Number 0 is internal */

	if (v->index < 0 || v->index >= mailbox->u.partial->composite_len)
	    return NULL;

	if (! mailbox->u.partial->composite[v->index].mss)
	    generate_mail_header(mailbox,v->index);
	
	return mailbox->u.partial->composite[v->index].mss;

    } else {
	struct folder_view V;
	struct MailboxView *Z = mailbox->u.partial->parent_mailbox;

	/* Shift by one */
	V.mailbox_number = v->mailbox_number-1;
	V.index          = v->index;

	if (Z->mailbox_type->magic != MAILBOXTYPE_magic)
	    panic("MBX VIEW PANIC",__FILE__,__LINE__,
		  "mt_give_header_partial",
		  "Bad type magic number",0);

	return Z->mailbox_type->mt_give_header_it(Z,index, &V);
    }

}

struct partial_sort {
    struct MailboxView         *parent_mailbox;
    struct composite_vector    *composite_record;
};


S_(sdt_give_header_s sdt_give_header_part)
static struct header_rec * sdt_give_header_part P_((struct sort_data *s,
						   struct folder_view *v));
static struct header_rec * sdt_give_header_part(s,v)
     struct sort_data *s;
     struct folder_view *v;
{
    if (0 == v->mailbox_number) {
	return s->u.part->composite_record->mss;
    } else {
	struct folder_view V;
	struct MailboxView *Z = s->u.part->parent_mailbox;

	/* Shift by one */
	V.mailbox_number = v->mailbox_number-1;
	V.index          = v->index;
	
	if (Z->mailbox_type->magic != MAILBOXTYPE_magic)
	    panic("MBX VIEW PANIC",__FILE__,__LINE__,
		  "sdt_give_header_part",
		  "Bad type magic number",0);

	return Z->mailbox_type->mt_give_header_it(Z,-1, &V);
    }
}

static struct sort_data_type part_sort = {
    SORTDATATYPE_magic,
    sdt_give_header_part
};


S_(mt_sort_mailbox_view mt_sort_partial_view)
     static void mt_sort_partial_view P_((struct MailboxView *mailbox,
				     hdr_compare_func   *func));
static void mt_sort_partial_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 = &part_sort;
	array[i].u.part         = safe_malloc(sizeof (* array[i].u.part));
	array[i].u.part->parent_mailbox   = mailbox->u.partial->parent_mailbox;
	array[i].u.part->composite_record = NULL;

	if (0 == mbx) {
	    int v = mailbox->view[i].index;
	    
	    array[i].u.part->composite_record = 
		& mailbox->u.partial->composite[v];
	}

    }

    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[i].u.part);
	array[i].u.part = NULL;
    }

    free(array);
}

static void generate_mail_data P_((struct MailboxView *mailbox,
				   int composite_index));


S_(mt_give_message_data_mailbox mt_give_message_data_partial)
static int mt_give_message_data_partial 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_partial(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;
{
        
    if (0 == v->mailbox_number) {   /* Number 0 is internal */

	if (v->index < 0 || v->index >= mailbox->u.partial->composite_len)
	    return 0;
	
	if (! mailbox->u.partial->composite[v->index].mss ||
	    mailbox->u.partial->composite[v->index].mss->offset == -1L)	    
	    generate_mail_data(mailbox,v->index);

	if (! mailbox->u.partial->composite[v->index].mss ||
	    mailbox->u.partial->composite[v->index].mss->offset == -1L ||
	    ! mailbox->u.partial->F)
	    return 0;
	
	if (ret_header) 
	    *ret_header = mailbox->u.partial->composite[v->index].mss;

	if (ret_F) 
	    *ret_F = mailbox->u.partial->F;
	
       
	/* Simulate prepare_message_access */

	if (! mailbox->u.partial->composite[v->index].mss->mime_parsed && 
	    parse_mime == NO_mime_parse) {
	    DPRINT(Debug,10,(&Debug,
			     "mt_give_message_data_partial: mime structure not needed\n"));
	} else if (! mailbox->u.partial->composite[v->index].mss->
		   mime_parsed) {
	    int status;

	    struct header_rec *entry = 
		mailbox->u.partial->composite[v->index].mss;
		 

	    DPRINT(Debug,10,(&Debug,
			     "mt_give_message_data_partial: Need parsing of mime structure (offset %ld)\n",
			     entry->offset
			     ));
	    
	    if (0 != fseek(mailbox->u.partial->F,
			   entry->offset,
			   SEEK_SET)) {
		
		DPRINT(Debug,10,(&Debug,
				 "mt_give_message_data_partial: seek to %ld failed\n",
				 mailbox->u.partial->composite[v->index].mss->offset));
		return 0;		
	    }

	    status = parse_mime(NULL,entry,mailbox->u.partial->F);
	    if (status <= 0) {
		DPRINT(Debug,10,(&Debug,
				 "mt_give_message_data_partial: parse_mime callback failed (%d)\n",
				 status));
	    }
	    

	}

	if (0 != fseek(mailbox->u.partial->F,
		       mailbox->u.partial->composite[v->index].mss->offset,
		       SEEK_SET)) {
	    
	    DPRINT(Debug,10,(&Debug,
			     "mt_give_message_data_partial: seek to %ld failed\n",
			     mailbox->u.partial->composite[v->index].mss->offset));
	    return 0;
	    
	}

	return 1;

    } else {
	struct folder_view V;
	struct MailboxView *Z = mailbox->u.partial->parent_mailbox;

	/* Shift by one */
	V.mailbox_number = v->mailbox_number-1;
	V.index          = v->index;

	if (Z->mailbox_type->magic != MAILBOXTYPE_magic)
	    panic("MBX VIEW PANIC",__FILE__,__LINE__,
		  "mt_give_message_data_partial",
		  "Bad type magic number",0);

	return Z->mailbox_type->mt_give_message_data_it(Z,index,
							ret_header,ret_F,
							counter,parse_mime,
							& V);
    }


}


static int check_tempfile P_((struct MailboxView *mailbox));
static int check_tempfile(mailbox) 
     struct MailboxView *mailbox;
{
    if (!mailbox->u.partial->F) {

	if (!mailbox->u.partial->fname) {
	    static int un = 1;
	    char *tmp;

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

	    mailbox->u.partial->fname = elm_message(FRM("%selmpartial-%d-%d"),
						    tmp, getpid (), un++);

	    DPRINT(Debug,9,(&Debug,
			    "check_tempfile: temporary folder name is %s\n",
			    mailbox->u.partial->fname));

	}


	mailbox->u.partial->F = safeopen_rdwr(mailbox->u.partial->fname);
	if (! mailbox->u.partial->F) {
	    DPRINT(Debug,9,(&Debug,
			    "check_tempfile: Can't create temporary folder %s\n",
			    mailbox->u.partial->fname));

	    lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCreate,
			      "Failed to create file for decoding."));

	    free(mailbox->u.partial->fname);
	    mailbox->u.partial->fname = NULL;
	    return 0;
	}

	DPRINT(Debug,9,(&Debug,
			"check_tempfile: temporary folder %s created\n",
			mailbox->u.partial->fname));

    }

    return 1;
}


S_(mt_write_mailbox_info mt_write_partial_info)
static void mt_write_partial_info P_((FILE *fp, struct MailboxView *mailbox,
				      int s, int cur_idx));
static void mt_write_partial_info(fp,mailbox,s,cur_idx)
     FILE *fp; 
     struct MailboxView *mailbox;
     int s;
     int cur_idx;
{
    if (0 == s) {   /* 0 is internal */
	int i;

	if (!check_tempfile(mailbox))
	    return;
	
	/* write out the pathname of the folder */    
	fprintf(fp,"F%s\n",
		mailbox->u.partial->fname);

	/* write out the folder size and message indices */
	fprintf(fp, "N%d\n", mailbox->u.partial->composite_len);

	for (i = 0; i < mailbox->u.partial->composite_len; ++i) {
	    if (! mailbox->u.partial->composite[i].mss ||
		-1 == mailbox->u.partial->composite[i].mss->offset) {

		/* Try build tagged messages */
		
		if (mailbox->u.partial->composite[i].mss &&
		    (mailbox->u.partial->composite[i].mss->status & TAGGED) ||
		    cur_idx == i) 
		    generate_mail_data(mailbox,i);
		
	    }

	    if (! mailbox->u.partial->composite[i].mss ||
		-1 == mailbox->u.partial->composite[i].mss->offset) 
		fprintf(fp, "I*\n");
	    else
		fprintf(fp, "I%ld\n",mailbox->u.partial->composite[i].mss->offset);

	}

    } else {
	struct MailboxView *Z = mailbox->u.partial->parent_mailbox;

	if (Z->mailbox_type->magic != MAILBOXTYPE_magic)
	    panic("MBX VIEW PANIC",__FILE__,__LINE__,
		  "mt_write_partial_info",
		  "Bad type magic number",0);

	/* Shift by one */
	Z->mailbox_type->mt_write_it_info(fp,Z,s-1,cur_idx);
    }
}

S_(mt_mailbox_title mt_partial_title)
static struct string * mt_partial_title P_((struct MailboxView *mailbox));
static struct string * mt_partial_title(mailbox)
     struct MailboxView *mailbox;
{
    return mailbox_title(mailbox->u.partial->parent_mailbox);
}

static void add_record P_((struct MailboxView *mailbox, struct folder_view *id,
			   struct partial_vector *part));
static void add_record (mailbox,id, part)
     struct MailboxView *mailbox;
     struct folder_view  *id;
     struct partial_vector *part;
{
    int i,j;

    for (i = 0; i < mailbox->u.partial->composite_len; i++) {
	
	if (0 == strcmp(mailbox->u.partial->composite[i].id,
			part->id))
	    break;          /* FOUND */
    }

    if (i >= mailbox->u.partial->composite_len) {
	i = mailbox->u.partial->composite_len;
	/* Add new record */

	mailbox->u.partial->composite =
	    safe_realloc(mailbox->u.partial->composite,
			 (i+1) * sizeof (mailbox->u.partial->composite[0]));

	mailbox->u.partial->composite[i].id    = safe_strdup(part->id);
	mailbox->u.partial->composite[i].total = part->total;

	mailbox->u.partial->composite[i].mss             = NULL;
	mailbox->u.partial->composite[i].locate_ids      = NULL;
	mailbox->u.partial->composite[i].locate_id_count = 0;
	
	DPRINT(Debug,9,(&Debug,
			"add_record: Added new partial message %s\n",
			mailbox->u.partial->composite[i].id));

	mailbox->u.partial->composite_len++;
    }

    /* Check if already added */
    for (j = 0; j < mailbox->u.partial->composite[i].locate_id_count; j++) {
	if (mailbox->u.partial->composite[i].locate_ids[j].mailbox_number 
	    == id->mailbox_number &&
	    mailbox->u.partial->composite[i].locate_ids[j].index == id->index)
	    return;   /* Already added */
    }

    j = mailbox->u.partial->composite[i].locate_id_count;
    mailbox->u.partial->composite[i].locate_ids =
	safe_realloc(mailbox->u.partial->composite[i].locate_ids,
		     (j+1) * sizeof (mailbox->u.partial->composite[i].
				     locate_ids[0]));

    mailbox->u.partial->composite[i].locate_ids[j] = *id;
    
    DPRINT(Debug,9,(&Debug,
		    "add_record: Part %d/%d of message %s is on message %d%d\n",
		    part->number,part->total,
		    part->id,
		    id->mailbox_number,id->index));

    mailbox->u.partial->composite[i].locate_id_count++;
}


S_(mt_make_mailbox_view mt_make_partial_view)
static void mt_make_partial_view (mailbox)
     struct MailboxView *mailbox;
{
    struct MailboxView * Z = mailbox->u.partial->parent_mailbox;
    
    int count = 0;
    int i,x;

    /* Remove old locations -- they will be recalculated on 
       rediscovered 
    */

    for (i = 0; i < mailbox->u.partial->composite_len; i++) {
	if (mailbox->u.partial->composite[i].locate_ids) {
	    free(mailbox->u.partial->composite[i].locate_ids);
	    mailbox->u.partial->composite[i].locate_ids = NULL;
	}
	mailbox->u.partial->composite[i].locate_id_count = 0;
	
    }

    for (i = 0; i < Z->view_len; i++) {
	int z;
	struct header_rec *X = give_header(Z,i);
		
	if (X && X->partial_len) {
	    struct folder_view id;
	    int j;

	    give_index_number(Z,i,&id);

	    /* Shift by one */
	    id.mailbox_number++;

	    for (j = 0; j < X->partial_len; j++) 
		add_record(mailbox,&id,& (X->partial_vector[j]));

	}
	else
	    count++;
    }
    

    for (i = 0; i < mailbox->u.partial->composite_len; i++) {
	struct header_rec *X = mailbox->u.partial->composite[i].mss;

	if (X && X->partial_len) {

	    struct folder_view id;
	    int j;

	    id.mailbox_number = 0;
	    id.index = i;


	    /* NOTE: This add_record() may increment
	       mailbox->u.partial->composite_len
	    */

	    for (j = 0; j < X->partial_len; j++) 
		add_record(mailbox,&id,& (X->partial_vector[j]));
	    
	}
	else
	    count++;
    }

    DPRINT(Debug,9,(&Debug,
		    "mt_make_partial_view: count = %d, composite_len = %d, parent view len = %d\n",
		    count, mailbox->u.partial->composite_len,Z->view_len));

    
    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 < Z->view_len; i++) {
	struct header_rec *X = give_header(Z,i);
	
	if (!X || ! X->partial_len) {
	    struct folder_view Y;

	    give_index_number(Z,i,&Y);

	    Y.mailbox_number ++;    /* Shift by one! */

	    if (x >= count)
		panic("MBX VIEW PANIC",__FILE__,__LINE__,
		      "mt_make_partial_view",
		      "overflow",0);

	    mailbox->view[x] = Y;
	    x++;
	}
    }

    for (i = 0; i < mailbox->u.partial->composite_len; i++) {
	struct header_rec *X = mailbox->u.partial->composite[i].mss;

	if (!X ||  !X->partial_len) {

	    if (x >= count)
		panic("MBX VIEW PANIC",__FILE__,__LINE__,
		      "mt_make_partial_view",
		      "overflow",0);

	    zero_folder_view(& (mailbox->view[x]));

	    mailbox->view[x].mailbox_number = 0;
	    mailbox->view[x].index          = i;
	    x++;

	}
    }

    mailbox->view_len = x;
}

S_(mt_add_mailbox_digest mt_add_partial_digest)
static void mt_add_partial_digest P_((struct MailboxView *mailbox,
				     mime_t *list,
				     time_t received_time,
				     char *env_from,
				     FILE *F,
				     charset_t defcharset));
static void mt_add_partial_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;
{
    add_digest(mailbox,list,received_time,env_from,F,defcharset);   
}


struct mailbox_type mt_partial = {
    MAILBOXTYPE_magic,
    mt_init_partial,
    mt_free_partial,
    mt_add_partial_storage,
    mt_update_view_partial,
    mt_get_main_partial_folder,
    mt_get_partial_storage,
    mt_get_partial_storage_count,
    mt_give_header_partial,
    mt_sort_partial_view,
    mt_give_message_data_partial,
    mt_write_partial_info,
    mt_partial_title,
    mt_make_partial_view,
    mt_add_partial_digest
};


static struct info_rec {
    FILE                   * F;         
    struct header_rec      * hdr;
    struct partial_vector  * p;
} * build_info_vector P_((struct MailboxView *mailbox,
			  int composite_index,
			  int *vector_len));

static struct info_rec * build_info_vector(mailbox,composite_index,
						vector_len)
     struct MailboxView *mailbox;
     int composite_index;
     int *vector_len;
{
    struct MailboxView * par = mailbox->u.partial->parent_mailbox;
    struct info_rec * ret = NULL;
    int i = 0;
    int k;

    struct composite_vector * Z = 
	& mailbox->u.partial->composite[composite_index];

    int alloced = Z->locate_id_count;

    if (!alloced) {
	DPRINT(Debug,9,(&Debug,
			"build_info_vector: No ids on %d ??? \n",
			composite_index));

	*vector_len = 0;
	return NULL;
    }

    ret = safe_malloc(alloced * sizeof(ret[0]));

    for (k = 0; k < Z->locate_id_count; k++) {

	struct folder_view res = Z->locate_ids[k];
	struct composite_vector *n1;



	if (res.mailbox_number != 0) {

	    FILE *F;
	    struct header_rec *hdr;
	    int n;

	    res.mailbox_number--;             /* Shift by one */

	    if (! par->mailbox_type->mt_give_message_data_it(par,-1,
							     &hdr,&F,NULL,
							     NO_mime_parse,
							     &res)) {
		DPRINT(Debug,9,(&Debug,
				"build_info_vector: [%d, %s] Message headers (%d/%d) or data not available on parent mailbox\n",
				k,Z->id,
				res.mailbox_number,res.index));
		continue;
	    }


	    for (n = 0; n < hdr->partial_len; n++) {
		if (0 == strcmp(hdr->partial_vector[n].id, Z->id)) {	    

		    struct partial_vector  * p = & hdr->partial_vector[n];
		    
		    if (alloced <= i) {
			alloced = i+1;
			ret = safe_realloc(ret,alloced * sizeof(ret[0]));	
		    }
		    
		    ret[i].F   = F;
		    ret[i].p   = p;
		    ret[i].hdr = hdr;		    
		    
		    i++;
		}
	    }

	} else if (res.index >= 0 &&
		   res.index < mailbox->u.partial->composite_len) {

	    struct header_rec *hdr = 
		mailbox->u.partial->composite[res.index].mss;
	    int n;


	    if (!hdr) {
		
		DPRINT(Debug,9,(&Debug,
				"build_info_vector: [%d, %s] Message %d headers not availabel on composite list ???\n",
				k,Z->id,
				Z->locate_ids[k].index));
		continue;

	    }

	    if (-1 == hdr->offset || !mailbox->u.partial->F) {
		DPRINT(Debug,9,(&Debug,
				"build_info_vector: [%d, %s] Message %s data not available (on composite list)??\n",
				k,Z->id,
				Z->locate_ids[k]));
		continue;				
	    }


	    for (n = 0; n < hdr->partial_len; n++) {
		if (0 == strcmp(hdr->partial_vector[n].id, Z->id)) {	    
		    
		    struct partial_vector  * p = & hdr->partial_vector[n];
		    
		    if (alloced <= i) {
			alloced = i+1;
			ret = safe_realloc(ret,alloced * sizeof(ret[0]));	
		    }
		    
		    ret[i].F   = mailbox->u.partial->F;
		    ret[i].p   = p;
		    ret[i].hdr = hdr;		    
		    
		    i++;
		}
	    }
	    
	} 
    }

    if (i > Z->locate_id_count) {
	DPRINT(Debug,9,(&Debug,
			"build_info_vector: [%s] Collected %d when %d expeced??\n",
			Z->id,i,Z->locate_id_count));
    }
    
    *vector_len = i;
 
    return ret;
}

static int generate_1 P_((struct MailboxView *mailbox, int composite_index,
			   struct info_rec * vec, int len));

static int generate_1(mailbox,composite_index,vec,len)
     struct MailboxView *mailbox;
     int composite_index;
     struct info_rec * vec;
     int len;
{
    int i;
    struct header_rec *h;

    for (i = 0; i < len; i++)
	if (1 == vec[i].p->number)
	    break;

    if (i >= len) {
	DPRINT(Debug,9,(&Debug,
			"generate_1: First part of message %s is not arrived\n",
			mailbox->u.partial->composite[composite_index].id));
	
	return i;                 /* First part is not arrived */
    }

    if (! mailbox->u.partial->composite[composite_index].mss) {
	h = safe_malloc(sizeof (*h));

	header_zero(h);
	
	mailbox->u.partial->composite[composite_index].mss = h;
    } else
	h = mailbox->u.partial->composite[composite_index].mss;

    h->offset = -1L;       /* Mark that message is not yet collected */
	    
    strfcpy(h->env_from,vec[i].hdr->env_from,sizeof h->env_from);
    h->header_charset = vec[i].hdr->header_charset;
    h->received_time  = vec[i].hdr->received_time;

    h->content_length   = -1; /* not found yet */
    h->lines            = -1;   /* UNKNOWN */

    return i;
}

static void generate_mail_header(mailbox,composite_index)
     struct MailboxView *mailbox;
     int composite_index;
{
    int len,i;
    struct info_rec * vec = build_info_vector(mailbox,composite_index,&len);
    struct header_rec *h;

    header_list_ptr parsed_headers = NULL;

    if (!vec)
	return;

    i = generate_1(mailbox,composite_index,vec,len);

    h = mailbox->u.partial->composite[composite_index].mss;
    if (!h)
	goto fail;

    /* Assume that first message fragment part includes full headers */

    if (0 != fseek(vec[i].F,vec[i].p->reference->offset,SEEK_SET)) {
	DPRINT(Debug,3,(&Debug,
			"generate_mail_header: seek to %ld failed\n",
			h->offset));
	goto fail;
    }

    parsed_headers = file_read_headers(vec[i].F,0);
    read_folder_headers_helper(h,parsed_headers);
    header_parse_helper(h,parsed_headers);
    delete_headers(&parsed_headers);

 fail:
    free(vec);
}

static void generate_mail_data(mailbox,composite_index)
     struct MailboxView *mailbox;
     int composite_index;
{
    int len,i;
    int total_count = -1;
    int header_not_full = 0;
    int *v1 = NULL;
    char * buffer1;
    struct header_rec *h;
    long written = 0;
    int warn = 0;
    long content_start;

    header_list_ptr parsed_headers = NULL;

    struct info_rec * vec = build_info_vector(mailbox,composite_index,&len);

    if (!vec)
	return;

    if (! mailbox->u.partial->composite[composite_index].mss) {
	generate_1(mailbox,composite_index,vec,len);
	header_not_full++;  /* NOT parsed yet */
    }

    h = mailbox->u.partial->composite[composite_index].mss;
    if (!h)
	goto fail;

    /* read_mailcaps() parses mailcaps only once */
    read_mailcaps();

    for (i = 0; i < len; i++) {
	if (total_count < vec[i].p->total)
	    total_count = vec[i].p->total;

	if (h->received_time < vec[i].hdr->received_time)
	    h->received_time = vec[i].hdr->received_time;

	if (!vec[i].hdr->mime_parsed) {
	    
	    /* Copy value */
	    if (vec[i].hdr -> content_length >= 0)
		vec[i].hdr->mime_rec.length = vec[i].hdr -> content_length;

	    if (vec[i].hdr->mime_rec.begin_offset <= 0)
		vec[i].hdr->mime_rec.begin_offset = 
		    skip_envelope(vec[i].hdr,vec[i].F);

	    if (mime_parser_parse(&(vec[i].hdr->mime_rec),
				  vec[i].hdr->header_charset,vec[i].F,
				  &(vec[i].hdr->header_error))) {
		int tmp = mime_classify_media(&(vec[i].hdr->mime_rec),
					      vec[i].hdr
					      );

		if (tmp >= 0) {
		    vec[i].hdr->mime_parsed            = 1;
		}
	    }	    	   	    
	}


	if (0 != strcmp(vec[i].hdr->env_from,
			vec[0].hdr->env_from)) {
	    if (!warn)  
		lib_error(CATGETS(elm_msg_cat, MeSet, MeFragmentedSender,
				  "Fragmented message have several different sender addresses"));
	    warn = 1;
	    DPRINT(Debug,9,(&Debug,
			    "generate_mail_data: envelope sender %s <-> %s\n",
			    vec[i].hdr->env_from,
			    vec[0].hdr->env_from));
	}

    }

    if (-1 == total_count) {
	DPRINT(Debug,9,(&Debug,
			"generate_mail_data: number of fragments of message %s is not known\n",
			mailbox->u.partial->composite[composite_index].id));
	goto fail;
    }

    if (total_count < 1) {
	DPRINT(Debug,9,(&Debug,
			"generate_mail_data: Imposible total count %d on %s\n",
			total_count,
			mailbox->u.partial->composite[composite_index].id));
	goto fail;
    }

    /* Check that all parts are arrived */

    v1 = malloc(total_count * sizeof (v1[0]));
    for (i = 0; i < total_count; i++) {
	v1[i] = -1;
    }

    for (i = 0; i < total_count; i++) {
	int j;

	for (j = 0; j < len; j++) {
	    if (i+1 == vec[j].p->number) {
		if (-1 != v1[i]) {
		    DPRINT(Debug,9,(&Debug,
				    "generate_mail_data: Part %d on message %s is several times\n" ,
				    i+1,
				    mailbox->u.partial->composite[composite_index].id));
		    goto fail;
		}
		v1[i] = j;
	    }
	}
    }

    for (i = 0; i < total_count; i++) {
	int j;
	if (-1 == v1[i]) {
	    DPRINT(Debug,9,(&Debug,
			    "generate_mail_data: Part %d on message %s is missed\n" ,
			    i+1,
			    mailbox->u.partial->composite[composite_index].id));
	    goto fail;
	}

	j = v1[i];

	if (-1 == vec[j].p->reference->offset ||
	    -1 == vec[j].p->reference->length) {
	    DPRINT(Debug,9,(&Debug,
			    "generate_mail_data: Part %d (on message %s) starting offset (%ld) or length (%ld) is mising\n" ,
			    i+1,
			    mailbox->u.partial->composite[composite_index].id,
			    vec[j].p->reference->offset,
			    vec[j].p->reference->length));
	    goto fail;
			    
	}

    }

    if (!check_tempfile(mailbox))
	goto fail;

    if (0 != fseek(mailbox->u.partial->F,0,SEEK_END)) {
	DPRINT(Debug,9,(&Debug,
			"generate_mail_data: Seek failure on %s\n",
			mailbox->u.partial->fname));
	goto fail;
    }

    h->offset = ftell(mailbox->u.partial->F);
    buffer1 = ctime(& h->received_time);
    
    fprintf(mailbox->u.partial->F,"From %s %.24s\n", 
	    h->env_from,buffer1);
    h->mime_rec.begin_offset = ftell(mailbox->u.partial->F);

    
    /* MIME says:           (RFC 2046)
       
    (2)   All of the header fields from the initial enclosing
          message, except those that start with "Content-" and
          the specific header fields "Subject", "Message-ID",
          "Encrypted", and "MIME-Version", must be copied, in
          order, to the new message.

    (3)   The header fields in the enclosed message which start
          with "Content-", plus the "Subject", "Message-ID",
          "Encrypted", and "MIME-Version" fields, must be
          appended, in order, to the header fields of the new
          message.  Any header fields in the enclosed message
          which do not start with "Content-" (except for the
          "Subject", "Message-ID", "Encrypted", and "MIME-
          Version" fields) will be ignored and dropped.

     HOWEVER

         for now we copy only Received: -headers. Dropping
         extra headers from enclosed message makes assembly more 
         complicated  (and dropping of Received: -headers
	 from enclosed message do not make sense.)
    */


    /* Copy some headers from part 1 */
    if (skip_envelope(vec[v1[0]].hdr, vec[v1[0]].F) != -1) {
	
	header_list_ptr all_headers = file_read_headers(vec[v1[0]].F,
							RHL_CHECK_HEADER|RHL_MARK_FOLDING);
	header_list_ptr next_hdr;

	for (next_hdr = all_headers; 
	     next_hdr; 
	     next_hdr = next_hdr -> next_header) {
	    CONST char * hdr_name = give_header_name(next_hdr->header_name);
	  

	    if (0 == istrcmp(hdr_name,"Received")) {

		out_state_t state;

		out_state_clear(&state,STATE_out_file);
		set_out_state_file(mailbox->u.partial->F,&state);
		state.EOLN_is_CRLF = vec[v1[0]].hdr->binary;

		state_write_header(&state,next_hdr,0,
				    vec[v1[0]].hdr->header_charset);
		
		out_state_destroy(&state);
	    }
	}

	if (all_headers)
	    delete_headers(&all_headers);


    } else {
	DPRINT(Debug,9,(&Debug,
			"generate_mail_data: failed seek beginning of part 1 headers\n"));
    }


    for (i = 0; i < total_count; i++) {
	char buf[VERY_LONG_STRING];
	int j = v1[i];
	int len = vec[j].p->reference->length;
	int l;

	if (len < 256) {
	    DPRINT(Debug,9,(&Debug,
			    "generate_mail_data:  Part %d is %d bytes\n",
			    i+1,len));
	}

        if (0 != fseek (vec[j].F,vec[j].p->reference->offset, SEEK_SET)) {
	    DPRINT(Debug,9,(&Debug,
			    "generate_mail_data: part %d - Seek to %ld failed.\n",
			    i+1,
			    vec[j].p->reference->offset));
	    

	    h->offset = -1L;   /* Indicate failure */
	    goto fail;	    
	}
	
	while (len > 0 &&
	       0 < (l = mail_gets(buf, sizeof buf, vec[j].F))) {
	    len -= l;
	    
	    if (fwrite(buf,1,l,mailbox->u.partial->F) < l) {
		DPRINT(Debug,9,(&Debug,
				"generate_mail_data: part %d  -- incompletet write\n",
				i+1));
		goto fail2;
	    }

	    written += l;
	}

	if (len > 0) {
	    DPRINT(Debug,9,(&Debug,
			    "generate_mail_data: part %d - all data not read\n",
			    i+1));
	    h->offset = -1L;   /* Indicate failure */
	    goto fail;	    	    
	}

    }

    if (EOF == fflush(mailbox->u.partial->F)) {
	DPRINT(Debug,9,(&Debug,
			"generate_mail_data: flush failed\n"));

    fail2:
	h->offset = -1L;   /* Indicate failure */
#ifdef FTRUNCATE
	if (0== truncate(mailbox->u.partial->fname,
			 h->offset)) {
	    DPRINT(Debug,9,(&Debug,
			    "generate_mail_data:  %s truncated to %ld\n",
			    mailbox->u.partial->fname,h->offset));
	}
#endif

	goto fail;	    	    	
    }

    DPRINT(Debug,9,(&Debug,
		    "generate_mail_data: %d  bytes copied from fragments",
		    written));

    /* written do not include copeid received headers, so recaluclate it */
    written = ftell(mailbox->u.partial->F) - h->mime_rec.begin_offset;

    DPRINT(Debug,9,(&Debug,", %d total\n",
		    written));

    /* Re-parse headers */

    if (0 != fseek(mailbox->u.partial->F,h->mime_rec.begin_offset,SEEK_SET)) {
	DPRINT(Debug,3,(&Debug,
			"generate_mail_data: seek to %ld failed\n",
			h->mime_rec.begin_offset));
	goto fail;
    }

    parsed_headers = file_read_headers(mailbox->u.partial->F,0);

    if (!parsed_headers) {
	DPRINT(Debug,3,(&Debug,
			"generate_mail_data:  No headers parsed! \n"));
    }

    read_folder_headers_helper(h,parsed_headers);
    header_parse_helper(h,parsed_headers);

    content_start = ftell(mailbox->u.partial->F);
    start_body_helper(h,content_start,parsed_headers);

    delete_headers(&parsed_headers);

    h->body_parsed          = 1;    /* Mark that data is downloaded */
                                    /* Effectively start_body_helper()
				       is called 
				    */

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

    if (h->content_length != written - (h->mime_rec.offset -
					h->mime_rec.begin_offset)) {
	h->content_length = written - (h->mime_rec.offset - 
				       h->mime_rec.begin_offset);

	DPRINT(Debug,10,(&Debug,
			 "generate_mail_data: setting content_length: %ld\n",
			 h->content_length
			 ));

    }
    h->mime_rec.length = h->content_length;

    DPRINT(Debug,10,(&Debug,
		     "generate_mail_data: {hdr)offset = %ld, {mime} begin_offset = %ld, {mime} offset = %ld\n",
		     h->offset,
		     h->mime_rec.begin_offset,
		     h->mime_rec.offset));

    header_not_full = 0;

    DPRINT(Debug,5,(&Debug,
		    "generate_mail_data: Message %s assembled -- %ld bytes - %d parts -- content length %ld\n",
		    mailbox->u.partial->composite[composite_index].id,
		    written,total_count,h->content_length
		    ));

 fail:
    if (header_not_full && 
	mailbox->u.partial->composite[composite_index].mss)
	header_free(& (mailbox->u.partial->composite[composite_index].mss));

    free(vec);
    if (v1)
	free(v1);
}

struct MailboxView * partial_to_mailbox_view (parent)
     struct MailboxView * parent;
{
    struct MailboxView *ret = malloc_view(&mt_partial);

    if (parent->magic         != MAILBOXVIEW_magic)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"partial_to_mailbox_view",
	      "Bad magic number",0);
    
    if (parent->mailbox_type->magic != MAILBOXTYPE_magic)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"partial_to_mailbox_view",
	      "Bad type magic number",0);


    ret->u.partial->parent_mailbox = parent;
    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