NeoMutt  2024-04-16-36-g75b6fb
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 (const struct Body *b, struct State *state)
 Decode an email's attachment.
 

Detailed Description

Decide how to display email content.

Authors
  • Michael R. Elkins
  • Pietro Cerutti
  • Richard Russon
  • Federico Kircheis
  • Reis Radomil
  • Ian Zimmerman
  • David Purton
  • Dennis Schön

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

◆ BUFO_SIZE

#define BUFO_SIZE   2000

Definition at line 69 of file handler.c.

◆ TXT_HTML

#define TXT_HTML   1

Definition at line 71 of file handler.c.

◆ TXT_PLAIN

#define TXT_PLAIN   2

Definition at line 72 of file handler.c.

◆ TXT_ENRICHED

#define TXT_ENRICHED   3

Definition at line 73 of file handler.c.

Typedef Documentation

◆ handler_t

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

Definition at line 85 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 93 of file handler.c.

94{
95 char length[5] = { 0 };
96 mutt_str_pretty_size(length, sizeof(length), b_email->length);
97 state_mark_attach(state);
98 char *charset = mutt_param_get(&b_email->parameter, "charset");
99 if (n == 0)
100 {
101 state_printf(state, _("[-- Type: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
102 TYPE(b_email), b_email->subtype, charset ? "; charset=" : "",
103 charset ? charset : "", ENCODING(b_email->encoding), length);
104 }
105 else
106 {
107 state_printf(state, _("[-- Alternative Type #%d: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
108 n, TYPE(b_email), b_email->subtype, charset ? "; charset=" : "",
109 charset ? charset : "", ENCODING(b_email->encoding), length);
110 }
111}
#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:72
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:186
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1101
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:85
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 120 of file handler.c.

121{
122 char bufo[BUFO_SIZE] = { 0 };
123 const char *ib = NULL;
124 char *ob = NULL;
125 size_t ibl, obl;
126
127 if (!bufi)
128 {
129 if (iconv_t_valid(cd))
130 {
131 ob = bufo;
132 obl = sizeof(bufo);
133 iconv(cd, NULL, NULL, &ob, &obl);
134 if (ob != bufo)
135 state_prefix_put(state, bufo, ob - bufo);
136 }
137 return;
138 }
139
140 if (!iconv_t_valid(cd))
141 {
142 state_prefix_put(state, bufi, *l);
143 *l = 0;
144 return;
145 }
146
147 ib = bufi;
148 ibl = *l;
149 while (true)
150 {
151 ob = bufo;
152 obl = sizeof(bufo);
153 mutt_ch_iconv(cd, &ib, &ibl, &ob, &obl, 0, "?", NULL);
154 if (ob == bufo)
155 break;
156 state_prefix_put(state, bufo, ob - bufo);
157 }
158 memmove(bufi, ib, ibl);
159 *l = ibl;
160}
#define BUFO_SIZE
Definition: handler.c:69
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:697
static bool iconv_t_valid(const iconv_t cd)
Is the conversion descriptor valid?
Definition: charset.h:113
void state_prefix_put(struct State *state, const char *buf, size_t buflen)
Write a prefixed fixed-string to the State.
Definition: state.c:204
+ 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 169 of file handler.c.

170{
171 if (!istext)
172 {
173 mutt_file_copy_bytes(state->fp_in, state->fp_out, len);
174 return;
175 }
176
177 state_set_prefix(state);
178
179 int c;
180 char bufi[BUFI_SIZE] = { 0 };
181 size_t l = 0;
182 while (((c = fgetc(state->fp_in)) != EOF) && len--)
183 {
184 if ((c == '\r') && len)
185 {
186 const int ch = fgetc(state->fp_in);
187 if (ch == '\n')
188 {
189 c = ch;
190 len--;
191 }
192 else
193 {
194 ungetc(ch, state->fp_in);
195 }
196 }
197
198 bufi[l++] = c;
199 if (l == sizeof(bufi))
200 convert_to_state(cd, bufi, &l, state);
201 }
202
203 convert_to_state(cd, bufi, &l, state);
204 convert_to_state(cd, 0, 0, state);
205
206 state_reset_prefix(state);
207}
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:256
#define BUFI_SIZE
Definition: handler.c:68
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:120
#define state_set_prefix(state)
Definition: state.h:56
#define state_reset_prefix(state)
Definition: state.h:57
FILE * fp_out
File to write to.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:49
+ 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 216 of file handler.c.

217{
218 /* soft line break */
219 if ((s[0] == '=') && (s[1] == '\0'))
220 return 1;
221
222 /* quoted-printable triple */
223 if ((s[0] == '=') && isxdigit((unsigned char) s[1]) && isxdigit((unsigned char) s[2]))
224 {
225 *d = (hexval(s[1]) << 4) | hexval(s[2]);
226 return 0;
227 }
228
229 /* something else */
230 return -1;
231}
#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 240 of file handler.c.

241{
242 char *d = NULL, *s = NULL;
243 char c = 0;
244
245 int kind = -1;
246 bool soft = false;
247
248 /* decode the line */
249
250 for (d = dest, s = src; *s;)
251 {
252 switch ((kind = qp_decode_triple(s, &c)))
253 {
254 case 0:
255 *d++ = c;
256 s += 3;
257 break; /* qp triple */
258 case -1:
259 *d++ = *s++;
260 break; /* single character */
261 case 1:
262 soft = true;
263 s++;
264 break; /* soft line break */
265 }
266 }
267
268 if (!soft && (last == '\n'))
269 {
270 /* neither \r nor \n as part of line-terminating CRLF
271 * may be qp-encoded, so remove \r and \n-terminate;
272 * see RFC2045, sect. 6.7, (1): General 8bit representation */
273 if ((kind == 0) && (c == '\r'))
274 *(d - 1) = '\n';
275 else
276 *d++ = '\n';
277 }
278
279 *d = '\0';
280 *l = d - dest;
281}
static int qp_decode_triple(char *s, char *d)
Decode a quoted-printable triplet.
Definition: handler.c:216
+ 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 308 of file handler.c.

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

359{
360 if ((ch < 32) || (ch > 95))
361 return 0;
362 return ch - 32;
363}
+ 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 372 of file handler.c.

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

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

486{
487 char type[256] = { 0 };
488 bool is_av = false;
489
490 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
491
492 const bool c_implicit_auto_view = cs_subset_bool(NeoMutt->sub, "implicit_auto_view");
493 if (c_implicit_auto_view)
494 {
495 /* $implicit_auto_view is essentially the same as "auto_view *" */
496 is_av = true;
497 }
498 else
499 {
500 /* determine if this type is on the user's auto_view list */
501 mutt_check_lookup_list(b, type, sizeof(type));
502 struct ListNode *np = NULL;
503 STAILQ_FOREACH(np, &AutoViewList, entries)
504 {
505 int i = mutt_str_len(np->data) - 1;
506 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
507 mutt_istrn_equal(type, np->data, i)) ||
508 mutt_istr_equal(type, np->data))
509 {
510 is_av = true;
511 break;
512 }
513 }
514
515 if (is_mmnoask(type))
516 is_av = true;
517 }
518
519 /* determine if there is a mailcap entry suitable for auto_view
520 *
521 * @warning type is altered by this call as a result of 'mime_lookup' support */
522 if (is_av)
523 return mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_AUTOVIEW);
524
525 return false;
526}
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:49
static bool is_mmnoask(const char *buf)
Metamail compatibility: should the attachment be autoviewed?
Definition: handler.c:434
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:483
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:61
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:342
#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 1326 of file handler.c.

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

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

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

1850{
1851 if (!mutt_can_decode(b))
1852 return true;
1853
1854 if (b->disposition != DISP_ATTACH)
1855 return false;
1856
1857 return cs_subset_bool(NeoMutt->sub, "honor_disposition");
1858}
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1865
+ 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 1865 of file handler.c.

1866{
1867 if (is_autoview(b))
1868 return true;
1869 if (b->type == TYPE_TEXT)
1870 return true;
1871 if (b->type == TYPE_MESSAGE)
1872 return true;
1873 if (b->type == TYPE_MULTIPART)
1874 {
1875 if (WithCrypto)
1876 {
1877 if (mutt_istr_equal(b->subtype, "signed") || mutt_istr_equal(b->subtype, "encrypted"))
1878 {
1879 return true;
1880 }
1881 }
1882
1883 for (struct Body *part = b->parts; part; part = part->next)
1884 {
1885 if (mutt_can_decode(part))
1886 return true;
1887 }
1888 }
1889 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1890 {
1892 return true;
1894 return true;
1895 }
1896
1897 return false;
1898}
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 ( const struct Body b,
struct State state 
)

Decode an email's attachment.

Parameters
bBody of the email
stateState of text being processed

Definition at line 1905 of file handler.c.

1906{
1907 int istext = mutt_is_text_part(b) && (b->disposition == DISP_INLINE);
1908 iconv_t cd = ICONV_T_INVALID;
1909
1910 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1911 {
1912 return;
1913 }
1914
1915 if (istext && (b->charset || (state->flags & STATE_CHARCONV)))
1916 {
1917 const char *charset = b->charset;
1918 if (!charset)
1919 {
1920 charset = mutt_param_get(&b->parameter, "charset");
1921 if (!charset && !slist_is_empty(cc_assumed_charset()))
1923 }
1924 if (charset && cc_charset())
1926 }
1927
1928 switch (b->encoding)
1929 {
1931 decode_quoted(state, b->length,
1932 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1934 cd);
1935 break;
1936 case ENC_BASE64:
1937 mutt_decode_base64(state, b->length,
1938 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1940 cd);
1941 break;
1942 case ENC_UUENCODED:
1943 decode_uuencoded(state, b->length,
1944 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1946 cd);
1947 break;
1948 default:
1949 decode_xbit(state, b->length,
1950 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1952 cd);
1953 break;
1954 }
1955}
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
Definition: config_cache.c:101
static void decode_uuencoded(struct State *state, long len, bool istext, iconv_t cd)
Decode uuencoded text.
Definition: handler.c:372
void mutt_decode_base64(struct State *state, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition: handler.c:1532
static void decode_quoted(struct State *state, long len, bool istext, iconv_t cd)
Decode an attachment encoded with quoted-printable.
Definition: handler.c:308
static void decode_xbit(struct State *state, long len, bool istext, iconv_t cd)
Decode xbit-encoded text.
Definition: handler.c:169
@ 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:594
const char * mutt_ch_get_default_charset(const struct Slist *const assumed_charset)
Get the default character set.
Definition: charset.c:465
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:73
#define ICONV_T_INVALID
Error value for iconv functions.
Definition: charset.h:101
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:142
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:37
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: