static char rcsid[] = "@(#)$Id: mime_selector.c,v 1.10 2006/04/13 16:35:40 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.10 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
*****************************************************************************/
#include "def_melib.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"mime");
void mime_selector_free (p)
struct mime_selected_handler **p;
{
if (MIME_selector_magic != (*p)->magic)
panic("MAILCAP PANIC",__FILE__,__LINE__,"mime_selector_free",
"Bad magic number",0);
(*p)->handler = NULL;
(*p)->entry = NULL;
(*p)->use_entry = 0;
(*p)->EC_decoder = null_EC_decoder;
(*p)->SG_decoder = null_SG_decoder;
(*p)->selected_alternative = NULL;
(*p)->magic = 0; /* Invalidate */
free(*p);
*p = NULL;
}
/* old mime_notplain() reinvented here
returns mask:
NOTPLAIN_need_metamail 0x01
NOTPLAIN_need_mailcap 0x02
NOTPLAIN_canuse_mailcap 0x04
*/
#if DEBUG
static char * debug_f P_((int c));
static char * debug_f(c)
int c;
{
static char buffer[80];
if (!c)
return "none";
buffer[0] = '\0';
buffer[2] = '\0'; /* In case there is unknown bits set */
if (c & NOTPLAIN_need_metamail)
strfcat(buffer,", NOTPLAIN_need_metamail",sizeof buffer);
if (c & NOTPLAIN_need_mailcap)
strfcat(buffer,", NOTPLAIN_need_mailcap",sizeof buffer);
if (c & NOTPLAIN_canuse_mailcap)
strfcat(buffer,", NOTPLAIN_canuse_mailcap",sizeof buffer);
if (c & NOTPLAIN_is_fallback)
strfcat(buffer,", NOTPLAIN_is_fallback",sizeof buffer);
return buffer +2;
}
#endif
int mime_classify_media(p,hdr)
mime_t *p;
struct header_rec * hdr;
{
int Flags;
struct media_type_handle * H = NULL;
int is_default = 0;
int is_fallback = 0;
int submask = 0;
if (p->magic != MIME_magic)
panic("MIME PANIC",__FILE__,__LINE__,"mime_classify_media",
"Bad magic number",0);
if (! p->TYPE) {
DPRINT(Debug,1,(&Debug,
"mime_classify_media(%p) NOT PARSED\n",
p));
submask = NOTPLAIN_need_metamail;
goto bad_encoding;
}
melib_register_decoders();
DPRINT(Debug,11,(&Debug,
"mime_classify_media(%p) << type: %p=%s/%s\n",
p,
p->TYPE,
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE)));
Flags = get_type_flags(p->TYPE);
if (Flags) {
DPRINT(Debug,11,(&Debug, " Flags: %s%s%s%s%s%s\n",
(Flags & MIME_RFC822) ? " MIME_RFC822" : "",
(Flags & MIME_MIXED) ? " MIME_MIXED" : "",
(Flags & MIME_DIGEST) ? " MIME_DIGEST" : "",
(Flags & MIME_ALTERNATIVE) ? " MIME_ALTERNATIVE" : "",
(Flags & MIME_SIGNED) ? " MIME_SIGNED" : "",
(Flags & MIME_ENCRYPTED) ? " MIME_ENCRYPTED" : ""
));
}
if (p->encoding < ENCODING_NONE ||
p->encoding >= ENCODING_EXPERIMENTAL) {
DPRINT(Debug,11,(&Debug,
"mime_classify_media(%p) -- type: %p=%s/%s; encoding=%s (%d)\n",
p,
p->TYPE,
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE),
ENCODING(p->encoding),p->encoding));
submask |= NOTPLAIN_need_metamail;
goto bad_encoding;
}
if (p->handler_data) {
if (MIME_selector_magic != p->handler_data->magic)
panic("MAILCAP PANIC",__FILE__,__LINE__,"mime_classify_media",
"Bad magic number",0);
} else {
p->handler_data = safe_malloc(sizeof (* p->handler_data));
p->handler_data->magic = MIME_selector_magic;
}
p->handler_data->handler = NULL; /* Not selected yet */
p->handler_data->entry = NULL;
p->handler_data->use_entry = 0;
p->handler_data->EC_decoder = null_EC_decoder;
p->handler_data->SG_decoder = null_SG_decoder;
p->handler_data->selected_alternative = NULL;
/* RESET loop variables */
H = NULL;
is_default = 0;
while(walk_mt_handler(p->TYPE,&H,&is_default,handle_pager)) {
int r;
if (H->type != handle_pager) {
mime_panic(__FILE__,__LINE__,"mime_classify_media",
"Unexpected handler type");
continue; /* not reached */
}
DPRINT(Debug,11,(&Debug,
"mime_classify_media [%s/%s] func = %p, selector(pager) = %p (media_type_handle %p) default:%d\n",
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE),
H->p.pager->func,
H->p.pager,
H,
is_default));
r = H->p.pager->selector(p,hdr);
if (r >= 0) {
p->handler_data->handler = H->p.pager;
is_fallback = r & NOTPLAIN_is_fallback;
submask |= (r & ~NOTPLAIN_is_fallback);
DPRINT(Debug,11,(&Debug,
"mime_classify_media: internal pager found for %s/%s, r=%d (%s)\n",
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE),
r, debug_f(r)));
if (is_fallback) {
DPRINT(Debug,11,(&Debug,
"mime_classify_media: ... but continuing search\n",
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE)));
} else
goto found;
}
}
/* Check mailcap */
/* RFC 1343 is not completely clear, but it is assumed that "test"
entry does _not_ need mail data ,,,
therefore we do NOT run arrange_decoded() on here ....
*/
/* RESET loop variables */
H = NULL;
is_default = 0;
while (walk_mt_handler(p->TYPE,&H,&is_default,handle_mailcap_entry)) {
struct mailcap_entry *f;
if (H->type != handle_mailcap_entry)
panic("MIME PARSER PANIC",__FILE__,__LINE__,
"mailcap_add_entries",
"Bad handler type",0);
DPRINT(Debug,11,(&Debug,
"mime_classify_media [%s/%s] mailcap = %p (media_type_handle %p) default:%d\n",
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE),
H->p.mailcap,
H,
is_default));
f = H->p.mailcap;
if (mailcap_is_valid_view(f,p)) {
submask |= NOTPLAIN_need_mailcap;
p->handler_data->entry = f;
DPRINT(Debug,11,(&Debug,
"mime_classify_media: mailcap pager found for %s/%s\n",
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE)));
goto found;
}
}
/* Not found */
submask |= NOTPLAIN_need_metamail;
found:
if ((submask | is_fallback) != p->mime_flags && submask >= 0) {
int a = (submask | is_fallback);
DPRINT(Debug,11,(&Debug,
"mime_classify_media: changing mime_flags from %d (%s) ",
p->mime_flags,debug_f(p->mime_flags)));
/* Do not call debug_f() twise on same output, return is
statically alloced!
*/
DPRINT(Debug,11,(&Debug,
"to %d (%s) for %s/%s\n",
a,debug_f(a),
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE)));
p->mime_flags = a;
if (p->mime_flags != a)
mime_panic(__FILE__,__LINE__,"mime_classify_media",
"mime_flags too narrow?");
}
bad_encoding:
DPRINT(Debug,11,(&Debug,
"mime_classify_media(%p) = %d (%s)\n",
p,
submask, debug_f(submask)));
return submask;
}
/* mime_classify_subparts replaces can_handle()
returns mask:
NOTPLAIN_need_metamail 0x01
NOTPLAIN_need_mailcap 0x02
NOTPLAIN_canuse_mailcap 0x04
*/
int mime_classify_subparts(ptr,hdr)
mime_t *ptr;
struct header_rec * hdr;
{
int i;
int count;
int submask = 0;
if (!ptr->parser_data) {
submask = NOTPLAIN_need_metamail;
goto out;
}
count = mime_parser_subparts(ptr->parser_data);
for (i = 0; i < count; i++) {
mime_t *att = mime_parser_index(ptr->parser_data,i);
if (att->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"mime_classify_subparts",
"Bad magic number (subpart)");
if (att->disposition == DISP_INLINE) {
int f = mime_classify_media(att, hdr);
if (f < 0) {
DPRINT(Debug,9,(&Debug,
"mime_classify_subparts -- Failed: %p=%s/%s (f=%d)\n",
att->TYPE,
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE),
f));
submask = -1;
goto out;
}
DPRINT(Debug,9,(&Debug,
"mime_classify_subparts: f=%d (%s): %p=%s/%s\n",
f,
debug_f(f),
att->TYPE,
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE)));
submask |= f;
} else {
DPRINT(Debug,9,(&Debug,
"mime_classify_subparts: Attachment: %p=%s/%s\n",
att->TYPE,
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE)));
}
}
out:
DPRINT(Debug,11,(&Debug,
"mime_classify_subparts(%p) = %d (%s)\n",
ptr,
submask,debug_f(submask)));
return submask;
}
/* mime_classify_best_alternative replaces best_alternative()
returns mask:
NOTPLAIN_need_metamail 0x01
NOTPLAIN_need_mailcap 0x02
NOTPLAIN_canuse_mailcap 0x04
*/
static int mask_score P_((int x));
static int mask_score(x)
int x;
{
int r = 0;
if (0 == x)
r = 10;
else {
r = 4;
if (x & NOTPLAIN_need_metamail) r -=4;
else if (x & NOTPLAIN_is_fallback) r -=3;
else if (x & NOTPLAIN_need_mailcap) r -=2;
else if (x & NOTPLAIN_canuse_mailcap) r -=1;
}
DPRINT(Debug,11,(&Debug," Mask %d (%s) score = %d\n",
x,debug_f(x),r));
return r;
}
int mime_classify_best_alternative(ptr, ret,hdr)
mime_t *ptr;
mime_t **ret;
struct header_rec * hdr;
{
mime_t * r = NULL;
int i;
int count;
int submask = 0;
int score = 0;
if (!ptr->parser_data) {
submask = NOTPLAIN_need_metamail;
goto out;
}
count = mime_parser_subparts(ptr->parser_data);
if (count < 1) {
submask = NOTPLAIN_need_metamail;
goto out;
}
r = mime_parser_index(ptr->parser_data,0);
submask = NOTPLAIN_need_metamail; /* DEFAULT -- recalculated later */
for (i = 0; i < count; i++) {
mime_t * att = mime_parser_index(ptr->parser_data,i);
int f;
int s;
if (att->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"mime_classify_best_alternative",
"Bad magic number");
/* We will ignore here Content-Disposition: -header,
because it does not make sense inside on multipart/alternative
*/
f = mime_classify_media(att,hdr);
if (f < 0) {
DPRINT(Debug,11,(&Debug,
"mime_classify_best_alternative -- Failed: %p=%s/%s (f=%d)\n",
att->TYPE,
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE),
f));
continue;
}
s = mask_score(f);
if ( s > score) {
r = att;
submask = f;
score = s;
DPRINT(Debug,11,(&Debug,
"-- mime_classify_best_alternative, found: %p=%s/%s [%d] flags=%d (%s), score=%d\n",
att->TYPE,
get_major_type_name(att->TYPE),
get_subtype_name(att->TYPE),
i,submask,debug_f(submask),
score
));
}
}
out:
DPRINT(Debug,11,(&Debug,
"mime_classify_best_alternative(%p) = %d (%s)",
ptr,
submask, debug_f(submask)));
if (r) {
DPRINT(Debug,11,(&Debug,
", found=%s/%s",
get_major_type_name(r->TYPE),
get_subtype_name(r->TYPE)));
}
DPRINT(Debug,11,(&Debug, "\n"));
if (ret)
*ret = r;
return submask;
}
void mime_decode (ptr, state_in, state_out, defcharset, mss, badtype)
mime_t *ptr;
in_state_t *state_in;
out_state_t *state_out;
charset_t defcharset;
struct header_rec *mss;
type_mismatch_prompt *badtype;
{
int j;
/* This routine calls the appropriate routine to decode the data
* described in "ptr".
*/
DPRINT(Debug,11,(&Debug,
"mime_decode -> state: offset=%ld, length=%ld, type=%s/%s, mime_flags=%d (%s) -- ",
(long) ptr -> offset, (long) ptr -> length,
get_major_type_name(ptr->TYPE),
get_subtype_name(ptr->TYPE),
ptr->mime_flags,
debug_f(ptr->mime_flags)));
for (j = 0; state_out->display_charset[j]; j++) {
DPRINT(Debug,11,(&Debug,
"'display charset[%d]'=%s ",j,
state_out->display_charset[j]->MIME_name ?
state_out->display_charset[j]->MIME_name :
"<no MIME name>"));
}
DPRINT(Debug,11,(&Debug,
", header charset='%s'\n",
defcharset->MIME_name ?
defcharset->MIME_name :
"<no MIME name>"));
if (ptr->magic != MIME_magic)
mime_panic(__FILE__,__LINE__,"mime_decode",
"Bad magic number");
if (!in_state_seekable(state_in)) {
mime_panic(__FILE__,__LINE__,"mime_decode",
"mime_decode: unsupported input state");
}
if (ptr->disposition == DISP_INLINE) {
if (!ptr->handler_data) {
state_puts("[ ",state_out);
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MeDecodeNoHandler,
"mime_decode: no handler selected"));
state_nlputs(" ]\n",state_out);
lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeNoHandler,
"mime_decode: no handler selected"));
return;
}
if (MIME_selector_magic != ptr->handler_data->magic)
mime_panic(__FILE__,__LINE__,"mime_decode",
"Bad magic number (handler_data)");
if (in_state_fseek(state_in,ptr->offset) != 0) {
/* state_nlputs or state_printf is needed for EOLN_is_CRLF
conversions */
state_puts("[ ",state_out);
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MeDecodeMimeSeekFailed,
"mime_decode: seek failed"));
state_nlputs(" ]\n",state_out);
lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeMimeSeekFailed,
"mime_decode: seek failed"));
return;
}
/* Use handler if it is not just fallback routine */
if (ptr->handler_data->handler &&
0 == (ptr->mime_flags & NOTPLAIN_is_fallback)) {
DPRINT(Debug,11,(&Debug,
"mime_decode: using builtin handler \n"));
ptr->handler_data->handler->func (ptr, state_in, state_out,
defcharset, mss, badtype);
} else if (ptr->handler_data->entry) {
if (ptr->handler_data->use_entry) {
char * file_name = NULL;
FILE * file_handle = NULL;
in_state_t newstate2;
in_state_clear(&newstate2,STATE_in_file);
DPRINT(Debug,11,(&Debug,
"mime_decode: using mailcap handler \n"));
if (NULL != (file_handle = arrange_decoded(ptr,state_in,state_out,&newstate2,
&file_name))) {
int x;
if (check_type_pattern) {
if (!check_type_magic(ptr,&newstate2, state_out,
badtype)) {
DPRINT(Debug,11,(&Debug,
"mime_decode: mime_type_rejected\n"));
goto FAILTYPE;
}
}
x =
run_mailcap_view(file_name,file_handle,state_out,ptr->handler_data->entry,ptr);
if (!x) {
DPRINT(Debug,11,(&Debug,
"mime_decode: ... mailcap handler failed\n"));
}
FAILTYPE:
unlink(file_name);
free(file_name);
} else {
DPRINT(Debug,11,(&Debug,
"mime_decode: ... decondig failed for mailcap handler\n"));
}
in_state_destroy(&newstate2);
} else {
DPRINT(Debug,11,(&Debug,
"mime_decode: ... mailcap handler skipped\n"));
goto is_null;
}
} else {
is_null:
if (ptr->handler_data->handler) {
DPRINT(Debug,11,(&Debug,
"mime_decode: using builtin (fallback) handler \n"));
ptr->handler_data->handler->func (ptr, state_in, state_out,
defcharset, mss, badtype);
} else {
DPRINT(Debug,11,(&Debug,
"mime_decode: using builtin null handler \n"));
null_decode(ptr, state_in, state_out,
defcharset, mss);
}
}
} else {
if (ptr->disposition == DISP_AUTOATTACH) {
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MeDecodeUnsupportedAttach,
"[ Type %.15s/%.30s treated as attachment, skipping... ]\n"),
get_major_type_name(ptr->TYPE),
get_subtype_name(ptr->TYPE));
if (state_out->displaying)
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MeDecodeUseVtosave,
"[ Use 'v' to view or save this part. ]\n"));
} else {
if (state_out->displaying)
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MeDecodeAttachUseV,
"[ Attachment, skipping... Use 'v' to view this part. ]\n"));
else
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MeDecodeAttachSkipping,
"[ Attachment, skipping... ]\n"));
}
}
DPRINT(Debug,11,(&Debug,
"mime_decode <- END\n"));
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1