NeoMutt  2021-02-05-666-ge300cd
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 <sys/stat.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 "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_attach.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)
 Manage a PGP or S/MIME encrypted MIME part. More...
 

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_can_decode (struct Body *a)
 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 64 of file handler.c.

◆ BUFO_SIZE

#define BUFO_SIZE   2000

Definition at line 65 of file handler.c.

◆ TXT_HTML

#define TXT_HTML   1

Definition at line 67 of file handler.c.

◆ TXT_PLAIN

#define TXT_PLAIN   2

Definition at line 68 of file handler.c.

◆ TXT_ENRICHED

#define TXT_ENRICHED   3

Definition at line 69 of file handler.c.

Typedef Documentation

◆ handler_t

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

Manage a PGP or S/MIME encrypted MIME part.

Parameters
bBody of the email
sState of text being processed
Return values
0Success
-1Error

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

87 {
88  char length[5];
89  mutt_str_pretty_size(length, sizeof(length), b->length);
91  char *charset = mutt_param_get(&b->parameter, "charset");
92  if (n == 0)
93  {
94  state_printf(s, _("[-- Type: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
95  TYPE(b), b->subtype, charset ? "; charset=" : "",
96  charset ? charset : "", ENCODING(b->encoding), length);
97  }
98  else
99  {
100  state_printf(s, _("[-- Alternative Type #%d: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
101  n, TYPE(b), b->subtype, charset ? "; charset=" : "",
102  charset ? charset : "", ENCODING(b->encoding), length);
103  }
104 }
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:187
#define _(a)
Definition: message.h:28
#define ENCODING(x)
Definition: mime.h:92
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
char * subtype
content-type subtype
Definition: body.h:37
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1679
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:73
#define TYPE(body)
Definition: mime.h:89
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
+ 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 113 of file handler.c.

114 {
115  char bufo[BUFO_SIZE];
116  const char *ib = NULL;
117  char *ob = NULL;
118  size_t ibl, obl;
119 
120  if (!bufi)
121  {
122  if (cd != (iconv_t) (-1))
123  {
124  ob = bufo;
125  obl = sizeof(bufo);
126  iconv(cd, NULL, NULL, &ob, &obl);
127  if (ob != bufo)
128  state_prefix_put(s, bufo, ob - bufo);
129  }
130  return;
131  }
132 
133  if (cd == (iconv_t) (-1))
134  {
135  state_prefix_put(s, bufi, *l);
136  *l = 0;
137  return;
138  }
139 
140  ib = bufi;
141  ibl = *l;
142  while (true)
143  {
144  ob = bufo;
145  obl = sizeof(bufo);
146  mutt_ch_iconv(cd, &ib, &ibl, &ob, &obl, 0, "?", NULL);
147  if (ob == bufo)
148  break;
149  state_prefix_put(s, bufo, ob - bufo);
150  }
151  memmove(bufi, ib, ibl);
152  *l = ibl;
153 }
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:622
void state_prefix_put(struct State *s, const char *buf, size_t buflen)
Write a prefixed fixed-string to the State.
Definition: state.c:205
#define BUFO_SIZE
Definition: handler.c:65
+ 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 162 of file handler.c.

163 {
164  if (!istext)
165  {
166  mutt_file_copy_bytes(s->fp_in, s->fp_out, len);
167  return;
168  }
169 
170  state_set_prefix(s);
171 
172  int c;
173  char bufi[BUFI_SIZE];
174  size_t l = 0;
175  while (((c = fgetc(s->fp_in)) != EOF) && len--)
176  {
177  if ((c == '\r') && len)
178  {
179  const int ch = fgetc(s->fp_in);
180  if (ch == '\n')
181  {
182  c = ch;
183  len--;
184  }
185  else
186  ungetc(ch, s->fp_in);
187  }
188 
189  bufi[l++] = c;
190  if (l == sizeof(bufi))
191  convert_to_state(cd, bufi, &l, s);
192  }
193 
194  convert_to_state(cd, bufi, &l, s);
195  convert_to_state(cd, 0, 0, s);
196 
198 }
#define state_reset_prefix(state)
Definition: state.h:54
FILE * fp_out
File to write to.
Definition: state.h:47
FILE * fp_in
File to read from.
Definition: state.h:46
#define BUFI_SIZE
Definition: handler.c:64
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:241
#define state_set_prefix(state)
Definition: state.h:53
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:113
+ 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 207 of file handler.c.

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

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

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

350 {
351  if ((ch < 32) || (ch > 95))
352  return 0;
353  return ch - 32;
354 }
+ 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 363 of file handler.c.

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

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

476 {
477  char type[256];
478  bool is_av = false;
479 
480  snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
481 
482  const bool c_implicit_autoview =
483  cs_subset_bool(NeoMutt->sub, "implicit_autoview");
484  if (c_implicit_autoview)
485  {
486  /* $implicit_autoview is essentially the same as "auto_view *" */
487  is_av = true;
488  }
489  else
490  {
491  /* determine if this type is on the user's auto_view list */
492  mutt_check_lookup_list(b, type, sizeof(type));
493  struct ListNode *np = NULL;
494  STAILQ_FOREACH(np, &AutoViewList, entries)
495  {
496  int i = mutt_str_len(np->data) - 1;
497  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
498  mutt_istrn_equal(type, np->data, i)) ||
499  mutt_istr_equal(type, np->data))
500  {
501  is_av = true;
502  break;
503  }
504  }
505 
506  if (is_mmnoask(type))
507  is_av = true;
508  }
509 
510  /* determine if there is a mailcap entry suitable for auto_view
511  *
512  * @warning type is altered by this call as a result of 'mime_lookup' support */
513  if (is_av)
514  return mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_AUTOVIEW);
515 
516  return false;
517 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Mailcap autoview field.
Definition: mailcap.h:60
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:621
Container for Accounts, Notifications.
Definition: neomutt.h:36
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:475
static bool is_mmnoask(const char *buf)
Metamail compatibility: should the attachment be autoviewed?
Definition: handler.c:424
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TYPE(body)
Definition: mime.h:89
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
char * data
String.
Definition: list.h:36
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:335
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
A List node for strings.
Definition: list.h:34
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:144
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ autoview_handler()

static int autoview_handler ( struct Body a,
struct State s 
)
static

Handler for autoviewable attachments - Implements handler_t.

Definition at line 522 of file handler.c.

523 {
524  struct MailcapEntry *entry = mailcap_entry_new();
525  char buf[1024];
526  char type[256];
527  struct Buffer *cmd = mutt_buffer_pool_get();
528  struct Buffer *tempfile = mutt_buffer_pool_get();
529  char *fname = NULL;
530  FILE *fp_in = NULL;
531  FILE *fp_out = NULL;
532  FILE *fp_err = NULL;
533  pid_t pid;
534  int rc = 0;
535 
536  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
537  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_AUTOVIEW);
538 
539  fname = mutt_str_dup(a->filename);
540  mutt_file_sanitize_filename(fname, true);
541  mailcap_expand_filename(entry->nametemplate, fname, tempfile);
542  FREE(&fname);
543 
544  if (entry->command)
545  {
546  mutt_buffer_strcpy(cmd, entry->command);
547 
548  /* mailcap_expand_command returns 0 if the file is required */
549  bool piped = mailcap_expand_command(a, mutt_buffer_string(tempfile), type, cmd);
550 
551  if (s->flags & MUTT_DISPLAY)
552  {
554  state_printf(s, _("[-- Autoview using %s --]\n"), mutt_buffer_string(cmd));
555  mutt_message(_("Invoking autoview command: %s"), mutt_buffer_string(cmd));
556  }
557 
558  fp_in = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
559  if (!fp_in)
560  {
561  mutt_perror("fopen");
562  mailcap_entry_free(&entry);
563  rc = -1;
564  goto cleanup;
565  }
566 
567  mutt_file_copy_bytes(s->fp_in, fp_in, a->length);
568 
569  if (piped)
570  {
571  unlink(mutt_buffer_string(tempfile));
572  fflush(fp_in);
573  rewind(fp_in);
574  pid = filter_create_fd(mutt_buffer_string(cmd), NULL, &fp_out, &fp_err,
575  fileno(fp_in), -1, -1);
576  }
577  else
578  {
579  mutt_file_fclose(&fp_in);
580  pid = filter_create(mutt_buffer_string(cmd), NULL, &fp_out, &fp_err);
581  }
582 
583  if (pid < 0)
584  {
585  mutt_perror(_("Can't create filter"));
586  if (s->flags & MUTT_DISPLAY)
587  {
589  state_printf(s, _("[-- Can't run %s. --]\n"), mutt_buffer_string(cmd));
590  }
591  rc = -1;
592  goto bail;
593  }
594 
595  if (s->prefix)
596  {
597  /* Remove ansi and formatting from autoview output in replies only. The
598  * user may want to see the formatting in the pager, but it shouldn't be
599  * in their quoted reply text too. */
600  struct Buffer *stripped = mutt_buffer_pool_get();
601  while (fgets(buf, sizeof(buf), fp_out))
602  {
603  mutt_buffer_strip_formatting(stripped, buf, false);
604  state_puts(s, s->prefix);
605  state_puts(s, mutt_buffer_string(stripped));
606  }
607  mutt_buffer_pool_release(&stripped);
608 
609  /* check for data on stderr */
610  if (fgets(buf, sizeof(buf), fp_err))
611  {
612  if (s->flags & MUTT_DISPLAY)
613  {
615  state_printf(s, _("[-- Autoview stderr of %s --]\n"), mutt_buffer_string(cmd));
616  }
617 
618  state_puts(s, s->prefix);
619  state_puts(s, buf);
620  while (fgets(buf, sizeof(buf), fp_err))
621  {
622  state_puts(s, s->prefix);
623  state_puts(s, buf);
624  }
625  }
626  }
627  else
628  {
629  mutt_file_copy_stream(fp_out, s->fp_out);
630  /* Check for stderr messages */
631  if (fgets(buf, sizeof(buf), fp_err))
632  {
633  if (s->flags & MUTT_DISPLAY)
634  {
636  state_printf(s, _("[-- Autoview stderr of %s --]\n"), mutt_buffer_string(cmd));
637  }
638 
639  state_puts(s, buf);
640  mutt_file_copy_stream(fp_err, s->fp_out);
641  }
642  }
643 
644  bail:
645  mutt_file_fclose(&fp_out);
646  mutt_file_fclose(&fp_err);
647 
648  filter_wait(pid);
649  if (piped)
650  mutt_file_fclose(&fp_in);
651  else
653 
654  if (s->flags & MUTT_DISPLAY)
656  }
657 
658 cleanup:
659  mailcap_entry_free(&entry);
660 
662  mutt_buffer_pool_release(&tempfile);
663 
664  return rc;
665 }
A mailcap entry.
Definition: mailcap.h:35
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:187
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:437
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
void mutt_buffer_strip_formatting(struct Buffer *dest, const char *src, bool strip_markers)
Removes ANSI and backspace formatting.
Definition: dlg_pager.c:1395
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define state_puts(STATE, STR)
Definition: state.h:55
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Mailcap autoview field.
Definition: mailcap.h:60
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
String manipulation buffer.
Definition: buffer.h:33
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
#define mutt_perror(...)
Definition: logging.h:89
FILE * fp_in
File to read from.
Definition: state.h:46
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:475
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:67
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:545
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
char * command
Definition: mailcap.h:37
char * subtype
content-type subtype
Definition: body.h:37
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:618
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:446
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:241
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:73
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * nametemplate
Definition: mailcap.h:43
#define TYPE(body)
Definition: mime.h:89
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ text_plain_handler()

static int text_plain_handler ( struct Body b,
struct State s 
)
static

Handler for plain text - Implements handler_t.

Return values
0Always

When generating format=flowed ($text_flowed is set) from format=fixed, strip all trailing spaces to improve interoperability; if $text_flowed is unset, simply verbatim copy input.

Definition at line 675 of file handler.c.

676 {
677  char *buf = NULL;
678  size_t sz = 0;
679 
680  while ((buf = mutt_file_read_line(buf, &sz, s->fp_in, NULL, MUTT_RL_NO_FLAGS)))
681  {
682  const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
683  if (!mutt_str_equal(buf, "-- ") && c_text_flowed)
684  {
685  size_t len = mutt_str_len(buf);
686  while ((len > 0) && (buf[len - 1] == ' '))
687  buf[--len] = '\0';
688  }
689  if (s->prefix)
690  state_puts(s, s->prefix);
691  state_puts(s, buf);
692  state_putc(s, '\n');
693  }
694 
695  FREE(&buf);
696  return 0;
697 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define state_puts(STATE, STR)
Definition: state.h:55
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:667
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
#define FREE(x)
Definition: memory.h:40
#define state_putc(STATE, STR)
Definition: state.h:56
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:

◆ message_handler()

static int message_handler ( struct Body a,
struct State s 
)
static

Handler for message/rfc822 body parts - Implements handler_t.

Definition at line 702 of file handler.c.

703 {
704  struct stat st;
705  struct Body *b = NULL;
706  LOFF_T off_start;
707  int rc = 0;
708 
709  off_start = ftello(s->fp_in);
710  if (off_start < 0)
711  return -1;
712 
713  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
714  (a->encoding == ENC_UUENCODED))
715  {
716  fstat(fileno(s->fp_in), &st);
717  b = mutt_body_new();
718  b->length = (LOFF_T) st.st_size;
720  }
721  else
722  b = a;
723 
724  if (b->parts)
725  {
726  CopyHeaderFlags chflags = CH_DECODE | CH_FROM;
727  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
728  if ((s->flags & MUTT_WEED) || ((s->flags & (MUTT_DISPLAY | MUTT_PRINTING)) && c_weed))
729  chflags |= CH_WEED | CH_REORDER;
730  if (s->prefix)
731  chflags |= CH_PREFIX;
732  if (s->flags & MUTT_DISPLAY)
733  chflags |= CH_DISPLAY;
734 
735  mutt_copy_hdr(s->fp_in, s->fp_out, off_start, b->parts->offset, chflags, s->prefix, 0);
736 
737  if (s->prefix)
738  state_puts(s, s->prefix);
739  state_putc(s, '\n');
740 
741  rc = mutt_body_handler(b->parts, s);
742  }
743 
744  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
745  (a->encoding == ENC_UUENCODED))
746  {
747  mutt_body_free(&b);
748  }
749 
750  return rc;
751 }
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define state_puts(STATE, STR)
Definition: state.h:55
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
FILE * fp_out
File to write to.
Definition: state.h:47
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
The body of an email.
Definition: body.h:34
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
parse a Message/RFC822 body
Definition: parse.c:1693
#define CH_WEED
Weed the headers?
Definition: copy.h:53
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:59
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
#define CH_DISPLAY
Display result to user.
Definition: copy.h:70
#define MUTT_WEED
Weed headers even when not in display mode.
Definition: state.h:35
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:104
Quoted-printable text.
Definition: mime.h:51
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1604
#define state_putc(STATE, STR)
Definition: state.h:56
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:57
UUEncoded text.
Definition: mime.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ external_body_handler()

static int external_body_handler ( struct Body b,
struct State s 
)
static

Handler for external-body emails - Implements handler_t.

Definition at line 756 of file handler.c.

757 {
758  const char *str = NULL;
759  char strbuf[1024];
760 
761  const char *access_type = mutt_param_get(&b->parameter, "access-type");
762  if (!access_type)
763  {
764  if (s->flags & MUTT_DISPLAY)
765  {
767  state_puts(s, _("[-- Error: message/external-body has no access-type "
768  "parameter --]\n"));
769  return 0;
770  }
771  else
772  return -1;
773  }
774 
775  const char *expiration = mutt_param_get(&b->parameter, "expiration");
776  time_t expire;
777  if (expiration)
778  expire = mutt_date_parse_date(expiration, NULL);
779  else
780  expire = -1;
781 
782  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
783  if (mutt_istr_equal(access_type, "x-mutt-deleted"))
784  {
785  if (s->flags & (MUTT_DISPLAY | MUTT_PRINTING))
786  {
787  char pretty_size[10];
788  char *length = mutt_param_get(&b->parameter, "length");
789  if (length)
790  {
791  long size = strtol(length, NULL, 10);
792  mutt_str_pretty_size(pretty_size, sizeof(pretty_size), size);
793  if (expire != -1)
794  {
795  str = ngettext(
796  /* L10N: If the translation of this string is a multi line string, then
797  each line should start with "[-- " and end with " --]".
798  The first "%s/%s" is a MIME type, e.g. "text/plain". The last %s
799  expands to a date as returned by `mutt_date_parse_date()`.
800 
801  Note: The size argument printed is not the actual number as passed
802  to gettext but the prettified version, e.g. size = 2048 will be
803  printed as 2K. Your language might be sensitive to that: For
804  example although '1K' and '1024' represent the same number your
805  language might inflect the noun 'byte' differently.
806 
807  Sadly, we can't do anything about that at the moment besides
808  passing the precise size in bytes. If you are interested the
809  function responsible for the prettification is
810  mutt_str_pretty_size() in mutt/string.c. */
811  "[-- This %s/%s attachment (size %s byte) has been deleted --]\n"
812  "[-- on %s --]\n",
813  "[-- This %s/%s attachment (size %s bytes) has been deleted --]\n"
814  "[-- on %s --]\n",
815  size);
816  }
817  else
818  {
819  str = ngettext(
820  /* L10N: If the translation of this string is a multi line string, then
821  each line should start with "[-- " and end with " --]".
822  The first "%s/%s" is a MIME type, e.g. "text/plain".
823 
824  Note: The size argument printed is not the actual number as passed
825  to gettext but the prettified version, e.g. size = 2048 will be
826  printed as 2K. Your language might be sensitive to that: For
827  example although '1K' and '1024' represent the same number your
828  language might inflect the noun 'byte' differently.
829 
830  Sadly, we can't do anything about that at the moment besides
831  passing the precise size in bytes. If you are interested the
832  function responsible for the prettification is
833  mutt_str_pretty_size() in mutt/string.c. */
834  "[-- This %s/%s attachment (size %s byte) has been deleted --]\n",
835  "[-- This %s/%s attachment (size %s bytes) has been deleted "
836  "--]\n",
837  size);
838  }
839  }
840  else
841  {
842  pretty_size[0] = '\0';
843  if (expire != -1)
844  {
845  /* L10N: If the translation of this string is a multi line string, then
846  each line should start with "[-- " and end with " --]".
847  The first "%s/%s" is a MIME type, e.g. "text/plain". The last %s
848  expands to a date as returned by `mutt_date_parse_date()`.
849 
850  Caution: Argument three %3$ is also defined but should not be used
851  in this translation! */
852  str = _("[-- This %s/%s attachment has been deleted --]\n[-- on %4$s "
853  "--]\n");
854  }
855  else
856  {
857  /* L10N: If the translation of this string is a multi line string, then
858  each line should start with "[-- " and end with " --]".
859  The first "%s/%s" is a MIME type, e.g. "text/plain". */
860  str = _("[-- This %s/%s attachment has been deleted --]\n");
861  }
862  }
863 
864  snprintf(strbuf, sizeof(strbuf), str, TYPE(b->parts), b->parts->subtype,
865  pretty_size, expiration);
866  state_attach_puts(s, strbuf);
867  if (b->parts->filename)
868  {
870  state_printf(s, _("[-- name: %s --]\n"), b->parts->filename);
871  }
872 
873  CopyHeaderFlags chflags = CH_DECODE;
874  if (c_weed)
875  chflags |= CH_WEED | CH_REORDER;
876 
877  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
878  chflags, NULL, 0);
879  }
880  }
881  else if (expiration && (expire < mutt_date_epoch()))
882  {
883  if (s->flags & MUTT_DISPLAY)
884  {
885  /* L10N: If the translation of this string is a multi line string, then
886  each line should start with "[-- " and end with " --]".
887  The "%s/%s" is a MIME type, e.g. "text/plain". */
888  snprintf(strbuf, sizeof(strbuf), _("[-- This %s/%s attachment is not included, --]\n[-- and the indicated external source has --]\n[-- expired. --]\n"),
889  TYPE(b->parts), b->parts->subtype);
890  state_attach_puts(s, strbuf);
891 
893  if (c_weed)
894  chflags |= CH_WEED | CH_REORDER;
895 
896  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
897  chflags, NULL, 0);
898  }
899  }
900  else
901  {
902  if (s->flags & MUTT_DISPLAY)
903  {
904  /* L10N: If the translation of this string is a multi line string, then
905  each line should start with "[-- " and end with " --]".
906  The "%s/%s" is a MIME type, e.g. "text/plain". The %s after
907  access-type is an access-type as defined by the MIME RFCs, e.g. "FTP",
908  "LOCAL-FILE", "MAIL-SERVER". */
909  snprintf(strbuf, sizeof(strbuf), _("[-- This %s/%s attachment is not included, --]\n[-- and the indicated access-type %s is unsupported --]\n"),
910  TYPE(b->parts), b->parts->subtype, access_type);
911  state_attach_puts(s, strbuf);
912 
914  if (c_weed)
915  chflags |= CH_WEED | CH_REORDER;
916 
917  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
918  chflags, NULL, 0);
919  }
920  }
921 
922  return 0;
923 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:187
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define state_puts(STATE, STR)
Definition: state.h:55
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:456
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
#define CH_WEED
Weed the headers?
Definition: copy.h:53
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:59
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1679
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
#define CH_DISPLAY
Display result to user.
Definition: copy.h:70
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:73
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:104
#define TYPE(body)
Definition: mime.h:89
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:104
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alternative_handler()

static int alternative_handler ( struct Body a,
struct State s 
)
static

Handler for multipart alternative emails - Implements handler_t.

Definition at line 928 of file handler.c.

929 {
930  struct Body *const head = a;
931  struct Body *choice = NULL;
932  struct Body *b = NULL;
933  bool mustfree = false;
934  int rc = 0;
935 
936  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
937  (a->encoding == ENC_UUENCODED))
938  {
939  struct stat st;
940  mustfree = true;
941  fstat(fileno(s->fp_in), &st);
942  b = mutt_body_new();
943  b->length = (long) st.st_size;
944  b->parts =
945  mutt_parse_multipart(s->fp_in, mutt_param_get(&a->parameter, "boundary"),
946  (long) st.st_size, mutt_istr_equal("digest", a->subtype));
947  }
948  else
949  b = a;
950 
951  a = b;
952 
953  /* First, search list of preferred types */
954  struct ListNode *np = NULL;
955  STAILQ_FOREACH(np, &AlternativeOrderList, entries)
956  {
957  int btlen; /* length of basetype */
958  bool wild; /* do we have a wildcard to match all subtypes? */
959 
960  char *c = strchr(np->data, '/');
961  if (c)
962  {
963  wild = ((c[1] == '*') && (c[2] == '\0'));
964  btlen = c - np->data;
965  }
966  else
967  {
968  wild = true;
969  btlen = mutt_str_len(np->data);
970  }
971 
972  if (a->parts)
973  b = a->parts;
974  else
975  b = a;
976  while (b)
977  {
978  const char *bt = TYPE(b);
979  if (mutt_istrn_equal(bt, np->data, btlen) && (bt[btlen] == 0))
980  {
981  /* the basetype matches */
982  if (wild || mutt_istr_equal(np->data + btlen + 1, b->subtype))
983  {
984  choice = b;
985  }
986  }
987  b = b->next;
988  }
989 
990  if (choice)
991  break;
992  }
993 
994  /* Next, look for an autoviewable type */
995  if (!choice)
996  {
997  if (a->parts)
998  b = a->parts;
999  else
1000  b = a;
1001  while (b)
1002  {
1003  if (is_autoview(b))
1004  choice = b;
1005  b = b->next;
1006  }
1007  }
1008 
1009  /* Then, look for a text entry */
1010  if (!choice)
1011  {
1012  if (a->parts)
1013  b = a->parts;
1014  else
1015  b = a;
1016  int type = 0;
1017  while (b)
1018  {
1019  if (b->type == TYPE_TEXT)
1020  {
1021  if (mutt_istr_equal("plain", b->subtype) && (type <= TXT_PLAIN))
1022  {
1023  choice = b;
1024  type = TXT_PLAIN;
1025  }
1026  else if (mutt_istr_equal("enriched", b->subtype) && (type <= TXT_ENRICHED))
1027  {
1028  choice = b;
1029  type = TXT_ENRICHED;
1030  }
1031  else if (mutt_istr_equal("html", b->subtype) && (type <= TXT_HTML))
1032  {
1033  choice = b;
1034  type = TXT_HTML;
1035  }
1036  }
1037  b = b->next;
1038  }
1039  }
1040 
1041  /* Finally, look for other possibilities */
1042  if (!choice)
1043  {
1044  if (a->parts)
1045  b = a->parts;
1046  else
1047  b = a;
1048  while (b)
1049  {
1050  if (mutt_can_decode(b))
1051  choice = b;
1052  b = b->next;
1053  }
1054  }
1055 
1056  if (choice)
1057  {
1058  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1059  if (s->flags & MUTT_DISPLAY && !c_weed)
1060  {
1061  fseeko(s->fp_in, choice->hdr_offset, SEEK_SET);
1062  mutt_file_copy_bytes(s->fp_in, s->fp_out, choice->offset - choice->hdr_offset);
1063  }
1064 
1065  const char *const c_show_multipart_alternative =
1066  cs_subset_string(NeoMutt->sub, "show_multipart_alternative");
1067  if (mutt_str_equal("info", c_show_multipart_alternative))
1068  {
1069  print_part_line(s, choice, 0);
1070  }
1071  mutt_body_handler(choice, s);
1072 
1073  /* Let it flow back to the main part */
1074  head->nowrap = choice->nowrap;
1075  choice->nowrap = false;
1076 
1077  if (mutt_str_equal("info", c_show_multipart_alternative))
1078  {
1079  if (a->parts)
1080  b = a->parts;
1081  else
1082  b = a;
1083  int count = 0;
1084  while (b)
1085  {
1086  if (choice != b)
1087  {
1088  count += 1;
1089  if (count == 1)
1090  state_putc(s, '\n');
1091 
1092  print_part_line(s, b, count);
1093  }
1094  b = b->next;
1095  }
1096  }
1097  }
1098  else if (s->flags & MUTT_DISPLAY)
1099  {
1100  /* didn't find anything that we could display! */
1101  state_mark_attach(s);
1102  state_puts(s, _("[-- Error: Could not display any parts of "
1103  "Multipart/Alternative --]\n"));
1104  rc = -1;
1105  }
1106 
1107  if (mustfree)
1108  mutt_body_free(&a);
1109 
1110  return rc;
1111 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define state_puts(STATE, STR)
Definition: state.h:55
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:475
#define TXT_HTML
Definition: handler.c:67
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:621
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
struct Body * mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
Parse a multipart structure.
Definition: parse.c:1709
struct Body * next
next attachment in the list
Definition: body.h:53
FILE * fp_out
File to write to.
Definition: state.h:47
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
The body of an email.
Definition: body.h:34
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
#define TXT_PLAIN
Definition: handler.c:68
bool nowrap
Do not wrap the output in the pager.
Definition: body.h:74
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
#define TXT_ENRICHED
Definition: handler.c:69
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Type: &#39;text/*&#39;.
Definition: mime.h:38
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1821
static void print_part_line(struct State *s, struct Body *b, int n)
Print a separator for the Mime part.
Definition: handler.c:86
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
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:241
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:73
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
#define TYPE(body)
Definition: mime.h:89
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
char * data
String.
Definition: list.h:36
Quoted-printable text.
Definition: mime.h:51
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1604
#define state_putc(STATE, STR)
Definition: state.h:56
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
A List node for strings.
Definition: list.h:34
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
UUEncoded text.
Definition: mime.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ multilingual_handler()

static int multilingual_handler ( struct Body a,
struct State s 
)
static

Handler for multi-lingual emails - Implements handler_t.

Return values
0Always

Definition at line 1117 of file handler.c.

1118 {
1119  struct Body *b = NULL;
1120  bool mustfree = false;
1121  int rc = 0;
1122 
1124  "RFC8255 >> entering in handler multilingual handler\n");
1125  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1126  (a->encoding == ENC_UUENCODED))
1127  {
1128  struct stat st;
1129  mustfree = true;
1130  fstat(fileno(s->fp_in), &st);
1131  b = mutt_body_new();
1132  b->length = (long) st.st_size;
1133  b->parts =
1134  mutt_parse_multipart(s->fp_in, mutt_param_get(&a->parameter, "boundary"),
1135  (long) st.st_size, mutt_istr_equal("digest", a->subtype));
1136  }
1137  else
1138  b = a;
1139 
1140  a = b;
1141 
1142  if (a->parts)
1143  b = a->parts;
1144  else
1145  b = a;
1146 
1147  struct Body *choice = NULL;
1148  struct Body *first_part = NULL;
1149  struct Body *zxx_part = NULL;
1150  struct ListNode *np = NULL;
1151 
1152  const struct Slist *c_preferred_languages =
1153  cs_subset_slist(NeoMutt->sub, "preferred_languages");
1154  if (c_preferred_languages)
1155  {
1156  struct Buffer *langs = mutt_buffer_pool_get();
1157  cs_subset_str_string_get(NeoMutt->sub, "preferred_languages", langs);
1158  mutt_debug(LL_DEBUG2, "RFC8255 >> preferred_languages set in config to '%s'\n",
1159  mutt_buffer_string(langs));
1160  mutt_buffer_pool_release(&langs);
1161 
1162  STAILQ_FOREACH(np, &c_preferred_languages->head, entries)
1163  {
1164  while (b)
1165  {
1166  if (mutt_can_decode(b))
1167  {
1168  if (!first_part)
1169  first_part = b;
1170 
1171  if (b->language && mutt_str_equal("zxx", b->language))
1172  zxx_part = b;
1173 
1174  mutt_debug(LL_DEBUG2, "RFC8255 >> comparing configuration preferred_language='%s' to mail part content-language='%s'\n",
1175  np->data, b->language);
1176  if (b->language && mutt_str_equal(np->data, b->language))
1177  {
1178  mutt_debug(LL_DEBUG2, "RFC8255 >> preferred_language='%s' matches content-language='%s' >> part selected to be displayed\n",
1179  np->data, b->language);
1180  choice = b;
1181  break;
1182  }
1183  }
1184 
1185  b = b->next;
1186  }
1187 
1188  if (choice)
1189  break;
1190 
1191  if (a->parts)
1192  b = a->parts;
1193  else
1194  b = a;
1195  }
1196  }
1197 
1198  if (choice)
1199  mutt_body_handler(choice, s);
1200  else
1201  {
1202  if (zxx_part)
1203  mutt_body_handler(zxx_part, s);
1204  else
1205  mutt_body_handler(first_part, s);
1206  }
1207 
1208  if (mustfree)
1209  mutt_body_free(&a);
1210 
1211  return rc;
1212 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
struct Body * mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
Parse a multipart structure.
Definition: parse.c:1709
struct Body * next
next attachment in the list
Definition: body.h:53
String list.
Definition: slist.h:46
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
The body of an email.
Definition: body.h:34
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Log at debug level 2.
Definition: logging.h:41
struct ListHead head
Definition: slist.h:48
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1821
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
int cs_subset_str_string_get(const struct ConfigSubset *sub, const char *name, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:370
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
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
char * data
String.
Definition: list.h:36
Quoted-printable text.
Definition: mime.h:51
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
char * language
content-language (RFC8255)
Definition: body.h:38
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1604
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
A List node for strings.
Definition: list.h:34
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
UUEncoded text.
Definition: mime.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ multipart_handler()

static int multipart_handler ( struct Body a,
struct State s 
)
static

Handler for multipart emails - Implements handler_t.

Definition at line 1217 of file handler.c.

1218 {
1219  struct Body *b = NULL, *p = NULL;
1220  struct stat st;
1221  int count;
1222  int rc = 0;
1223 
1224  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1225  (a->encoding == ENC_UUENCODED))
1226  {
1227  fstat(fileno(s->fp_in), &st);
1228  b = mutt_body_new();
1229  b->length = (long) st.st_size;
1230  b->parts =
1231  mutt_parse_multipart(s->fp_in, mutt_param_get(&a->parameter, "boundary"),
1232  (long) st.st_size, mutt_istr_equal("digest", a->subtype));
1233  }
1234  else
1235  b = a;
1236 
1237  for (p = b->parts, count = 1; p; p = p->next, count++)
1238  {
1239  if (s->flags & MUTT_DISPLAY)
1240  {
1241  state_mark_attach(s);
1242  if (p->description || p->filename || p->form_name)
1243  {
1244  /* L10N: %s is the attachment description, filename or form_name. */
1245  state_printf(s, _("[-- Attachment #%d: %s --]\n"), count,
1246  p->description ? p->description :
1247  p->filename ? p->filename :
1248  p->form_name);
1249  }
1250  else
1251  state_printf(s, _("[-- Attachment #%d --]\n"), count);
1252  print_part_line(s, p, 0);
1253  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1254  if (c_weed)
1255  {
1256  state_putc(s, '\n');
1257  }
1258  else
1259  {
1260  fseeko(s->fp_in, p->hdr_offset, SEEK_SET);
1261  mutt_file_copy_bytes(s->fp_in, s->fp_out, p->offset - p->hdr_offset);
1262  }
1263  }
1264 
1265  rc = mutt_body_handler(p, s);
1266  state_putc(s, '\n');
1267 
1268  if (rc != 0)
1269  {
1270  mutt_error(_("One or more parts of this message could not be displayed"));
1271  mutt_debug(LL_DEBUG1, "Failed on attachment #%d, type %s/%s\n", count,
1272  TYPE(p), NONULL(p->subtype));
1273  }
1274 
1275  const bool c_include_only_first =
1276  cs_subset_bool(NeoMutt->sub, "include_only_first");
1277  if ((s->flags & MUTT_REPLYING) && c_include_only_first && (s->flags & MUTT_FIRSTDONE))
1278  {
1279  break;
1280  }
1281  }
1282 
1283  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1284  (a->encoding == ENC_UUENCODED))
1285  {
1286  mutt_body_free(&b);
1287  }
1288 
1289  /* make failure of a single part non-fatal */
1290  if (rc < 0)
1291  rc = 1;
1292  return rc;
1293 }
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:187
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define NONULL(x)
Definition: string2.h:37
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
struct Body * mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
Parse a multipart structure.
Definition: parse.c:1709
struct Body * next
next attachment in the list
Definition: body.h:53
FILE * fp_out
File to write to.
Definition: state.h:47
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
The body of an email.
Definition: body.h:34
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
static void print_part_line(struct State *s, struct Body *b, int n)
Print a separator for the Mime part.
Definition: handler.c:86
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
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:241
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:73
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
#define TYPE(body)
Definition: mime.h:89
Log at debug level 1.
Definition: logging.h:40
Quoted-printable text.
Definition: mime.h:51
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1604
#define MUTT_FIRSTDONE
The first attachment has been done.
Definition: state.h:39
#define state_putc(STATE, STR)
Definition: state.h:56
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
UUEncoded text.
Definition: mime.h:54
+ 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 1304 of file handler.c.

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

◆ valid_pgp_encrypted_handler()

static int valid_pgp_encrypted_handler ( struct Body b,
struct State s 
)
static

Handler for valid pgp-encrypted emails - Implements handler_t.

Definition at line 1444 of file handler.c.

1445 {
1446  struct Body *octetstream = b->parts->next;
1447 
1448  /* clear out any mime headers before the handler, so they can't be spoofed. */
1450  mutt_env_free(&octetstream->mime_headers);
1451 
1452  int rc;
1453  /* Some clients improperly encode the octetstream part. */
1454  if (octetstream->encoding != ENC_7BIT)
1455  rc = run_decode_and_handler(octetstream, s, crypt_pgp_encrypted_handler, 0);
1456  else
1457  rc = crypt_pgp_encrypted_handler(octetstream, s);
1458  b->goodsig |= octetstream->goodsig;
1459 
1460  /* Relocate protected headers onto the multipart/encrypted part */
1461  if (!rc && octetstream->mime_headers)
1462  {
1463  b->mime_headers = octetstream->mime_headers;
1464  octetstream->mime_headers = NULL;
1465  }
1466 
1467  return rc;
1468 }
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
7-bit text
Definition: mime.h:49
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
bool goodsig
Good cryptographic signature.
Definition: body.h:76
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:1304
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
int crypt_pgp_encrypted_handler(struct Body *b, struct State *s)
Wrapper for CryptModuleSpecs::encrypted_handler()
Definition: cryptglue.c:253
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ malformed_pgp_encrypted_handler()

static int malformed_pgp_encrypted_handler ( struct Body b,
struct State s 
)
static

Handler for invalid pgp-encrypted emails - Implements handler_t.

Definition at line 1473 of file handler.c.

1474 {
1475  struct Body *octetstream = b->parts->next->next;
1476 
1477  /* clear out any mime headers before the handler, so they can't be spoofed. */
1479  mutt_env_free(&octetstream->mime_headers);
1480 
1481  /* exchange encodes the octet-stream, so re-run it through the decoder */
1482  int rc = run_decode_and_handler(octetstream, s, crypt_pgp_encrypted_handler, false);
1483  b->goodsig |= octetstream->goodsig;
1484 #ifdef USE_AUTOCRYPT
1485  b->is_autocrypt |= octetstream->is_autocrypt;
1486 #endif
1487 
1488  /* Relocate protected headers onto the multipart/encrypted part */
1489  if (!rc && octetstream->mime_headers)
1490  {
1491  b->mime_headers = octetstream->mime_headers;
1492  octetstream->mime_headers = NULL;
1493  }
1494 
1495  return rc;
1496 }
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
bool is_autocrypt
Flag autocrypt-decrypted messages for replying.
Definition: body.h:80
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
bool goodsig
Good cryptographic signature.
Definition: body.h:76
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:1304
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
int crypt_pgp_encrypted_handler(struct Body *b, struct State *s)
Wrapper for CryptModuleSpecs::encrypted_handler()
Definition: cryptglue.c:253
+ 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 1505 of file handler.c.

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

1605 {
1606  if (!b || !s)
1607  return -1;
1608 
1609  bool plaintext = false;
1610  handler_t handler = NULL;
1611  handler_t encrypted_handler = NULL;
1612  int rc = 0;
1613  static unsigned short recurse_level = 0;
1614 
1615  int oflags = s->flags;
1616 
1617  if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1618  {
1619  mutt_debug(LL_DEBUG1, "recurse level too deep. giving up.\n");
1620  return 1;
1621  }
1622  recurse_level++;
1623 
1624  /* first determine which handler to use to process this part */
1625 
1626  if (is_autoview(b))
1627  {
1628  handler = autoview_handler;
1629  s->flags &= ~MUTT_CHARCONV;
1630  }
1631  else if (b->type == TYPE_TEXT)
1632  {
1633  if (mutt_istr_equal("plain", b->subtype))
1634  {
1635  const bool c_reflow_text = cs_subset_bool(NeoMutt->sub, "reflow_text");
1636  /* avoid copying this part twice since removing the transfer-encoding is
1637  * the only operation needed. */
1638  if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b))
1639  {
1640  encrypted_handler = crypt_pgp_application_handler;
1641  handler = encrypted_handler;
1642  }
1643  else if (c_reflow_text && mutt_istr_equal("flowed", mutt_param_get(&b->parameter, "format")))
1644  {
1645  handler = rfc3676_handler;
1646  }
1647  else
1648  {
1649  handler = text_plain_handler;
1650  }
1651  }
1652  else if (mutt_istr_equal("enriched", b->subtype))
1653  handler = text_enriched_handler;
1654  else /* text body type without a handler */
1655  plaintext = false;
1656  }
1657  else if (b->type == TYPE_MESSAGE)
1658  {
1659  if (mutt_is_message_type(b->type, b->subtype))
1660  handler = message_handler;
1661  else if (mutt_istr_equal("delivery-status", b->subtype))
1662  plaintext = true;
1663  else if (mutt_istr_equal("external-body", b->subtype))
1664  handler = external_body_handler;
1665  }
1666  else if (b->type == TYPE_MULTIPART)
1667  {
1668  const char *const c_show_multipart_alternative =
1669  cs_subset_string(NeoMutt->sub, "show_multipart_alternative");
1670  if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1671  mutt_istr_equal("alternative", b->subtype))
1672  {
1673  handler = alternative_handler;
1674  }
1675  else if (!mutt_str_equal("inline", c_show_multipart_alternative) &&
1676  mutt_istr_equal("multilingual", b->subtype))
1677  {
1678  handler = multilingual_handler;
1679  }
1680  else if ((WithCrypto != 0) && mutt_istr_equal("signed", b->subtype))
1681  {
1682  if (!mutt_param_get(&b->parameter, "protocol"))
1683  mutt_error(_("Error: multipart/signed has no protocol"));
1684  else if (s->flags & MUTT_VERIFY)
1685  handler = mutt_signed_handler;
1686  }
1688  {
1689  encrypted_handler = valid_pgp_encrypted_handler;
1690  handler = encrypted_handler;
1691  }
1693  {
1694  encrypted_handler = malformed_pgp_encrypted_handler;
1695  handler = encrypted_handler;
1696  }
1697 
1698  if (!handler)
1699  handler = multipart_handler;
1700 
1701  if ((b->encoding != ENC_7BIT) && (b->encoding != ENC_8BIT) && (b->encoding != ENC_BINARY))
1702  {
1703  mutt_debug(LL_DEBUG1, "Bad encoding type %d for multipart entity, assuming 7 bit\n",
1704  b->encoding);
1705  b->encoding = ENC_7BIT;
1706  }
1707  }
1708  else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1709  {
1710  if (OptDontHandlePgpKeys && mutt_istr_equal("pgp-keys", b->subtype))
1711  {
1712  /* pass raw part through for key extraction */
1713  plaintext = true;
1714  }
1715  else if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b))
1716  {
1717  encrypted_handler = crypt_pgp_application_handler;
1718  handler = encrypted_handler;
1719  }
1720  else if (((WithCrypto & APPLICATION_SMIME) != 0) && mutt_is_application_smime(b))
1721  {
1722  encrypted_handler = crypt_smime_application_handler;
1723  handler = encrypted_handler;
1724  }
1725  }
1726 
1727  const bool c_honor_disposition =
1728  cs_subset_bool(NeoMutt->sub, "honor_disposition");
1729  /* only respect disposition == attachment if we're not
1730  * displaying from the attachment menu (i.e. pager) */
1731  if ((!c_honor_disposition || ((b->disposition != DISP_ATTACH) || OptViewAttach)) &&
1732  (plaintext || handler))
1733  {
1734  /* Prevent encrypted attachments from being included in replies
1735  * unless $include_encrypted is set. */
1736  const bool c_include_encrypted =
1737  cs_subset_bool(NeoMutt->sub, "include_encrypted");
1738  if ((s->flags & MUTT_REPLYING) && (s->flags & MUTT_FIRSTDONE) &&
1739  encrypted_handler && !c_include_encrypted)
1740  {
1741  goto cleanup;
1742  }
1743 
1744  rc = run_decode_and_handler(b, s, handler, plaintext);
1745  }
1746  /* print hint to use attachment menu for disposition == attachment
1747  * if we're not already being called from there */
1748  else if (s->flags & MUTT_DISPLAY)
1749  {
1750  struct Buffer msg = mutt_buffer_make(256);
1751 
1752  if (!OptViewAttach)
1753  {
1754  char keystroke[128] = { 0 };
1755  if (km_expand_key(keystroke, sizeof(keystroke),
1756  km_find_func(MENU_PAGER, OP_VIEW_ATTACHMENTS)))
1757  {
1758  if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1759  {
1760  /* L10N: %s expands to a keystroke/key binding, e.g. 'v'. */
1761  mutt_buffer_printf(&msg, _("[-- This is an attachment (use '%s' to view this part) --]\n"),
1762  keystroke);
1763  }
1764  else
1765  {
1766  /* L10N: %s/%s is a MIME type, e.g. "text/plain".
1767  The last %s expands to a keystroke/key binding, e.g. 'v'. */
1768  mutt_buffer_printf(&msg, _("[-- %s/%s is unsupported (use '%s' to view this part) --]\n"),
1769  TYPE(b), b->subtype, keystroke);
1770  }
1771  }
1772  else
1773  {
1774  if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1775  {
1776  mutt_buffer_strcpy(&msg, _("[-- This is an attachment (need "
1777  "'view-attachments' bound to key) --]\n"));
1778  }
1779  else
1780  {
1781  /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1782  mutt_buffer_printf(&msg, _("[-- %s/%s is unsupported (need 'view-attachments' bound to key) --]\n"),
1783  TYPE(b), b->subtype);
1784  }
1785  }
1786  }
1787  else
1788  {
1789  if (c_honor_disposition && (b->disposition == DISP_ATTACH))
1790  {
1791  mutt_buffer_strcpy(&msg, _("[-- This is an attachment --]\n"));
1792  }
1793  else
1794  {
1795  /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1796  mutt_buffer_printf(&msg, _("[-- %s/%s is unsupported --]\n"), TYPE(b), b->subtype);
1797  }
1798  }
1799  state_mark_attach(s);
1800  state_printf(s, "%s", mutt_buffer_string(&msg));
1801  mutt_buffer_dealloc(&msg);
1802  }
1803 
1804 cleanup:
1805  recurse_level--;
1806  s->flags = oflags | (s->flags & MUTT_FIRSTDONE);
1807  if (rc != 0)
1808  {
1809  mutt_debug(LL_DEBUG1, "Bailing on attachment of type %s/%s\n", TYPE(b),
1810  NONULL(b->subtype));
1811  }
1812 
1813  return rc;
1814 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:946
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:187
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define NONULL(x)
Definition: string2.h:37
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define WithCrypto
Definition: lib.h:113
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1385
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:475
static int alternative_handler(struct Body *a, struct State *s)
Handler for multipart alternative emails - Implements handler_t.
Definition: handler.c:928
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define mutt_error(...)
Definition: logging.h:88
int(* handler_t)(struct Body *b, struct State *s)
Manage a PGP or S/MIME encrypted MIME part.
Definition: handler.c:78
7-bit text
Definition: mime.h:49
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:623
String manipulation buffer.
Definition: buffer.h:33
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:484
#define _(a)
Definition: message.h:28
int text_enriched_handler(struct Body *a, struct State *s)
Handler for enriched text - Implements handler_t.
Definition: enriched.c:459
8-bit text
Definition: mime.h:50
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
int crypt_smime_application_handler(struct Body *b, struct State *s)
Wrapper for CryptModuleSpecs::application_handler()
Definition: cryptglue.c:452
Container for Accounts, Notifications.
Definition: neomutt.h:36
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
int crypt_pgp_application_handler(struct Body *b, struct State *s)
Wrapper for CryptModuleSpecs::application_handler()
Definition: cryptglue.c:240
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
Pager pager (email viewer)
Definition: type.h:54
static int malformed_pgp_encrypted_handler(struct Body *b, struct State *s)
Handler for invalid pgp-encrypted emails - Implements handler_t.
Definition: handler.c:1473
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
Content is attached.
Definition: mime.h:63
WHERE bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition: options.h:35
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
static int message_handler(struct Body *a, struct State *s)
Handler for message/rfc822 body parts - Implements handler_t.
Definition: handler.c:702
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
int mutt_signed_handler(struct Body *b, struct State *s)
Verify a "multipart/signed" body - Implements handler_t.
Definition: crypt.c:1156
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define MUTT_MIME_MAX_DEPTH
Definition: mime.h:69
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:918
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
Type: &#39;text/*&#39;.
Definition: mime.h:38
static int valid_pgp_encrypted_handler(struct Body *b, struct State *s)
Handler for valid pgp-encrypted emails - Implements handler_t.
Definition: handler.c:1444
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:1304
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:521
static int multilingual_handler(struct Body *a, struct State *s)
Handler for multi-lingual emails - Implements handler_t.
Definition: handler.c:1117
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:73
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
#define TYPE(body)
Definition: mime.h:89
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:40
static int autoview_handler(struct Body *a, struct State *s)
Handler for autoviewable attachments - Implements handler_t.
Definition: handler.c:522
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:565
Binary.
Definition: mime.h:53
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
static int multipart_handler(struct Body *a, struct State *s)
Handler for multipart emails - Implements handler_t.
Definition: handler.c:1217
WHERE bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:54
#define MUTT_FIRSTDONE
The first attachment has been done.
Definition: state.h:39
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int rfc3676_handler(struct Body *a, struct State *s)
Body handler implementing RFC3676 for format=flowed - Implements handler_t.
Definition: rfc3676.c:320
static int external_body_handler(struct Body *b, struct State *s)
Handler for external-body emails - Implements handler_t.
Definition: handler.c:756
static int text_plain_handler(struct Body *b, struct State *s)
Handler for plain text - Implements handler_t.
Definition: handler.c:675
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
Type: &#39;application/*&#39;.
Definition: mime.h:33
+ 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 a)

Will decoding the attachment produce any output.

Parameters
aBody of email to test
Return values
trueDecoding the attachment will produce output

Definition at line 1821 of file handler.c.

1822 {
1823  if (is_autoview(a))
1824  return true;
1825  if (a->type == TYPE_TEXT)
1826  return true;
1827  if (a->type == TYPE_MESSAGE)
1828  return true;
1829  if (a->type == TYPE_MULTIPART)
1830  {
1831  if (WithCrypto)
1832  {
1833  if (mutt_istr_equal(a->subtype, "signed") || mutt_istr_equal(a->subtype, "encrypted"))
1834  {
1835  return true;
1836  }
1837  }
1838 
1839  for (struct Body *b = a->parts; b; b = b->next)
1840  {
1841  if (mutt_can_decode(b))
1842  return true;
1843  }
1844  }
1845  else if ((WithCrypto != 0) && (a->type == TYPE_APPLICATION))
1846  {
1847  if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(a))
1848  return true;
1850  return true;
1851  }
1852 
1853  return false;
1854 }
#define WithCrypto
Definition: lib.h:113
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:475
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:623
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
Type: &#39;text/*&#39;.
Definition: mime.h:38
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1821
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:565
Type: &#39;application/*&#39;.
Definition: mime.h:33
+ 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 1861 of file handler.c.

1862 {
1863  int istext = mutt_is_text_part(b) && (b->disposition == DISP_INLINE);
1864  iconv_t cd = (iconv_t) (-1);
1865 
1866  if (istext && (b->charset || (s->flags & MUTT_CHARCONV)))
1867  {
1868  const char *charset = b->charset;
1869  if (!charset)
1870  {
1871  const char *const c_assumed_charset =
1872  cs_subset_string(NeoMutt->sub, "assumed_charset");
1873  charset = mutt_param_get(&b->parameter, "charset");
1874  if (!charset && c_assumed_charset)
1875  charset = mutt_ch_get_default_charset();
1876  }
1877  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
1878  if (charset && c_charset)
1879  cd = mutt_ch_iconv_open(c_charset, charset, MUTT_ICONV_HOOK_FROM);
1880  }
1881 
1882  fseeko(s->fp_in, b->offset, SEEK_SET);
1883  switch (b->encoding)
1884  {
1885  case ENC_QUOTED_PRINTABLE:
1886  decode_quoted(s, b->length,
1887  istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1889  cd);
1890  break;
1891  case ENC_BASE64:
1892  mutt_decode_base64(s, b->length,
1893  istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1895  cd);
1896  break;
1897  case ENC_UUENCODED:
1898  decode_uuencoded(s, b->length,
1899  istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1901  cd);
1902  break;
1903  default:
1904  decode_xbit(s, b->length,
1905  istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1907  cd);
1908  break;
1909  }
1910 
1911  if (cd != (iconv_t) (-1))
1912  iconv_close(cd);
1913 }
static void decode_xbit(struct State *s, long len, bool istext, iconv_t cd)
Decode xbit-encoded text.
Definition: handler.c:162
#define WithCrypto
Definition: lib.h:113
static void decode_uuencoded(struct State *s, long len, bool istext, iconv_t cd)
Decode uuencoded text.
Definition: handler.c:363
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
static void decode_quoted(struct State *s, long len, bool istext, iconv_t cd)
Decode an attachment encoded with quoted-printable.
Definition: handler.c:299
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
void mutt_decode_base64(struct State *s, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition: handler.c:1505
iconv_t mutt_ch_iconv_open(const char *tocode, const char *fromcode, uint8_t flags)
Set up iconv for conversions.
Definition: charset.c:569
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
char * mutt_ch_get_default_charset(void)
Get the default character set.
Definition: charset.c:442
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
#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:49
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:434
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:565
Quoted-printable text.
Definition: mime.h:51
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
UUEncoded text.
Definition: mime.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function: