NeoMutt  2025-12-11-435-g4ac674
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()

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 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:93
#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:187
int mutt_str_pretty_size(struct Buffer *buf, size_t num)
Display an abbreviated size, like 3.4K.
Definition muttlib.c:934
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()

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 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, obl;
132
133 if (!bufi)
134 {
135 if (iconv_t_valid(cd))
136 {
137 ob = bufo;
138 obl = sizeof(bufo);
139 iconv(cd, NULL, NULL, &ob, &obl);
140 if (ob != bufo)
141 state_prefix_put(state, bufo, ob - bufo);
142 }
143 return;
144 }
145
146 if (!iconv_t_valid(cd))
147 {
148 state_prefix_put(state, bufi, *l);
149 *l = 0;
150 return;
151 }
152
153 ib = bufi;
154 ibl = *l;
155 while (true)
156 {
157 ob = bufo;
158 obl = sizeof(bufo);
159 mutt_ch_iconv(cd, &ib, &ibl, &ob, &obl, 0, "?", NULL);
160 if (ob == bufo)
161 break;
162 state_prefix_put(state, bufo, ob - bufo);
163 }
164 memmove(bufi, ib, ibl);
165 *l = ibl;
166}
#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:683
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:205
+ 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 175 of file handler.c.

176{
177 if (!istext)
178 {
179 mutt_file_copy_bytes(state->fp_in, state->fp_out, len);
180 return;
181 }
182
183 state_set_prefix(state);
184
185 int c;
186 char bufi[BUFI_SIZE] = { 0 };
187 size_t l = 0;
188 while (((c = fgetc(state->fp_in)) != EOF) && len--)
189 {
190 if ((c == '\r') && len)
191 {
192 const int ch = fgetc(state->fp_in);
193 if (ch == '\n')
194 {
195 c = ch;
196 len--;
197 }
198 else
199 {
200 ungetc(ch, state->fp_in);
201 }
202 }
203
204 bufi[l++] = c;
205 if (l == sizeof(bufi))
206 convert_to_state(cd, bufi, &l, state);
207 }
208
209 convert_to_state(cd, bufi, &l, state);
210 convert_to_state(cd, 0, 0, state);
211
212 state_reset_prefix(state);
213}
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: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 222 of file handler.c.

223{
224 /* soft line break */
225 if ((s[0] == '=') && (s[1] == '\0'))
226 return 1;
227
228 /* quoted-printable triple */
229 if ((s[0] == '=') && mutt_isxdigit(s[1]) && mutt_isxdigit(s[2]))
230 {
231 *d = (hexval(s[1]) << 4) | hexval(s[2]);
232 return 0;
233 }
234
235 /* something else */
236 return -1;
237}
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:82
+ Here is the call graph for this function:
+ 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 246 of file handler.c.

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

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

static unsigned char decode_byte ( char ch)
static

Decode a uuencoded byte.

Parameters
chCharacter to decode
Return values
numDecoded value

Definition at line 364 of file handler.c.

365{
366 if ((ch < 32) || (ch > 95))
367 return 0;
368 return ch - 32;
369}
+ 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 378 of file handler.c.

379{
380 char tmps[128] = { 0 };
381 char *pt = NULL;
382 char bufi[BUFI_SIZE] = { 0 };
383 size_t k = 0;
384
385 if (istext)
386 state_set_prefix(state);
387
388 while (len > 0)
389 {
390 if (!fgets(tmps, sizeof(tmps), state->fp_in))
391 goto cleanup;
392 len -= mutt_str_len(tmps);
393 if (mutt_str_startswith(tmps, "begin "))
394 break;
395 }
396 while (len > 0)
397 {
398 if (!fgets(tmps, sizeof(tmps), state->fp_in))
399 goto cleanup;
400 len -= mutt_str_len(tmps);
401 if (mutt_str_startswith(tmps, "end"))
402 break;
403 pt = tmps;
404 const unsigned char linelen = decode_byte(*pt);
405 pt++;
406 for (unsigned char c = 0; (c < linelen) && *pt;)
407 {
408 for (char l = 2; (l <= 6) && pt[0] && pt[1]; l += 2)
409 {
410 char out = decode_byte(*pt) << l;
411 pt++;
412 out |= (decode_byte(*pt) >> (6 - l));
413 bufi[k++] = out;
414 c++;
415 if (c == linelen)
416 break;
417 }
418 convert_to_state(cd, bufi, &k, state);
419 pt++;
420 }
421 }
422
423cleanup:
424 convert_to_state(cd, bufi, &k, state);
425 convert_to_state(cd, 0, 0, state);
426
427 state_reset_prefix(state);
428}
static unsigned char decode_byte(char ch)
Decode a uuencoded byte.
Definition handler.c:364
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:500
+ 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 440 of file handler.c.

441{
442 const char *val = mutt_str_getenv("MM_NOASK");
443 if (!val)
444 return false;
445
446 char *p = NULL;
447 char tmp[1024] = { 0 };
448 char *q = NULL;
449
450 if (mutt_str_equal(val, "1"))
451 return true;
452
453 mutt_str_copy(tmp, val, sizeof(tmp));
454 p = tmp;
455
456 while ((p = strtok(p, ",")))
457 {
458 q = strrchr(p, '/');
459 if (q)
460 {
461 if (q[1] == '*')
462 {
463 if (mutt_istrn_equal(buf, p, q - p))
464 return true;
465 }
466 else
467 {
468 if (mutt_istr_equal(buf, p))
469 return true;
470 }
471 }
472 else
473 {
474 const size_t plen = mutt_istr_startswith(buf, p);
475 if ((plen != 0) && (buf[plen] == '/'))
476 return true;
477 }
478
479 p = NULL;
480 }
481
482 return false;
483}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:674
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition string.c:728
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:583
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()

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

492{
493 char type[256] = { 0 };
494 bool is_av = false;
495
496 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
497
499 ASSERT(md);
500
501 const bool c_implicit_auto_view = cs_subset_bool(NeoMutt->sub, "implicit_auto_view");
502 if (c_implicit_auto_view)
503 {
504 /* $implicit_auto_view is essentially the same as "auto-view *" */
505 is_av = true;
506 }
507 else
508 {
509 /* determine if this type is on the user's auto-view list */
510 mutt_check_lookup_list(b, type, sizeof(type));
511 struct ListNode *np = NULL;
512 STAILQ_FOREACH(np, &md->auto_view, entries)
513 {
514 int i = mutt_str_len(np->data);
515 i--;
516 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
517 mutt_istrn_equal(type, np->data, i)) ||
518 mutt_istr_equal(type, np->data))
519 {
520 is_av = true;
521 break;
522 }
523 }
524
525 if (is_mmnoask(type))
526 is_av = true;
527 }
528
529 /* determine if there is a mailcap entry suitable for auto-view
530 *
531 * @warning type is altered by this call as a result of 'mime-lookup' support */
532 if (is_av)
533 return mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_AUTOVIEW);
534
535 return false;
536}
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:440
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:585
#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()

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

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

1561{
1562 char buf[5] = { 0 };
1563 int ch, i;
1564 bool cr = false;
1565 char bufi[BUFI_SIZE] = { 0 };
1566 size_t l = 0;
1567
1568 buf[4] = '\0';
1569
1570 if (istext)
1571 state_set_prefix(state);
1572
1573 while (len > 0)
1574 {
1575 for (i = 0; (i < 4) && (len > 0); len--)
1576 {
1577 ch = fgetc(state->fp_in);
1578 if (ch == EOF)
1579 break;
1580 if ((ch >= 0) && (ch < 128) && ((base64val(ch) != -1) || (ch == '=')))
1581 buf[i++] = ch;
1582 }
1583 if (i != 4)
1584 {
1585 /* "i" may be zero if there is trailing whitespace, which is not an error */
1586 if (i != 0)
1587 mutt_debug(LL_DEBUG2, "didn't get a multiple of 4 chars\n");
1588 break;
1589 }
1590
1591 const int c1 = base64val(buf[0]);
1592 const int c2 = base64val(buf[1]);
1593
1594 /* first char */
1595 ch = (c1 << 2) | (c2 >> 4);
1596
1597 if (cr && (ch != '\n'))
1598 bufi[l++] = '\r';
1599
1600 cr = false;
1601
1602 if (istext && (ch == '\r'))
1603 cr = true;
1604 else
1605 bufi[l++] = ch;
1606
1607 /* second char */
1608 if (buf[2] == '=')
1609 break;
1610 const int c3 = base64val(buf[2]);
1611 ch = ((c2 & 0xf) << 4) | (c3 >> 2);
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 /* third char */
1624 if (buf[3] == '=')
1625 break;
1626 const int c4 = base64val(buf[3]);
1627 ch = ((c3 & 0x3) << 6) | c4;
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 if ((l + 8) >= sizeof(bufi))
1640 convert_to_state(cd, bufi, &l, state);
1641 }
1642
1643 if (cr)
1644 bufi[l++] = '\r';
1645
1646 convert_to_state(cd, bufi, &l, state);
1647 convert_to_state(cd, 0, 0, state);
1648
1649 state_reset_prefix(state);
1650}
#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 1659 of file handler.c.

1660{
1661 if (!b || !state)
1662 return -1;
1663
1664 bool plaintext = false;
1665 handler_t handler = NULL;
1666 handler_t encrypted_handler = NULL;
1667 int rc = 0;
1668 static unsigned short recurse_level = 0;
1669
1670 const int oflags = state->flags;
1671 const bool is_attachment_display = (oflags & STATE_DISPLAY_ATTACH);
1672
1673 if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1674 {
1675 mutt_debug(LL_DEBUG1, "recurse level too deep. giving up\n");
1676 return 1;
1677 }
1678 recurse_level++;
1679
1680 /* first determine which handler to use to process this part */
1681
1682 if (is_autoview(b))
1683 {
1684 handler = autoview_handler;
1685 state->flags &= ~STATE_CHARCONV;
1686 }
1687 else if (b->type == TYPE_TEXT)
1688 {
1689 if (mutt_istr_equal("plain", b->subtype))
1690 {
1691 const bool c_reflow_text = cs_subset_bool(NeoMutt->sub, "reflow_text");
1692 /* avoid copying this part twice since removing the transfer-encoding is
1693 * the only operation needed. */
1695 {
1696 encrypted_handler = crypt_pgp_application_handler;
1697 handler = encrypted_handler;
1698 }
1699 else if (c_reflow_text &&
1700 mutt_istr_equal("flowed", mutt_param_get(&b->parameter, "format")))
1701 {
1702 handler = rfc3676_handler;
1703 }
1704 else
1705 {
1706 handler = text_plain_handler;
1707 }
1708 }
1709 else if (mutt_istr_equal("enriched", b->subtype))
1710 {
1711 handler = text_enriched_handler;
1712 }
1713 else /* text body type without a handler */
1714 {
1715 plaintext = false;
1716 }
1717 }
1718 else if (b->type == TYPE_MESSAGE)
1719 {
1720 if (mutt_is_message_type(b->type, b->subtype))
1721 handler = message_handler;
1722 else if (mutt_istr_equal("delivery-status", b->subtype))
1723 plaintext = true;
1724 else if (mutt_istr_equal("external-body", b->subtype))
1725 handler = external_body_handler;
1726 }
1727 else if (b->type == TYPE_MULTIPART)
1728 {
1729 const char *const c_show_multipart_alternative = cs_subset_string(NeoMutt->sub, "show_multipart_alternative");
1730 if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1731 mutt_istr_equal("alternative", b->subtype))
1732 {
1733 handler = alternative_handler;
1734 }
1735 else if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1736 mutt_istr_equal("multilingual", b->subtype))
1737 {
1738 handler = multilingual_handler;
1739 }
1740 else if ((WithCrypto != 0) && mutt_istr_equal("signed", b->subtype))
1741 {
1742 if (!mutt_param_get(&b->parameter, "protocol"))
1743 mutt_error(_("Error: multipart/signed has no protocol"));
1744 else if (state->flags & STATE_VERIFY)
1745 handler = mutt_signed_handler;
1746 }
1748 {
1749 encrypted_handler = valid_pgp_encrypted_handler;
1750 handler = encrypted_handler;
1751 }
1753 {
1754 encrypted_handler = malformed_pgp_encrypted_handler;
1755 handler = encrypted_handler;
1756 }
1757
1758 if (!handler)
1759 handler = multipart_handler;
1760
1761 if ((b->encoding != ENC_7BIT) && (b->encoding != ENC_8BIT) && (b->encoding != ENC_BINARY))
1762 {
1763 mutt_debug(LL_DEBUG1, "Bad encoding type %d for multipart entity, assuming 7 bit\n",
1764 b->encoding);
1765 b->encoding = ENC_7BIT;
1766 }
1767 }
1768 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1769 {
1770 if (OptDontHandlePgpKeys && mutt_istr_equal("pgp-keys", b->subtype))
1771 {
1772 /* pass raw part through for key extraction */
1773 plaintext = true;
1774 }
1775 else if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b))
1776 {
1777 encrypted_handler = crypt_pgp_application_handler;
1778 handler = encrypted_handler;
1779 }
1780 else if (((WithCrypto & APPLICATION_SMIME) != 0) && mutt_is_application_smime(b))
1781 {
1782 encrypted_handler = crypt_smime_application_handler;
1783 handler = encrypted_handler;
1784 }
1785 }
1786
1787 if ((plaintext || handler) && (is_attachment_display || !mutt_prefer_as_attachment(b)))
1788 {
1789 /* only respect disposition == attachment if we're not
1790 * displaying from the attachment menu (i.e. pager) */
1791 /* Prevent encrypted attachments from being included in replies
1792 * unless $include_encrypted is set. */
1793 const bool c_include_encrypted = cs_subset_bool(NeoMutt->sub, "include_encrypted");
1794 if ((state->flags & STATE_REPLYING) && (state->flags & STATE_FIRSTDONE) &&
1795 encrypted_handler && !c_include_encrypted)
1796 {
1797 goto cleanup;
1798 }
1799
1800 rc = run_decode_and_handler(b, state, handler, plaintext);
1801 }
1802 else if (state->flags & STATE_DISPLAY)
1803 {
1804 /* print hint to use attachment menu for disposition == attachment
1805 * if we're not already being called from there */
1806 const bool c_honor_disposition = cs_subset_bool(NeoMutt->sub, "honor_disposition");
1807 struct Buffer *msg = buf_pool_get();
1808
1809 if (is_attachment_display)
1810 {
1811 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1812 {
1813 buf_strcpy(msg, _("[-- This is an attachment --]\n"));
1814 }
1815 else
1816 {
1817 /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1818 buf_printf(msg, _("[-- %s/%s is unsupported --]\n"), BODY_TYPE(b), b->subtype);
1819 }
1820 }
1821 else
1822 {
1823 struct Buffer *keystroke = buf_pool_get();
1824 if (keymap_expand_key(km_find_func(MdPager, OP_VIEW_ATTACHMENTS), keystroke))
1825 {
1826 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1827 {
1828 /* L10N: %s expands to a keystroke/key binding, e.g. 'v'. */
1829 buf_printf(msg, _("[-- This is an attachment (use '%s' to view this part) --]\n"),
1830 buf_string(keystroke));
1831 }
1832 else
1833 {
1834 /* L10N: %s/%s is a MIME type, e.g. "text/plain".
1835 The last %s expands to a keystroke/key binding, e.g. 'v'. */
1836 buf_printf(msg, _("[-- %s/%s is unsupported (use '%s' to view this part) --]\n"),
1837 BODY_TYPE(b), b->subtype, buf_string(keystroke));
1838 }
1839 }
1840 else
1841 {
1842 if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1843 {
1844 buf_strcpy(msg, _("[-- This is an attachment (need 'view-attachments' bound to key) --]\n"));
1845 }
1846 else
1847 {
1848 /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1849 buf_printf(msg, _("[-- %s/%s is unsupported (need 'view-attachments' bound to key) --]\n"),
1850 BODY_TYPE(b), b->subtype);
1851 }
1852 }
1853 buf_pool_release(&keystroke);
1854 }
1855 state_mark_attach(state);
1856 state_printf(state, "%s", buf_string(msg));
1857 buf_pool_release(&msg);
1858 }
1859
1860cleanup:
1861 recurse_level--;
1862 state->flags = oflags | (state->flags & STATE_FIRSTDONE);
1863 if (rc != 0)
1864 {
1865 mutt_debug(LL_DEBUG1, "Bailing on attachment of type %s/%s\n", BODY_TYPE(b),
1866 NONULL(b->subtype));
1867 }
1868
1869 return rc;
1870}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
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:609
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition crypt.c:467
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:504
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:548
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1506
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:236
static int alternative_handler(struct Body *b_email, struct State *state)
Handler for multipart alternative emails - Implements handler_t -.
Definition handler.c:950
int text_enriched_handler(struct Body *b_email, struct State *state)
Handler for enriched text - Implements handler_t -.
Definition enriched.c:469
static int text_plain_handler(struct Body *b_email, struct State *state)
Handler for plain text - Implements handler_t -.
Definition handler.c:694
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:541
static int external_body_handler(struct Body *b_email, struct State *state)
Handler for external-body emails - Implements handler_t -.
Definition handler.c:779
int rfc3676_handler(struct Body *b_email, struct State *state)
Handler for format=flowed - Implements handler_t -.
Definition rfc3676.c:327
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:1525
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:1496
static int message_handler(struct Body *b_email, struct State *state)
Handler for message/rfc822 body parts - Implements handler_t -.
Definition handler.c:721
static int multipart_handler(struct Body *b_email, struct State *state)
Handler for multipart emails - Implements handler_t -.
Definition handler.c:1249
static int multilingual_handler(struct Body *b_email, struct State *state)
Handler for multi-lingual emails - Implements handler_t -.
Definition handler.c:1141
int mutt_signed_handler(struct Body *b_email, struct State *state)
Handler for "multipart/signed" - Implements handler_t -.
Definition crypt.c:1241
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition handler.c:491
bool mutt_prefer_as_attachment(struct Body *b)
Do we want this part as an attachment?
Definition handler.c:1877
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:1338
bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition keymap.c:229
struct Keymap * km_find_func(const struct MenuDefinition *md, int func)
Find a function's mapping in a Menu.
Definition menu.c:157
@ 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
#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 STATE_CHARCONV
Do character set conversions.
Definition state.h:37
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:99
#define WithCrypto
Definition lib.h:124
struct MenuDefinition * MdPager
Pager Menu Definition.
Definition functions.c:64
unsigned int disposition
content-disposition, ContentDisposition
Definition body.h:42
+ 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 1877 of file handler.c.

1878{
1879 if (!mutt_can_decode(b))
1880 return true;
1881
1882 if (b->disposition != DISP_ATTACH)
1883 return false;
1884
1885 return cs_subset_bool(NeoMutt->sub, "honor_disposition");
1886}
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition handler.c:1893
+ 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 1893 of file handler.c.

1894{
1895 if (is_autoview(b))
1896 return true;
1897 if (b->type == TYPE_TEXT)
1898 return true;
1899 if (b->type == TYPE_MESSAGE)
1900 return true;
1901 if (b->type == TYPE_MULTIPART)
1902 {
1903 if (WithCrypto)
1904 {
1905 if (mutt_istr_equal(b->subtype, "signed") || mutt_istr_equal(b->subtype, "encrypted"))
1906 {
1907 return true;
1908 }
1909 }
1910
1911 for (struct Body *part = b->parts; part; part = part->next)
1912 {
1913 if (mutt_can_decode(part))
1914 return true;
1915 }
1916 }
1917 else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1918 {
1920 return true;
1922 return true;
1923 }
1924
1925 return false;
1926}
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 1933 of file handler.c.

1934{
1935 int istext = mutt_is_text_part(b) && (b->disposition == DISP_INLINE);
1936 iconv_t cd = ICONV_T_INVALID;
1937
1938 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1939 {
1940 return;
1941 }
1942
1943 if (istext && (b->charset || (state->flags & STATE_CHARCONV)))
1944 {
1945 const char *charset = b->charset;
1946 if (!charset)
1947 {
1948 charset = mutt_param_get(&b->parameter, "charset");
1949 if (!charset && !slist_is_empty(cc_assumed_charset()))
1951 }
1952 if (charset && cc_charset())
1954 }
1955
1956 switch (b->encoding)
1957 {
1959 decode_quoted(state, b->length,
1960 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1962 cd);
1963 break;
1964 case ENC_BASE64:
1965 mutt_decode_base64(state, b->length,
1966 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1968 cd);
1969 break;
1970 case ENC_UUENCODED:
1971 decode_uuencoded(state, b->length,
1972 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1974 cd);
1975 break;
1976 default:
1977 decode_xbit(state, b->length,
1978 istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1980 cd);
1981 break;
1982 }
1983}
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:378
void mutt_decode_base64(struct State *state, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition handler.c:1560
static void decode_quoted(struct State *state, long len, bool istext, iconv_t cd)
Decode an attachment encoded with quoted-printable.
Definition handler.c:314
static void decode_xbit(struct State *state, long len, bool istext, iconv_t cd)
Decode xbit-encoded text.
Definition handler.c:175
@ 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:580
const char * mutt_ch_get_default_charset(const struct Slist *const assumed_charset)
Get the default character set.
Definition charset.c:451
#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: