static char rcsid[] = "@(#)$Id: mime_decode.c,v 1.77.36.1 2007/10/28 08:15:04 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.77.36.1 $ $State: Exp $ * * Modified by: Kari Hurtta * (was hurtta+elm@ozone.FMI.FI) * * Initially written by: Michael Elkins , 1995 *****************************************************************************/ #include "def_melib.h" #include "s_me.h" DEBUG_VAR(Debug,__FILE__,"mime"); #if ANSI_C #define S_(x) static x; #else #define S_(x) #endif /* Prototype */ static void Xbit_decode P_((in_state_t *, out_state_t *, int, int)); static void Xbit_decode (s_in, s_out, length, is_text) in_state_t *s_in; out_state_t *s_out; int length; int is_text; { /* state_getl adds \n to end of file so do not use it .... */ int bytes = 0; /* the total number of bytes read so far */ int store_ch = 0; /* CRLF conversion */ int addprefix = 1; DPRINT(Debug,10,(&Debug, "Xbit_decode: length=%d, prefix=%s\n", length, s_out->prefix ? s_out->prefix : "")); while (1) { int ch; if (bytes >= length) break; ch = state_getc(s_in); if (EOF == ch) { DPRINT(Debug,10,(&Debug, "Xbit_decode: EOF bytes=%d\n", bytes)); break; } bytes++; if (addprefix) { state_add_prefix(s_out); addprefix = 0; } if (store_ch && ch != '\n') state_putc(store_ch,s_out); store_ch = 0; if (ch == '\r') store_ch = ch; else { if (ch == '\n' && s_out->EOLN_is_CRLF) state_putc('\r',s_out); state_putc(ch,s_out); if (ch == '\n') addprefix = 1; } } /* Make sure to flush anything left in the internal buffer. */ if (store_ch) /* for astext */ state_putc(store_ch,s_out); } void base64_decode (s_in, s_out, length, astext) in_state_t *s_in; out_state_t *s_out; int length; int astext; { /* Partially based on base64 decode on kehlist * (first occured on kehlist 1.1.2 9 Jun 1999 * Author: Kari E. Hurtta ) * * Well, basically same decoding routine is on * cs_add_streambyte_to_s_utf7() on lib/cs_utf.c * * And also found from kehpager (UTF7_convert() * on charset.c, kehpager 1.2 1994 * Author: Kari Hurtta ) * */ int bytes = 0; /* the total number of bytes read so far */ unsigned char ch, store_ch = 0; /* for astext -- CRLF conversion */ int corrupted = FALSE; int res = 0; /* Result of decoding */ int bit = 0; /* Number of bits on res */ int addprefix = 1; DPRINT(Debug,10,(&Debug, "base64_decode: length=%d, prefix=%s, astext=%d\n", length, s_out->prefix ? s_out->prefix : "", astext)); while (1) { int c; int code; if (bytes >= length) break; c = state_getc(s_in); if (EOF == c) { DPRINT(Debug,10,(&Debug, "base64_decode: EOF bytes=%d\n", bytes)); break; } bytes++; if (addprefix) { state_add_prefix(s_out); addprefix = 0; } if (' ' == c || '\t' == c || '\r' == c || '\n' == c) continue; if (c == '=') { DPRINT(Debug,10,(&Debug, "base64_decode: '=' seen bytes=%d\n", bytes)); break; } code = base64(c); if (-1 == code) { DPRINT(Debug,10,(&Debug, "base64_decode: char=%02x bad bytes=%d\n", c,bytes)); corrupted = TRUE; /* Perhaps corrupted */ continue; /* Bad characters are supposed to be skipped */ } /* store code value to res */ res <<= 6; res |= code; bit += 6; /* Look if there is enough bits on res for character */ if (bit >= 8) { /* extract characer value from res */ int ch = res >> (bit-8); res -= ch << (bit-8); bit -= 8; if (store_ch && ch != '\n') /* for astext */ state_putc(store_ch,s_out); store_ch = 0; if (astext && ch == '\r') store_ch = ch; else { if (ch == '\n' && astext && s_out->EOLN_is_CRLF) state_putc('\r',s_out); state_putc(ch,s_out); if (ch == '\n') addprefix = 1; } } } /* Make sure to flush anything left in the internal buffer. */ if (store_ch) /* for astext */ state_putc(store_ch,s_out); if (corrupted) { if (s_out->displaying) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_nlputs("\n[ ",s_out); state_printf(s_out,CATGETS(elm_msg_cat, MeSet, MeDecodeBASE64Corrupt, "BASE64 data was corrupt!")); state_nlputs(" ]\n",s_out); } lib_error (CATGETS(elm_msg_cat, MeSet, MeDecodeBASE64Corrupt, "BASE64 data was corrupt!")); } DPRINT(Debug,10,(&Debug, "base64_decode: read=%d bytes, corrupted=%d.\n", bytes,corrupted)); return; } void uudecode (s_in, s_out, length, astext) in_state_t *s_in; out_state_t *s_out; int length; int astext; { char buffer[256]; /* uuencoded lines should be under 80 characters */ int corrupted = FALSE; /* Mostly based on base64_decode() */ int bytes = 0; /* the total number of bytes read so far */ int len; char store_ch = 0; /* for astext */ int addprefix = 1; DPRINT(Debug,10,(&Debug, "uudecode: length=%d, prefix=%s, astext=%d\n", length, s_out->prefix ? s_out->prefix : "", astext)); do { len = state_getl (buffer, sizeof buffer, s_in); if (len > 0) bytes += len; if (bytes >= length) break; } while (len == 1 && 0 == strcmp(buffer,"\n") || len == 2 && 0 == strcmp(buffer,"\r\n")); if (len < 6 || strncmp(buffer,"begin ",6) != 0) { DPRINT(Debug,10,(&Debug, "uudecode: 'begin' was expected\n")); corrupted = TRUE; goto fail; } #define UUDECODE(x) (((x) - ' ') & 077) /* Both space ' ' and '`' character need to be treated * as 0 ... therefore & 077 is needed */ while (bytes < length) { int res = 0; /* Result of decoding */ int bit = 0; /* Number of bits on res */ int expected; /* Expected number of decoded bytes on line */ int coded = 0; int i; len = state_getl (buffer, sizeof buffer, s_in); if (len > 0) bytes += len; /* 'Remove' newline */ if (len > 0 && '\n' == buffer[len-1]) { len--; if (len > 0 && '\r' == buffer[len-1]) len--; } else { DPRINT(Debug,10,(&Debug, "uudecode: newline expected -- too long line?\n")); corrupted = TRUE; } if (len < 1) { DPRINT(Debug,10,(&Debug, "uudecode: empty line!\n")); corrupted = TRUE; /* short lines are padded with space and and space inficates value 0 */ expected = 0; } else expected = UUDECODE(buffer[0]); /* If last line before 'end' ? */ if (!expected) break; if (addprefix) { state_add_prefix(s_out); addprefix = 0; } for (i = 1; coded < expected; i++) { /* If line is short, it is badded with space * which means value 0 */ int code = i < len ? UUDECODE(buffer[i]) : 0; if (i >= len || buffer[i] < ' ' || (buffer[i] & 128)) { /*Ponentially corrupted */ corrupted = TRUE; } /* store code value to res */ res <<= 6; res |= code; bit += 6; /* Look if there is enough bits on res for character */ if (bit >= 8) { /* extract characer value from res */ int ch = res >> (bit-8); res -= ch << (bit-8); bit -= 8; /* count number of bytes decoded from line */ coded++; if (store_ch && ch != '\n') /* for astext */ state_putc(store_ch,s_out); store_ch = 0; if (astext && ch == '\r') store_ch = ch; else { if (ch == '\n' && astext && s_out->EOLN_is_CRLF) state_putc('\r',s_out); state_putc(ch,s_out); if (ch == '\n') addprefix = 1; } } } } /* Make sure to flush anything left in the internal buffer. */ if (store_ch) /* for astext */ state_putc(store_ch,s_out); len = state_getl (buffer, sizeof buffer, s_in); if (len > 0) bytes += len; if (len < 3 || strncmp(buffer,"end",3) != 0) { DPRINT(Debug,10,(&Debug, "uudecode: 'end' was expected\n")); corrupted = TRUE; } if (bytes > length) { DPRINT(Debug,10,(&Debug, "uudecode: Too many bytes readed (needed %d got %d)\n", length,bytes)); corrupted = TRUE; } fail: if (corrupted) { if (s_out->displaying) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_nlputs("\n[ ",s_out); state_printf(s_out,CATGETS(elm_msg_cat, MeSet, MeUUDECODECorrupt, "UUENCODED data was corrupt!")); state_nlputs(" ]\n",s_out); } lib_error (CATGETS(elm_msg_cat, MeSet, MeUUDECODECorrupt, "UUENCODED data was corrupt!")); } DPRINT(Debug,10,(&Debug, "uudecode: read=%d bytes, corrupted=%d.\n", bytes,corrupted)); return; } static unsigned char * us_str P_((char *str)); static unsigned char * us_str(str) char *str; { return (unsigned char *)str; } void quoted_printable_decode (s_in, s_out, length, astext) in_state_t *s_in; out_state_t *s_out; int length; int astext; { int bytes = 0; /* number of bytes read */ int nl = TRUE; /* flag to indicate hitting a new line */ unsigned char *p; int c1, c2; unsigned char ch, store_ch = 0; char buf[VERY_LONG_STRING]; int corrupted = 0; DPRINT(Debug,10,(&Debug, "quoted_printable_decode: length=%d, prefix=%s, astext=%d\n", length, s_out->prefix ? s_out->prefix : "", astext)); for (;;) { int len; if (bytes >= length) break; if ((len=state_getl (buf, sizeof buf, s_in)) <= 0) break; bytes += len; p = us_str(buf); while (*p) { /* If there is a prefix and this is the beginning of a new * line... */ if (nl) { state_add_prefix(s_out); nl = FALSE; } if (store_ch && *p != '\n') /* for astext */ state_putc(store_ch,s_out); store_ch = 0; if (*p == '=') { p++; /* Ignore spaces in end of line -- see MIME */ if (*p == '\r' || *p == ' ' || *p == '\t') { unsigned char *t = p; while (*t && (*t == '\r' || *t == ' ' || *t == '\t')) t++; if (*t && *t == '\n') p = t; } if (*p == '\n') { /* soft linebreak */ if (p >= us_str(buf) +len) break; p++; } else { c1 = hex(*p); if (c1 == -1) corrupted = TRUE; p++; c2 = hex(*p); if (c2 == -1) corrupted = TRUE; p++; ch = (c1 << 4) | c2; /* We not need here CR LF -> LF removing, because * CRLF's which presents end of line should NOT be * encoded. */ state_putc(ch,s_out); } } else { if (astext && *p == '\r') store_ch = *p; else { unsigned char ch; if (*p == '\n' && astext && s_out->EOLN_is_CRLF) state_putc('\r',s_out); ch = *p; state_putc(ch,s_out); } if (*p == '\n') { nl = TRUE; } if (p >= us_str(buf) +len) break; p++; } } } /* Flush anything left in the buffer */ if (store_ch) { /* for astext */ state_putc(store_ch,s_out); store_ch = 0; } if (corrupted) { if (s_out -> displaying) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_nlputs("\n[ ",s_out); state_printf(s_out, CATGETS(elm_msg_cat, MeSet, MeDecodeQPCorrupt, "Seems that QUOTED-PRINTABLE data was corrupted.")); state_nlputs(" ]\n",s_out); } lib_error (CATGETS(elm_msg_cat, MeSet, MeDecodeQPCorrupt, "Seems that QUOTED-PRINTABLE data was corrupted.")); } DPRINT(Debug,10,(&Debug, "quoted_printable_decode: read=%d bytes, corrupted=%d.\n", bytes,corrupted)); return; } /* -------------------------------------------------------------------------------------- */ void null_SG_decoder(body,sign,state_in,state_out,micalg, defcharset, mss, badtype) mime_t *body; mime_t *sign; in_state_t *state_in; out_state_t *state_out; const char *micalg; charset_t defcharset; struct header_rec *mss; type_mismatch_prompt *badtype; { if (state_out->displaying) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_nlputs("\n[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeUnsupportedSig, "Signature %s/%.30s is unsupported, not checked"), get_major_type_name(sign->TYPE), get_subtype_name(sign->TYPE)); state_nlputs(" ]\n",state_out); } lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeUnsupportedSig, "Signature %s/%.30s is unsupported, not checked"), get_major_type_name(sign->TYPE), get_subtype_name(sign->TYPE)); mime_decode(body,state_in,state_out, defcharset, mss, badtype); } void null_EC_decoder(init,data,state_in,state_out,defcharset, mss, badtype) mime_t *init; mime_t *data; in_state_t *state_in; out_state_t *state_out; charset_t defcharset; struct header_rec *mss; type_mismatch_prompt *badtype; { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_nlputs("\n[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeUnsupportedEnc, "Encryption %s/%.30s is unsupported"), get_major_type_name(init->TYPE), get_subtype_name(init->TYPE)); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeUnsupportedEnc, "Encryption %s/%.30s is unsupported"), get_major_type_name(init->TYPE), get_subtype_name(init->TYPE)); } static SG_decoder_t select_SG_decoder P_((const char *protocol)); static SG_decoder_t select_SG_decoder(protocol) CONST char *protocol; { #ifdef USE_PGP if (0 == istrcmp(protocol,"application/pgp-signature")) { DPRINT(Debug,11,(&Debug, "select_SG_decoder [%s] = pgp_SG_decoder\n", protocol)); return pgp_SG_decoder; } #endif DPRINT(Debug,11,(&Debug, "select_SG_decoder [%s] = null_SG_decoder\n", protocol)); return null_SG_decoder; } /* Prototype */ static void signed_decode P_((mime_t *part, in_state_t *streamin, out_state_t *streamout, charset_t defcharset, struct header_rec *hdr, type_mismatch_prompt *badtype)); /* Returns -1 on failure otherwise same mask than mime_classify_media() */ S_(mime_run_selector signed_selector) static int signed_selector(p,hdr) mime_t *p; struct header_rec * hdr; { int flags = 0; mime_t *z; int subflag = -1; if (p->parser_data && mime_parser_subparts(p->parser_data) > 0 && ( z = mime_parser_index(p->parser_data,0)) && 0 <= ( subflag = mime_classify_media(z,hdr) ) ) { CONST char *pv; SG_decoder_t sg_decode; pv = get_mime_param_compat(p->TYPE_opts,"protocol"); if (! pv) { DPRINT(Debug,11,(&Debug, "signed_selector(%p) -- type: %p=%s/%s, flags=%d -- no 'protocol'\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), get_type_flags(p->TYPE))); flags |= NOTPLAIN_need_metamail; goto done; } sg_decode = select_SG_decoder(pv); if (MIME_selector_magic != p->handler_data->magic) mime_panic(__FILE__,__LINE__,"signed_selector", "Bad magic number (handler_data)"); /* Record selection !! */ p->handler_data->SG_decoder = sg_decode; flags |= subflag; if (sg_decode != null_SG_decoder) { DPRINT(Debug,11,(&Debug, "signed_selector(%p) -- type: %p=%s/%s, flags=%d, protocol=%s\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), get_type_flags(p->TYPE), pv)); goto done; } else if (pagesigned) { DPRINT(Debug,9,(&Debug, "signed_selector(%p) -- type: %p=%s/%s, flags=%d, protocol=%s, pagesigned=TRUE\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), get_type_flags(p->TYPE), pv)); goto done; } DPRINT(Debug,11,(&Debug, "signed_selector(%p) -- type: %p=%s/%s, flags=%d, protocol=%s -- unsupported \n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), get_type_flags(p->TYPE), pv)); flags |= NOTPLAIN_need_metamail; } else flags |= NOTPLAIN_need_metamail; done: DPRINT(Debug,11,(&Debug, "signed_selector(%p) = %d\n", p, flags)); return flags; } S_(CT_decoder signed_decode) static void signed_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; { CONST char *pv; CONST char *micalg; SG_decoder_t decode; if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"signed_decode", "Bad magic number"); if (!in_state_seekable(state_in)) { mime_panic(__FILE__,__LINE__,"signed_decode", "signed_decode: unsupported input state"); } if (!ptr->parser_data) { CONST char * T = "multipart/signed"; state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); return; } if (mime_parser_subparts(ptr->parser_data) != 2) { /* 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, MeDecodeSignedNosubtypes, "Content-Type: multipart/signed, no subtypes")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeSignedNosubtypes, "Content-Type: multipart/signed, no subtypes")); return; } pv = get_mime_param_compat(ptr->TYPE_opts,"protocol"); if (!pv) { /* 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, MeDecodeNoProtocol, "'protocol' parameter is missing from Multipart/Signed -type!")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeNoProtocol, "'protocol' parameter is missing from Multipart/Signed -type!")); return; } micalg = get_mime_param_compat(ptr->TYPE_opts,"micalg"); if (!micalg) { micalg = ""; } if (MIME_selector_magic != ptr->handler_data->magic) mime_panic(__FILE__,__LINE__,"signed_decode", "Bad magic number (handler_data)"); decode = ptr->handler_data->SG_decoder; decode(mime_parser_index(ptr->parser_data,0), mime_parser_index(ptr->parser_data,1), state_in,state_out,micalg, defcharset, mss, badtype); } static EC_decoder_t select_EC_decoder P_((const char *protocol)); static EC_decoder_t select_EC_decoder(protocol) CONST char *protocol; { #ifdef USE_PGP if (0 == istrcmp(protocol,"application/pgp-encrypted")) { DPRINT(Debug,11,(&Debug, "select_EC_decoder [%s] = pgp_EC_decoder\n", protocol)); return pgp_EC_decoder; } #endif DPRINT(Debug,11,(&Debug, "select_EC_decoder [%s] = null_EC_decoder\n", protocol)); return null_EC_decoder; } /* Prototype */ static void encrypted_decode P_((mime_t *part, in_state_t *streamin, out_state_t *streamout, charset_t defcharset, struct header_rec *hdr, type_mismatch_prompt *badtype)); /* Returns -1 on failure otherwise same mask than mime_classify_media() */ S_(mime_run_selector encrypted_selector) static int encrypted_selector(p,hdr) mime_t *p; struct header_rec * hdr; { int flags = 0; if (p->parser_data && mime_parser_subparts(p->parser_data) > 0) { EC_decoder_t ec_decode; CONST char *pv; pv = get_mime_param_compat(p->TYPE_opts,"protocol"); if (!pv) { DPRINT(Debug,11,(&Debug, "encrypted_selector(%p) -- type: %p=%s/%s, flags=%d -- no 'protocol'\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), get_type_flags(p->TYPE))); flags |= NOTPLAIN_need_metamail; goto out; } ec_decode = select_EC_decoder(pv); if (MIME_selector_magic != p->handler_data->magic) mime_panic(__FILE__,__LINE__,"encrypted_selector", "Bad magic number (handler_data)"); /* Record selection !! */ p->handler_data->EC_decoder = ec_decode; if (ec_decode != null_EC_decoder) { DPRINT(Debug,11,(&Debug, "encrypted_selector(%p) -- type: %p=%s/%s, flags=%d, protocol=%s\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), get_type_flags(p->TYPE), pv)); /* TODO: We really not know on here can be show contents because we must decode it first to see .... */ flags = 0; goto out; } DPRINT(Debug,11,(&Debug, "encrypted_selector(%p) -- type: %p=%s/%s, flags=%d, protocol=%s\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), get_type_flags(p->TYPE), pv)); flags |= NOTPLAIN_need_metamail; } else flags |= NOTPLAIN_need_metamail; out: DPRINT(Debug,11,(&Debug, "encrypted_selector(%p)=%d\n", p,flags)); return flags; } S_(CT_decoder encrypted_decode) static void encrypted_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; { CONST char *pv; EC_decoder_t decode; if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"encrypted_decode", "Bad magic number"); if (!in_state_seekable(state_in)) { mime_panic(__FILE__,__LINE__,"encrypted_decode", "encrypted_decode: unsupported input state"); } if (!ptr->parser_data) { CONST char * T = "multipart/encrypted"; state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); return; } if (mime_parser_subparts(ptr->parser_data) != 2) { /* 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, MeDecodeEncryptedNosubtypes, "Content-Type: multipart/encrypted, no subtypes")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeEncryptedNosubtypes, "Content-Type: multipart/encrypted, no subtypes")); return; } pv = get_mime_param_compat(ptr->TYPE_opts,"protocol"); if (!pv) { /* 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, MeDecodeNoProtocolEnc, "'protocol' paramater is missing from multipart/encrypted -type!")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeNoProtocolEnc, "'protocol' paramater is missing from multipart/encrypted -type!")); return; } if (MIME_selector_magic != ptr->handler_data->magic) mime_panic(__FILE__,__LINE__,"encrypted_selector", "Bad magic number (handler_data)"); decode = ptr->handler_data->EC_decoder; decode(mime_parser_index(ptr->parser_data,0), mime_parser_index(ptr->parser_data,1), state_in,state_out,defcharset, mss, badtype); } /* Prototype */ static void alternative_decode P_((mime_t *part, in_state_t *streamin, out_state_t *streamout, charset_t defcharset, struct header_rec *hdr, type_mismatch_prompt *badtype)); /* Returns -1 on failure otherwise same mask than mime_classify_media() */ S_(mime_run_selector alternative_selector) static int alternative_selector(p,hdr) mime_t *p; struct header_rec * hdr; { int flags = 0; mime_t * z = NULL; if (p->parser_data && mime_parser_subparts(p->parser_data) > 0 && 0 <= ( flags = mime_classify_best_alternative(p,&z,hdr))) { if (MIME_selector_magic != p->handler_data->magic) mime_panic(__FILE__,__LINE__,"alternative_selector", "Bad magic number (handler_data)"); /* Record selection !! */ p->handler_data->selected_alternative = z; /* If pagealternative is not set, we must able to handle all parts ... */ if (!pagealternative) { DPRINT(Debug,11,(&Debug, "alternative_selector: pagealternative is not set, we must able to handle all parts ...\n")); flags = mime_classify_subparts(p,hdr); } DPRINT(Debug,11,(&Debug, "alternative_selector(%p) -- type: %p=%s/%s, " "best_alternative: %p=%s/%s\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), z->TYPE, get_major_type_name(z->TYPE), get_subtype_name(z->TYPE))); goto out; } else flags |= NOTPLAIN_need_metamail; out: DPRINT(Debug,11,(&Debug, "alternative_selector(%p)=%d\n", p,flags)); return flags; } S_(CT_decoder alternative_decode) static void alternative_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; { mime_t *best = NULL; if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"alternative_decode", "Bad magic number"); if (!in_state_seekable(state_in)) { mime_panic(__FILE__,__LINE__,"alternative_decode", "alternative_decode: unsupported input state"); } if (!ptr->parser_data) { CONST char * T = "multipart/alternative"; state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); return; } if ( mime_parser_subparts(ptr->parser_data) < 1) { /* 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, MeDecodeAlternativeNosubtypes, "Content-Type: multipart/alternative, no subtypes")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeAlternativeNosubtypes, "Content-Type: multipart/alternative, no subtypes")); return; } if (MIME_selector_magic != ptr->handler_data->magic) mime_panic(__FILE__,__LINE__,"alternative_decode", "Bad magic number (handler_data)"); best = ptr->handler_data->selected_alternative; if (best) { if (best->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"alternative_decode", "Bad magic number (selected alternative)"); DPRINT(Debug,11,(&Debug, "multipart_alternative: Type: %.15s/%.30s, Encoding: %d, Size: %ld\n", get_major_type_name(best->TYPE), get_subtype_name(best->TYPE), best->encoding, (long) best->length)); if (in_state_fseek(state_in,best->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, MeDecodeAlternativeSeekFailed, "multipart_alternative: seek failed")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeAlternativeSeekFailed, "multipart_alternative: seek failed")); return; } if (state_out->displaying) { char tmp[40]; char *Encoding = "???"; switch (best->disposition) { case DISP_ATTACH: state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeSelAttachA, "[ Selecting attach: ")); break; default: state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeSelPartA, "[ Selecting part: ")); } tmp[0] = '\0'; if (best->description && string_len(best->description) > 0) { state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeDescA, "\"%.60S\" ]\n"), best->description); state_puts("[ ",state_out); } else { int mp = give_dt_enumerate_as_int(&mime_parameters); CONST struct string *dv; CONST char * dva; /* 0 == plain 1 == encoded 2 == plain-and-encoded */ if (mp && (dv = get_mime_param(best->DISPOSITION_opts,"filename")) ) { state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeDescFilenameA, "Filename: %.60S ]\n"), dv); state_puts("[ ",state_out); } else if ((dva = get_mime_param_compat(best->DISPOSITION_opts, "filename"))) { state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeDescFilenameA1, "Filename: %.60s ]\n"), dva); state_puts("[ ",state_out); } } Encoding = ENCODING(best->encoding); /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeDescC, "Type: %.15s/%.30s, Encoding: %s, Size: %d ]\n"), get_major_type_name(best->TYPE), get_subtype_name(best->TYPE), Encoding, best->length); state_nlputs("\n", state_out); } else { if (best->description) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeContentDescA, "Content-Description: %.300S\n"), best->description); state_nlputs("\n", state_out); } } mime_decode (best, state_in, state_out, defcharset, mss, badtype); } else { /* 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, MeDecodeCtNoAlternative, "Content-Type: multipart/alternative, alternative not found")); state_nlputs(" ]\n", state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeCtNoAlternative, "Content-Type: multipart/alternative, alternative not found")); } } /* Prototype */ static void multipart_0_decode P_((mime_t *part, in_state_t *streamin, out_state_t *streamout, charset_t defcharset, struct header_rec *hdr, type_mismatch_prompt *badtype)); /* Returns -1 on failure otherwise same mask than mime_classify_media() */ S_(mime_run_selector multipart_selector) static int multipart_selector(p,hdr) mime_t *p; struct header_rec * hdr; { int flags = 0; int Flags = get_type_flags(p->TYPE); int subflag = -1; if ((0 <= ( subflag = mime_classify_subparts(p,hdr))) && ((Flags & MIME_MIXED) || (Flags & MIME_DIGEST)) ) { DPRINT(Debug,11,(&Debug, "multipart_selector(%p) -- type: %p=%s/%s, flags=%d\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), get_type_flags(p->TYPE))); if (pagemultipart && 0 != ( subflag & NOTPLAIN_need_metamail)) { flags |= subflag & ~NOTPLAIN_need_metamail; DPRINT(Debug,11,(&Debug, "multipart_selector(%p) (pagemultipart=TRUE)\n", p)); } else flags |= subflag; goto done; } else if (get_major_type_code(p->TYPE) == MIME_TYPE_MULTIPART && pagemultipart) { DPRINT(Debug,11,(&Debug, "multipart_selector(%p) -- type: %p=%s/%s " "(pagemultipart=TRUE)\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE))); if (subflag > 0) { /* Copy NOTPLAIN_need_mailcap 0x02 NOTPLAIN_canuse_mailcap 0x04 */ flags |= subflag & ~NOTPLAIN_need_metamail; } goto done; } else flags |= NOTPLAIN_need_metamail; done: DPRINT(Debug,11,(&Debug, "multipart_selector(%p) = %d\n", p,flags)); return flags; } static int may_group P_((mime_t *ptr)); static int may_group(ptr) mime_t *ptr; { CONST struct string *dv; CONST char * dva; CONST char * st; if (ptr->disposition != DISP_INLINE) return 0; if (ptr->description && string_len(ptr->description) > 0) return 0; dv = get_mime_param(ptr->DISPOSITION_opts,"filename"); if (dv) return 0; dva = get_mime_param_compat(ptr->DISPOSITION_opts,"filename"); if (dva) return 0; if (get_major_type_code(ptr->TYPE) != MIME_TYPE_TEXT || 0 != istrcmp(get_subtype_name(ptr->TYPE),"plain")) return 0; if (0 != (ptr->mime_flags & NOTPLAIN_is_fallback) || 0 != (ptr->mime_flags & NOTPLAIN_need_metamail)) return 0; /* Unsupported charset */ return 1; } static void multipart_one_decode P_((mime_t *att, in_state_t *state_in, out_state_t *state_out, int nattach, int count, charset_t defcharset, struct header_rec *mss, type_mismatch_prompt *badtype)); static void multipart_one_decode(att,state_in,state_out,nattach,count, defcharset,mss,badtype) mime_t *att; in_state_t *state_in; out_state_t *state_out; int nattach; int count; charset_t defcharset; struct header_rec *mss; type_mismatch_prompt *badtype; { CONST struct string *dv; if (in_state_fseek(state_in,att->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, MeDecodeMultipartSeekFail, "multipart_decode: seek failed")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeMultipartSeekFail, "multipart_decode: seek failed")); return; } /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ if (nattach > 1) state_nlputs("\n", state_out); if (state_out->displaying) { char tmp[40]; char *Encoding = "???"; switch (att->disposition) { case DISP_ATTACH: state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeAttachA, "[ Attach #%d/%d: "), nattach,count); break; default: state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodePartA, "[ Part #%d/%d: "), nattach,count); } tmp[0] = '\0'; if (att->description && string_len(att->description) > 0) { state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeDescA, "\"%.60S\" ]\n"), att->description); state_puts("[ ",state_out); } else { int mp = give_dt_enumerate_as_int(&mime_parameters); CONST struct string *dv; CONST char * dva; /* 0 == plain 1 == encoded 2 == plain-and-encoded */ if (mp && (dv = get_mime_param(att->DISPOSITION_opts, "filename")) ) { state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeDescFilenameA, "Filename: %.60S ]\n"), dv); state_puts("[ ",state_out); } else if ((dva = get_mime_param_compat(att->DISPOSITION_opts, "filename"))) { state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeDescFilenameA1, "Filename: %.60s ]\n"), dva); state_puts("[ ",state_out); } } Encoding = ENCODING(att->encoding); /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeDescC, "Type: %.15s/%.30s, Encoding: %s, Size: %d ]\n"), get_major_type_name(att->TYPE), get_subtype_name(att->TYPE), Encoding, att->length); state_nlputs("\n", state_out); } else { if (att->description) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodeContentDescA, "Content-Description: %.300S\n"), att->description); state_nlputs("\n", state_out); } } mime_decode (att, state_in, state_out, defcharset, mss, badtype); } S_(CT_decoder multipart_mixed_decode) static void multipart_mixed_decode P_((mime_t *ptr, in_state_t *state_in, out_state_t *state_out, charset_t defcharset, struct header_rec *mss, type_mismatch_prompt *badtype)); static void multipart_mixed_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 count; int outer, inner = 0; /* Group text/plain parts together ... Note that mime parts do not necessary have ending CRLF. That also allow changing charset on middle of line. RFC 2046 says: NOTE: The CRLF preceding the boundary delimiter line is conceptually attached to the boundary so that it is possible to have a part that does not end with a CRLF (line break). Body parts that must be considered to end with line breaks, therefore, must have two CRLFs preceding the boundary delimiter line, the first of which is part of the preceding body part, and the second of which is part of the encapsulation boundary. */ if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"multipart_mixed_decode", "Bad magic number"); if (!ptr->parser_data) { CONST char * T = "multipart/mixed"; state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); return; } if (!in_state_seekable(state_in)) mime_panic(__FILE__,__LINE__,"multipart_mixed_decode", "unsupported input state"); count = mime_parser_subparts(ptr->parser_data); for (outer = 0; outer < count; outer=inner) { mime_t *part_outer = mime_parser_index(ptr->parser_data,outer); CONST int nattach = outer+1; if (! may_group(part_outer)) { one_part: if (part_outer->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"multipart_mixed_decode", "Bad magic number (subpart)"); DPRINT(Debug,11,(&Debug, "multipart_mixed_decode: [%d]: Type: %p (%s/%s), Encoding: %d, Size: %ld\n", nattach, part_outer->TYPE, get_major_type_name(part_outer->TYPE), get_subtype_name(part_outer->TYPE), part_outer->encoding, (long) part_outer->length)); multipart_one_decode(part_outer,state_in,state_out,nattach,count, defcharset, mss, badtype); inner = outer+1; } else { int scan; int len = 0; for (scan = outer; scan < count; scan++) { mime_t *part_scan = mime_parser_index(ptr->parser_data,scan); if (! may_group(part_scan)) break; len += part_scan->length; } if (scan == nattach) goto one_part; /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ if (nattach > 1) state_nlputs("\n", state_out); if (state_out->displaying) { state_printf(state_out,CATGETS(elm_msg_cat, MeSet, MeDecodePartsDesc, "[ Parts #%d-%d/%d: Type: text/plain, Size: %d ]\n"), nattach,scan,count,len); state_nlputs("\n", state_out); } for (inner = outer; inner < scan; inner++) { mime_t *part_inner = mime_parser_index(ptr->parser_data,inner); if (part_inner->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"multipart_mixed_decode", "Bad magic number (subpart)"); DPRINT(Debug,11,(&Debug, "multipart_mixed_decode: [%d]: Type: %p (%s/%s), Encoding: %d, Size: %ld\n", nattach, part_inner->TYPE, get_major_type_name(part_inner->TYPE), get_subtype_name(part_inner->TYPE), part_inner->encoding, (long) part_inner->length)); mime_decode (part_inner, state_in, state_out, defcharset, mss, badtype); } } } } S_(CT_decoder multipart_0_decode) static void multipart_0_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 count; if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"multipart_0_decode", "Bad magic number"); if (!ptr->parser_data) { CONST char * T = "multipart/*"; state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); return; } if (!in_state_seekable(state_in)) { mime_panic(__FILE__,__LINE__,"multipart_0_decode", "unsupported input state"); } count = mime_parser_subparts(ptr->parser_data); if (!count) { /* 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, MeDecodeMultipartNoparts, "Content-Type: multipart/*, no subparts")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeMultipartNoparts, "Content-Type: multipart/*, no subparts")); } else { int i; for (i = 0; i < count; i++) { mime_t *att = mime_parser_index(ptr->parser_data,i); CONST int nattach = i+1; if (att->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"multipart_0_decode", "Bad magic number (subpart)"); DPRINT(Debug,11,(&Debug, "multipart_0_decode: [%d]: Type: %p (%s/%s), Encoding: %d, Size: %ld\n", nattach, att->TYPE, get_major_type_name(att->TYPE), get_subtype_name(att->TYPE), att->encoding, (long) att->length)); multipart_one_decode(att,state_in,state_out,nattach,count, defcharset, mss, badtype); } } } /* Prototype */ static void rfc822_decode P_((mime_t *part, in_state_t *instream, out_state_t *outstream, charset_t defcharset, struct header_rec *hdr, type_mismatch_prompt *badtype)); int rfc822_header_filter(hdr,flag) header_list_ptr hdr; int flag; /* elm_filter */ { char buf[80]; strfcpy(buf,give_header_name(hdr->header_name),78); strfcat(buf,": ", sizeof buf); if (flag) { if (matches_weedlist (buf)) return 0; else return 1; } else return 1; } static void nomime_decode P_((mime_t *ptr, in_state_t *state_in, out_state_t *state_out)); static void nomime_decode (ptr, state_in, state_out) mime_t *ptr; in_state_t *state_in; out_state_t *state_out; { int j; DPRINT(Debug,11,(&Debug, "nomime_decode -> state: offset=%ld, length=%ld -- ", (long) ptr -> offset, (long) ptr -> length)); 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 : "")); } DPRINT(Debug,11,(&Debug, "\n")); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"nomime_decode", "Bad magic number"); if (!in_state_seekable(state_in)) { mime_panic(__FILE__,__LINE__,"nomime_decode", "nomime_decode: unsupported input state"); } 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, MeDecodeNoMimeSeekFailed, "nomime_decode: seek failed")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeNoMimeSeekFailed, "nomime_decode: seek failed")); return; } /* default-nomime-charset gives assumed charset */ state_out -> filter = default_nomime_charset; /* No MIME is just text ... */ Xbit_decode (state_in, state_out, ptr->length, 1); DPRINT(Debug,11,(&Debug, "nomime_decode <- END\n")); } /* Returns -1 on failure otherwise same mask than mime_classify_media() */ S_(mime_run_selector rfc822_selector) static int rfc822_selector(p,hdr) mime_t *p; struct header_rec * hdr; { int flags = 0; int subflag = -1; if (0 <= ( subflag = mime_classify_subparts(p, hdr /* Correct? */ ))) { DPRINT(Debug,11,(&Debug, "rfc822_selector(%p) -- type: %p=%s/%s\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE))); flags |= subflag; goto done; } else flags |= NOTPLAIN_need_metamail; done: DPRINT(Debug,11,(&Debug, "rfc822_selector(%p) = %d\n", p,flags)); return flags; } S_(CT_decoder rfc822_decode) static void rfc822_decode (mt, state_in, state_out, defcharset, mss, badtype) mime_t *mt; in_state_t *state_in; out_state_t *state_out; charset_t defcharset; struct header_rec *mss; type_mismatch_prompt *badtype; { /* This looks a lot like multipart_decode() except that we want to print * the headers for the message. NOTE: "mt" should be a pointer to the * RFC822 attachment, NOT its subpart, since we need the offset in order * to print out the headers. */ header_list_ptr headers = NULL; header_list_ptr From_header, mime_version, osv; int decode_headers = 1; if (mt->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"rfc822_decode", "Bad magic number"); if (!in_state_seekable(state_in)) { mime_panic(__FILE__,__LINE__,"rfc822_decode", "rfc822_decode: unsupported input state"); } if (in_state_fseek(state_in,mt->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, MeDecodeRFC822SeekFailed, "rfc822_decode: seek failed")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeRFC822SeekFailed, "rfc822_decode: seek failed")); return; } if (!mt->parser_data) { CONST char * T = "message/rfc822"; state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeTypeNotparsed, "Content-Type: %s not parsed"), T); return; } headers = state_read_headers(state_in, RHL_MARK_FOLDING); mime_version = locate_header_by_name(headers,"MIME-Version"); osv = locate_header_by_name(headers,"X-ELM-OSV"); if (!mime_version && !req_mime_hdrencoding && !req_mime_hdrencoding) decode_headers = 0; if (osv && osv->body) { char value[20]; if (mime_get_param("no-hdr-encoding",value,osv->body, sizeof value) && atoi(value) > 0) decode_headers = 0; /* FIXME: Update defcharset */ } From_header = locate_header_by_name(headers,"From"); if (From_header) { struct string * buffer = give_decoded_header(From_header, decode_headers, defcharset); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeStartMail, "-- Start of included mail From: %S\n"), buffer); free_string(&buffer); } else state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeStartMail1, "-- Start of included mail.\n")); /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_nlputs("\n",state_out); state_write_headers(state_out,headers, rfc822_header_filter, elm_filter, decode_headers, defcharset ); delete_headers(&headers); /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_nlputs("\n",state_out); if (mime_parser_subparts(mt->parser_data) != 1) { /* 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, MeDecodeNoRFC822, "rfc822_decode: no body of RFC 822 mail")); state_nlputs(" ]\n",state_out); lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeNoRFC822, "rfc822_decode: no body of RFC 822 mail")); return; } else { mime_t * part = mime_parser_index(mt->parser_data,0); if (part->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"rfc822_decode", "Bad magic number (parts)"); /* TODO: Handle Pre-MIME Content-types ... */ if (mime_version || !req_mime_bodyencoding) mime_decode (part, state_in, state_out, defcharset, /* TODO: Is it correct to pass parent's message record??? (mss) */ NULL, badtype); else nomime_decode (part, state_in, state_out); } state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeEndMail, "-- End of included mail.\n")); return; } int run_cte_decoder (ptr, state_in, state_out) mime_t *ptr; in_state_t *state_in; out_state_t *state_out; { int is_text; DPRINT(Debug,11,(&Debug, "run_cte_decoder -> state: offset=%ld, length=%ld\n", (long) ptr -> offset, (long) ptr -> length)); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"run_cte_decoder", "Bad magic number"); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file): ftell=%ld\n", in_state_ftell(state_in))); } else { DPRINT(Debug,11,(&Debug, " (\?\?\?\?): magic=%d\n", state_in->magic)); } /* 7bit and 8bit are only allowed for line orienteed types */ if (ptr->encoding == ENCODING_NONE || ptr->encoding == ENCODING_7BIT || ptr->encoding == ENCODING_8BIT) { DPRINT(Debug,11,(&Debug, "run_cte_decoder: textual encoding (%s)\n", ENCODING(ptr->encoding))); is_text = 1; } else is_text = give_text_type_code(ptr->TYPE); DPRINT(Debug,11,(&Debug, "run_cte_decoder: is_text=%d; type=%p (%s/%s); encoding =%s (%d)\n", is_text, ptr->TYPE, get_major_type_name(ptr->TYPE), get_subtype_name(ptr->TYPE), ENCODING(ptr->encoding), ptr->encoding)); if (ptr->encoding == ENCODING_BASE64) base64_decode (state_in, state_out, ptr->length, is_text); else if (ptr->encoding == ENCODING_QUOTED) quoted_printable_decode (state_in, state_out, ptr->length, is_text); else if (ptr->encoding == ENCODING_UUENCODED) uudecode (state_in, state_out, ptr->length, is_text); else if (ptr->encoding != ENCODING_NONE && ptr->encoding != ENCODING_7BIT && ptr->encoding != ENCODING_8BIT && ptr->encoding != ENCODING_BINARY) { DPRINT(Debug,11,(&Debug, "run_cte_decoder=0 <- END; \n")); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file); ftell=%ld\n", in_state_ftell(state_in))); } return 0; } else Xbit_decode (state_in, state_out, ptr->length, is_text); DPRINT(Debug,11,(&Debug, "run_cte_decoder=1 <- END; \n")); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file); ftell=%ld\n", in_state_ftell(state_in))); } return 1; } int set_filter (ptr, state, default_content_charset,override_charset) mime_t *ptr; out_state_t *state; charset_t default_content_charset; charset_t override_charset; /* IF set, ignore charset= -paramater */ { int code; charset_t tmp; DPRINT(Debug,40,(&Debug, "set_filter -> state: offset=%d, length=%ld\n", (long) ptr -> offset, (long) ptr -> length)); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"set_filter", "Bad magic number"); state -> filter = NULL; /* So that messages can be printed .. */ code = mime_get_charset (&tmp, ptr->TYPE_opts, state->display_charset, default_content_charset ); if (override_charset && override_charset != tmp) { state_printf(state, CATGETS(elm_msg_cat, MeSet, MeDecodeCharsetOverride, "[ Charset %.15s ignored, treated as %.15s ]\n"), tmp->MIME_name ? tmp->MIME_name : "", override_charset->MIME_name ? override_charset->MIME_name : ""); state_nlputs("\n",state); state -> filter = override_charset; } else { if (0 == code) { /* Don't show this part (or copy to reply buffer) ... */ state_printf(state, CATGETS(elm_msg_cat, MeSet, MeDecodeCharsetSkipping, "[ Charset %.15s unsupported, skipping... ]\n"), tmp->MIME_name ? tmp->MIME_name : ""); if (state->displaying) { state_printf(state, CATGETS(elm_msg_cat, MeSet, MeDecodeUseVtoView, "[ Use 'v' to view or save this part. ]\n")); state_printf(state, CATGETS(elm_msg_cat, MeSet, MeDecodeUseOtoOverride, "[ You can also use 'O' to override charset information. ]\n")); } state -> filter = tmp; DPRINT(Debug,40,(&Debug, "set_filter=0 filter=%p '%s' (type=%p)\n", state -> filter, state -> filter->MIME_name ? state -> filter->MIME_name : "", state -> filter->charset_type)); return 0; } else { if (code < 0) { DPRINT(Debug,40,(&Debug, " code=%d charset_convert_ok=%d\n", code,charset_convert_ok)); if (code == -3) { /* Converted without lossage */ if (!charset_convert_ok && (!tmp->MIME_name || 0 != istrcmp(tmp->MIME_name,"US-ASCII"))) state_printf(state, CATGETS(elm_msg_cat, MeSet, MeDecodeCharsetConvertNoLoss, "[ Charset %.15s converted... ]\n"), tmp->MIME_name ? tmp->MIME_name : ""); } else { state_printf(state, CATGETS(elm_msg_cat, MeSet, MeDecodeCharsetConvert, "[ Charset %.15s unsupported, converting... ]\n"), tmp->MIME_name ? tmp->MIME_name : ""); if (state->displaying) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_printf(state, CATGETS(elm_msg_cat, MeSet, MeDecodeUseAlsoV, "[ You can also use 'v' to view or save this part. ]\n")); state_nlputs("\n",state); } } } state -> filter = tmp; } } DPRINT(Debug,40,(&Debug, "set_filter=1 filter=%p '%s' (type=%p)\n", state -> filter, state -> filter->MIME_name ? state -> filter->MIME_name : "", state -> filter->charset_type)); return 1; } /* Prototype */ static void text_decode P_((mime_t *part, in_state_t *instream, out_state_t *outstream, charset_t defcharset, struct header_rec *hdr, type_mismatch_prompt *badtype)); /* Returns -1 on failure otherwise same mask than mime_classify_media() */ S_(mime_run_selector text_selector) static int text_selector(p,hdr) mime_t *p; struct header_rec * hdr; { int flags = NOTPLAIN_need_metamail; /* If mime_get_charsets < 0, we may want call metamail * (instead of filtering to US-ASCII) */ int r; charset_t buf1; charset_t disp_vector[2]; /* If charset is overrided, do not use metamail ... */ if (hdr && hdr->override_charset) { DPRINT(Debug,11,(&Debug, "text_selector(%p) -- override charset %s\n", hdr->override_charset->MIME_name ? hdr->override_charset->MIME_name : "")); flags = 0; goto done; } disp_vector[0] = display_charset; disp_vector[1] = NULL; if ((r=mime_get_charset(&buf1,p->TYPE_opts,disp_vector,NULL)) > 0) { DPRINT(Debug,11,(&Debug, "text_selector(%p) -- type: %p=%s/%s; charset=%s\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), buf1->MIME_name ? buf1->MIME_name : "")); flags = 0; goto done; } if (r < 0 && buf1 == system_charset) { DPRINT(Debug,11,(&Debug, "text_selector(%p) -- type: %p=%s/%s; charset=%s -- is system charset ...\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), buf1->MIME_name ? buf1->MIME_name : "")); flags = 0; goto done; } if (r == -3 && charset_convert_ok) { DPRINT(Debug,11,(&Debug, "text_selector(%p) -- type: %p=%s/%s; charset=%s -- charset_convert_ok=TRUE\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), buf1->MIME_name ? buf1->MIME_name : "")); flags = 0; goto done; } if (r < 0 && page_known_charsets) { DPRINT(Debug,11,(&Debug, "text_selector(%p) -- type: %p=%s/%s; charset=%s -- page_known_charsets=TRUE\n", p, p->TYPE, get_major_type_name(p->TYPE), get_subtype_name(p->TYPE), buf1->MIME_name ? buf1->MIME_name : "")); flags = 0; goto done; } if (-3 == r) /* Is fallback -- is conversion */ flags = NOTPLAIN_is_fallback; done: DPRINT(Debug,11,(&Debug, "text_selector(%p) = %d\n", p, flags)); return flags; } static void text_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; { DPRINT(Debug,11,(&Debug, "text_decode -> state: offset=%ld, length=%ld \n", (long) ptr -> offset, (long) ptr -> length)); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"text_decode", "Bad magic number"); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file): ftell=%ld\n", in_state_ftell(state_in))); } if (set_filter(ptr,state_out,default_mimetext_charset, mss ? mss->override_charset : NULL)) { if (!run_cte_decoder(ptr,state_in, state_out)) { state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeEncodingSkipping, "[ Unsupported encoding, skipping... ]\n")); if (state_out->displaying) state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeUseVEncodedSave, "[ Use 'v' to save this part in encoded form. ]\n")); } } state_out -> filter = NULL; DPRINT(Debug,11,(&Debug, "text_decode <- END; \n")); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file); ftell=%ld\n", in_state_ftell(state_in))); } } FILE * arrange_binary(ptr,state_in,state_out,newstate2, name) mime_t *ptr; in_state_t *state_in; out_state_t *state_out; in_state_t *newstate2; char **name; { FILE * tmpfp = NULL; char *fname = NULL; char *tmp; DPRINT(Debug,11,(&Debug, "arrange_binary -> state: offset=%ld, length=%ld \n", (long) ptr -> offset, (long) ptr -> length)); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"arrange_binary", "Bad magic number"); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file): ftell=%ld\n", in_state_ftell(state_in))); } tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir"); if (!tmp) return NULL; fname = elm_message(FRM("%selmdecode-%d"), tmp, getpid ()); if (NULL == (tmpfp = safeopen_rdwr(fname))) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCreate, "Failed to create file for decoding.")); if (state_out) { state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCreate, "Failed to create file for decoding.")); state_nlputs(" ]\n",state_out); } } else { /* Tempfile opened */ int c = EOF, prev = EOF; int is_binary = ptr->encoding == ENCODING_BINARY; long pos; if (name) *name = fname; else unlink(fname); /* We can unlink it now ... */ DPRINT(Debug,11,(&Debug, " : is_binary = %d\n",is_binary)); if (in_state_fseek(state_in,ptr->begin_offset) != 0) { lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeArrangeSeekFail, "arrange_binary: seek failed")); return NULL; } while ((pos = in_state_ftell(state_in)) < ptr -> offset + ptr ->length && EOF != (c = state_getc(state_in))) { if (pos < ptr -> offset) { /* --- HEADER PART -- */ if ('\n' == c && '\r' != prev) { if (is_binary) { DPRINT(Debug,11,(&Debug, "arrange_binary -- (header) not really binary input!\n")); is_binary = 0; } fputc('\r',tmpfp); } } else if (!is_binary && '\n' == c && '\r' != prev) { fputc('\r',tmpfp); } fputc(c,tmpfp); prev = c; } rewind(tmpfp); /* Rewind it for reading */ set_in_state_file(tmpfp,newstate2); } if (!name) free(fname); return tmpfp; } FILE * arrange_decoded(ptr,state_in,state_out,newstate2,name) mime_t *ptr; in_state_t *state_in; out_state_t *state_out; in_state_t *newstate2; char **name; { FILE * tmpfp = NULL; int result = 1; char *fname = NULL; out_state_t newstate; char *tmp; out_state_clear(&newstate,STATE_out_file); DPRINT(Debug,11,(&Debug, "arrange_decoded -> state: offset=%ld, length=%ld \n", (long) ptr -> offset, (long) ptr -> length)); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"arrange_decoded", "Bad magic number"); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file): ftell=%ld\n", in_state_ftell(state_in))); } tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir"); if (!tmp) return NULL; fname = elm_message(FRM("%selmdecode.%d"), tmp, getpid ()); if (NULL == (tmpfp = safeopen_rdwr(fname))) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCreate, "Failed to create file for decoding.")); if (state_out) { state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeFailedCreate, "Failed to create file for decoding.")); state_nlputs(" ]\n",state_out); } result = 0; } else { /* Tempfile opened */ if (name) *name = fname; else unlink(fname); /* We can unlink it now ... */ if (state_out) newstate.displaying = state_out->displaying; else newstate.displaying = 0; set_out_state_file(tmpfp, &newstate); newstate.prefix = NULL; /* No prefix in that pass */ if (state_out) { newstate.filter = state_out->filter; newstate.display_charset = state_out->display_charset; } else { static charset_t default_vector[2]; default_vector[0] = display_charset; default_vector[1] = NULL; newstate.filter = NULL; newstate.display_charset = default_vector; } if (run_cte_decoder(ptr,state_in,&newstate)) { if (EOF == fflush(tmpfp)) { /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ lib_error(CATGETS(elm_msg_cat, MeSet, MeDecodeErrorFlush, "Error when flushing temporary file.")); if (state_out) { state_puts("[ ",state_out); state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeErrorFlush, "Error when flushing temporary file.")); state_nlputs(" ]\n",state_out); } result = 0; } rewind(tmpfp); /* Rewind it for reading */ set_in_state_file(tmpfp,newstate2); } else { /* Run decoder failed */ if (state_out) { state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeEncodingSkipping, "[ Unsupported encoding, skipping... ]\n")); if (state_out->displaying) state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeUseVEncodedSave, "[ Use 'v' to save this part in encoded form. ]\n")); } result = 0; } } out_state_destroy(&newstate); DPRINT(Debug,11,(&Debug, "arrange_decoded; result=%d\n",result)); if (!result && tmpfp) { fclose(tmpfp); tmpfp = NULL; if (name) { unlink(fname); /* Unlink was delayed */ *name = NULL; } free(fname); } else { if (!name) free(fname); } return tmpfp; } /* Prototype */ static void elm_decode P_((mime_t *part, in_state_t *instream, out_state_t *outstream, charset_t defcharset, struct header_rec *hdr, type_mismatch_prompt *badtype)); static void elm_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; { in_state_t newstate2; FILE *tmpfp; char buffer[LONG_STRING]; in_state_clear(&newstate2,STATE_in_file); DPRINT(Debug,11,(&Debug, "elm_decode -> state: offset=%ld, length=%ld; \n", (long) ptr -> offset, (long) ptr -> length)); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"elm_decode", "Bad magic number"); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file): ftell=%ld\n", in_state_ftell(state_in))); } if (NULL != (tmpfp = arrange_decoded(ptr,state_in,state_out,&newstate2,NULL))) { if (check_type_pattern) { if (!check_type_magic(ptr,&newstate2, state_out, badtype)) { DPRINT(Debug,11,(&Debug, "elm_decode: mime_type_rejected\n")); goto FAILTYPE; } } if (set_filter(ptr,state_out,NULL, mss ? mss->override_charset : NULL)) { int len, crypted = 0; int count = 0; int ok = getkey(OFF); while((len = state_getl(buffer,sizeof(buffer),&newstate2)) > 0) { count += len; if (ok > 0) { if (!strncmp(buffer, START_ENCODE, strlen(START_ENCODE))) { state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeStartElmEncoded, "-- Start of (Elm) encoded section.\n")); crypted = ON; continue; } else if (!strncmp(buffer, END_ENCODE, strlen(END_ENCODE))) { crypted = OFF; state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeEndElmEncoded, "-- End of (Elm) encoded section.\n")); continue; } else if (crypted) { no_ret(buffer); encode(buffer); if (state_out->EOLN_is_CRLF) strfcat(buffer, "\r\n", sizeof buffer); else strfcat(buffer, "\n", sizeof buffer); } } state_add_prefix(state_out); state_puts(buffer,state_out); } DPRINT(Debug,11,(&Debug, "elm_decode: Read %d bytes from temp file\n", count)); } FAILTYPE: fclose(tmpfp); } DPRINT(Debug,11,(&Debug, "elm_decode <- END; \n")); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file); ftell=%ld\n", in_state_ftell(state_in))); } in_state_destroy(&newstate2); } /* Prototype */ static void text_unsupported_decode P_((mime_t *part, in_state_t *instream, out_state_t *outsream, charset_t defcharset, struct header_rec *hdr, type_mismatch_prompt *badtype)); /* Returns -1 on failure otherwise same mask than mime_classify_media() */ S_(mime_run_selector text_unsupported_selector) static int text_unsupported_selector(p,hdr) mime_t *p; struct header_rec * hdr; { int flags = NOTPLAIN_is_fallback; /* Notice: if (decoder == text_unsupported_decode) * we return TRUE, because we want call metamail * if it is available */ DPRINT(Debug,11,(&Debug, "text_unsupported_selector(%p)=%d\n", p,flags)); return flags; } static void text_unsupported_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; { DPRINT(Debug,11,(&Debug, "text_unsupported_decode -> state: offset=%ld, length=%ld; \n", (long) ptr -> offset, (long) ptr -> length)); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"text_unsupported_decode", "Bad magic number"); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file): ftell=%ld\n", in_state_ftell(state_in))); } /* state_nlputs or state_printf is needed for EOLN_is_CRLF conversions */ state_printf(state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeUnsupportedText, "[ %s/%.30s is unsupported, treating like TEXT/PLAIN ]\n"), get_major_type_name(ptr->TYPE), get_subtype_name(ptr->TYPE)); state_nlputs("\n",state_out); text_decode (ptr, state_in, state_out, defcharset, mss, badtype); DPRINT(Debug,11,(&Debug, "text_unsupported_decode <- END; \n")); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file); ftell=%ld\n", in_state_ftell(state_in))); } } void null_decode (ptr, state_in, state_out, defcharset, mss) mime_t *ptr; in_state_t *state_in; out_state_t *state_out; charset_t defcharset; struct header_rec *mss; { DPRINT(Debug,11,(&Debug, "null_decode <-> state: offset=%ld, length=%ld; \n", (long) ptr -> offset, (long) ptr -> length)); if (ptr->magic != MIME_magic) mime_panic(__FILE__,__LINE__,"null_decode", "Bad magic number"); if (in_state_seekable(state_in)) { DPRINT(Debug,11,(&Debug, " (file): ftell=%ld\n", in_state_ftell(state_in))); } state_printf (state_out, CATGETS(elm_msg_cat, MeSet, MeDecodeUnsupportedSkip, "[ %.15s/%.30s is not supported, 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")); } #if __GNUC__ #define MTH struct media_type_handle #define PAGER(A) handle_pager, { pager: & A } #define REGISTER_MT_HANDLER(A,B,R) \ register_mt_handler(give_media_type2(A,B,1),& R) #define REGISTER_MT_DEFHANDLER(A,R) \ register_mt_defhandler(A,& R) #else #define MTH struct COMPAT_media_type_handle #define PAGER(A) handle_pager, (void *) & A #define REGISTER_MT_HANDLER(A,B,R) \ register_mt_handler(give_media_type2(A,B,1),(struct media_type_handle *)& R) #define REGISTER_MT_DEFHANDLER(A,R) \ register_mt_defhandler(A,(struct media_type_handle *)& R) #endif static struct mt_handle_pager alternative_1 = { alternative_decode, alternative_selector }; static MTH alternative_2 = { PAGER(alternative_1) }; static struct mt_handle_pager signed_1 = { signed_decode, signed_selector }; static MTH signed_2 = { PAGER(signed_1) }; static struct mt_handle_pager encrypted_1 = { encrypted_decode, encrypted_selector }; static MTH encrypted_2 = { PAGER(encrypted_1) }; static struct mt_handle_pager multipart_0_1 = { multipart_0_decode, multipart_selector }; static MTH multipart_0_2 = { PAGER(multipart_0_1) }; static struct mt_handle_pager multipart_mixed_1 = { multipart_mixed_decode, multipart_selector }; static MTH multipart_mixed_2 = { PAGER(multipart_mixed_1) }; static struct mt_handle_pager rfc822_1 = { rfc822_decode, rfc822_selector }; static MTH rfc822_2 = { PAGER(rfc822_1) }; static struct mt_handle_pager text_1 = { text_decode, text_selector }; static MTH text_2 = { PAGER(text_1) }; #ifdef USE_PGP static struct mt_handle_pager pgp_1 = { pgp_decode, pgp_selector }; static MTH pgp_2 = { PAGER(pgp_1) }; #endif static struct mt_handle_pager text_unsupported_1 = { text_unsupported_decode, text_unsupported_selector }; static MTH text_unsupported_2 = { PAGER(text_unsupported_1) }; static struct mt_handle_pager elm_1 = { elm_decode, text_selector }; static MTH elm_2 = { PAGER(elm_1) }; static struct mt_handle_pager partial_1 = { partial_decode, partial_selector }; static MTH partial_2 = { PAGER(partial_1) }; static int melib_register_decoders_called = 0; void melib_register_decoders() { if (melib_register_decoders_called) return; /* multipart types */ REGISTER_MT_HANDLER(MIME_TYPE_MULTIPART,"alternative",alternative_2); REGISTER_MT_HANDLER(MIME_TYPE_MULTIPART,"signed", signed_2); REGISTER_MT_HANDLER(MIME_TYPE_MULTIPART,"encrypted", encrypted_2); REGISTER_MT_HANDLER(MIME_TYPE_MULTIPART,"mixed", multipart_mixed_2); REGISTER_MT_DEFHANDLER(MIME_TYPE_MULTIPART, multipart_0_2); /* message types */ REGISTER_MT_HANDLER(MIME_TYPE_MESSAGE,"rfc822", rfc822_2); REGISTER_MT_HANDLER(MIME_TYPE_MESSAGE,"delivery-status", text_2); REGISTER_MT_HANDLER(MIME_TYPE_MESSAGE,"partial", partial_2); REGISTER_MT_HANDLER(MIME_TYPE_MESSAGE,"disposition-notification", text_2); /* text types */ REGISTER_MT_HANDLER(MIME_TYPE_TEXT,"plain", text_2); REGISTER_MT_HANDLER(MIME_TYPE_TEXT,"rfc822-headers", text_2); #ifdef USE_PGP REGISTER_MT_HANDLER(MIME_TYPE_TEXT,"x-pgp", pgp_2); #endif REGISTER_MT_DEFHANDLER(MIME_TYPE_TEXT, text_unsupported_2); /* application types */ #ifdef USE_PGP REGISTER_MT_HANDLER(MIME_TYPE_APPLICATION,"pgp", pgp_2); REGISTER_MT_HANDLER(MIME_TYPE_APPLICATION,"x-pgp", pgp_2); #endif REGISTER_MT_HANDLER(MIME_TYPE_APPLICATION,"X-ELM-encode", elm_2); #if 0 /* TODO: is this needed? */ /* Unknown leaf types */ REGISTER_MT_DEFHANDLER(MIME_TYPE_LEAF, XXXX); #endif melib_register_decoders_called++; } int is_rfc1522 (s) char *s; { /* Returns TRUE if the string contains RFC 1522 format encoded data */ while ((s = strchr (s, '=')) != NULL) { s++; if (*s == '?') return TRUE; } return FALSE; } /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */