NeoMutt  2023-11-03-107-g582dc1
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 "gui/lib.h"
#include "mutt.h"
#include "handler.h"
#include "attach/lib.h"
#include "key/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "copy.h"
#include "enriched.h"
#include "globals.h"
#include "mailcap.h"
#include "mutt_logging.h"
#include "muttlib.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_email, struct State *state)
 

Functions

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

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 61 of file handler.c.

◆ BUFO_SIZE

#define BUFO_SIZE   2000

Definition at line 62 of file handler.c.

◆ TXT_HTML

#define TXT_HTML   1

Definition at line 64 of file handler.c.

◆ TXT_PLAIN

#define TXT_PLAIN   2

Definition at line 65 of file handler.c.

◆ TXT_ENRICHED

#define TXT_ENRICHED   3

Definition at line 66 of file handler.c.

Typedef Documentation

◆ handler_t

typedef int(* handler_t) (struct Body *b_email, struct State *state)

Definition at line 78 of file handler.c.

Function Documentation

◆ print_part_line()

static void print_part_line ( struct State state,
struct Body b_email,
int  n 
)
static

Print a separator for the Mime part.

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

Definition at line 86 of file handler.c.

87{
88 char length[5] = { 0 };
89 mutt_str_pretty_size(length, sizeof(length), b_email->length);
90 state_mark_attach(state);
91 char *charset = mutt_param_get(&b_email->parameter, "charset");
92 if (n == 0)
93 {
94 state_printf(state, _("[-- Type: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
95 TYPE(b_email), b_email->subtype, charset ? "; charset=" : "",
96 charset ? charset : "", ENCODING(b_email->encoding), length);
97 }
98 else
99 {
100 state_printf(state, _("[-- Alternative Type #%d: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
101 n, TYPE(b_email), b_email->subtype, charset ? "; charset=" : "",
102 charset ? charset : "", ENCODING(b_email->encoding), length);
103 }
104}
#define ENCODING(x)
Definition: mime.h:92
#define TYPE(body)
Definition: mime.h:89
#define _(a)
Definition: message.h:28
void state_mark_attach(struct State *state)
Write a unique marker around content.
Definition: state.c:71
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:185
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1641
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 state 
)
static

Convert text and write it to a file.

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

Definition at line 113 of file handler.c.

114{
115 char bufo[BUFO_SIZE] = { 0 };
116 const char *ib = NULL;
117 char *ob = NULL;
118 size_t ibl, obl;
119
120 if (!bufi)
121 {
122 if (iconv_t_valid(cd))
123 {
124 ob = bufo;
125 obl = sizeof(bufo);
126 iconv(cd, NULL, NULL, &ob, &obl);
127 if (ob != bufo)
128 state_prefix_put(state, bufo, ob - bufo);
129 }
130 return;
131 }
132
133 if (!iconv_t_valid(cd))
134 {
135 state_prefix_put(state, bufi, *l);
136 *l = 0;
137 return;
138 }
139
140 ib = bufi;
141 ibl = *l;
142 while (true)
143 {
144 ob = bufo;
145 obl = sizeof(bufo);
146 mutt_ch_iconv(cd, &ib, &ibl, &ob, &obl, 0, "?", NULL);
147 if (ob == bufo)
148 break;
149 state_prefix_put(state, bufo, ob - bufo);
150 }
151 memmove(bufi, ib, ibl);
152 *l = ibl;
153}
#define BUFO_SIZE
Definition: handler.c:62
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:692
static bool iconv_t_valid(const iconv_t cd)
Is the conversion descriptor valid?
Definition: charset.h:112
void state_prefix_put(struct State *state, const char *buf, size_t buflen)
Write a prefixed fixed-string to the State.
Definition: state.c:203
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ decode_xbit()

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

Decode xbit-encoded text.

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

Definition at line 162 of file handler.c.

163{
164 if (!istext)
165 {
166 mutt_file_copy_bytes(state->fp_in, state->fp_out, len);
167 return;
168 }
169
170 state_set_prefix(state);
171
172 int c;
173 char bufi[BUFI_SIZE] = { 0 };
174 size_t l = 0;
175 while (((c = fgetc(state->fp_in)) != EOF) && len--)
176 {
177 if ((c == '\r') && len)
178 {
179 const int ch = fgetc(state->fp_in);
180 if (ch == '\n')
181 {
182 c = ch;
183 len--;
184 }
185 else
186 {
187 ungetc(ch, state->fp_in);
188 }
189 }
190
191 bufi[l++] = c;
192 if (l == sizeof(bufi))
193 convert_to_state(cd, bufi, &l, state);
194 }
195
196 convert_to_state(cd, bufi, &l, state);
197 convert_to_state(cd, 0, 0, state);
198
199 state_reset_prefix(state);
200}
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:232
#define BUFI_SIZE
Definition: handler.c:61
static void convert_to_state(iconv_t cd, char *bufi, size_t *l, struct State *state)
Convert text and write it to a file.
Definition: handler.c:113
#define state_set_prefix(state)
Definition: state.h:55
#define state_reset_prefix(state)
Definition: state.h:56
FILE * fp_out
File to write to.
Definition: state.h:49
FILE * fp_in
File to read from.
Definition: state.h:48
+ 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 209 of file handler.c.

210{
211 /* soft line break */
212 if ((s[0] == '=') && (s[1] == '\0'))
213 return 1;
214
215 /* quoted-printable triple */
216 if ((s[0] == '=') && isxdigit((unsigned char) s[1]) && isxdigit((unsigned char) s[2]))
217 {
218 *d = (hexval(s[1]) << 4) | hexval(s[2]);
219 return 0;
220 }
221
222 /* something else */
223 return -1;
224}
#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 233 of file handler.c.

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

◆ decode_quoted()

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

Decode an attachment encoded with quoted-printable.

Parameters
stateState 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 301 of file handler.c.

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

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

◆ decode_uuencoded()

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

Decode uuencoded text.

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

Definition at line 365 of file handler.c.

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

428{
429 const char *val = mutt_str_getenv("MM_NOASK");
430 if (!val)
431 return false;
432
433 char *p = NULL;
434 char tmp[1024] = { 0 };
435 char *q = NULL;
436
437 if (mutt_str_equal(val, "1"))
438 return true;
439
440 mutt_str_copy(tmp, val, sizeof(tmp));
441 p = tmp;
442
443 while ((p = strtok(p, ",")))
444 {
445 q = strrchr(p, '/');
446 if (q)
447 {
448 if (q[1] == '*')
449 {
450 if (mutt_istrn_equal(buf, p, q - p))
451 return true;
452 }
453 else
454 {
455 if (mutt_istr_equal(buf, p))
456 return true;
457 }
458 }
459 else
460 {
461 const size_t plen = mutt_istr_startswith(buf, p);
462 if ((plen != 0) && (buf[plen] == '/'))
463 return true;
464 }
465
466 p = NULL;
467 }
468
469 return false;
470}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:775
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:763
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:862
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:653
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
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:525
+ 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 478 of file handler.c.

479{
480 char type[256] = { 0 };
481 bool is_av = false;
482
483 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
484
485 const bool c_implicit_auto_view = cs_subset_bool(NeoMutt->sub, "implicit_auto_view");
486 if (c_implicit_auto_view)
487 {
488 /* $implicit_auto_view is essentially the same as "auto_view *" */
489 is_av = true;
490 }
491 else
492 {
493 /* determine if this type is on the user's auto_view list */
494 mutt_check_lookup_list(b, type, sizeof(type));
495 struct ListNode *np = NULL;
496 STAILQ_FOREACH(np, &AutoViewList, entries)
497 {
498 int i = mutt_str_len(np->data) - 1;
499 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
500 mutt_istrn_equal(type, np->data, i)) ||
501 mutt_istr_equal(type, np->data))
502 {
503 is_av = true;
504 break;
505 }
506 }
507
508 if (is_mmnoask(type))
509 is_av = true;
510 }
511
512 /* determine if there is a mailcap entry suitable for auto_view
513 *
514 * @warning type is altered by this call as a result of 'mime_lookup' support */
515 if (is_av)
516 return mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_AUTOVIEW);
517
518 return false;
519}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
struct ListHead AutoViewList
List of mime types to auto view.
Definition: globals.c:50
static bool is_mmnoask(const char *buf)
Metamail compatibility: should the attachment be autoviewed?
Definition: handler.c:427
bool mailcap_lookup(struct Body *b, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:480
@ 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:339
#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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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 state,
handler_t  handler,
bool  plaintext 
)
static

Run an appropriate decoder for an email.

Parameters
bBody of the email
stateState 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 1319 of file handler.c.

1321{
1322 char *save_prefix = NULL;
1323 FILE *fp = NULL;
1324 size_t tmplength = 0;
1325 LOFF_T tmpoffset = 0;
1326 int decode = 0;
1327 int rc = 0;
1328#ifndef USE_FMEMOPEN
1329 struct Buffer *tempfile = NULL;
1330#endif
1331
1332 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1333 {
1334 return -1;
1335 }
1336
1337#ifdef USE_FMEMOPEN
1338 char *temp = NULL;
1339 size_t tempsize = 0;
1340#endif
1341
1342 /* see if we need to decode this part before processing it */
1343 if ((b->encoding == ENC_BASE64) || (b->encoding == ENC_QUOTED_PRINTABLE) ||
1344 (b->encoding == ENC_UUENCODED) || (plaintext || mutt_is_text_part(b)))
1345 /* text subtypes may require character set conversion even with 8bit encoding */
1346 {
1347 const int orig_type = b->type;
1348 if (plaintext)
1349 {
1350 b->type = TYPE_TEXT;
1351 }
1352 else
1353 {
1354 /* decode to a tempfile, saving the original destination */
1355 fp = state->fp_out;
1356#ifdef USE_FMEMOPEN
1357 state->fp_out = open_memstream(&temp, &tempsize);
1358 if (!state->fp_out)
1359 {
1360 mutt_error(_("Unable to open 'memory stream'"));
1361 mutt_debug(LL_DEBUG1, "Can't open 'memory stream'\n");
1362 return -1;
1363 }
1364#else
1365 tempfile = buf_pool_get();
1366 buf_mktemp(tempfile);
1367 state->fp_out = mutt_file_fopen(buf_string(tempfile), "w");
1368 if (!state->fp_out)
1369 {
1370 mutt_error(_("Unable to open temporary file"));
1371 mutt_debug(LL_DEBUG1, "Can't open %s\n", buf_string(tempfile));
1372 buf_pool_release(&tempfile);
1373 return -1;
1374 }
1375#endif
1376 /* decoding the attachment changes the size and offset, so save a copy
1377 * of the "real" values now, and restore them after processing */
1378 tmplength = b->length;
1379 tmpoffset = b->offset;
1380
1381 /* if we are decoding binary bodies, we don't want to prefix each
1382 * line with the prefix or else the data will get corrupted. */
1383 save_prefix = state->prefix;
1384 state->prefix = NULL;
1385
1386 decode = 1;
1387 }
1388
1389 mutt_decode_attachment(b, state);
1390
1391 if (decode)
1392 {
1393 b->length = ftello(state->fp_out);
1394 b->offset = 0;
1395#ifdef USE_FMEMOPEN
1396 /* When running under torify, mutt_file_fclose(&state->fp_out) does not seem to
1397 * update tempsize. On the other hand, fflush does. See
1398 * https://github.com/neomutt/neomutt/issues/440 */
1399 fflush(state->fp_out);
1400#endif
1401 mutt_file_fclose(&state->fp_out);
1402
1403 /* restore final destination and substitute the tempfile for input */
1404 state->fp_out = fp;
1405 fp = state->fp_in;
1406#ifdef USE_FMEMOPEN
1407 if (tempsize)
1408 {
1409 state->fp_in = fmemopen(temp, tempsize, "r");
1410 }
1411 else
1412 { /* fmemopen can't handle zero-length buffers */
1413 state->fp_in = mutt_file_fopen("/dev/null", "r");
1414 }
1415 if (!state->fp_in)
1416 {
1417 mutt_perror(_("failed to re-open 'memory stream'"));
1418 FREE(&temp);
1419 return -1;
1420 }
1421#else
1422 state->fp_in = fopen(buf_string(tempfile), "r");
1423 unlink(buf_string(tempfile));
1424 buf_pool_release(&tempfile);
1425#endif
1426 /* restore the prefix */
1427 state->prefix = save_prefix;
1428 }
1429
1430 b->type = orig_type;
1431 }
1432
1433 /* process the (decoded) body part */
1434 if (handler)
1435 {
1436 rc = handler(b, state);
1437 if (rc != 0)
1438 {
1439 mutt_debug(LL_DEBUG1, "Failed on attachment of type %s/%s\n", TYPE(b),
1440 NONULL(b->subtype));
1441 }
1442
1443 if (decode)
1444 {
1445 b->length = tmplength;
1446 b->offset = tmpoffset;
1447
1448 /* restore the original source stream */
1449 mutt_file_fclose(&state->fp_in);
1450 state->fp_in = fp;
1451 }
1452 }
1453 state->flags |= STATE_FIRSTDONE;
1454#ifdef USE_FMEMOPEN
1455 FREE(&temp);
1456#endif
1457
1458 return rc;
1459}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:733
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
void mutt_decode_attachment(struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1898
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define FREE(x)
Definition: memory.h:45
@ 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 STATE_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:444
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#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. STATE_DISPLAY.
Definition: state.h:51
char * prefix
String to add to the beginning of each output line.
Definition: state.h:50
#define buf_mktemp(buf)
Definition: tmp.h:33
+ 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 state,
size_t  len,
bool  istext,
iconv_t  cd 
)

Decode base64-encoded text.

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

Definition at line 1525 of file handler.c.

1526{
1527 char buf[5] = { 0 };
1528 int ch, i;
1529 bool cr = false;
1530 char bufi[BUFI_SIZE] = { 0 };
1531 size_t l = 0;
1532
1533 buf[4] = '\0';
1534
1535 if (istext)
1536 state_set_prefix(state);
1537
1538 while (len > 0)
1539 {
1540 for (i = 0; (i < 4) && (len > 0); len--)
1541 {
1542 ch = fgetc(state->fp_in);
1543 if (ch == EOF)
1544 break;
1545 if ((ch >= 0) && (ch < 128) && ((base64val(ch) != -1) || (ch == '=')))
1546 buf[i++] = ch;
1547 }
1548 if (i != 4)
1549 {
1550 /* "i" may be zero if there is trailing whitespace, which is not an error */
1551 if (i != 0)
1552 mutt_debug(LL_DEBUG2, "didn't get a multiple of 4 chars\n");
1553 break;
1554 }
1555
1556 const int c1 = base64val(buf[0]);
1557 const int c2 = base64val(buf[1]);
1558
1559 /* first char */
1560 ch = (c1 << 2) | (c2 >> 4);
1561
1562 if (cr && (ch != '\n'))
1563 bufi[l++] = '\r';
1564
1565 cr = false;
1566
1567 if (istext && (ch == '\r'))
1568 cr = true;
1569 else
1570 bufi[l++] = ch;
1571
1572 /* second char */
1573 if (buf[2] == '=')
1574 break;
1575 const int c3 = base64val(buf[2]);
1576 ch = ((c2 & 0xf) << 4) | (c3 >> 2);
1577
1578 if (cr && (ch != '\n'))
1579 bufi[l++] = '\r';
1580
1581 cr = false;
1582
1583 if (istext && (ch == '\r'))
1584 cr = true;
1585 else
1586 bufi[l++] = ch;
1587
1588 /* third char */
1589 if (buf[3] == '=')
1590 break;
1591 const int c4 = base64val(buf[3]);
1592 ch = ((c3 & 0x3) << 6) | c4;
1593
1594 if (cr && (ch != '\n'))
1595 bufi[l++] = '\r';
1596
1597 cr = false;
1598
1599 if (istext && (ch == '\r'))
1600 cr = true;
1601 else
1602 bufi[l++] = ch;
1603
1604 if ((l + 8) >= sizeof(bufi))
1605 convert_to_state(cd, bufi, &l, state);
1606 }
1607
1608 if (cr)
1609 bufi[l++] = '\r';
1610
1611 convert_to_state(cd, bufi, &l, state);
1612 convert_to_state(cd, 0, 0, state);
1613
1614 state_reset_prefix(state);
1615}
#define base64val(ch)
Definition: base64.h:30
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
+ 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 state 
)

Handler for the Body of an email.

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

Definition at line 1624 of file handler.c.

1625{
1626 if (!b || !state)
1627 return -1;
1628
1629 bool plaintext = false;
1630 handler_t handler = NULL;
1631 handler_t encrypted_handler = NULL;
1632 int rc = 0;
1633 static unsigned short recurse_level = 0;
1634
1635 const int oflags = state->flags;
1636 const bool is_attachment_display = (oflags & STATE_DISPLAY_ATTACH);
1637
1638 if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1639 {
1640 mutt_debug(LL_DEBUG1, "recurse level too deep. giving up.\n");
1641 return 1;
1642 }
1643 recurse_level++;
1644
1645 /* first determine which handler to use to process this part */
1646
1647 if (is_autoview(b))
1648 {
1649 handler = autoview_handler;
1650 state->flags &= ~STATE_CHARCONV;
1651 }
1652 else if (b->type == TYPE_TEXT)
1653 {
1654 if (mutt_istr_equal("plain", b->subtype))
1655 {
1656 const bool c_reflow_text = cs_subset_bool(NeoMutt->sub, "reflow_text");
1657 /* avoid copying this part twice since removing the transfer-encoding is
1658 * the only operation needed. */
1660 {
1661 encrypted_handler = crypt_pgp_application_handler;
1662 handler = encrypted_handler;
1663 }
1664 else if (c_reflow_text &&
1665 mutt_istr_equal("flowed", mutt_param_get(&b->parameter, "format")))
1666 {
1667 handler = rfc3676_handler;
1668 }
1669 else
1670 {
1671 handler = text_plain_handler;
1672 }
1673 }
1674 else if (mutt_istr_equal("enriched", b->subtype))
1675 {
1676 handler = text_enriched_handler;
1677 }
1678 else /* text body type without a handler */
1679 {
1680 plaintext = false;
1681 }
1682 }
1683 else if (b->type == TYPE_MESSAGE)
1684 {
1685 if (mutt_is_message_type(b->type, b->subtype))
1686 handler = message_handler;
1687 else if (mutt_istr_equal("delivery-status", b->subtype))
1688 plaintext = true;
1689 else if (mutt_istr_equal("external-body", b->subtype))
1690 handler = external_body_handler;
1691 }
1692 else if (b->type == TYPE_MULTIPART)
1693 {
1694 const char *const c_show_multipart_alternative = cs_subset_string(NeoMutt->sub, "show_multipart_alternative");
1695 if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1696 mutt_istr_equal("alternative", b->subtype))
1697 {
1698 handler = alternative_handler;
1699 }
1700 else if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1701 mutt_istr_equal("multilingual", b->subtype))
1702 {
1703 handler = multilingual_handler;
1704 }
1705 else if ((WithCrypto != 0) && mutt_istr_equal("signed", b->subtype))
1706 {
1707 if (!mutt_param_get(&b->parameter, "protocol"))
1708 mutt_error(_("Error: multipart/signed has no protocol"));
1709 else if (state->flags & STATE_VERIFY)
1710 handler = mutt_signed_handler;
1711 }
1713 {
1714 encrypted_handler = valid_pgp_encrypted_handler;
1715 handler = encrypted_handler;
1716 }
1718 {
1719 encrypted_handler = malformed_pgp_encrypted_handler;
1720 handler = encrypted_handler;
1721 }
1722
1723 if (!handler)
1724 handler = multipart_handler;
1725
1726 if ((b->encoding != ENC_7BIT) && (b->encoding != ENC_8BIT) && (b->encoding != ENC_BINARY))
1727 {
1728 mutt_debug(LL_DEBUG1, "Bad encoding type %d for multipart entity, assuming 7 bit\n",
1729 b->encoding);
1730 b->encoding = ENC_7BIT;
1731 }
1732 }
1733 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1734 {
1735 if (OptDontHandlePgpKeys && mutt_istr_equal("pgp-keys", b->subtype))
1736 {
1737 /* pass raw part through for key extraction */
1738 plaintext = true;
1739 }
1740 else if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b))
1741 {
1742 encrypted_handler = crypt_pgp_application_handler;
1743 handler = encrypted_handler;
1744 }
1745 else if (((WithCrypto & APPLICATION_SMIME) != 0) && mutt_is_application_smime(b))
1746 {
1747 encrypted_handler = crypt_smime_application_handler;
1748 handler = encrypted_handler;
1749 }
1750 }
1751
1752 if ((plaintext || handler) && (is_attachment_display || !mutt_prefer_as_attachment(b)))
1753 {
1754 /* only respect disposition == attachment if we're not
1755 * displaying from the attachment menu (i.e. pager) */
1756 /* Prevent encrypted attachments from being included in replies
1757 * unless $include_encrypted is set. */
1758 const bool c_include_encrypted = cs_subset_bool(NeoMutt->sub, "include_encrypted");
1759 if ((state->flags & STATE_REPLYING) && (state->flags & STATE_FIRSTDONE) &&
1760 encrypted_handler && !c_include_encrypted)
1761 {
1762 goto cleanup;
1763 }
1764
1765 rc = run_decode_and_handler(b, state, handler, plaintext);
1766 }
1767 else if (state->flags & STATE_DISPLAY)
1768 {
1769 /* print hint to use attachment menu for disposition == attachment
1770 * if we're not already being called from there */
1771 const bool c_honor_disposition = cs_subset_bool(NeoMutt->sub, "honor_disposition");
1772 struct Buffer *msg = buf_pool_get();
1773
1774 if (is_attachment_display)
1775 {
1776 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1777 {
1778 buf_strcpy(msg, _("[-- This is an attachment --]\n"));
1779 }
1780 else
1781 {
1782 /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1783 buf_printf(msg, _("[-- %s/%s is unsupported --]\n"), TYPE(b), b->subtype);
1784 }
1785 }
1786 else
1787 {
1788 char keystroke[128] = { 0 };
1789 if (km_expand_key(keystroke, sizeof(keystroke),
1790 km_find_func(MENU_PAGER, OP_VIEW_ATTACHMENTS)))
1791 {
1792 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1793 {
1794 /* L10N: %s expands to a keystroke/key binding, e.g. 'v'. */
1795 buf_printf(msg, _("[-- This is an attachment (use '%s' to view this part) --]\n"),
1796 keystroke);
1797 }
1798 else
1799 {
1800 /* L10N: %s/%s is a MIME type, e.g. "text/plain".
1801 The last %s expands to a keystroke/key binding, e.g. 'v'. */
1802 buf_printf(msg, _("[-- %s/%s is unsupported (use '%s' to view this part) --]\n"),
1803 TYPE(b), b->subtype, keystroke);
1804 }
1805 }
1806 else
1807 {
1808 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1809 {
1810 buf_strcpy(msg, _("[-- This is an attachment (need 'view-attachments' bound to key) --]\n"));
1811 }
1812 else
1813 {
1814 /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1815 buf_printf(msg, _("[-- %s/%s is unsupported (need 'view-attachments' bound to key) --]\n"),
1816 TYPE(b), b->subtype);
1817 }
1818 }
1819 }
1820 state_mark_attach(state);
1821 state_printf(state, "%s", buf_string(msg));
1822 buf_pool_release(&msg);
1823 }
1824
1825cleanup:
1826 recurse_level--;
1827 state->flags = oflags | (state->flags & STATE_FIRSTDONE);
1828 if (rc != 0)
1829 {
1830 mutt_debug(LL_DEBUG1, "Bailing on attachment of type %s/%s\n", TYPE(b),
1831 NONULL(b->subtype));
1832 }
1833
1834 return rc;
1835}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:537
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:598
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:456
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:493
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1466
bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition: globals.c:69
int crypt_pgp_application_handler(struct Body *b_email, struct State *state)
Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -.
Definition: cryptglue.c:237
static int alternative_handler(struct Body *b_email, struct State *state)
Handler for multipart alternative emails - Implements handler_t -.
Definition: handler.c:934
int text_enriched_handler(struct Body *b_email, struct State *state)
Handler for enriched text - Implements handler_t -.
Definition: enriched.c:466
static int text_plain_handler(struct Body *b_email, struct State *state)
Handler for plain text - Implements handler_t -.
Definition: handler.c:677
int crypt_smime_application_handler(struct Body *b_email, struct State *state)
Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -.
Definition: cryptglue.c:444
static int autoview_handler(struct Body *b_email, struct State *state)
Handler for autoviewable attachments - Implements handler_t -.
Definition: handler.c:524
static int external_body_handler(struct Body *b_email, struct State *state)
Handler for external-body emails - Implements handler_t -.
Definition: handler.c:762
int rfc3676_handler(struct Body *b_email, struct State *state)
Handler for format=flowed - Implements handler_t -.
Definition: rfc3676.c:320
static int malformed_pgp_encrypted_handler(struct Body *b_email, struct State *state)
Handler for invalid pgp-encrypted emails - Implements handler_t -.
Definition: handler.c:1493
static int valid_pgp_encrypted_handler(struct Body *b_email, struct State *state)
Handler for valid pgp-encrypted emails - Implements handler_t -.
Definition: handler.c:1464
static int message_handler(struct Body *b_email, struct State *state)
Handler for message/rfc822 body parts - Implements handler_t -.
Definition: handler.c:704
static int multipart_handler(struct Body *b_email, struct State *state)
Handler for multipart emails - Implements handler_t -.
Definition: handler.c:1230
static int multilingual_handler(struct Body *b_email, struct State *state)
Handler for multi-lingual emails - Implements handler_t -.
Definition: handler.c:1122
int mutt_signed_handler(struct Body *b_email, struct State *state)
Handler for "multipart/signed" - Implements handler_t -.
Definition: crypt.c:1136
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:478
bool mutt_prefer_as_attachment(struct Body *b)
Do we want this part as an attachment?
Definition: handler.c:1842
int(* handler_t)(struct Body *b_email, struct State *state)
Definition: handler.c:78
static int run_decode_and_handler(struct Body *b, struct State *state, handler_t handler, bool plaintext)
Run an appropriate decoder for an email.
Definition: handler.c:1319
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: lib.c:513
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: lib.c:461
@ 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 STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define STATE_DISPLAY_ATTACH
We are displaying an attachment.
Definition: state.h:40
#define STATE_REPLYING
Are we replying?
Definition: state.h:38
#define STATE_VERIFY
Perform signature verification.
Definition: state.h:33
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:92
#define WithCrypto
Definition: lib.h:117
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:55
+ 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 1842 of file handler.c.

1843{
1844 if (!mutt_can_decode(b))
1845 return true;
1846
1847 if (b->disposition != DISP_ATTACH)
1848 return false;
1849
1850 return cs_subset_bool(NeoMutt->sub, "honor_disposition");
1851}
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1858
+ 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 1858 of file handler.c.

1859{
1860 if (is_autoview(b))
1861 return true;
1862 if (b->type == TYPE_TEXT)
1863 return true;
1864 if (b->type == TYPE_MESSAGE)
1865 return true;
1866 if (b->type == TYPE_MULTIPART)
1867 {
1868 if (WithCrypto)
1869 {
1870 if (mutt_istr_equal(b->subtype, "signed") || mutt_istr_equal(b->subtype, "encrypted"))
1871 {
1872 return true;
1873 }
1874 }
1875
1876 for (struct Body *part = b->parts; part; part = part->next)
1877 {
1878 if (mutt_can_decode(part))
1879 return true;
1880 }
1881 }
1882 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1883 {
1885 return true;
1887 return true;
1888 }
1889
1890 return false;
1891}
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 state 
)

Decode an email's attachment.

Parameters
bBody of the email
stateState of text being processed

Definition at line 1898 of file handler.c.

1899{
1900 int istext = mutt_is_text_part(b) && (b->disposition == DISP_INLINE);
1901 iconv_t cd = ICONV_T_INVALID;
1902
1903 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1904 {
1905 return;
1906 }
1907
1908 if (istext && (b->charset || (state->flags & STATE_CHARCONV)))
1909 {
1910 const char *charset = b->charset;
1911 if (!charset)
1912 {
1913 charset = mutt_param_get(&b->parameter, "charset");
1914 if (!charset && !slist_is_empty(cc_assumed_charset()))
1916 }
1917 if (charset && cc_charset())
1919 }
1920
1921 switch (b->encoding)
1922 {
1924 decode_quoted(state, b->length,
1925 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1927 cd);
1928 break;
1929 case ENC_BASE64:
1930 mutt_decode_base64(state, b->length,
1931 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1933 cd);
1934 break;
1935 case ENC_UUENCODED:
1936 decode_uuencoded(state, b->length,
1937 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1939 cd);
1940 break;
1941 default:
1942 decode_xbit(state, b->length,
1943 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1945 cd);
1946 break;
1947 }
1948}
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:115
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
Definition: config_cache.c:100
static void decode_uuencoded(struct State *state, long len, bool istext, iconv_t cd)
Decode uuencoded text.
Definition: handler.c:365
void mutt_decode_base64(struct State *state, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition: handler.c:1525
static void decode_quoted(struct State *state, long len, bool istext, iconv_t cd)
Decode an attachment encoded with quoted-printable.
Definition: handler.c:301
static void decode_xbit(struct State *state, long len, bool istext, iconv_t cd)
Decode xbit-encoded text.
Definition: handler.c:162
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
iconv_t mutt_ch_iconv_open(const char *tocode, const char *fromcode, uint8_t flags)
Set up iconv for conversions.
Definition: charset.c:589
const char * mutt_ch_get_default_charset(const struct Slist *const assumed_charset)
Get the default character set.
Definition: charset.c:460
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:72
#define ICONV_T_INVALID
Error value for iconv functions.
Definition: charset.h:100
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:178
#define STATE_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
+ Here is the call graph for this function:
+ Here is the caller graph for this function: