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 (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 : "" )); } 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: */