NeoMutt  2025-12-11-1039-g550ac6
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 <iconv.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "config/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 "ncrypt/lib.h"
#include "pager/lib.h"
#include "body.h"
#include "copy_email.h"
#include "enriched.h"
#include "envelope.h"
#include "globals.h"
#include "mailcap.h"
#include "mime.h"
#include "module_data.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "parameter.h"
#include "parse.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
 Input buffer size for handler operations.
#define BUFO_SIZE   2000
 Output buffer size for handler operations.
#define TXT_HTML   1
 HTML text format.
#define TXT_PLAIN   2
 Plain text format.
#define TXT_ENRICHED   3
 Enriched text format.

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
  • Thomas Klausner

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

Input buffer size for handler operations.

Definition at line 72 of file handler.c.

◆ BUFO_SIZE

#define BUFO_SIZE   2000

Output buffer size for handler operations.

Definition at line 73 of file handler.c.

◆ TXT_HTML

#define TXT_HTML   1

HTML text format.

Definition at line 75 of file handler.c.

◆ TXT_PLAIN

#define TXT_PLAIN   2

Plain text format.

Definition at line 76 of file handler.c.

◆ TXT_ENRICHED

#define TXT_ENRICHED   3

Enriched text format.

Definition at line 77 of file handler.c.

Typedef Documentation

◆ handler_t

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

Definition at line 89 of file handler.c.

Function Documentation

◆ print_part_line()

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

98{
99 struct Buffer *length = buf_pool_get();
100 mutt_str_pretty_size(length, b_email->length);
101 state_mark_attach(state);
102 char *charset = mutt_param_get(&b_email->parameter, "charset");
103 if (n == 0)
104 {
105 state_printf(state, _("[-- Type: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
106 BODY_TYPE(b_email), b_email->subtype, charset ? "; charset=" : "",
107 charset ? charset : "", ENCODING(b_email->encoding), buf_string(length));
108 }
109 else
110 {
111 state_printf(state, _("[-- Alternative Type #%d: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
112 n, BODY_TYPE(b_email), b_email->subtype,
113 charset ? "; charset=" : "", charset ? charset : "",
114 ENCODING(b_email->encoding), buf_string(length));
115 }
116 buf_pool_release(&length);
117}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
#define BODY_TYPE(body)
Get the type name of a body part.
Definition mime.h:92
#define ENCODING(x)
Get the encoding name for an encoding type.
Definition mime.h:97
#define _(a)
Definition message.h:28
void state_mark_attach(struct State *state)
Write a unique marker around content.
Definition state.c:73
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition state.c:190
int mutt_str_pretty_size(struct Buffer *buf, size_t num)
Display an abbreviated size, like 3.4K.
Definition muttlib.c:943
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition parameter.c:85
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
char * subtype
content-type subtype
Definition body.h:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
String manipulation buffer.
Definition buffer.h:36
Here is the call graph for this function:
Here is the caller graph for this function:

◆ convert_to_state()

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

127{
128 char bufo[BUFO_SIZE] = { 0 };
129 const char *ib = NULL;
130 char *ob = NULL;
131 size_t ibl = 0;
132 size_t obl = 0;
133
134 if (!bufi)
135 {
136 if (iconv_t_valid(cd))
137 {
138 ob = bufo;
139 obl = sizeof(bufo);
140 iconv(cd, NULL, NULL, &ob, &obl);
141 if (ob != bufo)
142 state_prefix_put(state, bufo, ob - bufo);
143 }
144 return;
145 }
146
147 if (!iconv_t_valid(cd))
148 {
149 state_prefix_put(state, bufi, *l);
150 *l = 0;
151 return;
152 }
153
154 ib = bufi;
155 ibl = *l;
156 while (true)
157 {
158 ob = bufo;
159 obl = sizeof(bufo);
160 mutt_ch_iconv(cd, &ib, &ibl, &ob, &obl, 0, "?", NULL);
161 if (ob == bufo)
162 break;
163 state_prefix_put(state, bufo, ob - bufo);
164 }
165 memmove(bufi, ib, ibl);
166 *l = ibl;
167}
#define BUFO_SIZE
Output buffer size for handler operations.
Definition handler.c:73
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:685
static bool iconv_t_valid(const iconv_t cd)
Is the conversion descriptor valid?
Definition charset.h:123
void state_prefix_put(struct State *state, const char *buf, size_t buflen)
Write a prefixed fixed-string to the State.
Definition state.c:211
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decode_xbit()

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

177{
178 if (!istext)
179 {
180 mutt_file_copy_bytes(state->fp_in, state->fp_out, len);
181 return;
182 }
183
184 state_set_prefix(state);
185
186 int c;
187 char bufi[BUFI_SIZE] = { 0 };
188 size_t l = 0;
189 while (((c = fgetc(state->fp_in)) != EOF) && len--)
190 {
191 if ((c == '\r') && len)
192 {
193 const int ch = fgetc(state->fp_in);
194 if (ch == '\n')
195 {
196 c = ch;
197 len--;
198 }
199 else
200 {
201 ungetc(ch, state->fp_in);
202 }
203 }
204
205 bufi[l++] = c;
206 if (l == sizeof(bufi))
207 convert_to_state(cd, bufi, &l, state);
208 }
209
210 convert_to_state(cd, bufi, &l, state);
211 convert_to_state(cd, 0, 0, state);
212
213 state_reset_prefix(state);
214}
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:192
#define BUFI_SIZE
Input buffer size for handler operations.
Definition handler.c:72
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:126
#define state_set_prefix(state)
Definition state.h:62
#define state_reset_prefix(state)
Definition state.h:63
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
Here is the call graph for this function:
Here is the caller graph for this function:

◆ qp_decode_triple()

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

224{
225 /* soft line break */
226 if ((s[0] == '=') && (s[1] == '\0'))
227 return 1;
228
229 /* quoted-printable triple */
230 if ((s[0] == '=') && mutt_isxdigit(s[1]) && mutt_isxdigit(s[2]))
231 {
232 *d = (hexval(s[1]) << 4) | hexval(s[2]);
233 return 0;
234 }
235
236 /* something else */
237 return -1;
238}
bool mutt_isxdigit(int arg)
Wrapper for isxdigit(3).
Definition ctype.c:111
#define hexval(ch)
Convert hexadecimal character to its integer value.
Definition mime.h:81
Here is the call graph for this function:
Here is the caller graph for this function:

◆ qp_decode_line()

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

248{
249 char *d = NULL;
250 char *s = NULL;
251 char c = 0;
252
253 int kind = -1;
254 bool soft = false;
255
256 /* decode the line */
257
258 for (d = dest, s = src; *s;)
259 {
260 switch ((kind = qp_decode_triple(s, &c)))
261 {
262 case 0:
263 *d++ = c;
264 s += 3;
265 break; /* qp triple */
266 case -1:
267 *d++ = *s++;
268 break; /* single character */
269 case 1:
270 soft = true;
271 s++;
272 break; /* soft line break */
273 default:
274 break;
275 }
276 }
277
278 if (!soft && (last == '\n'))
279 {
280 /* neither \r nor \n as part of line-terminating CRLF
281 * may be qp-encoded, so remove \r and \n-terminate;
282 * see RFC2045, sect. 6.7, (1): General 8bit representation */
283 if ((kind == 0) && (c == '\r'))
284 *(d - 1) = '\n';
285 else
286 *d++ = '\n';
287 }
288
289 *d = '\0';
290 *l = d - dest;
291}
static int qp_decode_triple(char *s, char *d)
Decode a quoted-printable triplet.
Definition handler.c:223
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decode_quoted()

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

319{
320 char line[256] = { 0 };
321 char decline[512] = { 0 };
322 size_t l = 0;
323 size_t l3 = 0;
324
325 if (istext)
326 state_set_prefix(state);
327
328 while (len > 0)
329 {
330 /* It's ok to use a fixed size buffer for input, even if the line turns
331 * out to be longer than this. Just process the line in chunks. This
332 * really shouldn't happen according the MIME spec, since Q-P encoded
333 * lines are at most 76 characters, but we should be liberal about what
334 * we accept. */
335 if (!fgets(line, MIN((ssize_t) sizeof(line), len + 1), state->fp_in))
336 break;
337
338 size_t linelen = strlen(line);
339 len -= linelen;
340
341 /* inspect the last character we read so we can tell if we got the
342 * entire line. */
343 const int last = (linelen != 0) ? line[linelen - 1] : 0;
344
345 /* chop trailing whitespace if we got the full line */
346 if (last == '\n')
347 {
348 while ((linelen > 0) && mutt_isspace(line[linelen - 1]))
349 linelen--;
350 line[linelen] = '\0';
351 }
352
353 /* decode and do character set conversion */
354 qp_decode_line(decline + l, line, &l3, last);
355 l += l3;
356 convert_to_state(cd, decline, &l, state);
357 }
358
359 convert_to_state(cd, 0, 0, state);
360 state_reset_prefix(state);
361}
bool mutt_isspace(int arg)
Wrapper for isspace(3).
Definition ctype.c:96
static void qp_decode_line(char *dest, char *src, size_t *l, int last)
Decode a line of quoted-printable text.
Definition handler.c:247
#define MIN(a, b)
Return the minimum of two values.
Definition memory.h:40
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decode_byte()

unsigned char decode_byte ( char ch)
static

Decode a uuencoded byte.

Parameters
chCharacter to decode
Return values
numDecoded value

Definition at line 368 of file handler.c.

369{
370 if ((ch < 32) || (ch > 95))
371 return 0;
372 return ch - 32;
373}
Here is the caller graph for this function:

◆ decode_uuencoded()

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

383{
384 char tmps[128] = { 0 };
385 char *pt = NULL;
386 char bufi[BUFI_SIZE] = { 0 };
387 size_t k = 0;
388
389 if (istext)
390 state_set_prefix(state);
391
392 while (len > 0)
393 {
394 if (!fgets(tmps, sizeof(tmps), state->fp_in))
395 goto cleanup;
396 len -= mutt_str_len(tmps);
397 if (mutt_str_startswith(tmps, "begin "))
398 break;
399 }
400 while (len > 0)
401 {
402 if (!fgets(tmps, sizeof(tmps), state->fp_in))
403 goto cleanup;
404 len -= mutt_str_len(tmps);
405 if (mutt_str_startswith(tmps, "end"))
406 break;
407 pt = tmps;
408 const unsigned char linelen = decode_byte(*pt);
409 pt++;
410 for (unsigned char c = 0; (c < linelen) && *pt;)
411 {
412 for (char l = 2; (l <= 6) && pt[0] && pt[1]; l += 2)
413 {
414 char out = decode_byte(*pt) << l;
415 pt++;
416 out |= (decode_byte(*pt) >> (6 - l));
417 bufi[k++] = out;
418 c++;
419 if (c == linelen)
420 break;
421 }
422 convert_to_state(cd, bufi, &k, state);
423 pt++;
424 }
425 }
426
427cleanup:
428 convert_to_state(cd, bufi, &k, state);
429 convert_to_state(cd, 0, 0, state);
430
431 state_reset_prefix(state);
432}
static unsigned char decode_byte(char ch)
Decode a uuencoded byte.
Definition handler.c:368
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_mmnoask()

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

445{
446 const char *val = mutt_str_getenv("MM_NOASK");
447 if (!val)
448 return false;
449
450 char *p = NULL;
451 char tmp[1024] = { 0 };
452 char *q = NULL;
453
454 if (mutt_str_equal(val, "1"))
455 return true;
456
457 mutt_str_copy(tmp, val, sizeof(tmp));
458 p = tmp;
459
460 while ((p = strtok(p, ",")))
461 {
462 q = strrchr(p, '/');
463 if (q)
464 {
465 if (q[1] == '*')
466 {
467 if (mutt_istrn_equal(buf, p, q - p))
468 return true;
469 }
470 else
471 {
472 if (mutt_istr_equal(buf, p))
473 return true;
474 }
475 }
476 else
477 {
478 const size_t plen = mutt_istr_startswith(buf, p);
479 if ((plen != 0) && (buf[plen] == '/'))
480 return true;
481 }
482
483 p = NULL;
484 }
485
486 return false;
487}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition string.c:732
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:587
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
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:457
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_autoview()

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

496{
497 char type[256] = { 0 };
498 bool is_av = false;
499
500 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
501
503 ASSERT(mod_data);
504
505 const bool c_implicit_auto_view = cs_subset_bool(NeoMutt->sub, "implicit_auto_view");
506 if (c_implicit_auto_view)
507 {
508 /* $implicit_auto_view is essentially the same as "auto-view *" */
509 is_av = true;
510 }
511 else
512 {
513 /* determine if this type is on the user's auto-view list */
514 mutt_check_lookup_list(b, type, sizeof(type));
515 struct ListNode *np = NULL;
516 STAILQ_FOREACH(np, &mod_data->auto_view, entries)
517 {
518 int i = mutt_str_len(np->data);
519 i--;
520 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
521 mutt_istrn_equal(type, np->data, i)) ||
522 mutt_istr_equal(type, np->data))
523 {
524 is_av = true;
525 break;
526 }
527 }
528
529 if (is_mmnoask(type))
530 is_av = true;
531 }
532
533 /* determine if there is a mailcap entry suitable for auto-view
534 *
535 * @warning type is altered by this call as a result of 'mime-lookup' support */
536 if (is_av)
537 return mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_AUTOVIEW);
538
539 return false;
540}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
static bool is_mmnoask(const char *buf)
Metamail compatibility: should the attachment be autoviewed?
Definition handler.c:444
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:484
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition mailcap.h:61
@ MODULE_ID_EMAIL
ModuleEmail, Email code
Definition module_api.h:64
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define ASSERT(COND)
Definition signal2.h:59
Email private Module data.
Definition module_data.h:32
struct ListHead auto_view
List of mime types to auto view.
Definition module_data.h:35
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_decode_and_handler()

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

1351{
1352 const char *save_prefix = NULL;
1353 FILE *fp = NULL;
1354 size_t tmplength = 0;
1355 LOFF_T tmpoffset = 0;
1356 int decode = 0;
1357 int rc = 0;
1358#ifndef USE_FMEMOPEN
1359 struct Buffer *tempfile = NULL;
1360#endif
1361
1362 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1363 {
1364 return -1;
1365 }
1366
1367#ifdef USE_FMEMOPEN
1368 char *temp = NULL;
1369 size_t tempsize = 0;
1370#endif
1371
1372 /* see if we need to decode this part before processing it */
1373 if ((b->encoding == ENC_BASE64) || (b->encoding == ENC_QUOTED_PRINTABLE) ||
1374 (b->encoding == ENC_UUENCODED) || (plaintext || mutt_is_text_part(b)))
1375 /* text subtypes may require character set conversion even with 8bit encoding */
1376 {
1377 const int orig_type = b->type;
1378 if (plaintext)
1379 {
1380 b->type = TYPE_TEXT;
1381 }
1382 else
1383 {
1384 /* decode to a tempfile, saving the original destination */
1385 fp = state->fp_out;
1386#ifdef USE_FMEMOPEN
1387 state->fp_out = open_memstream(&temp, &tempsize);
1388 if (!state->fp_out)
1389 {
1390 mutt_error(_("Unable to open 'memory stream'"));
1391 mutt_debug(LL_DEBUG1, "Can't open 'memory stream'\n");
1392 return -1;
1393 }
1394#else
1395 tempfile = buf_pool_get();
1396 buf_mktemp(tempfile);
1397 state->fp_out = mutt_file_fopen(buf_string(tempfile), "w");
1398 if (!state->fp_out)
1399 {
1400 mutt_error(_("Unable to open temporary file"));
1401 mutt_debug(LL_DEBUG1, "Can't open %s\n", buf_string(tempfile));
1402 buf_pool_release(&tempfile);
1403 return -1;
1404 }
1405#endif
1406 /* decoding the attachment changes the size and offset, so save a copy
1407 * of the "real" values now, and restore them after processing */
1408 tmplength = b->length;
1409 tmpoffset = b->offset;
1410
1411 /* if we are decoding binary bodies, we don't want to prefix each
1412 * line with the prefix or else the data will get corrupted. */
1413 save_prefix = state->prefix;
1414 state->prefix = NULL;
1415
1416 decode = 1;
1417 }
1418
1419 mutt_decode_attachment(b, state);
1420
1421 if (decode)
1422 {
1423 b->length = ftello(state->fp_out);
1424 b->offset = 0;
1425#ifdef USE_FMEMOPEN
1426 /* When running under torify, mutt_file_fclose(&state->fp_out) does not seem to
1427 * update tempsize. On the other hand, fflush does. See
1428 * https://github.com/neomutt/neomutt/issues/440 */
1429 fflush(state->fp_out);
1430#endif
1431 mutt_file_fclose(&state->fp_out);
1432
1433 /* restore final destination and substitute the tempfile for input */
1434 state->fp_out = fp;
1435 fp = state->fp_in;
1436#ifdef USE_FMEMOPEN
1437 if (tempsize)
1438 {
1439 state->fp_in = fmemopen(temp, tempsize, "r");
1440 }
1441 else
1442 { /* fmemopen can't handle zero-length buffers */
1443 state->fp_in = mutt_file_fopen("/dev/null", "r");
1444 }
1445 if (!state->fp_in)
1446 {
1447 mutt_perror(_("failed to re-open 'memory stream'"));
1448 FREE(&temp);
1449 state->fp_in = fp;
1450 state->prefix = save_prefix;
1451 b->length = tmplength;
1452 b->offset = tmpoffset;
1453 return -1;
1454 }
1455#else
1456 state->fp_in = mutt_file_fopen(buf_string(tempfile), "r");
1457 unlink(buf_string(tempfile));
1458 buf_pool_release(&tempfile);
1459 if (!state->fp_in)
1460 {
1461 mutt_perror(_("failed to re-open temporary file"));
1462 state->fp_in = fp;
1463 state->prefix = save_prefix;
1464 b->length = tmplength;
1465 b->offset = tmpoffset;
1466 return -1;
1467 }
1468#endif
1469 /* restore the prefix */
1470 state->prefix = save_prefix;
1471 }
1472
1473 b->type = orig_type;
1474 }
1475
1476 /* process the (decoded) body part */
1477 if (handler)
1478 {
1479 rc = handler(b, state);
1480 if (rc != 0)
1481 {
1482 mutt_debug(LL_DEBUG1, "Failed on attachment of type %s/%s\n",
1483 BODY_TYPE(b), NONULL(b->subtype));
1484 }
1485
1486 if (decode)
1487 {
1488 b->length = tmplength;
1489 b->offset = tmpoffset;
1490
1491 /* restore the original source stream */
1492 mutt_file_fclose(&state->fp_in);
1493 state->fp_in = fp;
1494 }
1495 }
1496 state->flags |= STATE_FIRSTDONE;
1497#ifdef USE_FMEMOPEN
1498 FREE(&temp);
1499#endif
1500
1501 return rc;
1502}
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1950
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
@ 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
@ STATE_FIRSTDONE
The first attachment has been done.
Definition state.h:44
bool mutt_is_text_part(const struct Body *b)
Is this part of an email in plain text?
Definition muttlib.c:399
#define NONULL(x)
Definition string2.h:44
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
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
#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 1571 of file handler.c.

1572{
1573 char buf[5] = { 0 };
1574 int ch;
1575 int i;
1576 bool cr = false;
1577 char bufi[BUFI_SIZE] = { 0 };
1578 size_t l = 0;
1579
1580 buf[4] = '\0';
1581
1582 if (istext)
1583 state_set_prefix(state);
1584
1585 while (len > 0)
1586 {
1587 for (i = 0; (i < 4) && (len > 0); len--)
1588 {
1589 ch = fgetc(state->fp_in);
1590 if (ch == EOF)
1591 break;
1592 if ((ch >= 0) && (ch < 128) && ((base64val(ch) != -1) || (ch == '=')))
1593 buf[i++] = ch;
1594 }
1595 if (i != 4)
1596 {
1597 /* "i" may be zero if there is trailing whitespace, which is not an error */
1598 if (i != 0)
1599 mutt_debug(LL_DEBUG2, "didn't get a multiple of 4 chars\n");
1600 break;
1601 }
1602
1603 const int c1 = base64val(buf[0]);
1604 if (c1 == -1) /* '=' (or any non-base64 char) at slot 0: stop */
1605 break;
1606 const int c2 = base64val(buf[1]);
1607 if (c2 == -1) /* '=' at slot 1: invalid padding, stop */
1608 break;
1609
1610 /* first char */
1611 ch = (c1 << 2) | (c2 >> 4);
1612
1613 if (cr && (ch != '\n'))
1614 bufi[l++] = '\r';
1615
1616 cr = false;
1617
1618 if (istext && (ch == '\r'))
1619 cr = true;
1620 else
1621 bufi[l++] = ch;
1622
1623 /* second char */
1624 if (buf[2] == '=')
1625 break;
1626 const int c3 = base64val(buf[2]);
1627 ch = ((c2 & 0xf) << 4) | (c3 >> 2);
1628
1629 if (cr && (ch != '\n'))
1630 bufi[l++] = '\r';
1631
1632 cr = false;
1633
1634 if (istext && (ch == '\r'))
1635 cr = true;
1636 else
1637 bufi[l++] = ch;
1638
1639 /* third char */
1640 if (buf[3] == '=')
1641 break;
1642 const int c4 = base64val(buf[3]);
1643 ch = ((c3 & 0x3) << 6) | c4;
1644
1645 if (cr && (ch != '\n'))
1646 bufi[l++] = '\r';
1647
1648 cr = false;
1649
1650 if (istext && (ch == '\r'))
1651 cr = true;
1652 else
1653 bufi[l++] = ch;
1654
1655 if ((l + 8) >= sizeof(bufi))
1656 convert_to_state(cd, bufi, &l, state);
1657 }
1658
1659 if (cr)
1660 bufi[l++] = '\r';
1661
1662 convert_to_state(cd, bufi, &l, state);
1663 convert_to_state(cd, 0, 0, state);
1664
1665 state_reset_prefix(state);
1666}
#define base64val(ch)
Convert base64 character to its numeric value.
Definition base64.h:33
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
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 1675 of file handler.c.

1676{
1677 if (!b || !state)
1678 return -1;
1679
1680 bool plaintext = false;
1681 handler_t handler = NULL;
1682 handler_t encrypted_handler = NULL;
1683 int rc = 0;
1684 static unsigned short recurse_level = 0;
1685
1686 const int oflags = state->flags;
1687 const bool is_attachment_display = (oflags & STATE_DISPLAY_ATTACH);
1688
1689 if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1690 {
1691 mutt_debug(LL_DEBUG1, "recurse level too deep. giving up\n");
1692 return 1;
1693 }
1694 recurse_level++;
1695
1696 /* first determine which handler to use to process this part */
1697
1698 if (is_autoview(b))
1699 {
1700 handler = autoview_handler;
1701 state->flags &= ~STATE_CHARCONV;
1702 }
1703 else if (b->type == TYPE_TEXT)
1704 {
1705 if (mutt_istr_equal("plain", b->subtype))
1706 {
1707 const bool c_reflow_text = cs_subset_bool(NeoMutt->sub, "reflow_text");
1708 /* avoid copying this part twice since removing the transfer-encoding is
1709 * the only operation needed. */
1711 {
1712 encrypted_handler = crypt_pgp_application_handler;
1713 handler = encrypted_handler;
1714 }
1715 else if (c_reflow_text &&
1716 mutt_istr_equal("flowed", mutt_param_get(&b->parameter, "format")))
1717 {
1718 handler = rfc3676_handler;
1719 }
1720 else
1721 {
1722 handler = text_plain_handler;
1723 }
1724 }
1725 else if (mutt_istr_equal("enriched", b->subtype))
1726 {
1727 handler = text_enriched_handler;
1728 }
1729 else /* text body type without a handler */
1730 {
1731 plaintext = false;
1732 }
1733 }
1734 else if (b->type == TYPE_MESSAGE)
1735 {
1736 if (mutt_is_message_type(b->type, b->subtype))
1737 handler = message_handler;
1738 else if (mutt_istr_equal("delivery-status", b->subtype))
1739 plaintext = true;
1740 else if (mutt_istr_equal("external-body", b->subtype))
1741 handler = external_body_handler;
1742 }
1743 else if (b->type == TYPE_MULTIPART)
1744 {
1745 const char *const c_show_multipart_alternative = cs_subset_string(NeoMutt->sub, "show_multipart_alternative");
1746 if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1747 mutt_istr_equal("alternative", b->subtype))
1748 {
1749 handler = alternative_handler;
1750 }
1751 else if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1752 mutt_istr_equal("multilingual", b->subtype))
1753 {
1754 handler = multilingual_handler;
1755 }
1756 else if ((WithCrypto != 0) && mutt_istr_equal("signed", b->subtype))
1757 {
1758 if (!mutt_param_get(&b->parameter, "protocol"))
1759 mutt_error(_("Error: multipart/signed has no protocol"));
1760 else if (state->flags & STATE_VERIFY)
1761 handler = mutt_signed_handler;
1762 }
1764 {
1765 encrypted_handler = valid_pgp_encrypted_handler;
1766 handler = encrypted_handler;
1767 }
1769 {
1770 encrypted_handler = malformed_pgp_encrypted_handler;
1771 handler = encrypted_handler;
1772 }
1773
1774 if (!handler)
1775 handler = multipart_handler;
1776
1777 if ((b->encoding != ENC_7BIT) && (b->encoding != ENC_8BIT) && (b->encoding != ENC_BINARY))
1778 {
1779 mutt_debug(LL_DEBUG1, "Bad encoding type %d for multipart entity, assuming 7 bit\n",
1780 b->encoding);
1781 b->encoding = ENC_7BIT;
1782 }
1783 }
1784 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1785 {
1786 if (OptDontHandlePgpKeys && mutt_istr_equal("pgp-keys", b->subtype))
1787 {
1788 /* pass raw part through for key extraction */
1789 plaintext = true;
1790 }
1791 else if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b))
1792 {
1793 encrypted_handler = crypt_pgp_application_handler;
1794 handler = encrypted_handler;
1795 }
1796 else if (((WithCrypto & APPLICATION_SMIME) != 0) && mutt_is_application_smime(b))
1797 {
1798 encrypted_handler = crypt_smime_application_handler;
1799 handler = encrypted_handler;
1800 }
1801 }
1802
1803 if ((plaintext || handler) && (is_attachment_display || !mutt_prefer_as_attachment(b)))
1804 {
1805 /* only respect disposition == attachment if we're not
1806 * displaying from the attachment menu (i.e. pager) */
1807 /* Prevent encrypted attachments from being included in replies
1808 * unless $include_encrypted is set. */
1809 const bool c_include_encrypted = cs_subset_bool(NeoMutt->sub, "include_encrypted");
1810 if ((state->flags & STATE_REPLYING) && (state->flags & STATE_FIRSTDONE) &&
1811 encrypted_handler && !c_include_encrypted)
1812 {
1813 goto cleanup;
1814 }
1815
1816 rc = run_decode_and_handler(b, state, handler, plaintext);
1817 }
1818 else if (state->flags & STATE_DISPLAY)
1819 {
1820 /* print hint to use attachment menu for disposition == attachment
1821 * if we're not already being called from there */
1822 const bool c_honor_disposition = cs_subset_bool(NeoMutt->sub, "honor_disposition");
1823 struct Buffer *msg = buf_pool_get();
1824
1825 if (is_attachment_display)
1826 {
1827 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1828 {
1829 buf_strcpy(msg, _("[-- This is an attachment --]\n"));
1830 }
1831 else
1832 {
1833 /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1834 buf_printf(msg, _("[-- %s/%s is unsupported --]\n"), BODY_TYPE(b), b->subtype);
1835 }
1836 }
1837 else
1838 {
1839 struct Buffer *keystroke = buf_pool_get();
1840 const struct MenuDefinition *md_pager = pager_get_menu_definition();
1841 if (keymap_expand_key(km_find_func(md_pager, OP_VIEW_ATTACHMENTS), keystroke))
1842 {
1843 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1844 {
1845 /* L10N: %s expands to a keystroke/key binding, e.g. 'v'. */
1846 buf_printf(msg, _("[-- This is an attachment (use '%s' to view this part) --]\n"),
1847 buf_string(keystroke));
1848 }
1849 else
1850 {
1851 /* L10N: %s/%s is a MIME type, e.g. "text/plain".
1852 The last %s expands to a keystroke/key binding, e.g. 'v'. */
1853 buf_printf(msg, _("[-- %s/%s is unsupported (use '%s' to view this part) --]\n"),
1854 BODY_TYPE(b), b->subtype, buf_string(keystroke));
1855 }
1856 }
1857 else
1858 {
1859 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1860 {
1861 buf_strcpy(msg, _("[-- This is an attachment (need 'view-attachments' bound to key) --]\n"));
1862 }
1863 else
1864 {
1865 /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1866 buf_printf(msg, _("[-- %s/%s is unsupported (need 'view-attachments' bound to key) --]\n"),
1867 BODY_TYPE(b), b->subtype);
1868 }
1869 }
1870 buf_pool_release(&keystroke);
1871 }
1872 state_mark_attach(state);
1873 state_printf(state, "%s", buf_string(msg));
1874 buf_pool_release(&msg);
1875 }
1876
1877cleanup:
1878 recurse_level--;
1879 state->flags = oflags | (state->flags & STATE_FIRSTDONE);
1880 if (rc != 0)
1881 {
1882 mutt_debug(LL_DEBUG1, "Bailing on attachment of type %s/%s\n", BODY_TYPE(b),
1883 NONULL(b->subtype));
1884 }
1885
1886 return rc;
1887}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:610
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition crypt.c:468
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:505
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:549
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1653
bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition globals.c:46
int crypt_pgp_application_handler(struct Body *b_email, struct State *state)
Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -.
Definition cryptglue.c:266
static int alternative_handler(struct Body *b_email, struct State *state)
Handler for multipart alternative emails - Implements handler_t -.
Definition handler.c:955
int text_enriched_handler(struct Body *b_email, struct State *state)
Handler for enriched text - Implements handler_t -.
Definition enriched.c:474
static int text_plain_handler(struct Body *b_email, struct State *state)
Handler for plain text - Implements handler_t -.
Definition handler.c:699
int crypt_smime_application_handler(struct Body *b_email, struct State *state)
Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -.
Definition cryptglue.c:524
static int autoview_handler(struct Body *b_email, struct State *state)
Handler for autoviewable attachments - Implements handler_t -.
Definition handler.c:545
static int external_body_handler(struct Body *b_email, struct State *state)
Handler for external-body emails - Implements handler_t -.
Definition handler.c:784
int rfc3676_handler(struct Body *b_email, struct State *state)
Handler for format=flowed - Implements handler_t -.
Definition rfc3676.c:329
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:1536
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:1507
static int message_handler(struct Body *b_email, struct State *state)
Handler for message/rfc822 body parts - Implements handler_t -.
Definition handler.c:726
static int multipart_handler(struct Body *b_email, struct State *state)
Handler for multipart emails - Implements handler_t -.
Definition handler.c:1259
static int multilingual_handler(struct Body *b_email, struct State *state)
Handler for multi-lingual emails - Implements handler_t -.
Definition handler.c:1146
int mutt_signed_handler(struct Body *b_email, struct State *state)
Handler for "multipart/signed" - Implements handler_t -.
Definition crypt.c:1251
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition handler.c:495
bool mutt_prefer_as_attachment(struct Body *b)
Do we want this part as an attachment?
Definition handler.c:1894
int(* handler_t)(struct Body *b_email, struct State *state)
Definition handler.c:89
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:1349
bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition keymap.c:247
struct Keymap * km_find_func(const struct MenuDefinition *md, int func)
Find a function's mapping in a Menu.
Definition menu.c:141
@ 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
Maximum nesting depth for MIME parts to prevent stack overflow.
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
@ STATE_CHARCONV
Do character set conversions.
Definition state.h:41
@ STATE_REPLYING
Are we replying?
Definition state.h:43
@ STATE_VERIFY
Perform signature verification.
Definition state.h:38
@ STATE_DISPLAY_ATTACH
We are displaying an attachment.
Definition state.h:45
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:112
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
#define WithCrypto
Definition lib.h:132
struct MenuDefinition * pager_get_menu_definition(void)
Get the Pager Menu Definition.
Definition functions.c:1116
unsigned int disposition
content-disposition, ContentDisposition
Definition body.h:42
Functions for a Dialog or Window.
Definition menudef.h:44
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 1894 of file handler.c.

1895{
1896 if (!mutt_can_decode(b))
1897 return true;
1898
1899 if (b->disposition != DISP_ATTACH)
1900 return false;
1901
1902 return cs_subset_bool(NeoMutt->sub, "honor_disposition");
1903}
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition handler.c:1910
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 1910 of file handler.c.

1911{
1912 if (is_autoview(b))
1913 return true;
1914 if (b->type == TYPE_TEXT)
1915 return true;
1916 if (b->type == TYPE_MESSAGE)
1917 return true;
1918 if (b->type == TYPE_MULTIPART)
1919 {
1920 if (WithCrypto)
1921 {
1922 if (mutt_istr_equal(b->subtype, "signed") || mutt_istr_equal(b->subtype, "encrypted"))
1923 {
1924 return true;
1925 }
1926 }
1927
1928 for (struct Body *part = b->parts; part; part = part->next)
1929 {
1930 if (mutt_can_decode(part))
1931 return true;
1932 }
1933 }
1934 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1935 {
1937 return true;
1939 return true;
1940 }
1941
1942 return false;
1943}
The body of an email.
Definition body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
struct Body * next
next attachment in the list
Definition body.h:72
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 1950 of file handler.c.

1951{
1952 int istext = mutt_is_text_part(b) && (b->disposition == DISP_INLINE);
1953 iconv_t cd = ICONV_T_INVALID;
1954
1955 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1956 {
1957 return;
1958 }
1959
1960 if (istext && (b->charset || (state->flags & STATE_CHARCONV)))
1961 {
1962 const char *charset = b->charset;
1963 if (!charset)
1964 {
1965 charset = mutt_param_get(&b->parameter, "charset");
1966 if (!charset && !slist_is_empty(cc_assumed_charset()))
1968 }
1969 if (charset && cc_charset())
1971 }
1972
1973 switch (b->encoding)
1974 {
1976 decode_quoted(state, b->length,
1977 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1979 cd);
1980 break;
1981 case ENC_BASE64:
1982 mutt_decode_base64(state, b->length,
1983 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1985 cd);
1986 break;
1987 case ENC_UUENCODED:
1988 decode_uuencoded(state, b->length,
1989 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1991 cd);
1992 break;
1993 default:
1994 decode_xbit(state, b->length,
1995 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1997 cd);
1998 break;
1999 }
2000}
const char * cc_charset(void)
Get the cached value of $charset.
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
static void decode_uuencoded(struct State *state, long len, bool istext, iconv_t cd)
Decode uuencoded text.
Definition handler.c:382
void mutt_decode_base64(struct State *state, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition handler.c:1571
static void decode_quoted(struct State *state, long len, bool istext, iconv_t cd)
Decode an attachment encoded with quoted-printable.
Definition handler.c:318
static void decode_xbit(struct State *state, long len, bool istext, iconv_t cd)
Decode xbit-encoded text.
Definition handler.c:176
@ 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:581
const char * mutt_ch_get_default_charset(const struct Slist *const assumed_charset)
Get the default character set.
Definition charset.c:452
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
#define ICONV_T_INVALID
Error value for iconv functions.
Definition charset.h:111
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition slist.c:140
char * charset
Send mode: charset of attached file as stored on disk.
Definition body.h:79
Here is the call graph for this function:
Here is the caller graph for this function: