NeoMutt  2022-04-29-323-g5fcc6c
Teaching an old dog new tricks
DOXYGEN
handler.c File Reference

Decide how to display email content. More...

#include "config.h"
#include <ctype.h>
#include <iconv.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "handler.h"
#include "attach/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "copy.h"
#include "enriched.h"
#include "keymap.h"
#include "mailcap.h"
#include "mutt_globals.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "opcodes.h"
#include "options.h"
#include "rfc3676.h"
#include <libintl.h>
+ Include dependency graph for handler.c:

Go to the source code of this file.

Macros

#define BUFI_SIZE   1000
 
#define BUFO_SIZE   2000
 
#define TXT_HTML   1
 
#define TXT_PLAIN   2
 
#define TXT_ENRICHED   3
 

Typedefs

typedef int(* handler_t) (struct Body *b, struct State *s)
 

Functions

static void print_part_line (struct State *s, struct Body *b, int n)
 Print a separator for the Mime part. More...
 
static void convert_to_state (iconv_t cd, char *bufi, size_t *l, struct State *s)
 Convert text and write it to a file. More...
 
static void decode_xbit (struct State *s, long len, bool istext, iconv_t cd)
 Decode xbit-encoded text. More...
 
static int qp_decode_triple (char *s, char *d)
 Decode a quoted-printable triplet. More...
 
static void qp_decode_line (char *dest, char *src, size_t *l, int last)
 Decode a line of quoted-printable text. More...
 
static void decode_quoted (struct State *s, long len, bool istext, iconv_t cd)
 Decode an attachment encoded with quoted-printable. More...
 
static unsigned char decode_byte (char ch)
 Decode a uuencoded byte. More...
 
static void decode_uuencoded (struct State *s, long len, bool istext, iconv_t cd)
 Decode uuencoded text. More...
 
static bool is_mmnoask (const char *buf)
 Metamail compatibility: should the attachment be autoviewed? More...
 
static bool is_autoview (struct Body *b)
 Should email body be filtered by mailcap. More...
 
static int autoview_handler (struct Body *a, struct State *s)
 Handler for autoviewable attachments - Implements handler_t -. More...
 
static int text_plain_handler (struct Body *b, struct State *s)
 Handler for plain text - Implements handler_t -. More...
 
static int message_handler (struct Body *a, struct State *s)
 Handler for message/rfc822 body parts - Implements handler_t -. More...
 
static int external_body_handler (struct Body *b, struct State *s)
 Handler for external-body emails - Implements handler_t -. More...
 
static int alternative_handler (struct Body *a, struct State *s)
 Handler for multipart alternative emails - Implements handler_t -. More...
 
static int multilingual_handler (struct Body *a, struct State *s)
 Handler for multi-lingual emails - Implements handler_t -. More...
 
static int multipart_handler (struct Body *a, struct State *s)
 Handler for multipart emails - Implements handler_t -. More...
 
static int run_decode_and_handler (struct Body *b, struct State *s, handler_t handler, bool plaintext)
 Run an appropriate decoder for an email. More...
 
static int valid_pgp_encrypted_handler (struct Body *b, struct State *s)
 Handler for valid pgp-encrypted emails - Implements handler_t -. More...
 
static int malformed_pgp_encrypted_handler (struct Body *b, struct State *s)
 Handler for invalid pgp-encrypted emails - Implements handler_t -. More...
 
void mutt_decode_base64 (struct State *s, size_t len, bool istext, iconv_t cd)
 Decode base64-encoded text. More...
 
int mutt_body_handler (struct Body *b, struct State *s)
 Handler for the Body of an email. More...
 
bool mutt_prefer_as_attachment (struct Body *b)
 Do we want this part as an attachment? More...
 
bool mutt_can_decode (struct Body *b)
 Will decoding the attachment produce any output. More...
 
void mutt_decode_attachment (struct Body *b, struct State *s)
 Decode an email's attachment. More...
 

Detailed Description

Decide how to display email content.

Authors
  • Michael R. Elkins

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file handler.c.

Macro Definition Documentation

◆ BUFI_SIZE

#define BUFI_SIZE   1000

Definition at line 62 of file handler.c.

◆ BUFO_SIZE

#define BUFO_SIZE   2000

Definition at line 63 of file handler.c.

◆ TXT_HTML

#define TXT_HTML   1

Definition at line 65 of file handler.c.

◆ TXT_PLAIN

#define TXT_PLAIN   2

Definition at line 66 of file handler.c.

◆ TXT_ENRICHED

#define TXT_ENRICHED   3

Definition at line 67 of file handler.c.

Typedef Documentation

◆ handler_t

typedef int(* handler_t) (struct Body *b, struct State *s)

Definition at line 79 of file handler.c.

Function Documentation

◆ print_part_line()

static void print_part_line ( struct State s,
struct Body b,
int  n 
)
static

Print a separator for the Mime part.

Parameters
sState of text being processed
bBody of the email
nPart number for multipart emails (0 otherwise)

Definition at line 87 of file handler.c.

88{
89 char length[5] = { 0 };
90 mutt_str_pretty_size(length, sizeof(length), b->length);
92 char *charset = mutt_param_get(&b->parameter, "charset");
93 if (n == 0)
94 {
95 state_printf(s, _("[-- Type: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
96 TYPE(b), b->subtype, charset ? "; charset=" : "",
97 charset ? charset : "", ENCODING(b->encoding), length);
98 }
99 else
100 {
101 state_printf(s, _("[-- Alternative Type #%d: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
102 n, TYPE(b), b->subtype, charset ? "; charset=" : "",
103 charset ? charset : "", ENCODING(b->encoding), length);
104 }
105}
#define ENCODING(x)
Definition: mime.h:92
#define TYPE(body)
Definition: mime.h:89
#define _(a)
Definition: message.h:28
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:183
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:71
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1673
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ convert_to_state()

static void convert_to_state ( iconv_t  cd,
char *  bufi,
size_t *  l,
struct State s 
)
static

Convert text and write it to a file.

Parameters
cdIconv conversion descriptor
bufiBuffer with text to convert
lLength of buffer
sState to write to

Definition at line 114 of file handler.c.

115{
116 char bufo[BUFO_SIZE] = { 0 };
117 const char *ib = NULL;
118 char *ob = NULL;
119 size_t ibl, obl;
120
121 if (!bufi)
122 {
123 if (cd != (iconv_t) (-1))
124 {
125 ob = bufo;
126 obl = sizeof(bufo);
127 iconv(cd, NULL, NULL, &ob, &obl);
128 if (ob != bufo)
129 state_prefix_put(s, bufo, ob - bufo);
130 }
131 return;
132 }
133
134 if (cd == (iconv_t) (-1))
135 {
136 state_prefix_put(s, bufi, *l);
137 *l = 0;
138 return;
139 }
140
141 ib = bufi;
142 ibl = *l;
143 while (true)
144 {
145 ob = bufo;
146 obl = sizeof(bufo);
147 mutt_ch_iconv(cd, &ib, &ibl, &ob, &obl, 0, "?", NULL);
148 if (ob == bufo)
149 break;
150 state_prefix_put(s, bufo, ob - bufo);
151 }
152 memmove(bufi, ib, ibl);
153 *l = ibl;
154}
#define BUFO_SIZE
Definition: handler.c:63
size_t mutt_ch_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, const char **inrepls, const char *outrepl, int *iconverrno)
Change the encoding of a string.
Definition: charset.c:617
void state_prefix_put(struct State *s, const char *buf, size_t buflen)
Write a prefixed fixed-string to the State.
Definition: state.c:201
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ decode_xbit()

static void decode_xbit ( struct State s,
long  len,
bool  istext,
iconv_t  cd 
)
static

Decode xbit-encoded text.

Parameters
sState to work with
lenLength of text to decode
istextMime part is plain text
cdIconv conversion descriptor

Definition at line 163 of file handler.c.

164{
165 if (!istext)
166 {
167 mutt_file_copy_bytes(s->fp_in, s->fp_out, len);
168 return;
169 }
170
172
173 int c;
174 char bufi[BUFI_SIZE] = { 0 };
175 size_t l = 0;
176 while (((c = fgetc(s->fp_in)) != EOF) && len--)
177 {
178 if ((c == '\r') && len)
179 {
180 const int ch = fgetc(s->fp_in);
181 if (ch == '\n')
182 {
183 c = ch;
184 len--;
185 }
186 else
187 ungetc(ch, s->fp_in);
188 }
189
190 bufi[l++] = c;
191 if (l == sizeof(bufi))
192 convert_to_state(cd, bufi, &l, s);
193 }
194
195 convert_to_state(cd, bufi, &l, s);
196 convert_to_state(cd, 0, 0, s);
197
199}
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:229
#define BUFI_SIZE
Definition: handler.c:62
static void convert_to_state(iconv_t cd, char *bufi, size_t *l, struct State *s)
Convert text and write it to a file.
Definition: handler.c:114
#define state_set_prefix(state)
Definition: state.h:54
#define state_reset_prefix(state)
Definition: state.h:55
FILE * fp_out
File to write to.
Definition: state.h:48
FILE * fp_in
File to read from.
Definition: state.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ qp_decode_triple()

static int qp_decode_triple ( char *  s,
char *  d 
)
static

Decode a quoted-printable triplet.

Parameters
sState to work with
dDecoded character
Return values
0Success
-1Error

Definition at line 208 of file handler.c.

209{
210 /* soft line break */
211 if ((s[0] == '=') && (s[1] == '\0'))
212 return 1;
213
214 /* quoted-printable triple */
215 if ((s[0] == '=') && isxdigit((unsigned char) s[1]) && isxdigit((unsigned char) s[2]))
216 {
217 *d = (hexval(s[1]) << 4) | hexval(s[2]);
218 return 0;
219 }
220
221 /* something else */
222 return -1;
223}
#define hexval(ch)
Definition: mime.h:80
+ Here is the caller graph for this function:

◆ qp_decode_line()

static void qp_decode_line ( char *  dest,
char *  src,
size_t *  l,
int  last 
)
static

Decode a line of quoted-printable text.

Parameters
destBuffer for result
srcText to decode
lBytes written to buffer
lastLast character of the line

Definition at line 232 of file handler.c.

233{
234 char *d = NULL, *s = NULL;
235 char c = 0;
236
237 int kind = -1;
238 bool soft = false;
239
240 /* decode the line */
241
242 for (d = dest, s = src; *s;)
243 {
244 switch ((kind = qp_decode_triple(s, &c)))
245 {
246 case 0:
247 *d++ = c;
248 s += 3;
249 break; /* qp triple */
250 case -1:
251 *d++ = *s++;
252 break; /* single character */
253 case 1:
254 soft = true;
255 s++;
256 break; /* soft line break */
257 }
258 }
259
260 if (!soft && (last == '\n'))
261 {
262 /* neither \r nor \n as part of line-terminating CRLF
263 * may be qp-encoded, so remove \r and \n-terminate;
264 * see RFC2045, sect. 6.7, (1): General 8bit representation */
265 if ((kind == 0) && (c == '\r'))
266 *(d - 1) = '\n';
267 else
268 *d++ = '\n';
269 }
270
271 *d = '\0';
272 *l = d - dest;
273}
static int qp_decode_triple(char *s, char *d)
Decode a quoted-printable triplet.
Definition: handler.c:208
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ decode_quoted()

static void decode_quoted ( struct State s,
long  len,
bool  istext,
iconv_t  cd 
)
static

Decode an attachment encoded with quoted-printable.

Parameters
sState to work with
lenLength of text to decode
istextMime part is plain text
cdIconv conversion descriptor

Why doesn't this overflow any buffers? First, it's guaranteed that the length of a line grows when you en-code it to quoted-printable. That means that we always can store the result in a buffer of at most the same size.

Now, we don't special-case if the line we read with fgets() isn't terminated. We don't care about this, since 256 > 78, so corrupted input will just be corrupted a bit more. That implies that 256+1 bytes are always sufficient to store the result of qp_decode_line.

Finally, at soft line breaks, some part of a multibyte character may have been left over by convert_to_state(). This shouldn't be more than 6 characters, so 256+7 should be sufficient memory to store the decoded data.

Just to make sure that I didn't make some off-by-one error above, we just use 512 for the target buffer's size.

Definition at line 300 of file handler.c.

301{
302 char line[256] = { 0 };
303 char decline[512] = { 0 };
304 size_t l = 0;
305 size_t l3;
306
307 if (istext)
309
310 while (len > 0)
311 {
312 /* It's ok to use a fixed size buffer for input, even if the line turns
313 * out to be longer than this. Just process the line in chunks. This
314 * really shouldn't happen according the MIME spec, since Q-P encoded
315 * lines are at most 76 characters, but we should be liberal about what
316 * we accept. */
317 if (!fgets(line, MIN((ssize_t) sizeof(line), len + 1), s->fp_in))
318 break;
319
320 size_t linelen = strlen(line);
321 len -= linelen;
322
323 /* inspect the last character we read so we can tell if we got the
324 * entire line. */
325 const int last = (linelen != 0) ? line[linelen - 1] : 0;
326
327 /* chop trailing whitespace if we got the full line */
328 if (last == '\n')
329 {
330 while ((linelen > 0) && IS_SPACE(line[linelen - 1]))
331 linelen--;
332 line[linelen] = '\0';
333 }
334
335 /* decode and do character set conversion */
336 qp_decode_line(decline + l, line, &l3, last);
337 l += l3;
338 convert_to_state(cd, decline, &l, s);
339 }
340
341 convert_to_state(cd, 0, 0, s);
343}
static void qp_decode_line(char *dest, char *src, size_t *l, int last)
Decode a line of quoted-printable text.
Definition: handler.c:232
#define MIN(a, b)
Definition: memory.h:31
#define IS_SPACE(ch)
Definition: string2.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ decode_byte()

static unsigned char decode_byte ( char  ch)
static

Decode a uuencoded byte.

Parameters
chCharacter to decode
Return values
numDecoded value

Definition at line 350 of file handler.c.

351{
352 if ((ch < 32) || (ch > 95))
353 return 0;
354 return ch - 32;
355}
+ Here is the caller graph for this function:

◆ decode_uuencoded()

static void decode_uuencoded ( struct State s,
long  len,
bool  istext,
iconv_t  cd 
)
static

Decode uuencoded text.

Parameters
sState to work with
lenLength of text to decode
istextMime part is plain text
cdIconv conversion descriptor

Definition at line 364 of file handler.c.

365{
366 char tmps[128] = { 0 };
367 char *pt = NULL;
368 char bufi[BUFI_SIZE] = { 0 };
369 size_t k = 0;
370
371 if (istext)
373
374 while (len > 0)
375 {
376 if (!fgets(tmps, sizeof(tmps), s->fp_in))
377 goto cleanup;
378 len -= mutt_str_len(tmps);
379 if (mutt_str_startswith(tmps, "begin "))
380 break;
381 }
382 while (len > 0)
383 {
384 if (!fgets(tmps, sizeof(tmps), s->fp_in))
385 goto cleanup;
386 len -= mutt_str_len(tmps);
387 if (mutt_str_startswith(tmps, "end"))
388 break;
389 pt = tmps;
390 const unsigned char linelen = decode_byte(*pt);
391 pt++;
392 for (unsigned char c = 0; (c < linelen) && *pt;)
393 {
394 for (char l = 2; (l <= 6) && pt[0] && pt[1]; l += 2)
395 {
396 char out = decode_byte(*pt) << l;
397 pt++;
398 out |= (decode_byte(*pt) >> (6 - l));
399 bufi[k++] = out;
400 c++;
401 if (c == linelen)
402 break;
403 }
404 convert_to_state(cd, bufi, &k, s);
405 pt++;
406 }
407 }
408
409cleanup:
410 convert_to_state(cd, bufi, &k, s);
411 convert_to_state(cd, 0, 0, s);
412
414}
static unsigned char decode_byte(char ch)
Decode a uuencoded byte.
Definition: handler.c:350
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_mmnoask()

static bool is_mmnoask ( const char *  buf)
static

Metamail compatibility: should the attachment be autoviewed?

Parameters
bufMime type, e.g. 'text/plain'
Return values
trueMetamail "no ask" is true

Test if the MM_NOASK environment variable should allow autoviewing of the attachment.

Note
If MM_NOASK=1 then the function will automatically return true.

Definition at line 426 of file handler.c.

427{
428 const char *val = mutt_str_getenv("MM_NOASK");
429 if (!val)
430 return false;
431
432 char *p = NULL;
433 char tmp[1024] = { 0 };
434 char *q = NULL;
435
436 if (mutt_str_equal(val, "1"))
437 return true;
438
439 mutt_str_copy(tmp, val, sizeof(tmp));
440 p = tmp;
441
442 while ((p = strtok(p, ",")))
443 {
444 q = strrchr(p, '/');
445 if (q)
446 {
447 if (q[1] == '*')
448 {
449 if (mutt_istrn_equal(buf, p, q - p))
450 return true;
451 }
452 else
453 {
454 if (mutt_istr_equal(buf, p))
455 return true;
456 }
457 }
458 else
459 {
460 const size_t plen = mutt_istr_startswith(buf, p);
461 if ((plen != 0) && (buf[plen] == '/'))
462 return true;
463 }
464
465 p = NULL;
466 }
467
468 return false;
469}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:927
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:524
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_autoview()

static bool is_autoview ( struct Body b)
static

Should email body be filtered by mailcap.

Parameters
bBody of the email
Return values
1body part should be filtered by a mailcap entry prior to viewing inline
0otherwise

Definition at line 477 of file handler.c.

478{
479 char type[256] = { 0 };
480 bool is_av = false;
481
482 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
483
484 const bool c_implicit_auto_view = cs_subset_bool(NeoMutt->sub, "implicit_auto_view");
485 if (c_implicit_auto_view)
486 {
487 /* $implicit_auto_view is essentially the same as "auto_view *" */
488 is_av = true;
489 }
490 else
491 {
492 /* determine if this type is on the user's auto_view list */
493 mutt_check_lookup_list(b, type, sizeof(type));
494 struct ListNode *np = NULL;
495 STAILQ_FOREACH(np, &AutoViewList, entries)
496 {
497 int i = mutt_str_len(np->data) - 1;
498 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
499 mutt_istrn_equal(type, np->data, i)) ||
500 mutt_istr_equal(type, np->data))
501 {
502 is_av = true;
503 break;
504 }
505 }
506
507 if (is_mmnoask(type))
508 is_av = true;
509 }
510
511 /* determine if there is a mailcap entry suitable for auto_view
512 *
513 * @warning type is altered by this call as a result of 'mime_lookup' support */
514 if (is_av)
515 return mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_AUTOVIEW);
516
517 return false;
518}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
static bool is_mmnoask(const char *buf)
Metamail compatibility: should the attachment be autoviewed?
Definition: handler.c:426
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:473
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:60
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:336
struct ListHead AutoViewList
List of mime types to auto view.
Definition: mutt_globals.h:61
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ run_decode_and_handler()

static int run_decode_and_handler ( struct Body b,
struct State s,
handler_t  handler,
bool  plaintext 
)
static

Run an appropriate decoder for an email.

Parameters
bBody of the email
sState to work with
handlerCallback function to process the content - Implements handler_t
plaintextIs the content in plain text
Return values
0Success
-1Error

Definition at line 1293 of file handler.c.

1295{
1296 char *save_prefix = NULL;
1297 FILE *fp = NULL;
1298 size_t tmplength = 0;
1299 LOFF_T tmpoffset = 0;
1300 int decode = 0;
1301 int rc = 0;
1302#ifndef USE_FMEMOPEN
1303 struct Buffer *tempfile = NULL;
1304#endif
1305
1306 if (!mutt_file_seek(s->fp_in, b->offset, SEEK_SET))
1307 {
1308 return -1;
1309 }
1310
1311#ifdef USE_FMEMOPEN
1312 char *temp = NULL;
1313 size_t tempsize = 0;
1314#endif
1315
1316 /* see if we need to decode this part before processing it */
1317 if ((b->encoding == ENC_BASE64) || (b->encoding == ENC_QUOTED_PRINTABLE) ||
1318 (b->encoding == ENC_UUENCODED) || (plaintext || mutt_is_text_part(b)))
1319 /* text subtypes may require character set conversion even with 8bit encoding */
1320 {
1321 const int orig_type = b->type;
1322 if (!plaintext)
1323 {
1324 /* decode to a tempfile, saving the original destination */
1325 fp = s->fp_out;
1326#ifdef USE_FMEMOPEN
1327 s->fp_out = open_memstream(&temp, &tempsize);
1328 if (!s->fp_out)
1329 {
1330 mutt_error(_("Unable to open 'memory stream'"));
1331 mutt_debug(LL_DEBUG1, "Can't open 'memory stream'\n");
1332 return -1;
1333 }
1334#else
1335 tempfile = mutt_buffer_pool_get();
1336 mutt_buffer_mktemp(tempfile);
1337 s->fp_out = mutt_file_fopen(mutt_buffer_string(tempfile), "w");
1338 if (!s->fp_out)
1339 {
1340 mutt_error(_("Unable to open temporary file"));
1341 mutt_debug(LL_DEBUG1, "Can't open %s\n", mutt_buffer_string(tempfile));
1342 mutt_buffer_pool_release(&tempfile);
1343 return -1;
1344 }
1345#endif
1346 /* decoding the attachment changes the size and offset, so save a copy
1347 * of the "real" values now, and restore them after processing */
1348 tmplength = b->length;
1349 tmpoffset = b->offset;
1350
1351 /* if we are decoding binary bodies, we don't want to prefix each
1352 * line with the prefix or else the data will get corrupted. */
1353 save_prefix = s->prefix;
1354 s->prefix = NULL;
1355
1356 decode = 1;
1357 }
1358 else
1359 b->type = TYPE_TEXT;
1360
1362
1363 if (decode)
1364 {
1365 b->length = ftello(s->fp_out);
1366 b->offset = 0;
1367#ifdef USE_FMEMOPEN
1368 /* When running under torify, mutt_file_fclose(&s->fp_out) does not seem to
1369 * update tempsize. On the other hand, fflush does. See
1370 * https://github.com/neomutt/neomutt/issues/440 */
1371 fflush(s->fp_out);
1372#endif
1374
1375 /* restore final destination and substitute the tempfile for input */
1376 s->fp_out = fp;
1377 fp = s->fp_in;
1378#ifdef USE_FMEMOPEN
1379 if (tempsize)
1380 {
1381 s->fp_in = fmemopen(temp, tempsize, "r");
1382 }
1383 else
1384 { /* fmemopen can't handle zero-length buffers */
1385 s->fp_in = mutt_file_fopen("/dev/null", "r");
1386 }
1387 if (!s->fp_in)
1388 {
1389 mutt_perror(_("failed to re-open 'memory stream'"));
1390 FREE(&temp);
1391 return -1;
1392 }
1393#else
1394 s->fp_in = fopen(mutt_buffer_string(tempfile), "r");
1395 unlink(mutt_buffer_string(tempfile));
1396 mutt_buffer_pool_release(&tempfile);
1397#endif
1398 /* restore the prefix */
1399 s->prefix = save_prefix;
1400 }
1401
1402 b->type = orig_type;
1403 }
1404
1405 /* process the (decoded) body part */
1406 if (handler)
1407 {
1408 rc = handler(b, s);
1409 if (rc != 0)
1410 {
1411 mutt_debug(LL_DEBUG1, "Failed on attachment of type %s/%s\n", TYPE(b),
1412 NONULL(b->subtype));
1413 }
1414
1415 if (decode)
1416 {
1417 b->length = tmplength;
1418 b->offset = tmpoffset;
1419
1420 /* restore the original source stream */
1422 s->fp_in = fp;
1423 }
1424 }
1425 s->flags |= MUTT_FIRSTDONE;
1426#ifdef USE_FMEMOPEN
1427 FREE(&temp);
1428#endif
1429
1430 return rc;
1431}
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:706
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1866
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define FREE(x)
Definition: memory.h:43
@ ENC_UUENCODED
UUEncoded text.
Definition: mime.h:54
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
#define MUTT_FIRSTDONE
The first attachment has been done.
Definition: state.h:39
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:433
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define NONULL(x)
Definition: string2.h:37
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
String manipulation buffer.
Definition: buffer.h:34
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:50
char * prefix
String to add to the beginning of each output line.
Definition: state.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_decode_base64()

void mutt_decode_base64 ( struct State s,
size_t  len,
bool  istext,
iconv_t  cd 
)

Decode base64-encoded text.

Parameters
sState to work with
lenLength of text to decode
istextMime part is plain text
cdIconv conversion descriptor

Definition at line 1497 of file handler.c.

1498{
1499 char buf[5] = { 0 };
1500 int ch, i;
1501 bool cr = false;
1502 char bufi[BUFI_SIZE] = { 0 };
1503 size_t l = 0;
1504
1505 buf[4] = '\0';
1506
1507 if (istext)
1509
1510 while (len > 0)
1511 {
1512 for (i = 0; (i < 4) && (len > 0); len--)
1513 {
1514 ch = fgetc(s->fp_in);
1515 if (ch == EOF)
1516 break;
1517 if ((ch >= 0) && (ch < 128) && ((base64val(ch) != -1) || (ch == '=')))
1518 buf[i++] = ch;
1519 }
1520 if (i != 4)
1521 {
1522 /* "i" may be zero if there is trailing whitespace, which is not an error */
1523 if (i != 0)
1524 mutt_debug(LL_DEBUG2, "didn't get a multiple of 4 chars\n");
1525 break;
1526 }
1527
1528 const int c1 = base64val(buf[0]);
1529 const int c2 = base64val(buf[1]);
1530
1531 /* first char */
1532 ch = (c1 << 2) | (c2 >> 4);
1533
1534 if (cr && (ch != '\n'))
1535 bufi[l++] = '\r';
1536
1537 cr = false;
1538
1539 if (istext && (ch == '\r'))
1540 cr = true;
1541 else
1542 bufi[l++] = ch;
1543
1544 /* second char */
1545 if (buf[2] == '=')
1546 break;
1547 const int c3 = base64val(buf[2]);
1548 ch = ((c2 & 0xf) << 4) | (c3 >> 2);
1549
1550 if (cr && (ch != '\n'))
1551 bufi[l++] = '\r';
1552
1553 cr = false;
1554
1555 if (istext && (ch == '\r'))
1556 cr = true;
1557 else
1558 bufi[l++] = ch;
1559
1560 /* third char */
1561 if (buf[3] == '=')
1562 break;
1563 const int c4 = base64val(buf[3]);
1564 ch = ((c3 & 0x3) << 6) | c4;
1565
1566 if (cr && (ch != '\n'))
1567 bufi[l++] = '\r';
1568
1569 cr = false;
1570
1571 if (istext && (ch == '\r'))
1572 cr = true;
1573 else
1574 bufi[l++] = ch;
1575
1576 if ((l + 8) >= sizeof(bufi))
1577 convert_to_state(cd, bufi, &l, s);
1578 }
1579
1580 if (cr)
1581 bufi[l++] = '\r';
1582
1583 convert_to_state(cd, bufi, &l, s);
1584 convert_to_state(cd, 0, 0, s);
1585
1587}
#define base64val(ch)
Definition: base64.h:30
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_body_handler()

int mutt_body_handler ( struct Body b,
struct State s 
)

Handler for the Body of an email.

Parameters
bBody of the email
sState to work with
Return values
0Success
-1Error

Definition at line 1596 of file handler.c.

1597{
1598 if (!b || !s)
1599 return -1;
1600
1601 bool plaintext = false;
1602 handler_t handler = NULL;
1603 handler_t encrypted_handler = NULL;
1604 int rc = 0;
1605 static unsigned short recurse_level = 0;
1606
1607 const int oflags = s->flags;
1608 const bool is_attachment_display = (oflags & MUTT_DISPLAY_ATTACH);
1609
1610 if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1611 {
1612 mutt_debug(LL_DEBUG1, "recurse level too deep. giving up.\n");
1613 return 1;
1614 }
1615 recurse_level++;
1616
1617 /* first determine which handler to use to process this part */
1618
1619 if (is_autoview(b))
1620 {
1621 handler = autoview_handler;
1622 s->flags &= ~MUTT_CHARCONV;
1623 }
1624 else if (b->type == TYPE_TEXT)
1625 {
1626 if (mutt_istr_equal("plain", b->subtype))
1627 {
1628 const bool c_reflow_text = cs_subset_bool(NeoMutt->sub, "reflow_text");
1629 /* avoid copying this part twice since removing the transfer-encoding is
1630 * the only operation needed. */
1632 {
1633 encrypted_handler = crypt_pgp_application_handler;
1634 handler = encrypted_handler;
1635 }
1636 else if (c_reflow_text &&
1637 mutt_istr_equal("flowed", mutt_param_get(&b->parameter, "format")))
1638 {
1639 handler = rfc3676_handler;
1640 }
1641 else
1642 {
1643 handler = text_plain_handler;
1644 }
1645 }
1646 else if (mutt_istr_equal("enriched", b->subtype))
1647 handler = text_enriched_handler;
1648 else /* text body type without a handler */
1649 plaintext = false;
1650 }
1651 else if (b->type == TYPE_MESSAGE)
1652 {
1653 if (mutt_is_message_type(b->type, b->subtype))
1654 handler = message_handler;
1655 else if (mutt_istr_equal("delivery-status", b->subtype))
1656 plaintext = true;
1657 else if (mutt_istr_equal("external-body", b->subtype))
1658 handler = external_body_handler;
1659 }
1660 else if (b->type == TYPE_MULTIPART)
1661 {
1662 const char *const c_show_multipart_alternative = cs_subset_string(NeoMutt->sub, "show_multipart_alternative");
1663 if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1664 mutt_istr_equal("alternative", b->subtype))
1665 {
1666 handler = alternative_handler;
1667 }
1668 else if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1669 mutt_istr_equal("multilingual", b->subtype))
1670 {
1671 handler = multilingual_handler;
1672 }
1673 else if ((WithCrypto != 0) && mutt_istr_equal("signed", b->subtype))
1674 {
1675 if (!mutt_param_get(&b->parameter, "protocol"))
1676 mutt_error(_("Error: multipart/signed has no protocol"));
1677 else if (s->flags & MUTT_VERIFY)
1678 handler = mutt_signed_handler;
1679 }
1681 {
1682 encrypted_handler = valid_pgp_encrypted_handler;
1683 handler = encrypted_handler;
1684 }
1686 {
1687 encrypted_handler = malformed_pgp_encrypted_handler;
1688 handler = encrypted_handler;
1689 }
1690
1691 if (!handler)
1692 handler = multipart_handler;
1693
1694 if ((b->encoding != ENC_7BIT) && (b->encoding != ENC_8BIT) && (b->encoding != ENC_BINARY))
1695 {
1696 mutt_debug(LL_DEBUG1, "Bad encoding type %d for multipart entity, assuming 7 bit\n",
1697 b->encoding);
1698 b->encoding = ENC_7BIT;
1699 }
1700 }
1701 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1702 {
1703 if (OptDontHandlePgpKeys && mutt_istr_equal("pgp-keys", b->subtype))
1704 {
1705 /* pass raw part through for key extraction */
1706 plaintext = true;
1707 }
1708 else if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b))
1709 {
1710 encrypted_handler = crypt_pgp_application_handler;
1711 handler = encrypted_handler;
1712 }
1713 else if (((WithCrypto & APPLICATION_SMIME) != 0) && mutt_is_application_smime(b))
1714 {
1715 encrypted_handler = crypt_smime_application_handler;
1716 handler = encrypted_handler;
1717 }
1718 }
1719
1720 /* only respect disposition == attachment if we're not
1721 * displaying from the attachment menu (i.e. pager) */
1722 if ((plaintext || handler) && (is_attachment_display || !mutt_prefer_as_attachment(b)))
1723 {
1724 /* Prevent encrypted attachments from being included in replies
1725 * unless $include_encrypted is set. */
1726 const bool c_include_encrypted = cs_subset_bool(NeoMutt->sub, "include_encrypted");
1727 if ((s->flags & MUTT_REPLYING) && (s->flags & MUTT_FIRSTDONE) &&
1728 encrypted_handler && !c_include_encrypted)
1729 {
1730 goto cleanup;
1731 }
1732
1733 rc = run_decode_and_handler(b, s, handler, plaintext);
1734 }
1735 /* print hint to use attachment menu for disposition == attachment
1736 * if we're not already being called from there */
1737 else if (s->flags & MUTT_DISPLAY)
1738 {
1739 const bool c_honor_disposition = cs_subset_bool(NeoMutt->sub, "honor_disposition");
1740 struct Buffer msg = mutt_buffer_make(256);
1741
1742 if (!is_attachment_display)
1743 {
1744 char keystroke[128] = { 0 };
1745 if (km_expand_key(keystroke, sizeof(keystroke),
1746 km_find_func(MENU_PAGER, OP_VIEW_ATTACHMENTS)))
1747 {
1748 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1749 {
1750 /* L10N: %s expands to a keystroke/key binding, e.g. 'v'. */
1751 mutt_buffer_printf(&msg, _("[-- This is an attachment (use '%s' to view this part) --]\n"),
1752 keystroke);
1753 }
1754 else
1755 {
1756 /* L10N: %s/%s is a MIME type, e.g. "text/plain".
1757 The last %s expands to a keystroke/key binding, e.g. 'v'. */
1758 mutt_buffer_printf(&msg, _("[-- %s/%s is unsupported (use '%s' to view this part) --]\n"),
1759 TYPE(b), b->subtype, keystroke);
1760 }
1761 }
1762 else
1763 {
1764 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1765 {
1766 mutt_buffer_strcpy(&msg, _("[-- This is an attachment (need 'view-attachments' bound to key) --]\n"));
1767 }
1768 else
1769 {
1770 /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1771 mutt_buffer_printf(&msg, _("[-- %s/%s is unsupported (need 'view-attachments' bound to key) --]\n"),
1772 TYPE(b), b->subtype);
1773 }
1774 }
1775 }
1776 else
1777 {
1778 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1779 {
1780 mutt_buffer_strcpy(&msg, _("[-- This is an attachment --]\n"));
1781 }
1782 else
1783 {
1784 /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1785 mutt_buffer_printf(&msg, _("[-- %s/%s is unsupported --]\n"), TYPE(b), b->subtype);
1786 }
1787 }
1789 state_printf(s, "%s", mutt_buffer_string(&msg));
1790 mutt_buffer_dealloc(&msg);
1791 }
1792
1793cleanup:
1794 recurse_level--;
1795 s->flags = oflags | (s->flags & MUTT_FIRSTDONE);
1796 if (rc != 0)
1797 {
1798 mutt_debug(LL_DEBUG1, "Bailing on attachment of type %s/%s\n", TYPE(b),
1799 NONULL(b->subtype));
1800 }
1801
1802 return rc;
1803}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:542
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:599
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:461
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:498
static int multipart_handler(struct Body *a, struct State *s)
Handler for multipart emails - Implements handler_t -.
Definition: handler.c:1211
static int message_handler(struct Body *a, struct State *s)
Handler for message/rfc822 body parts - Implements handler_t -.
Definition: handler.c:703
static int malformed_pgp_encrypted_handler(struct Body *b, struct State *s)
Handler for invalid pgp-encrypted emails - Implements handler_t -.
Definition: handler.c:1465
int rfc3676_handler(struct Body *a, struct State *s)
Body handler implementing RFC3676 for format=flowed - Implements handler_t -.
Definition: rfc3676.c:318
int mutt_signed_handler(struct Body *b, struct State *s)
Verify a "multipart/signed" body - Implements handler_t -.
Definition: crypt.c:1122
static int autoview_handler(struct Body *a, struct State *s)
Handler for autoviewable attachments - Implements handler_t -.
Definition: handler.c:523
static int text_plain_handler(struct Body *b, struct State *s)
Handler for plain text - Implements handler_t -.
Definition: handler.c:676
int text_enriched_handler(struct Body *a, struct State *s)
Handler for enriched text - Implements handler_t -.
Definition: enriched.c:459
static int multilingual_handler(struct Body *a, struct State *s)
Handler for multi-lingual emails - Implements handler_t -.
Definition: handler.c:1109
static int alternative_handler(struct Body *a, struct State *s)
Handler for multipart alternative emails - Implements handler_t -.
Definition: handler.c:925
static int valid_pgp_encrypted_handler(struct Body *b, struct State *s)
Handler for valid pgp-encrypted emails - Implements handler_t -.
Definition: handler.c:1436
static int external_body_handler(struct Body *b, struct State *s)
Handler for external-body emails - Implements handler_t -.
Definition: handler.c:755
int crypt_smime_application_handler(struct Body *b, struct State *s)
Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -.
Definition: cryptglue.c:444
int crypt_pgp_application_handler(struct Body *b, struct State *s)
Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -.
Definition: cryptglue.c:237
int(* handler_t)(struct Body *b, struct State *s)
Definition: handler.c:79
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:477
bool mutt_prefer_as_attachment(struct Body *b)
Do we want this part as an attachment?
Definition: handler.c:1810
static int run_decode_and_handler(struct Body *b, struct State *s, handler_t handler, bool plaintext)
Run an appropriate decoder for an email.
Definition: handler.c:1293
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: keymap.c:956
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:928
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_BINARY
Binary.
Definition: mime.h:53
@ ENC_8BIT
8-bit text
Definition: mime.h:50
#define MUTT_MIME_MAX_DEPTH
Definition: mime.h:69
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define MUTT_DISPLAY_ATTACH
We are displaying an attachment.
Definition: state.h:40
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define WithCrypto
Definition: lib.h:116
bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition: options.h:41
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1441
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_prefer_as_attachment()

bool mutt_prefer_as_attachment ( struct Body b)

Do we want this part as an attachment?

Parameters
bBody of email to test
Return values
trueWe want this part as an attachment

Definition at line 1810 of file handler.c.

1811{
1812 if (!mutt_can_decode(b))
1813 return true;
1814
1815 if (b->disposition != DISP_ATTACH)
1816 return false;
1817
1818 return cs_subset_bool(NeoMutt->sub, "honor_disposition");
1819}
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1826
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_can_decode()

bool mutt_can_decode ( struct Body b)

Will decoding the attachment produce any output.

Parameters
bBody of email to test
Return values
trueDecoding the attachment will produce output

Definition at line 1826 of file handler.c.

1827{
1828 if (is_autoview(b))
1829 return true;
1830 if (b->type == TYPE_TEXT)
1831 return true;
1832 if (b->type == TYPE_MESSAGE)
1833 return true;
1834 if (b->type == TYPE_MULTIPART)
1835 {
1836 if (WithCrypto)
1837 {
1838 if (mutt_istr_equal(b->subtype, "signed") || mutt_istr_equal(b->subtype, "encrypted"))
1839 {
1840 return true;
1841 }
1842 }
1843
1844 for (struct Body *part = b->parts; part; part = part->next)
1845 {
1846 if (mutt_can_decode(part))
1847 return true;
1848 }
1849 }
1850 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1851 {
1853 return true;
1855 return true;
1856 }
1857
1858 return false;
1859}
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
struct Body * next
next attachment in the list
Definition: body.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_decode_attachment()

void mutt_decode_attachment ( struct Body b,
struct State s 
)

Decode an email's attachment.

Parameters
bBody of the email
sState of text being processed

Definition at line 1866 of file handler.c.

1867{
1868 int istext = mutt_is_text_part(b) && (b->disposition == DISP_INLINE);
1869 iconv_t cd = (iconv_t) (-1);
1870
1871 if (!mutt_file_seek(s->fp_in, b->offset, SEEK_SET))
1872 {
1873 return;
1874 }
1875
1876 if (istext && (b->charset || (s->flags & MUTT_CHARCONV)))
1877 {
1878 const char *charset = b->charset;
1879 if (!charset)
1880 {
1881 const struct Slist *const c_assumed_charset = cs_subset_slist(NeoMutt->sub, "assumed_charset");
1882 charset = mutt_param_get(&b->parameter, "charset");
1883 if (!charset && c_assumed_charset)
1884 charset = mutt_ch_get_default_charset();
1885 }
1886 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
1887 if (charset && c_charset)
1888 cd = mutt_ch_iconv_open(c_charset, charset, MUTT_ICONV_HOOK_FROM);
1889 }
1890
1891 switch (b->encoding)
1892 {
1894 decode_quoted(s, b->length,
1895 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1897 cd);
1898 break;
1899 case ENC_BASE64:
1901 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1903 cd);
1904 break;
1905 case ENC_UUENCODED:
1907 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1909 cd);
1910 break;
1911 default:
1912 decode_xbit(s, b->length,
1913 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1915 cd);
1916 break;
1917 }
1918
1919 if (cd != (iconv_t) (-1))
1920 iconv_close(cd);
1921}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
static void decode_uuencoded(struct State *s, long len, bool istext, iconv_t cd)
Decode uuencoded text.
Definition: handler.c:364
static void decode_quoted(struct State *s, long len, bool istext, iconv_t cd)
Decode an attachment encoded with quoted-printable.
Definition: handler.c:300
static void decode_xbit(struct State *s, long len, bool istext, iconv_t cd)
Decode xbit-encoded text.
Definition: handler.c:163
void mutt_decode_base64(struct State *s, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition: handler.c:1497
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
char * mutt_ch_get_default_charset(void)
Get the default character set.
Definition: charset.c:439
iconv_t mutt_ch_iconv_open(const char *tocode, const char *fromcode, uint8_t flags)
Set up iconv for conversions.
Definition: charset.c:564
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:72
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:78
String list.
Definition: slist.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function: