1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: mimedesc.c 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2013-2020 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "../pith/headers.h"
20 #include "../pith/mimedesc.h"
21 #include "../pith/mimetype.h"
22 #include "../pith/state.h"
23 #include "../pith/conf.h"
24 #include "../pith/mailview.h"
25 #include "../pith/rfc2231.h"
26 #include "../pith/editorial.h"
27 #include "../pith/mailpart.h"
28 #include "../pith/mailcap.h"
29 #include "../pith/smime.h"
32 /* internal prototypes */
33 int mime_known_text_subtype(char *);
34 ATTACH_S
*next_attachment(void);
35 void format_mime_size(char *, size_t, BODY
*, int);
36 int mime_show(BODY
*);
40 * Def's to help in sorting out multipart/alternative
44 #define SHOW_ALL_EXT 2
48 * Def's to control format_mime_size output
51 #define FMS_SPACE 0x01
54 /*----------------------------------------------------------------------
55 Add lines to the attachments structure
57 Args: body -- body of the part being described
58 prefix -- The prefix for numbering the parts
59 num -- The number of this specific part
60 should_show -- Flag indicating which of alternate parts should be shown
61 multalt -- Flag indicating the part is one of the multipart
62 alternative parts (so suppress editorial comment)
64 Result: The ps_global->attachments data structure is filled in. This
65 is called recursively to descend through all the parts of a message.
66 The description strings filled in are malloced and should be freed.
70 describe_mime(struct mail_bodystruct
*body
, char *prefix
, int num
,
71 int should_show
, int multalt
, int flags
)
75 char numx
[NUMXLEN
], string
[800], *description
;
76 int n
, named
= 0, can_display_ext
;
82 if(body
->type
== TYPEMULTIPART
){
85 if(strucmp(body
->subtype
, "alternative") == 0){
86 int effort
, best_effort
= SHOW_NONE
;
88 /*---- Figure out which alternative part to display ---*/
90 * This is kind of complicated because some TEXT types
91 * are more displayable than others. We don't want to
92 * commit to displaying a text-part alternative that we
93 * don't directly recognize unless that's all there is.
95 for(part
=body
->nested
.part
, n
=1; part
; part
=part
->next
, n
++)
96 if(flags
& FM_FORCEPREFPLN
97 || (!(flags
& FM_FORCENOPREFPLN
)
98 && F_ON(F_PREFER_PLAIN_TEXT
, ps_global
)
99 && part
->body
.type
== TYPETEXT
100 && (!part
->body
.subtype
101 || !strucmp(part
->body
.subtype
, "PLAIN")))){
102 if((effort
= mime_show(&part
->body
)) != SHOW_ALL_EXT
){
103 best_effort
= effort
;
108 else if((effort
= mime_show(&part
->body
)) >= best_effort
109 && (part
->body
.type
!= TYPETEXT
|| mime_known_text_subtype(part
->body
.subtype
))
110 && effort
!= SHOW_ALL_EXT
){
111 best_effort
= effort
;
114 else if(part
->body
.type
== TYPETEXT
&& alt_to_show
== 0){
115 best_effort
= effort
;
119 else if(!strucmp(body
->subtype
, "digest")){
120 memset(a
= next_attachment(), 0, sizeof(ATTACH_S
));
122 prefix
[n
= strlen(prefix
) - 1] = '\0';
123 a
->number
= cpystr(prefix
);
127 a
->number
= cpystr("");
129 a
->description
= cpystr("Multipart/Digest");
131 a
->can_display
= MCD_INTERNAL
;
132 (a
+1)->description
= NULL
;
135 else if(!strucmp(body
->subtype
, OUR_PKCS7_ENCLOSURE_SUBTYPE
)){
136 memset(a
= next_attachment(), 0, sizeof(ATTACH_S
));
138 prefix
[n
= strlen(prefix
) - 1] = '\0';
139 a
->number
= cpystr(prefix
);
143 a
->number
= cpystr("");
145 a
->description
= body
->description
? cpystr(body
->description
)
148 a
->can_display
= MCD_INTERNAL
;
149 (a
+1)->description
= NULL
;
152 else if(mailcap_can_display(body
->type
, body
->subtype
, body
, 0)
154 = mailcap_can_display(body
->type
, body
->subtype
, body
, 1))){
155 memset(a
= next_attachment(), 0, sizeof(ATTACH_S
));
157 prefix
[n
= strlen(prefix
) - 1] = '\0';
158 a
->number
= cpystr(prefix
);
162 a
->number
= cpystr("");
164 snprintf(string
, sizeof(string
), "%s/%s", body_type_names(body
->type
),
166 string
[sizeof(string
)-1] = '\0';
167 a
->description
= cpystr(string
);
169 a
->can_display
= MCD_EXTERNAL
;
171 a
->can_display
|= MCD_EXT_PROMPT
;
172 (a
+1)->description
= NULL
;
175 for(part
=body
->nested
.part
, n
=1; part
; part
=part
->next
, n
++){
176 snprintf(numx
, sizeof(numx
), "%s%d.", prefix
, n
);
177 numx
[sizeof(numx
)-1] = '\0';
179 * Last arg to describe_mime here. If we have chosen one part
180 * of a multipart/alternative to display then we suppress
181 * the editorial messages on the other parts.
183 describe_mime(&(part
->body
),
184 (part
->body
.type
== TYPEMULTIPART
) ? numx
: prefix
,
185 n
, should_show
&& (n
== alt_to_show
|| !alt_to_show
),
186 alt_to_show
!= 0, flags
);
190 char tmp1
[MAILTMPLEN
], tmp2
[MAILTMPLEN
];
193 a
= next_attachment();
194 format_mime_size(a
->size
, sizeof(a
->size
), body
, FMS_SPACE
);
196 a
->suppress_editorial
= (multalt
!= 0);
198 snprintf(tmp1
, sizeof(tmp1
), "%s", body
->description
? body
->description
: "");
199 tmp1
[sizeof(tmp1
)-1] = '\0';
200 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
: "");
201 tmp2
[sizeof(tmp2
)-1] = '\0';
203 description
= (body
->description
)
204 ? (char *) rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
,
206 : (body
->type
== TYPEMESSAGE
207 && body
->encoding
<= ENCBINARY
209 && strucmp(body
->subtype
, "rfc822") == 0
210 && body
->nested
.msg
->env
211 && body
->nested
.msg
->env
->subject
)
212 ? (char *) rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
, SIZEOF_20KBUF
, tmp2
)
213 : (body
->type
== TYPEMESSAGE
215 && !strucmp(body
->subtype
, "delivery-status"))
219 description
= iutf8ncpy((char *)(tmp_20k_buf
+1000), description
, 1000);
220 snprintf(string
, sizeof(string
), "%s%s%s%s",
221 type_desc(body
->type
,body
->subtype
,body
->parameter
,
222 body
->disposition
.type
? body
->disposition
.parameter
: NULL
, 0),
223 (description
&& description
[0]) ? ", \"" : "",
224 (description
&& description
[0]) ? description
: "",
225 (description
&& description
[0]) ? "\"": "");
226 string
[sizeof(string
)-1] = '\0';
227 a
->description
= cpystr(string
);
230 if(body
->disposition
.type
){
231 named
= strucmp(body
->disposition
.type
, "inline");
238 * This test remains for backward compatibility
240 if(body
&& (value
= parameter_val(body
->parameter
, "name")) != NULL
){
241 named
= strucmp(value
, "Message Body");
242 fs_give((void **) &value
);
247 * Make sure we have the tools available to display the
248 * type/subtype, *AND* that we can decode it if needed.
249 * Of course, if it's text, we display it anyway in the
250 * mail_view_screen so put off testing mailcap until we're
251 * explicitly asked to display that segment 'cause it could
252 * be expensive to test...
254 if((body
->type
== TYPETEXT
&& !named
)
255 || MIME_VCARD(body
->type
,body
->subtype
)
256 || MIME_VCALENDAR(body
->type
, body
->subtype
)){
257 a
->test_deferred
= 1;
258 a
->can_display
= MCD_INTERNAL
;
261 a
->test_deferred
= 0;
262 a
->can_display
= mime_can_display(body
->type
, body
->subtype
, body
);
266 * Deferred means we can display it
268 a
->shown
= MIME_VCALENDAR(body
->type
, body
->subtype
)
269 || ((a
->can_display
& MCD_INTERNAL
)
270 && !MIME_VCARD(body
->type
,body
->subtype
)
271 && (!named
|| multalt
272 || (body
->type
== TYPETEXT
&& num
== 1
273 && !(*prefix
&& strcmp(prefix
,"1."))))
274 && (body
->type
!= TYPEMESSAGE
275 || (body
->type
== TYPEMESSAGE
276 && body
->encoding
<= ENCBINARY
))
278 ll
= (strlen(prefix
) + 16) * sizeof(char);
279 a
->number
= (char *) fs_get(ll
);
280 snprintf(a
->number
, ll
, "%s%d",prefix
, num
);
281 a
->number
[ll
-1] = '\0';
282 (a
+1)->description
= NULL
;
283 if(body
->type
== TYPEMESSAGE
&& body
->encoding
<= ENCBASE64
284 && body
->subtype
&& strucmp(body
->subtype
, "rfc822") == 0){
285 body
= body
->nested
.msg
->body
; /* NUMXLEN = sizeof(numx) */
286 snprintf(numx
, sizeof(numx
), "%.*s%d.", NUMXLEN
-20, prefix
, num
);
287 numx
[sizeof(numx
)-1] = '\0';
288 describe_mime(body
, numx
, 1, should_show
, 0, flags
);
295 mime_known_text_subtype(char *subtype
)
298 static char *known_types
[] = {
306 if(!(subtype
&& *subtype
))
309 for(p
= known_types
; *p
; p
++)
310 if(!strucmp(subtype
, *p
))
317 * Returns attribute value or NULL.
318 * Value returned needs to be freed by caller
321 parameter_val(PARAMETER
*param
, char *attribute
)
323 if(!(param
&& attribute
&& attribute
[0]))
326 return(rfc2231_get_param(param
, attribute
, NULL
, NULL
));
331 * Get sender_filename, the filename set by the sender in the attachment.
332 * If a sender_filename buffer is passed in, the answer is copied to it
333 * and a pointer to it is returned. If sender_filename is passed in as NULL
334 * then an allocated copy of the sender filename is returned instead.
335 * If ext_ptr is non-NULL then it is set to point to the extension name.
336 * It is not a separate copy, it points into the string sender_filename.
339 get_filename_parameter(char *sender_filename
, size_t sfsize
, BODY
*body
, char **ext_ptr
)
342 char *decoded_name
= NULL
;
343 char *filename
= NULL
;
353 sender_filename
[0] = '\0';
357 * First check for Content-Disposition's "filename" parameter and
358 * if that isn't found for the deprecated Content-Type "name" parameter.
360 if((p
= parameter_val(body
->disposition
.parameter
, "filename"))
361 || (p
= parameter_val(body
->parameter
, "name"))){
364 * If somebody sent us and incorrectly rfc2047 encoded
365 * parameter value instead of what rfc2231 suggest we
366 * grudglingly try to fix it.
368 if(p
[0] == '=' && p
[1] == '?')
369 decoded_name
= (char *) rfc1522_decode_to_utf8((unsigned char *) tmp
,
375 filename
= last_cmpnt(decoded_name
);
378 filename
= decoded_name
;
383 strncpy(sender_filename
, filename
, sfsize
-1);
384 sender_filename
[sfsize
-1] = '\0';
387 sender_filename
= cpystr(filename
);
391 fs_give((void **) &p
);
393 /* ext_ptr will end up pointing into sender_filename string */
394 if(ext_ptr
&& sender_filename
)
395 mt_get_file_ext(sender_filename
, ext_ptr
);
397 return(sender_filename
);
401 /*----------------------------------------------------------------------
402 Return a pointer to the next attachment struct
408 next_attachment(void)
413 for(a
= ps_global
->atmts
; a
->description
; a
++)
416 if((n
= a
- ps_global
->atmts
) + 1 >= ps_global
->atmts_allocated
){
417 ps_global
->atmts_allocated
*= 2;
418 fs_resize((void **)&ps_global
->atmts
,
419 ps_global
->atmts_allocated
* sizeof(ATTACH_S
));
420 a
= &ps_global
->atmts
[n
];
428 /*----------------------------------------------------------------------
429 Zero out the attachments structure and free up storage
432 zero_atmts(ATTACH_S
*atmts
)
436 for(a
= atmts
; a
->description
!= NULL
; a
++){
437 a
->tmpdir
= NULL
; /* short lived variabled, cleared right after use */
438 a
->cid_tmpfile
= NULL
; /* resetting pointer is enough */
439 fs_give((void **)&(a
->description
));
440 fs_give((void **)&(a
->number
));
443 atmts
->description
= NULL
;
448 body_type_names(int t
)
451 static char body_type
[TLEN
+ 1];
455 strncpy(body_type
, /* copy the given type */
456 (t
> -1 && t
< TYPEMAX
&& body_types
[t
])
457 ? body_types
[t
] : "Other", TLEN
);
458 body_type
[sizeof(body_type
)-1] = '\0';
460 for(p
= body_type
+ 1; *p
; p
++) /* make it presentable */
461 if(isascii((unsigned char) (*p
)) && isupper((unsigned char) (*p
)))
462 *p
= tolower((unsigned char)(*p
));
464 return(body_type
); /* present it */
468 /*----------------------------------------------------------------------
469 Mapping table use to neatly display charset parameters
472 static struct set_names
{
475 } charset_names
[] = {
476 {"US-ASCII", "Plain Text"},
477 {"ISO-8859-1", "Latin 1 (Western Europe)"},
478 {"ISO-8859-2", "Latin 2 (Eastern Europe)"},
479 {"ISO-8859-3", "Latin 3 (Southern Europe)"},
480 {"ISO-8859-4", "Latin 4 (Northern Europe)"},
481 {"ISO-8859-5", "Latin & Cyrillic"},
482 {"ISO-8859-6", "Latin & Arabic"},
483 {"ISO-8859-7", "Latin & Greek"},
484 {"ISO-8859-8", "Latin & Hebrew"},
485 {"ISO-8859-9", "Latin 5 (Turkish)"},
486 {"ISO-8859-10", "Latin 6 (Nordic)"},
487 {"ISO-8859-11", "Latin & Thai"},
488 {"ISO-8859-13", "Latin 7 (Baltic)"},
489 {"ISO-8859-14", "Latin 8 (Celtic)"},
490 {"ISO-8859-15", "Latin 9 (Euro)"},
491 {"KOI8-R", "Latin & Russian"},
492 {"KOI8-U", "Latin & Ukrainian"},
493 {"VISCII", "Latin & Vietnamese"},
494 {"GB2312", "Latin & Simplified Chinese"},
495 {"BIG5", "Latin & Traditional Chinese"},
496 {"EUC-JP", "Latin & Japanese"},
497 {"Shift-JIS", "Latin & Japanese"},
498 {"Shift_JIS", "Latin & Japanese"},
499 {"EUC-KR", "Latin & Korean"},
500 {"ISO-2022-CN", "Latin & Chinese"},
501 {"ISO-2022-JP", "Latin & Japanese"},
502 {"ISO-2022-KR", "Latin & Korean"},
503 {"UTF-7", "7-bit encoded Unicode"},
504 {"UTF-8", "Internet-standard Unicode"},
505 {"ISO-2022-JP-2", "Multilingual"},
510 /*----------------------------------------------------------------------
511 Return a nicely formatted description of the type of the part
515 type_desc(int type
, char *subtype
, PARAMETER
*params
, PARAMETER
*disp_params
, int full
)
517 static char type_d
[200];
522 sstrncpy(&p
, body_type_names(type
), sizeof(type_d
)-(p
-type_d
));
525 sstrncpy(&p
, subtype
, sizeof(type_d
)-(p
-type_d
));
528 type_d
[sizeof(type_d
)-1] = '\0';
532 parmval
= parameter_val(params
, "charset");
535 for(i
= 0; charset_names
[i
].rfcname
; i
++)
536 if(!strucmp(parmval
, charset_names
[i
].rfcname
)){
537 if(!strucmp(parmval
, ps_global
->display_charmap
538 ? ps_global
->display_charmap
: "us-ascii")
539 || !strucmp(parmval
, "us-ascii"))
545 if(i
>= 0){ /* charset to write */
546 if(charset_names
[i
].rfcname
){
547 sstrncpy(&p
, " (charset: ", sizeof(type_d
)-(p
-type_d
));
548 sstrncpy(&p
, charset_names
[i
].rfcname
549 ? charset_names
[i
].rfcname
: "Unknown", sizeof(type_d
)-(p
-type_d
));
551 sstrncpy(&p
, " \"", sizeof(type_d
)-(p
-type_d
));
552 sstrncpy(&p
, charset_names
[i
].humanname
553 ? charset_names
[i
].humanname
554 : parmval
, sizeof(type_d
)-(p
-type_d
));
555 if(sizeof(type_d
)-(p
-type_d
) > 0)
559 sstrncpy(&p
, ")", sizeof(type_d
)-(p
-type_d
));
562 sstrncpy(&p
, " (charset: ", sizeof(type_d
)-(p
-type_d
));
563 sstrncpy(&p
, parmval
, sizeof(type_d
)-(p
-type_d
));
564 sstrncpy(&p
, ")", sizeof(type_d
)-(p
-type_d
));
568 fs_give((void **) &parmval
);
574 if(full
&& subtype
&& strucmp(subtype
, "external-body") == 0)
575 if((parmval
= parameter_val(params
, "access-type")) != NULL
){
576 snprintf(p
, sizeof(type_d
)-(p
-type_d
), " (%s%s)", full
? "Access: " : "", parmval
);
577 fs_give((void **) &parmval
);
586 if(full
&& type
!= TYPEMULTIPART
&& type
!= TYPEMESSAGE
){
587 unsigned char decodebuf
[10000];
588 if((parmval
= parameter_val(params
, "name")) != NULL
){
589 rfc1522_decode_to_utf8(decodebuf
, sizeof(decodebuf
), parmval
);
590 snprintf(p
, sizeof(type_d
)-(p
-type_d
), " (Name: \"%s\")", decodebuf
);
591 fs_give((void **) &parmval
);
593 else if((parmval
= parameter_val(disp_params
, "filename")) != NULL
){
594 rfc1522_decode_to_utf8(decodebuf
, sizeof(decodebuf
), parmval
);
595 snprintf(p
, sizeof(type_d
)-(p
-type_d
), " (Filename: \"%s\")", decodebuf
);
596 fs_give((void **) &parmval
);
600 type_d
[sizeof(type_d
)-1] = '\0';
609 format_mime_size(char *string
, size_t stringlen
, struct mail_bodystruct
*b
, int flags
)
611 char tmp
[10], *p
= NULL
;
620 if(flags
& FMS_SPACE
)
625 if(b
->type
== TYPETEXT
){
626 if(flags
& FMS_SPACE
)
632 strncpy(p
= string
, byte_string((3 * b
->size
.bytes
) / 4), stringlen
-(string
-origstring
));
636 case ENCQUOTEDPRINTABLE
:
637 if(flags
& FMS_SPACE
)
644 if(b
->type
== TYPETEXT
)
645 /* lines with no CRLF aren't counted, just add one so it makes more sense */
646 snprintf(string
, stringlen
-(string
-origstring
), "%s lines", comatose(b
->size
.lines
+1));
648 strncpy(p
= string
, byte_string(b
->size
.bytes
), stringlen
-(string
-origstring
));
653 origstring
[stringlen
-1] = '\0';
656 for(; *p
&& (isascii((unsigned char) *p
) && (isdigit((unsigned char) *p
)
657 || ispunct((unsigned char) *p
))); p
++)
660 snprintf(tmp
, sizeof(tmp
), (flags
& FMS_SPACE
) ? " %-5.5s" : " %s", p
);
661 tmp
[sizeof(tmp
)-1] = '\0';
662 strncpy(p
, tmp
, stringlen
-(p
-origstring
));
665 origstring
[stringlen
-1] = '\0';
670 /*----------------------------------------------------------------------
671 Determine if we can show all, some or none of the parts of a body
673 Args: body --- The message body to check
675 Returns: SHOW_ALL, SHOW_ALL_EXT, SHOW_PART or SHOW_NONE depending on
676 how much of the body can be shown and who can show it.
679 mime_show(struct mail_bodystruct
*body
)
681 int effort
, best_effort
;
689 if(!strucmp(body
->subtype
, "rfc822"))
690 return(mime_show(body
->nested
.msg
->body
) == SHOW_ALL
691 ? SHOW_ALL
: SHOW_PARTS
);
692 /* else fall thru to default case... */
696 * Since we're testing for internal displayability, give the
697 * internal result over an external viewer
699 effort
= mime_can_display(body
->type
, body
->subtype
, body
);
700 if(effort
== MCD_NONE
)
702 else if(effort
& MCD_INTERNAL
)
705 return(SHOW_ALL_EXT
);
708 best_effort
= SHOW_NONE
;
709 for(p
= body
->nested
.part
; p
; p
= p
->next
)
710 if((effort
= mime_show(&p
->body
)) > best_effort
)
711 best_effort
= effort
;
722 fcc_size_guess(struct mail_bodystruct
*body
)
727 if(body
->type
== TYPEMULTIPART
){
730 for(part
= body
->nested
.part
; part
; part
= part
->next
)
731 size
+= fcc_size_guess(&part
->body
);
734 size
= body
->size
.bytes
;
736 * If it is ENCBINARY we will be base64 encoding it. This
737 * ideally increases the size by a factor of 4/3, but there
738 * is a per-line increase in that because of the CRLFs and
739 * because the number of characters in the line might not
740 * be a factor of 3. So push it up by 3/2 instead. This still
741 * won't catch all the cases. In particular, attachments with
742 * lots of short lines (< 10) will expand by more than that,
743 * but that's ok since this is an optimization. That's why
744 * so_cs_puts uses the 3/2 factor when it does a resize, so
745 * that it won't have to resize linearly until it gets there.
747 if(body
->encoding
== ENCBINARY
)
757 /*----------------------------------------------------------------------
758 Format a strings describing one unshown part of a Mime message
760 Args: number -- A string with the part number i.e. "3.2.1"
761 body -- The body part
762 type -- 1 - Not shown, but can be
763 2 - Not shown, cannot be shown
765 width -- allowed width per line of editorial comment
766 pc -- function used to write the description comment
768 Result: formatted description written to object ref'd by "pc"
771 part_desc(char *number
, BODY
*body
, int type
, int width
, int flags
, gf_io_t pc
)
774 char buftmp
[MAILTMPLEN
], sizebuf
[256];
776 if(!gf_puts(NEWLINE
, pc
))
777 return("No space for description");
779 format_mime_size(sizebuf
, 256, body
, FMS_NONE
);
781 snprintf(buftmp
, sizeof(buftmp
), "%s", body
->description
? body
->description
: "");
782 buftmp
[sizeof(buftmp
)-1] = '\0';
783 snprintf(tmp_20k_buf
+10000, SIZEOF_20KBUF
-10000, "Part %s, %s%.2048s%s%s %s.",
785 body
->description
== NULL
? "" : "\"",
786 body
->description
== NULL
? ""
787 : (char *)rfc1522_decode_to_utf8((unsigned char *)tmp_20k_buf
, 10000, buftmp
),
788 body
->description
== NULL
? "" : "\" ",
789 type_desc(body
->type
, body
->subtype
, body
->parameter
, NULL
, 1),
791 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
793 iutf8ncpy((char *)tmp_20k_buf
, (char *)(tmp_20k_buf
+10000), 10000);
794 tmp_20k_buf
[10000] = '\0';
796 t
= &tmp_20k_buf
[strlen(tmp_20k_buf
)];
799 /* if smime and not attempting print */
800 if(F_OFF(F_DONT_DO_SMIME
, ps_global
) && is_pkcs7_body(body
) && type
!= 3){
802 sstrncpy(&t
, "\015\012", SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
804 if(ps_global
->smime
&& ps_global
->smime
->need_passphrase
){
806 "This part is a PKCS7 S/MIME enclosure. "
807 "You may be able to view it by entering the correct passphrase "
808 "with the \"Decrypt\" command.",
809 SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
813 "This part is a PKCS7 S/MIME enclosure. "
814 "Press \"^E\" for more information.",
815 SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
822 sstrncpy(&t
, "\015\012", SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
825 if(MIME_VCARD(body
->type
,body
->subtype
))
827 /* TRANSLATORS: This is the description of an attachment that isn't being
828 shown but that can be viewed or saved. */
829 _("Not Shown. Use the \"V\" command to view or save to address book."), SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
832 /* TRANSLATORS: This is the description of an attachment that isn't being
833 shown but that can be viewed or saved. */
834 _("Not Shown. Use the \"V\" command to view or save this part."), SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
839 sstrncpy(&t
, "Cannot ", SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
840 if(body
->type
!= TYPEAUDIO
&& body
->type
!= TYPEVIDEO
)
841 sstrncpy(&t
, "dis", SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
844 "play this part. Press \"V\" then \"S\" to save in a file.", SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
848 sstrncpy(&t
, _("Unable to print this part."), SIZEOF_20KBUF
-(t
-tmp_20k_buf
));
853 if(!(t
= format_editorial(tmp_20k_buf
, width
, flags
, NULL
, pc
))){
854 if(!gf_puts(NEWLINE
, pc
))
855 t
= "No space for description";
862 /*----------------------------------------------------------------------
863 Can we display this type/subtype?
865 Args: type -- the MIME type to check
866 subtype -- the MIME subtype
868 use_viewer -- tell caller he should run external viewer cmd to view
872 MCD_NONE if we can't display this type at all
873 MCD_INTERNAL if we can display it internally
874 MCD_EXTERNAL if it can be displayed via an external viewer
878 mime_can_display(int type
, char *subtype
, BODY
*body
)
880 return((mailcap_can_display(type
, subtype
, body
, 0)
882 : (mailcap_can_display(type
, subtype
, body
, 1)
883 ? (MCD_EXT_PROMPT
| MCD_EXTERNAL
) : MCD_NONE
))
884 | ((type
== TYPETEXT
|| type
== TYPEMESSAGE
885 || MIME_VCARD(type
,subtype
))
886 ? MCD_INTERNAL
: MCD_NONE
));