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