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 (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: */