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

Decide how to display email content. More...

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

Go to the source code of this file.

Macros

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

Typedefs

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

Functions

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

Detailed Description

Decide how to display email content.

Authors
  • Michael R. Elkins

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

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

Definition in file handler.c.

Macro Definition Documentation

◆ BUFI_SIZE

#define BUFI_SIZE   1000

Definition at line 63 of file handler.c.

◆ BUFO_SIZE

#define BUFO_SIZE   2000

Definition at line 64 of file handler.c.

◆ TXT_HTML

#define TXT_HTML   1

Definition at line 66 of file handler.c.

◆ TXT_PLAIN

#define TXT_PLAIN   2

Definition at line 67 of file handler.c.

◆ TXT_ENRICHED

#define TXT_ENRICHED   3

Definition at line 68 of file handler.c.

Typedef Documentation

◆ handler_t

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

Definition at line 80 of file handler.c.

Function Documentation

◆ print_part_line()

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

Print a separator for the Mime part.

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

Definition at line 88 of file handler.c.

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

◆ convert_to_state()

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

Convert text and write it to a file.

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

Definition at line 115 of file handler.c.

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

◆ decode_xbit()

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

Decode xbit-encoded text.

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

Definition at line 164 of file handler.c.

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

◆ qp_decode_triple()

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

Decode a quoted-printable triplet.

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

Definition at line 209 of file handler.c.

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

◆ qp_decode_line()

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

Decode a line of quoted-printable text.

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

Definition at line 233 of file handler.c.

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

◆ decode_quoted()

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

Decode an attachment encoded with quoted-printable.

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

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

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

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

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

Definition at line 301 of file handler.c.

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

◆ decode_byte()

static unsigned char decode_byte ( char  ch)
static

Decode a uuencoded byte.

Parameters
chCharacter to decode
Return values
numDecoded value

Definition at line 351 of file handler.c.

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

◆ decode_uuencoded()

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

Decode uuencoded text.

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

Definition at line 365 of file handler.c.

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

◆ is_mmnoask()

static bool is_mmnoask ( const char *  buf)
static

Metamail compatibility: should the attachment be autoviewed?

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

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

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

Definition at line 427 of file handler.c.

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

◆ is_autoview()

static bool is_autoview ( struct Body b)
static

Should email body be filtered by mailcap.

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

Definition at line 478 of file handler.c.

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

◆ run_decode_and_handler()

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

Run an appropriate decoder for an email.

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

Definition at line 1294 of file handler.c.

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

◆ mutt_decode_base64()

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

Decode base64-encoded text.

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

Definition at line 1498 of file handler.c.

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

◆ mutt_body_handler()

int mutt_body_handler ( struct Body b,
struct State s 
)

Handler for the Body of an email.

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

Definition at line 1597 of file handler.c.

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

◆ mutt_prefer_as_attachment()

bool mutt_prefer_as_attachment ( struct Body b)

Do we want this part as an attachment?

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

Definition at line 1811 of file handler.c.

1812 {
1813  if (!mutt_can_decode(b))
1814  return true;
1815 
1816  if (b->disposition != DISP_ATTACH)
1817  return false;
1818 
1819  return cs_subset_bool(NeoMutt->sub, "honor_disposition");
1820 }
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1827
+ 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 1827 of file handler.c.

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

◆ mutt_decode_attachment()

void mutt_decode_attachment ( struct Body b,
struct State s 
)

Decode an email's attachment.

Parameters
bBody of the email
sState of text being processed

Definition at line 1867 of file handler.c.

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