static char rcsid[] = "@(#)$Id: digest.c,v 1.15 2006/04/09 07:37:36 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.15 $   $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");

struct current_digest {
    FILE *F;

    int                  message_count;	/* max message number      */
    struct header_rec  **headers; /* array of header structure pointers */

};


struct mv_digest {
    struct current_digest   ** the_digest;
    int                     digest_count;
};

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

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


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

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

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

    mbx->u.digest->the_digest       = NULL;
    mbx->u.digest->digest_count     = 0;

}

static void free_digest P_((struct current_digest   ** digest));

S_(mt_free_mailbox mt_free_digest)
static void mt_free_digest P_((struct MailboxView *mbx));
static void mt_free_digest(mbx)
     struct MailboxView *mbx;
{
    if (mbx->u.digest->the_digest) {
	int i;

	for (i = 0; i < mbx->u.digest->digest_count; i++)
	    if (mbx->u.digest->the_digest[i])
		free_digest( & (mbx->u.digest->the_digest[i]) );

	free(mbx->u.digest->the_digest);
	mbx->u.digest->the_digest = NULL;
    }
    mbx->u.digest->digest_count = 0;

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


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

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

    for (i = 0; i < mailbox->u.digest->digest_count; i++)
	count += mailbox->u.digest->the_digest[i]->message_count;

      if (count != mailbox->view_len) {
	  
	  mt_make_digest_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_digest=0\n"));
      return 0;
}

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


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

    return NULL;
}

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

/* Can be called from signal handler */
static int mt_get_digest_storage_count(mailbox) 
     struct MailboxView *mailbox;
{
    return mailbox->u.digest->digest_count;
}

S_(mt_give_header_mailbox mt_give_header_digest)
static struct header_rec * mt_give_header_digest P_((struct MailboxView *mailbox,
						     int index,
						     struct folder_view *v));
static struct header_rec * mt_give_header_digest(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.digest->digest_count ||
	! mailbox->u.digest->the_digest || 
	! mailbox->u.digest->the_digest[mbx]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_give_header_digest",
	      "bad mailbox number",0);
	return NULL;
    }
    idx = v->index;
    
    if (idx < 0 || 
	idx >= mailbox->u.digest->the_digest[mbx]->message_count ||
	! mailbox->u.digest->the_digest[mbx]->headers ||
	! mailbox->u.digest->the_digest[mbx]->headers[idx]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_give_header_digest",
	      "bad internal index",0);
	return NULL;
    }
    
    return mailbox->u.digest->the_digest[mbx]->headers[idx];
    
}

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

static struct sort_data_type dgt_sort = {
    SORTDATATYPE_magic,
    sdt_give_header_dgt
};


S_(mt_sort_mailbox_view mt_sort_digest_view)
     static void mt_sort_digest_view P_((struct MailboxView *mailbox,
				     hdr_compare_func   *func));
static void mt_sort_digest_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 = &dgt_sort;
	array[i].u.dgt          = mailbox->u.digest->the_digest[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_digest)
static int mt_give_message_data_digest 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_digest(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.digest->digest_count ||
	! mailbox->u.digest->the_digest || 
	! mailbox->u.digest->the_digest[mbx]) {
	panic("MBX VIEW PANIC",__FILE__,__LINE__,
	      "mt_give_message_data_digest",
	      "bad mailbox number",0);
	return 0;
    }
    idx = v->index;

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

    if (! mailbox->u.digest->the_digest[mbx]->F)
	return 0;

    hdr = mailbox->u.digest->the_digest[mbx]->headers[idx];

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

    if (ret_F) {
	*ret_F = mailbox->u.digest->the_digest[mbx]->F;

	if (0 != fseek(mailbox->u.digest->the_digest[mbx]->F,
		       hdr->offset,SEEK_SET)) {

	    DPRINT(Debug,10,(&Debug,
			     "mt_give_message_data_digest: seek to %ld failed\n",
			     hdr->offset));
	    return 0;

	}
    }

    return 1;
}


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

S_(mt_mailbox_title mt_digest_title)
static struct string * mt_digest_title P_((struct MailboxView *mailbox));
static struct string * mt_digest_title(mailbox)
     struct MailboxView *mailbox;
{
    if (1 == mailbox->u.digest->digest_count) {
	if (*hostname && menu_display_host) 
	    return format_string(CATGETS(elm_msg_cat, ElmSet, 
					 ElmShownDigest1TitleOn,
					 "Digest on %s"),
				 hostname);

	return format_string(CATGETS(elm_msg_cat, ElmSet, 
				     ElmShownDigest1Title,
				     "Digest"));


    }

    if (*hostname && menu_display_host) 
	return format_string(CATGETS(elm_msg_cat, ElmSet, 
				     ElmShownDigestTitleOn,
				     "%d digests on %s"),
			     mailbox->u.digest->digest_count,hostname);

    return format_string(CATGETS(elm_msg_cat, ElmSet, 
				 ElmShownDigestTitle,
				 "%d digests"),
			 mailbox->u.digest->digest_count);
}

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

    for (i = 0; i < mailbox->u.digest->digest_count; i++)
	count += mailbox->u.digest->the_digest[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.digest->digest_count; i++) {
	int j;

	for (j =  0; j < mailbox->u.digest->the_digest[i]->message_count; 
	     j++) {
	    if (x >= count)
		panic("MBX VIEW PANIC",__FILE__,__LINE__,
		      "mt_make_digest_view",
		      "overflow",0);
	    zero_folder_view(& (mailbox->view[x]));

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


    mailbox->view_len = x;
}

static void malloc_header_vector P_((struct current_digest *d,
				      int count));
static void malloc_header_vector(d,count)
     struct current_digest *d;
     int count;
{
    int i;
    d->headers = safe_malloc(count * sizeof (d->headers[0]));

    for (i = 0; i < count; i++) {
	d->headers[i] = NULL;
    }
}

static struct current_digest * new_digest P_((FILE *F));

static void handle_intro P_((struct header_rec *h,
			      mime_t *parent,
			      time_t received_time,
			      char *env_from,
			      FILE *F,
			      charset_t defcharset));
static void handle_intro(h,parent,received_time,env_from,F,defcharset)
     struct header_rec *h;
     mime_t *parent;
     time_t received_time;
     char *env_from;
     FILE *F;
     charset_t defcharset;

{
    /* Show introduction part (usually text/plain) as message */

    header_list_ptr parsed_headers = NULL;

    h->received_time = received_time;
    h->time_sent     = received_time - 60;

    h->mime_rec.begin_offset  = parent->begin_offset;
    h->offset        = parent->begin_offset;   /* NO envelope or headers so
						  begin_offset is same
						  than mail offset */
    strfcpy(h->env_from,env_from, sizeof (h->env_from));

    h->content_length = parent->length;
    h->lines          = -1;   /* UNKNOWN */
    h->body_parsed      = 1;    /* Mark that data is downloaded */
    
    mime_t_copy(& h->mime_rec, parent);
    
    /* read_mailcaps() parses mailcaps only once */
    read_mailcaps();

    if (h->mime_rec.parser_data) {
	int tmp = mime_classify_media(&(h->mime_rec),h);
	if (tmp >= 0)
	    h->mime_parsed = 1;
    }
}

static void handle_rfc822 P_((struct header_rec *h,
			      mime_t *parent,
			      time_t received_time,
			      char *env_from,
			      FILE *F,
			      charset_t defcharset));
static void handle_rfc822(h,parent,received_time,env_from,F,defcharset)
     struct header_rec *h;
     mime_t *parent;
     time_t received_time;
     char *env_from;
     FILE *F;
     charset_t defcharset;

{
    int l;
    header_list_ptr parsed_headers = NULL;

    h->received_time = received_time;
    h->time_sent     = received_time - 120;

    h->mime_rec.begin_offset  = parent->offset;    /* No envelope From_ -line */
    h->offset        = parent->offset;   /* begin of header -- begin
					    on data on rfc822  type
					 */

    strfcpy(h->env_from,env_from, sizeof (h->env_from));

    if (0 != fseek(F,h->offset,SEEK_SET)) {
	DPRINT(Debug,3,(&Debug,
			"handle_rfc822: seek to %ld failed\n",
			h->offset));
	return;
    }

    h->binary                 = FALSE;  /* Binary flag is not handled
					   here!!! */
    
    h->header_charset         = defcharset; 
    /* read_folder_headers() will re-set header_charset
       if it sees X-ELM-OSV header with parameter
       hdr-charset
    */
    
    h->content_length   = -1; /* not found yet */
    /* read_folder_headers_helper() will re-set content_length
       if it sees Content-Length header 
    */

    h->lines            = -1;   /* UNKNOWN */
    h->body_parsed      = 1;    /* Mark that data is downloaded */

    parsed_headers = file_read_headers(F,0);
    l = ftell(F) - h->offset    ;
    DPRINT(Debug,10,(&Debug,
		     "handle_rfc822:  rfc822 header length  = %ld\n",
		     l));


    read_folder_headers_helper(h,parsed_headers);

    if (h->header_charset != defcharset) {
	DPRINT(Debug,10,(&Debug,
			 "handle_rfc822: header charset was modified: %s\n",
			 h->header_charset->MIME_name ?
			 h->header_charset->MIME_name :
			 "<no MIME name>"
			 ));
	
    }
    
    if (-1 != h->content_length) {
	DPRINT(Debug,10,(&Debug,
			 "handle_rfc822: content_length set: %ld\n",
			 h->content_length
			 ));
    }

    /* Length of body of mail == length of data of rfc822 type -
                                 header length 
    */

    if (h->content_length != parent->length - l) {
	h->content_length = parent->length -l;
	DPRINT(Debug,10,(&Debug,
			 "handle_rfc822: setting content_length: %ld\n",
			 h->content_length
			 ));
    }

    header_parse_helper(h,parsed_headers);
    
    if (mime_parser_subparts(parent->parser_data) != 1) {
	DPRINT(Debug,10,(&Debug,
			 "handle_rfc822: no subparts\n")); 
	
    } else {
	mime_t * part = mime_parser_index(parent->parser_data,0);

	if (part->length != h->content_length) {   /* ERROR ??? */
	    DPRINT(Debug,10,(&Debug,
			     "handle_rfc822:  parent subpart length %ld != mail body length %ld\n",
			     part->length, h->content_length));  

	}


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

	mime_t_copy(& h->mime_rec, part);
	
	if (h->mime_rec.parser_data) {
	    int tmp = mime_classify_media(&(h->mime_rec),h);
	    if (tmp >= 0)
		h->mime_parsed = 1;
	}

    }
    delete_headers(&parsed_headers);
    
}

S_(mt_add_mailbox_digest mt_add_digest_digest)
static void mt_add_digest_digest P_((struct MailboxView *mailbox,
				     mime_t *list,
				     time_t received_time,
				     char *env_from,
				     FILE *F,
				     charset_t defcharset));
static void mt_add_digest_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;
{
    struct current_digest * d = new_digest(F);
    int count;

    mailbox->u.digest->the_digest    = 
	safe_realloc(mailbox->u.digest->the_digest,
		     sizeof ( mailbox->u.digest->the_digest[0]) *
		     ( mailbox->u.digest->digest_count + 1));
    
    mailbox->u.digest->the_digest[mailbox->u.digest->digest_count] = d;
    mailbox->u.digest->digest_count++;
    
    if (!list->parser_data) {
	DPRINT(Debug,3,(&Debug,
			"mt_add_digest_digest: Content-Type %s/%s not parsed\n",
			get_major_type_name(list->TYPE),
			get_subtype_name(list->TYPE)));
	
	return;
    }
    count = mime_parser_subparts(list->parser_data);
    
    if (get_type_flags(list->TYPE) & MIME_DIGEST) {
	int i;

	malloc_header_vector(d,count);

	for (i = 0; i < count; i++) {
	    mime_t * part = mime_parser_index(list->parser_data,i);

	    struct header_rec *h = safe_malloc(sizeof(*h));
	    
	    header_zero(h);
	    d->headers[d->message_count++] = h;

	    h->index_number_X = d->message_count;

	    if (get_type_flags(part->TYPE) & MIME_RFC822)
		handle_rfc822(h,part,received_time,env_from,F,defcharset);
	    else
		handle_intro(h,part,received_time,env_from,F,defcharset);
	}


    } else if (get_major_type_code(list->TYPE) == MIME_TYPE_MULTIPART) {
	int i,cnt = 0;

	for (i = 0; i < count; i++) {
	    mime_t * part = mime_parser_index(list->parser_data,i);
	    
	    if (get_type_flags(part->TYPE) & MIME_RFC822)
		cnt++;
	}

	if (cnt > 0) {
	    malloc_header_vector(d,cnt);

	    for (i = 0; i < count && d->message_count < cnt; i++) {
		mime_t * part = mime_parser_index(list->parser_data,i);

		if (get_type_flags(part->TYPE) & MIME_RFC822) {
		    struct header_rec *h = safe_malloc(sizeof(*h));

		    header_zero(h);
		    d->headers[d->message_count++] = h;

		    h->index_number_X = d->message_count;

		    handle_rfc822(h,part,received_time,env_from,F,defcharset);
		}

	    }

	} else {
	    DPRINT(Debug,3,(&Debug,
			    "mt_add_digest_digest: no rfc822 parts on %s/%s\n",
			    get_major_type_name(list->TYPE),
			    get_subtype_name(list->TYPE)));
	}

    } else if (get_type_flags(list->TYPE) & MIME_RFC822) {
	struct header_rec *h = safe_malloc(sizeof(*h));
	
	header_zero(h);
	malloc_header_vector(d,1);
	d->headers[0] = h;
	d->message_count = 1;

	handle_rfc822(h,list,received_time,env_from,F,defcharset);

    } else {
	DPRINT(Debug,3,(&Debug,
			"mt_add_digest_digest: Content-Type %s/%s is not digest\n",
			get_major_type_name(list->TYPE),
			get_subtype_name(list->TYPE)));
    }
}


static struct mailbox_type mt_digest = {
    MAILBOXTYPE_magic,
    mt_init_digest,
    mt_free_digest,
    mt_add_digest_storage,
    mt_update_view_digest,
    mt_get_main_digest_folder,
    mt_get_digest_storage,
    mt_get_digest_storage_count,
    mt_give_header_digest,
    mt_sort_digest_view,
    mt_give_message_data_digest,
    mt_write_digest_info,
    mt_digest_title,
    mt_make_digest_view,
    mt_add_digest_digest
};

static void free_digest(digest)
     struct current_digest   ** digest;
{
    (*digest)->F = NULL;               /* This si shared by caller,
					  so do not fclose() */
    
    if ((*digest)->headers) {
	int i;
	
	for (i = 0; i < (*digest)->message_count; i++) {
	    if ((*digest)->headers[i])
		header_free( & ((*digest)->headers[i]));
	}
	free((*digest)->headers);
	(*digest)->headers  = NULL;
    }

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

static struct current_digest * new_digest(F)
     FILE *F;
{
    struct current_digest * result = NULL;

    result  = safe_malloc( sizeof (*result));
    
    result->F              = F;     /* SHARED !!! */
    result->message_count  = 0;
   
    result->headers        = NULL;

    return result;
}


struct MailboxView * digest_to_mailbox_view(list,received_time,env_from,F,
					    defcharset)
     mime_t *list;
     time_t received_time;
     char * env_from;
     FILE *F;
     charset_t defcharset;
{
    struct MailboxView *ret = malloc_view(&mt_digest);
    
    if (list) {
	if (list->magic != MIME_magic)
	    mime_panic(__FILE__,__LINE__,"digest_to_mailbox_view",
		       "Bad magic number");


	ret->mailbox_type->mt_add_it_digest(ret,list,received_time,
					    env_from, F, defcharset);
	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