diff options
Diffstat (limited to 'pith/mimedesc.c')
-rw-r--r-- | pith/mimedesc.c | 879 |
1 files changed, 879 insertions, 0 deletions
diff --git a/pith/mimedesc.c b/pith/mimedesc.c new file mode 100644 index 00000000..66b39839 --- /dev/null +++ b/pith/mimedesc.c @@ -0,0 +1,879 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: mimedesc.c 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $"; +#endif + +/* + * ======================================================================== + * Copyright 2006-2008 University of Washington + * Copyright 2013 Eduardo Chappa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "../pith/headers.h" +#include "../pith/mimedesc.h" +#include "../pith/mimetype.h" +#include "../pith/state.h" +#include "../pith/conf.h" +#include "../pith/mailview.h" +#include "../pith/rfc2231.h" +#include "../pith/editorial.h" +#include "../pith/mailpart.h" +#include "../pith/mailcap.h" +#include "../pith/smime.h" + + +/* internal prototypes */ +int mime_known_text_subtype(char *); +ATTACH_S *next_attachment(void); +void format_mime_size(char *, size_t, BODY *, int); +int mime_show(BODY *); + + +/* + * Def's to help in sorting out multipart/alternative + */ +#define SHOW_NONE 0 +#define SHOW_PARTS 1 +#define SHOW_ALL_EXT 2 +#define SHOW_ALL 3 + +/* + * Def's to control format_mime_size output + */ +#define FMS_NONE 0x00 +#define FMS_SPACE 0x01 + + +/*---------------------------------------------------------------------- + Add lines to the attachments structure + + Args: body -- body of the part being described + prefix -- The prefix for numbering the parts + num -- The number of this specific part + should_show -- Flag indicating which of alternate parts should be shown + multalt -- Flag indicating the part is one of the multipart + alternative parts (so suppress editorial comment) + +Result: The ps_global->attachments data structure is filled in. This +is called recursively to descend through all the parts of a message. +The description strings filled in are malloced and should be freed. + + ----*/ +void +describe_mime(struct mail_bodystruct *body, char *prefix, int num, + int should_show, int multalt, int flags) +{ + PART *part; + char numx[512], string[800], *description; + int n, named = 0, can_display_ext; + ATTACH_S *a; + + if(!body) + return; + + if(body->type == TYPEMULTIPART){ + int alt_to_show = 0; + + if(strucmp(body->subtype, "alternative") == 0){ + int effort, best_effort = SHOW_NONE; + + /*---- Figure out which alternative part to display ---*/ + /* + * This is kind of complicated because some TEXT types + * are more displayable than others. We don't want to + * commit to displaying a text-part alternative that we + * don't directly recognize unless that's all there is. + */ + for(part=body->nested.part, n=1; part; part=part->next, n++) + if(flags & FM_FORCEPREFPLN + || (!(flags & FM_FORCENOPREFPLN) + && F_ON(F_PREFER_PLAIN_TEXT, ps_global) + && part->body.type == TYPETEXT + && (!part->body.subtype + || !strucmp(part->body.subtype, "PLAIN")))){ + if((effort = mime_show(&part->body)) != SHOW_ALL_EXT){ + best_effort = effort; + alt_to_show = n; + break; + } + } + else if((effort = mime_show(&part->body)) >= best_effort + && (part->body.type != TYPETEXT || mime_known_text_subtype(part->body.subtype)) + && effort != SHOW_ALL_EXT){ + best_effort = effort; + alt_to_show = n; + } + else if(part->body.type == TYPETEXT && alt_to_show == 0){ + best_effort = effort; + alt_to_show = n; + } + } + else if(!strucmp(body->subtype, "digest")){ + memset(a = next_attachment(), 0, sizeof(ATTACH_S)); + if(*prefix){ + prefix[n = strlen(prefix) - 1] = '\0'; + a->number = cpystr(prefix); + prefix[n] = '.'; + } + else + a->number = cpystr(""); + + a->description = cpystr("Multipart/Digest"); + a->body = body; + a->can_display = MCD_INTERNAL; + (a+1)->description = NULL; + } +#ifdef SMIME + else if(!strucmp(body->subtype, OUR_PKCS7_ENCLOSURE_SUBTYPE)){ + memset(a = next_attachment(), 0, sizeof(ATTACH_S)); + if(*prefix){ + prefix[n = strlen(prefix) - 1] = '\0'; + a->number = cpystr(prefix); + prefix[n] = '.'; + } + else + a->number = cpystr(""); + + a->description = body->description ? cpystr(body->description) + : cpystr(""); + a->body = body; + a->can_display = MCD_INTERNAL; + (a+1)->description = NULL; + } +#endif /* SMIME */ + else if(mailcap_can_display(body->type, body->subtype, body, 0) + || (can_display_ext + = mailcap_can_display(body->type, body->subtype, body, 1))){ + memset(a = next_attachment(), 0, sizeof(ATTACH_S)); + if(*prefix){ + prefix[n = strlen(prefix) - 1] = '\0'; + a->number = cpystr(prefix); + prefix[n] = '.'; + } + else + a->number = cpystr(""); + + snprintf(string, sizeof(string), "%s/%s", body_type_names(body->type), + body->subtype); + string[sizeof(string)-1] = '\0'; + a->description = cpystr(string); + a->body = body; + a->can_display = MCD_EXTERNAL; + if(can_display_ext) + a->can_display |= MCD_EXT_PROMPT; + (a+1)->description = NULL; + } + + for(part=body->nested.part, n=1; part; part=part->next, n++){ + snprintf(numx, sizeof(numx), "%s%d.", prefix, n); + numx[sizeof(numx)-1] = '\0'; + /* + * Last arg to describe_mime here. If we have chosen one part + * of a multipart/alternative to display then we suppress + * the editorial messages on the other parts. + */ + describe_mime(&(part->body), + (part->body.type == TYPEMULTIPART) ? numx : prefix, + n, should_show && (n == alt_to_show || !alt_to_show), + alt_to_show != 0, flags); + } + } + else{ + char tmp1[MAILTMPLEN], tmp2[MAILTMPLEN]; + size_t ll; + + a = next_attachment(); + format_mime_size(a->size, sizeof(a->size), body, FMS_SPACE); + + a->suppress_editorial = (multalt != 0); + + snprintf(tmp1, sizeof(tmp1), "%s", body->description ? body->description : ""); + tmp1[sizeof(tmp1)-1] = '\0'; + snprintf(tmp2, sizeof(tmp2), "%s", (!body->description && body->type == TYPEMESSAGE && body->encoding <= ENCBINARY && body->subtype && strucmp(body->subtype, "rfc822") == 0 && body->nested.msg->env && body->nested.msg->env->subject) ? body->nested.msg->env->subject : ""); + tmp2[sizeof(tmp2)-1] = '\0'; + + description = (body->description) + ? (char *) rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, + SIZEOF_20KBUF, tmp1) + : (body->type == TYPEMESSAGE + && body->encoding <= ENCBINARY + && body->subtype + && strucmp(body->subtype, "rfc822") == 0 + && body->nested.msg->env + && body->nested.msg->env->subject) + ? (char *) rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, SIZEOF_20KBUF, tmp2) + : (body->type == TYPEMESSAGE + && body->subtype + && !strucmp(body->subtype, "delivery-status")) + ? "Delivery Status" + : NULL; + + description = iutf8ncpy((char *)(tmp_20k_buf+1000), description, 1000); + snprintf(string, sizeof(string), "%s%s%s%s", + type_desc(body->type,body->subtype,body->parameter, + body->disposition.type ? body->disposition.parameter : NULL, 0), + (description && description[0]) ? ", \"" : "", + (description && description[0]) ? description : "", + (description && description[0]) ? "\"": ""); + string[sizeof(string)-1] =- '\0'; + a->description = cpystr(string); + a->body = body; + + if(body->disposition.type){ + named = strucmp(body->disposition.type, "inline"); + } + else{ + char *value; + + + /* + * This test remains for backward compatibility + */ + if(body && (value = parameter_val(body->parameter, "name")) != NULL){ + named = strucmp(value, "Message Body"); + fs_give((void **) &value); + } + } + + /* + * Make sure we have the tools available to display the + * type/subtype, *AND* that we can decode it if needed. + * Of course, if it's text, we display it anyway in the + * mail_view_screen so put off testing mailcap until we're + * explicitly asked to display that segment 'cause it could + * be expensive to test... + */ + if((body->type == TYPETEXT && !named) + || MIME_VCARD(body->type,body->subtype)){ + a->test_deferred = 1; + a->can_display = MCD_INTERNAL; + } + else{ + a->test_deferred = 0; + a->can_display = mime_can_display(body->type, body->subtype, body); + } + + /* + * Deferred means we can display it + */ + a->shown = ((a->can_display & MCD_INTERNAL) + && !MIME_VCARD(body->type,body->subtype) + && (!named || multalt + || (body->type == TYPETEXT && num == 1 + && !(*prefix && strcmp(prefix,"1.")))) + && (body->type != TYPEMESSAGE + || (body->type == TYPEMESSAGE + && body->encoding <= ENCBINARY)) + && should_show); + ll = (strlen(prefix) + 16) * sizeof(char); + a->number = (char *) fs_get(ll); + snprintf(a->number, ll, "%s%d",prefix, num); + a->number[ll-1] = '\0'; + (a+1)->description = NULL; + if(body->type == TYPEMESSAGE && body->encoding <= ENCBINARY + && body->subtype && strucmp(body->subtype, "rfc822") == 0){ + body = body->nested.msg->body; + snprintf(numx, sizeof(numx), "%.*s%d.", sizeof(numx)-20, prefix, num); + numx[sizeof(numx)-1] = '\0'; + describe_mime(body, numx, 1, should_show, 0, flags); + } + } +} + + +int +mime_known_text_subtype(char *subtype) +{ + char **p; + static char *known_types[] = { + "plain", + "html", + "enriched", + "richtext", + NULL + }; + + if(!(subtype && *subtype)) + return(1); + + for(p = known_types; *p; p++) + if(!strucmp(subtype, *p)) + return(1); + return(0); +} + + +/* + * Returns attribute value or NULL. + * Value returned needs to be freed by caller + */ +char * +parameter_val(PARAMETER *param, char *attribute) +{ + if(!(param && attribute && attribute[0])) + return(NULL); + + return(rfc2231_get_param(param, attribute, NULL, NULL)); +} + + +/* + * Get sender_filename, the filename set by the sender in the attachment. + * If a sender_filename buffer is passed in, the answer is copied to it + * and a pointer to it is returned. If sender_filename is passed in as NULL + * then an allocated copy of the sender filename is returned instead. + * If ext_ptr is non-NULL then it is set to point to the extension name. + * It is not a separate copy, it points into the string sender_filename. + */ +char * +get_filename_parameter(char *sender_filename, size_t sfsize, BODY *body, char **ext_ptr) +{ + char *p = NULL; + char *decoded_name = NULL; + char *filename = NULL; + char tmp[1000]; + + if(!body) + return(NULL); + + if(sender_filename){ + if(sfsize <= 0) + return(NULL); + + sender_filename[0] = '\0'; + } + + /* + * First check for Content-Disposition's "filename" parameter and + * if that isn't found for the deprecated Content-Type "name" parameter. + */ + if((p = parameter_val(body->disposition.parameter, "filename")) + || (p = parameter_val(body->parameter, "name"))){ + + /* + * If somebody sent us and incorrectly rfc2047 encoded + * parameter value instead of what rfc2231 suggest we + * grudglingly try to fix it. + */ + if(p[0] == '=' && p[1] == '?') + decoded_name = (char *) rfc1522_decode_to_utf8((unsigned char *) tmp, + sizeof(tmp), p); + + if(!decoded_name) + decoded_name = p; + + filename = last_cmpnt(decoded_name); + + if(!filename) + filename = decoded_name; + } + + if(filename){ + if(sender_filename){ + strncpy(sender_filename, filename, sfsize-1); + sender_filename[sfsize-1] = '\0'; + } + else + sender_filename = cpystr(filename); + } + + if(p) + fs_give((void **) &p); + + /* ext_ptr will end up pointing into sender_filename string */ + if(ext_ptr && sender_filename) + mt_get_file_ext(sender_filename, ext_ptr); + + return(sender_filename); +} + + +/*---------------------------------------------------------------------- + Return a pointer to the next attachment struct + + Args: none + + ----*/ +ATTACH_S * +next_attachment(void) +{ + ATTACH_S *a; + int n; + + for(a = ps_global->atmts; a->description; a++) + ; + + if((n = a - ps_global->atmts) + 1 >= ps_global->atmts_allocated){ + ps_global->atmts_allocated *= 2; + fs_resize((void **)&ps_global->atmts, + ps_global->atmts_allocated * sizeof(ATTACH_S)); + a = &ps_global->atmts[n]; + } + + return(a); +} + + + +/*---------------------------------------------------------------------- + Zero out the attachments structure and free up storage + ----*/ +void +zero_atmts(ATTACH_S *atmts) +{ + ATTACH_S *a; + + for(a = atmts; a->description != NULL; a++){ + fs_give((void **)&(a->description)); + fs_give((void **)&(a->number)); + } + + atmts->description = NULL; +} + + +char * +body_type_names(int t) +{ +#define TLEN 31 + static char body_type[TLEN + 1]; + char *p; + + body_type[0] = '\0'; + strncpy(body_type, /* copy the given type */ + (t > -1 && t < TYPEMAX && body_types[t]) + ? body_types[t] : "Other", TLEN); + body_type[sizeof(body_type)-1] = '\0'; + + for(p = body_type + 1; *p; p++) /* make it presentable */ + if(isascii((unsigned char) (*p)) && isupper((unsigned char) (*p))) + *p = tolower((unsigned char)(*p)); + + return(body_type); /* present it */ +} + + +/*---------------------------------------------------------------------- + Mapping table use to neatly display charset parameters + ----*/ + +static struct set_names { + char *rfcname, + *humanname; +} charset_names[] = { + {"US-ASCII", "Plain Text"}, + {"ISO-8859-1", "Latin 1 (Western Europe)"}, + {"ISO-8859-2", "Latin 2 (Eastern Europe)"}, + {"ISO-8859-3", "Latin 3 (Southern Europe)"}, + {"ISO-8859-4", "Latin 4 (Northern Europe)"}, + {"ISO-8859-5", "Latin & Cyrillic"}, + {"ISO-8859-6", "Latin & Arabic"}, + {"ISO-8859-7", "Latin & Greek"}, + {"ISO-8859-8", "Latin & Hebrew"}, + {"ISO-8859-9", "Latin 5 (Turkish)"}, + {"ISO-8859-10", "Latin 6 (Nordic)"}, + {"ISO-8859-11", "Latin & Thai"}, + {"ISO-8859-13", "Latin 7 (Baltic)"}, + {"ISO-8859-14", "Latin 8 (Celtic)"}, + {"ISO-8859-15", "Latin 9 (Euro)"}, + {"KOI8-R", "Latin & Russian"}, + {"KOI8-U", "Latin & Ukranian"}, + {"VISCII", "Latin & Vietnamese"}, + {"GB2312", "Latin & Simplified Chinese"}, + {"BIG5", "Latin & Traditional Chinese"}, + {"EUC-JP", "Latin & Japanese"}, + {"Shift-JIS", "Latin & Japanese"}, + {"Shift_JIS", "Latin & Japanese"}, + {"EUC-KR", "Latin & Korean"}, + {"ISO-2022-CN", "Latin & Chinese"}, + {"ISO-2022-JP", "Latin & Japanese"}, + {"ISO-2022-KR", "Latin & Korean"}, + {"UTF-7", "7-bit encoded Unicode"}, + {"UTF-8", "Internet-standard Unicode"}, + {"ISO-2022-JP-2", "Multilingual"}, + {NULL, NULL} +}; + + +/*---------------------------------------------------------------------- + Return a nicely formatted discription of the type of the part + ----*/ + +char * +type_desc(int type, char *subtype, PARAMETER *params, PARAMETER *disp_params, int full) +{ + static char type_d[200]; + int i; + char *p, *parmval; + + p = type_d; + sstrncpy(&p, body_type_names(type), sizeof(type_d)-(p-type_d)); + if(full && subtype){ + *p++ = '/'; + sstrncpy(&p, subtype, sizeof(type_d)-(p-type_d)); + } + + type_d[sizeof(type_d)-1] = '\0'; + + switch(type){ + case TYPETEXT: + parmval = parameter_val(params, "charset"); + + if(parmval){ + for(i = 0; charset_names[i].rfcname; i++) + if(!strucmp(parmval, charset_names[i].rfcname)){ + if(!strucmp(parmval, ps_global->display_charmap + ? ps_global->display_charmap : "us-ascii") + || !strucmp(parmval, "us-ascii")) + i = -1; + + break; + } + + if(i >= 0){ /* charset to write */ + if(charset_names[i].rfcname){ + sstrncpy(&p, " (charset: ", sizeof(type_d)-(p-type_d)); + sstrncpy(&p, charset_names[i].rfcname + ? charset_names[i].rfcname : "Unknown", sizeof(type_d)-(p-type_d)); + if(full){ + sstrncpy(&p, " \"", sizeof(type_d)-(p-type_d)); + sstrncpy(&p, charset_names[i].humanname + ? charset_names[i].humanname + : parmval, sizeof(type_d)-(p-type_d)); + if(sizeof(type_d)-(p-type_d) > 0) + *p++ = '\"'; + } + + sstrncpy(&p, ")", sizeof(type_d)-(p-type_d)); + } + else{ + sstrncpy(&p, " (charset: ", sizeof(type_d)-(p-type_d)); + sstrncpy(&p, parmval, sizeof(type_d)-(p-type_d)); + sstrncpy(&p, ")", sizeof(type_d)-(p-type_d)); + } + } + + fs_give((void **) &parmval); + } + + break; + + case TYPEMESSAGE: + if(full && subtype && strucmp(subtype, "external-body") == 0) + if((parmval = parameter_val(params, "access-type")) != NULL){ + snprintf(p, sizeof(type_d)-(p-type_d), " (%s%s)", full ? "Access: " : "", parmval); + fs_give((void **) &parmval); + } + + break; + + default: + break; + } + + if(full && type != TYPEMULTIPART && type != TYPEMESSAGE){ + if((parmval = parameter_val(params, "name")) != NULL){ + snprintf(p, sizeof(type_d)-(p-type_d), " (Name: \"%s\")", parmval); + fs_give((void **) &parmval); + } + else if((parmval = parameter_val(disp_params, "filename")) != NULL){ + snprintf(p, sizeof(type_d)-(p-type_d), " (Filename: \"%s\")", parmval); + fs_give((void **) &parmval); + } + } + + type_d[sizeof(type_d)-1] = '\0'; + + return(type_d); +} + + + + +void +format_mime_size(char *string, size_t stringlen, struct mail_bodystruct *b, int flags) +{ + char tmp[10], *p = NULL; + char *origstring; + + + if(stringlen <= 0) + return; + + origstring = string; + + if(flags & FMS_SPACE) + *string++ = ' '; + + switch(b->encoding){ + case ENCBASE64 : + if(b->type == TYPETEXT){ + if(flags & FMS_SPACE) + *(string-1) = '~'; + else + *string++ = '~'; + } + + strncpy(p = string, byte_string((3 * b->size.bytes) / 4), stringlen-(string-origstring)); + break; + + default : + case ENCQUOTEDPRINTABLE : + if(flags & FMS_SPACE) + *(string-1) = '~'; + else + *string++ = '~'; + + case ENC8BIT : + case ENC7BIT : + if(b->type == TYPETEXT) + /* lines with no CRLF aren't counted, just add one so it makes more sense */ + snprintf(string, stringlen-(string-origstring), "%s lines", comatose(b->size.lines+1)); + else + strncpy(p = string, byte_string(b->size.bytes), stringlen-(string-origstring)); + + break; + } + + origstring[stringlen-1] = '\0'; + + if(p){ + for(; *p && (isascii((unsigned char) *p) && (isdigit((unsigned char) *p) + || ispunct((unsigned char) *p))); p++) + ; + + snprintf(tmp, sizeof(tmp), (flags & FMS_SPACE) ? " %-5.5s" : " %s", p); + tmp[sizeof(tmp)-1] = '\0'; + strncpy(p, tmp, stringlen-(p-origstring)); + } + + origstring[stringlen-1] = '\0'; +} + + + +/*---------------------------------------------------------------------- + Determine if we can show all, some or none of the parts of a body + +Args: body --- The message body to check + +Returns: SHOW_ALL, SHOW_ALL_EXT, SHOW_PART or SHOW_NONE depending on + how much of the body can be shown and who can show it. + ----*/ +int +mime_show(struct mail_bodystruct *body) +{ + int effort, best_effort; + PART *p; + + if(!body) + return(SHOW_NONE); + + switch(body->type) { + case TYPEMESSAGE: + if(!strucmp(body->subtype, "rfc822")) + return(mime_show(body->nested.msg->body) == SHOW_ALL + ? SHOW_ALL: SHOW_PARTS); + /* else fall thru to default case... */ + + default: + /* + * Since we're testing for internal displayability, give the + * internal result over an external viewer + */ + effort = mime_can_display(body->type, body->subtype, body); + if(effort == MCD_NONE) + return(SHOW_NONE); + else if(effort & MCD_INTERNAL) + return(SHOW_ALL); + else + return(SHOW_ALL_EXT); + + case TYPEMULTIPART: + best_effort = SHOW_NONE; + for(p = body->nested.part; p; p = p->next) + if((effort = mime_show(&p->body)) > best_effort) + best_effort = effort; + + return(best_effort); + } +} + + +/* + * fcc_size_guess + */ +long +fcc_size_guess(struct mail_bodystruct *body) +{ + long size = 0L; + + if(body){ + if(body->type == TYPEMULTIPART){ + PART *part; + + for(part = body->nested.part; part; part = part->next) + size += fcc_size_guess(&part->body); + } + else{ + size = body->size.bytes; + /* + * If it is ENCBINARY we will be base64 encoding it. This + * ideally increases the size by a factor of 4/3, but there + * is a per-line increase in that because of the CRLFs and + * because the number of characters in the line might not + * be a factor of 3. So push it up by 3/2 instead. This still + * won't catch all the cases. In particular, attachements with + * lots of short lines (< 10) will expand by more than that, + * but that's ok since this is an optimization. That's why + * so_cs_puts uses the 3/2 factor when it does a resize, so + * that it won't have to resize linearly until it gets there. + */ + if(body->encoding == ENCBINARY) + size = 3*size/2; + } + } + + return(size); +} + + + +/*---------------------------------------------------------------------- + Format a strings describing one unshown part of a Mime message + +Args: number -- A string with the part number i.e. "3.2.1" + body -- The body part + type -- 1 - Not shown, but can be + 2 - Not shown, cannot be shown + 3 - Can't print + width -- allowed width per line of editorial comment + pc -- function used to write the description comment + +Result: formatted description written to object ref'd by "pc" + ----*/ +char * +part_desc(char *number, BODY *body, int type, int width, int flags, gf_io_t pc) +{ + char *t; + char buftmp[MAILTMPLEN], sizebuf[256]; + + if(!gf_puts(NEWLINE, pc)) + return("No space for description"); + + format_mime_size(sizebuf, 256, body, FMS_NONE); + + snprintf(buftmp, sizeof(buftmp), "%s", body->description ? body->description : ""); + buftmp[sizeof(buftmp)-1] = '\0'; + snprintf(tmp_20k_buf+10000, SIZEOF_20KBUF-10000, "Part %s, %s%.2048s%s%s %s.", + number, + body->description == NULL ? "" : "\"", + body->description == NULL ? "" + : (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf, 10000, buftmp), + body->description == NULL ? "" : "\" ", + type_desc(body->type, body->subtype, body->parameter, NULL, 1), + sizebuf); + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + + iutf8ncpy((char *)tmp_20k_buf, (char *)(tmp_20k_buf+10000), 10000); + tmp_20k_buf[10000] = '\0'; + + t = &tmp_20k_buf[strlen(tmp_20k_buf)]; + +#ifdef SMIME + /* if smime and not attempting print */ + if(F_OFF(F_DONT_DO_SMIME, ps_global) && is_pkcs7_body(body) && type != 3){ + + sstrncpy(&t, "\015\012", SIZEOF_20KBUF-(t-tmp_20k_buf)); + + if(ps_global->smime && ps_global->smime->need_passphrase){ + sstrncpy(&t, + "This part is a PKCS7 S/MIME enclosure. " + "You may be able to view it by entering the correct passphrase " + "with the \"Decrypt\" command.", + SIZEOF_20KBUF-(t-tmp_20k_buf)); + } + else{ + sstrncpy(&t, + "This part is a PKCS7 S/MIME enclosure. " + "Press \"^E\" for more information.", + SIZEOF_20KBUF-(t-tmp_20k_buf)); + } + + } else +#endif + + if(type){ + sstrncpy(&t, "\015\012", SIZEOF_20KBUF-(t-tmp_20k_buf)); + switch(type) { + case 1: + if(MIME_VCARD(body->type,body->subtype)) + sstrncpy(&t, + /* TRANSLATORS: This is the description of an attachment that isn't being + shown but that can be viewed or saved. */ + _("Not Shown. Use the \"V\" command to view or save to address book."), SIZEOF_20KBUF-(t-tmp_20k_buf)); + else + sstrncpy(&t, + /* TRANSLATORS: This is the description of an attachment that isn't being + shown but that can be viewed or saved. */ + _("Not Shown. Use the \"V\" command to view or save this part."), SIZEOF_20KBUF-(t-tmp_20k_buf)); + + break; + + case 2: + sstrncpy(&t, "Cannot ", SIZEOF_20KBUF-(t-tmp_20k_buf)); + if(body->type != TYPEAUDIO && body->type != TYPEVIDEO) + sstrncpy(&t, "dis", SIZEOF_20KBUF-(t-tmp_20k_buf)); + + sstrncpy(&t, + "play this part. Press \"V\" then \"S\" to save in a file.", SIZEOF_20KBUF-(t-tmp_20k_buf)); + break; + + case 3: + sstrncpy(&t, _("Unable to print this part."), SIZEOF_20KBUF-(t-tmp_20k_buf)); + break; + } + } + + if(!(t = format_editorial(tmp_20k_buf, width, flags, NULL, pc))){ + if(!gf_puts(NEWLINE, pc)) + t = "No space for description"; + } + + return(t); +} + + +/*---------------------------------------------------------------------- + Can we display this type/subtype? + + Args: type -- the MIME type to check + subtype -- the MIME subtype + params -- parameters + use_viewer -- tell caller he should run external viewer cmd to view + + Result: Returns: + + MCD_NONE if we can't display this type at all + MCD_INTERNAL if we can display it internally + MCD_EXTERNAL if it can be displayed via an external viewer + + ----*/ +int +mime_can_display(int type, char *subtype, BODY *body) +{ + return((mailcap_can_display(type, subtype, body, 0) + ? MCD_EXTERNAL + : (mailcap_can_display(type, subtype, body, 1) + ? (MCD_EXT_PROMPT | MCD_EXTERNAL) : MCD_NONE)) + | ((type == TYPETEXT || type == TYPEMESSAGE + || MIME_VCARD(type,subtype)) + ? MCD_INTERNAL : MCD_NONE)); +} |