NeoMutt  2018-07-16 +952-a2da0a
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 <limits.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/mutt.h"
#include "email/lib.h"
#include "mutt.h"
#include "handler.h"
#include "copy.h"
#include "enriched.h"
#include "filter.h"
#include "globals.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "ncrypt/ncrypt.h"
#include "opcodes.h"
#include "options.h"
#include "rfc1524.h"
#include "rfc3676.h"
#include "state.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 TXTHTML   1
 
#define TXTPLAIN   2
 
#define TXTENRICHED   3
 

Typedefs

typedef int(* handler_t) (struct Body *b, struct State *s)
 typedef handler_t - 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...
 

Variables

bool HonorDisposition
 Config: Don't display MIME parts inline if they have a disposition of 'attachment'. More...
 
bool ImplicitAutoview
 Config: Display MIME attachments inline if a 'copiousoutput' mailcap entry exists. More...
 
bool IncludeOnlyfirst
 Config: Only include the first attachment when replying. More...
 
char * PreferredLanguages
 Config: Preferred languages for multilingual MIME. More...
 
bool ReflowText
 Config: Reformat paragraphs of 'format=flowed' text. More...
 
char * ShowMultipartAlternative
 Config: How to display 'multipart/alternative' MIME parts. 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

#define BUFI_SIZE   1000

Definition at line 71 of file handler.c.

#define BUFO_SIZE   2000

Definition at line 72 of file handler.c.

#define TXTHTML   1

Definition at line 74 of file handler.c.

#define TXTPLAIN   2

Definition at line 75 of file handler.c.

#define TXTENRICHED   3

Definition at line 76 of file handler.c.

Typedef Documentation

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

typedef handler_t - Manage a PGP or S/MIME encrypted MIME part

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

Definition at line 85 of file handler.c.

Function Documentation

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

94 {
95  char length[5];
96  mutt_str_pretty_size(length, sizeof(length), b->length);
98  char *charset = mutt_param_get(&b->parameter, "charset");
99  if (n != 0)
100  {
101  state_printf(s, _("[-- Alternative Type #%d: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
102  n, TYPE(b), b->subtype, charset ? "; charset=" : "",
103  charset ? charset : "", ENCODING(b->encoding), length);
104  }
105  else
106  {
107  state_printf(s, _("[-- Type: %s/%s%s%s, Encoding: %s, Size: %s --]\n"),
108  TYPE(b), b->subtype, charset ? "; charset=" : "",
109  charset ? charset : "", ENCODING(b->encoding), length);
110  }
111 }
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:137
#define _(a)
Definition: message.h:28
#define ENCODING(X)
Definition: mime.h:84
unsigned int encoding
content-transfer-encoding
Definition: body.h:68
char * subtype
content-type subtype
Definition: body.h:36
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
#define TYPE(X)
Definition: mime.h:82
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:41
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:81
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: string.c:1015
struct ParameterList parameter
parameters of the content-type
Definition: body.h:38

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

168 {
169  if (!istext)
170  {
171  mutt_file_copy_bytes(s->fpin, s->fpout, len);
172  return;
173  }
174 
175  state_set_prefix(s);
176 
177  int c;
178  char bufi[BUFI_SIZE];
179  size_t l = 0;
180  while ((c = fgetc(s->fpin)) != EOF && len--)
181  {
182  if ((c == '\r') && len)
183  {
184  const int ch = fgetc(s->fpin);
185  if (ch == '\n')
186  {
187  c = ch;
188  len--;
189  }
190  else
191  ungetc(ch, s->fpin);
192  }
193 
194  bufi[l++] = c;
195  if (l == sizeof(bufi))
196  convert_to_state(cd, bufi, &l, s);
197  }
198 
199  convert_to_state(cd, bufi, &l, s);
200  convert_to_state(cd, 0, 0, s);
201 
203 }
#define state_reset_prefix(s)
Definition: state.h:50
#define state_set_prefix(s)
Definition: state.h:49
FILE * fpout
Definition: state.h:34
#define BUFI_SIZE
Definition: handler.c:71
FILE * fpin
Definition: state.h:33
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:120
int mutt_file_copy_bytes(FILE *in, FILE *out, size_t size)
Copy some content from one file to another.
Definition: file.c:237

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

213 {
214  /* soft line break */
215  if ((*s == '=') && !(*(s + 1)))
216  return 1;
217 
218  /* quoted-printable triple */
219  if ((*s == '=') && isxdigit((unsigned char) *(s + 1)) &&
220  isxdigit((unsigned char) *(s + 2)))
221  {
222  *d = (hexval(*(s + 1)) << 4) | hexval(*(s + 2));
223  return 0;
224  }
225 
226  /* something else */
227  return -1;
228 }
#define hexval(c)
Definition: mime.h:75

+ Here is the caller graph for this function:

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

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 STRING > 78, so corrupted input will just be corrupted a bit more. That implies that STRING+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 STRING + 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 STRING*2 for the target buffer's size.

Definition at line 305 of file handler.c.

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static unsigned char decode_byte ( char  ch)
static

Decode a uuencoded byte.

Parameters
chCharacter to decode
Return values
numDecoded value

Definition at line 357 of file handler.c.

358 {
359  if (ch == 96)
360  return 0;
361  return ch - 32;
362 }

+ Here is the caller graph for this function:

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

372 {
373  char tmps[SHORT_STRING];
374  char *pt = NULL;
375  char bufi[BUFI_SIZE];
376  size_t k = 0;
377 
378  if (istext)
379  state_set_prefix(s);
380 
381  while (len > 0)
382  {
383  if (!fgets(tmps, sizeof(tmps), s->fpin))
384  return;
385  len -= mutt_str_strlen(tmps);
386  if (mutt_str_startswith(tmps, "begin ", CASE_MATCH))
387  break;
388  }
389  while (len > 0)
390  {
391  if (!fgets(tmps, sizeof(tmps), s->fpin))
392  return;
393  len -= mutt_str_strlen(tmps);
394  if (mutt_str_startswith(tmps, "end", CASE_MATCH))
395  break;
396  pt = tmps;
397  const unsigned char linelen = decode_byte(*pt);
398  pt++;
399  for (unsigned char c = 0; c < linelen;)
400  {
401  for (char l = 2; l <= 6; l += 2)
402  {
403  char out = decode_byte(*pt) << l;
404  pt++;
405  out |= (decode_byte(*pt) >> (6 - l));
406  bufi[k++] = out;
407  c++;
408  if (c == linelen)
409  break;
410  }
411  convert_to_state(cd, bufi, &k, s);
412  pt++;
413  }
414  }
415 
416  convert_to_state(cd, bufi, &k, s);
417  convert_to_state(cd, 0, 0, s);
418 
420 }
#define state_reset_prefix(s)
Definition: state.h:50
#define SHORT_STRING
Definition: string2.h:34
#define state_set_prefix(s)
Definition: state.h:49
Match case when comparing strings.
Definition: string2.h:69
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
static unsigned char decode_byte(char ch)
Decode a uuencoded byte.
Definition: handler.c:357
#define BUFI_SIZE
Definition: handler.c:71
FILE * fpin
Definition: state.h:33
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:166
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:120

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 automaticaly return true.

Definition at line 432 of file handler.c.

433 {
434  char *p = NULL;
435  char tmp[LONG_STRING], *q = NULL;
436 
437  const char *val = mutt_str_getenv("MM_NOASK");
438  if (!val)
439  return false;
440 
441  if (mutt_str_strcmp(val, "1") == 0)
442  return true;
443 
444  mutt_str_strfcpy(tmp, val, sizeof(tmp));
445  p = tmp;
446 
447  while ((p = strtok(p, ",")))
448  {
449  q = strrchr(p, '/');
450  if (q)
451  {
452  if (*(q + 1) == '*')
453  {
454  if (mutt_str_strncasecmp(buf, p, q - p) == 0)
455  return true;
456  }
457  else
458  {
459  if (mutt_str_strcasecmp(buf, p) == 0)
460  return true;
461  }
462  }
463  else
464  {
465  const size_t plen = mutt_str_startswith(buf, p, CASE_IGNORE);
466  if ((plen != 0) && (buf[plen] == '/'))
467  return true;
468  }
469 
470  p = NULL;
471  }
472 
473  return false;
474 }
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
#define LONG_STRING
Definition: string2.h:36
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:1049
int mutt_str_strncasecmp(const char *a, const char *b, size_t l)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:653
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
Ignore case when comparing strings.
Definition: string2.h:70
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:166
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:612

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

483 {
484  char type[SHORT_STRING];
485  bool is_av = false;
486 
487  snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
488 
489  if (ImplicitAutoview)
490  {
491  /* $implicit_autoview is essentially the same as "auto_view *" */
492  is_av = true;
493  }
494  else
495  {
496  /* determine if this type is on the user's auto_view list */
497  mutt_check_lookup_list(b, type, sizeof(type));
498  struct ListNode *np = NULL;
499  STAILQ_FOREACH(np, &AutoViewList, entries)
500  {
501  int i = mutt_str_strlen(np->data) - 1;
502  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
503  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
504  (mutt_str_strcasecmp(type, np->data) == 0))
505  {
506  is_av = true;
507  break;
508  }
509  }
510 
511  if (is_mmnoask(type))
512  is_av = true;
513  }
514 
515  /* determine if there is a mailcap entry suitable for auto_view
516  *
517  * @warning type is altered by this call as a result of 'mime_lookup' support */
518  if (is_av)
519  return rfc1524_mailcap_lookup(b, type, NULL, MUTT_AUTOVIEW);
520 
521  return false;
522 }
#define SHORT_STRING
Definition: string2.h:34
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
static bool is_mmnoask(const char *buf)
Metamail compatibility: should the attachment be autoviewed?
Definition: handler.c:432
char * subtype
content-type subtype
Definition: body.h:36
int mutt_str_strncasecmp(const char *a, const char *b, size_t l)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:653
#define TYPE(X)
Definition: mime.h:82
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * data
Definition: list.h:35
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:325
int rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, int opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:437
Mailcap autoview field.
Definition: mutt.h:179
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
bool ImplicitAutoview
Config: Display MIME attachments inline if a &#39;copiousoutput&#39; mailcap entry exists.
Definition: handler.c:65
A List node for strings.
Definition: list.h:33

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Handler for autoviewable attachments - Implements handler_t.

Definition at line 527 of file handler.c.

528 {
529  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
530  char buffer[LONG_STRING];
531  char type[STRING];
532  char command[HUGE_STRING];
533  char tempfile[PATH_MAX] = "";
534  char *fname = NULL;
535  FILE *fpin = NULL;
536  FILE *fpout = NULL;
537  FILE *fperr = NULL;
538  int piped = false;
539  pid_t thepid;
540  int rc = 0;
541 
542  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
543  rfc1524_mailcap_lookup(a, type, entry, MUTT_AUTOVIEW);
544 
545  fname = mutt_str_strdup(a->filename);
546  mutt_file_sanitize_filename(fname, true);
547  rfc1524_expand_filename(entry->nametemplate, fname, tempfile, sizeof(tempfile));
548  FREE(&fname);
549 
550  if (entry->command)
551  {
552  mutt_str_strfcpy(command, entry->command, sizeof(command));
553 
554  /* rfc1524_expand_command returns 0 if the file is required */
555  piped = rfc1524_expand_command(a, tempfile, type, command, sizeof(command));
556 
557  if (s->flags & MUTT_DISPLAY)
558  {
560  state_printf(s, _("[-- Autoview using %s --]\n"), command);
561  mutt_message(_("Invoking autoview command: %s"), command);
562  }
563 
564  fpin = mutt_file_fopen(tempfile, "w+");
565  if (!fpin)
566  {
567  mutt_perror("fopen");
568  rfc1524_free_entry(&entry);
569  return -1;
570  }
571 
572  mutt_file_copy_bytes(s->fpin, fpin, a->length);
573 
574  if (!piped)
575  {
576  mutt_file_fclose(&fpin);
577  thepid = mutt_create_filter(command, NULL, &fpout, &fperr);
578  }
579  else
580  {
581  unlink(tempfile);
582  fflush(fpin);
583  rewind(fpin);
584  thepid = mutt_create_filter_fd(command, NULL, &fpout, &fperr, fileno(fpin), -1, -1);
585  }
586 
587  if (thepid < 0)
588  {
589  mutt_perror(_("Can't create filter"));
590  if (s->flags & MUTT_DISPLAY)
591  {
593  state_printf(s, _("[-- Can't run %s. --]\n"), command);
594  }
595  rc = -1;
596  goto bail;
597  }
598 
599  if (s->prefix)
600  {
601  while (fgets(buffer, sizeof(buffer), fpout))
602  {
603  state_puts(s->prefix, s);
604  state_puts(buffer, s);
605  }
606  /* check for data on stderr */
607  if (fgets(buffer, sizeof(buffer), fperr))
608  {
609  if (s->flags & MUTT_DISPLAY)
610  {
612  state_printf(s, _("[-- Autoview stderr of %s --]\n"), command);
613  }
614 
615  state_puts(s->prefix, s);
616  state_puts(buffer, s);
617  while (fgets(buffer, sizeof(buffer), fperr))
618  {
619  state_puts(s->prefix, s);
620  state_puts(buffer, s);
621  }
622  }
623  }
624  else
625  {
626  mutt_file_copy_stream(fpout, s->fpout);
627  /* Check for stderr messages */
628  if (fgets(buffer, sizeof(buffer), fperr))
629  {
630  if (s->flags & MUTT_DISPLAY)
631  {
633  state_printf(s, _("[-- Autoview stderr of %s --]\n"), command);
634  }
635 
636  state_puts(buffer, s);
637  mutt_file_copy_stream(fperr, s->fpout);
638  }
639  }
640 
641  bail:
642  mutt_file_fclose(&fpout);
643  mutt_file_fclose(&fperr);
644 
645  mutt_wait_filter(thepid);
646  if (piped)
647  mutt_file_fclose(&fpin);
648  else
649  mutt_file_unlink(tempfile);
650 
651  if (s->flags & MUTT_DISPLAY)
653  }
654  rfc1524_free_entry(&entry);
655 
656  return rc;
657 }
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:137
#define MUTT_DISPLAY
output is displayed to the user
Definition: state.h:40
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:47
#define mutt_perror(...)
Definition: logging.h:89
#define mutt_message(...)
Definition: logging.h:87
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:192
char * prefix
Definition: state.h:35
#define _(a)
Definition: message.h:28
#define LONG_STRING
Definition: string2.h:36
FILE * fpout
Definition: state.h:34
int flags
Definition: state.h:36
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:141
char * nametemplate
Definition: rfc1524.h:45
void mutt_file_sanitize_filename(char *f, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:578
#define HUGE_STRING
Definition: string2.h:37
char * subtype
content-type subtype
Definition: body.h:36
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:410
int mutt_file_copy_stream(FILE *fin, FILE *fout)
Copy the contents of one file into another.
Definition: file.c:264
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
#define PATH_MAX
Definition: mutt.h:46
#define state_puts(x, y)
Definition: state.h:51
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
#define TYPE(X)
Definition: mime.h:82
int rfc1524_expand_filename(char *nametemplate, char *oldfile, char *newfile, size_t nflen)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:504
A mailcap entry.
Definition: rfc1524.h:37
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:41
FILE * fpin
Definition: state.h:33
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:548
#define STRING
Definition: string2.h:35
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
int mutt_file_fclose(FILE **f)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
int rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, int opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:437
Mailcap autoview field.
Definition: mutt.h:179
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:401
#define FREE(x)
Definition: memory.h:46
pid_t mutt_create_filter(const char *s, FILE **in, FILE **out, FILE **err)
Set up filter program.
Definition: filter.c:216
pid_t mutt_create_filter_fd(const char *cmd, FILE **in, FILE **out, FILE **err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:64
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
int mutt_file_copy_bytes(FILE *in, FILE *out, size_t size)
Copy some content from one file to another.
Definition: file.c:237
int rfc1524_expand_command(struct Body *a, char *filename, char *type, char *command, int clen)
Expand expandos in a command.
Definition: rfc1524.c:72

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

668 {
669  char *buf = NULL;
670  size_t l = 0, sz = 0;
671 
672  while ((buf = mutt_file_read_line(buf, &sz, s->fpin, NULL, 0)))
673  {
674  if ((mutt_str_strcmp(buf, "-- ") != 0) && TextFlowed)
675  {
676  l = mutt_str_strlen(buf);
677  while (l > 0 && buf[l - 1] == ' ')
678  buf[--l] = '\0';
679  }
680  if (s->prefix)
681  state_puts(s->prefix, s);
682  state_puts(buf, s);
683  state_putc('\n', s);
684  }
685 
686  FREE(&buf);
687  return 0;
688 }
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:632
char * prefix
Definition: state.h:35
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
WHERE bool TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: globals.h:259
#define state_putc(x, y)
Definition: state.h:52
#define state_puts(x, y)
Definition: state.h:51
FILE * fpin
Definition: state.h:33
#define FREE(x)
Definition: memory.h:46
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:612

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Handler for message/rfc822 body parts - Implements handler_t.

Definition at line 693 of file handler.c.

694 {
695  struct stat st;
696  struct Body *b = NULL;
697  LOFF_T off_start;
698  int rc = 0;
699 
700  off_start = ftello(s->fpin);
701  if (off_start < 0)
702  return -1;
703 
704  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
705  (a->encoding == ENC_UUENCODED))
706  {
707  fstat(fileno(s->fpin), &st);
708  b = mutt_body_new();
709  b->length = (LOFF_T) st.st_size;
711  }
712  else
713  b = a;
714 
715  if (b->parts)
716  {
717  mutt_copy_hdr(s->fpin, s->fpout, off_start, b->parts->offset,
718  (((s->flags & MUTT_WEED) ||
719  ((s->flags & (MUTT_DISPLAY | MUTT_PRINTING)) && Weed)) ?
720  (CH_WEED | CH_REORDER) :
721  0) |
722  (s->prefix ? CH_PREFIX : 0) | CH_DECODE | CH_FROM |
723  ((s->flags & MUTT_DISPLAY) ? CH_DISPLAY : 0),
724  s->prefix);
725 
726  if (s->prefix)
727  state_puts(s->prefix, s);
728  state_putc('\n', s);
729 
730  rc = mutt_body_handler(b->parts, s);
731  }
732 
733  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
734  (a->encoding == ENC_UUENCODED))
735  {
736  mutt_body_free(&b);
737  }
738 
739  return rc;
740 }
#define MUTT_DISPLAY
output is displayed to the user
Definition: state.h:40
char * prefix
Definition: state.h:35
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
#define CH_FROM
retain the "From " message separator?
Definition: copy.h:51
#define MUTT_PRINTING
are we printing? - MUTT_DISPLAY "light"
Definition: state.h:45
The body of an email.
Definition: body.h:33
int mutt_copy_hdr(FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags, const char *prefix)
Copy header from one file to another.
Definition: copy.c:72
FILE * fpout
Definition: state.h:34
#define state_putc(x, y)
Definition: state.h:52
int flags
Definition: state.h:36
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
parse a Message/RFC822 body
Definition: parse.c:1384
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:42
#define CH_WEED
weed the headers?
Definition: copy.h:48
bool Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:38
unsigned int encoding
content-transfer-encoding
Definition: body.h:68
Base-64 encoded text.
Definition: mime.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
#define state_puts(x, y)
Definition: state.h:51
#define CH_REORDER
Re-order output of headers.
Definition: copy.h:54
#define CH_DECODE
do RFC1522 decoding?
Definition: copy.h:49
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
#define CH_DISPLAY
display result to user
Definition: copy.h:65
#define MUTT_WEED
weed headers even when not in display mode
Definition: state.h:43
FILE * fpin
Definition: state.h:33
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:56
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:1502
#define CH_PREFIX
use IndentString string?
Definition: copy.h:52
UUEncoded text.
Definition: mime.h:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Handler for external-body emails - Implements handler_t.

Definition at line 745 of file handler.c.

746 {
747  const char *str = NULL;
748  char strbuf[LONG_STRING]; // STRING might be too short but LONG_STRING should be large enough
749 
750  const char *access_type = mutt_param_get(&b->parameter, "access-type");
751  if (!access_type)
752  {
753  if (s->flags & MUTT_DISPLAY)
754  {
756  state_puts(_("[-- Error: message/external-body has no access-type "
757  "parameter --]\n"),
758  s);
759  return 0;
760  }
761  else
762  return -1;
763  }
764 
765  const char *expiration = mutt_param_get(&b->parameter, "expiration");
766  time_t expire;
767  if (expiration)
768  expire = mutt_date_parse_date(expiration, NULL);
769  else
770  expire = -1;
771 
772  if (mutt_str_strcasecmp(access_type, "x-mutt-deleted") == 0)
773  {
774  if (s->flags & (MUTT_DISPLAY | MUTT_PRINTING))
775  {
776  char pretty_size[10];
777  char *length = mutt_param_get(&b->parameter, "length");
778  if (length)
779  {
780  long size = strtol(length, NULL, 10);
781  mutt_str_pretty_size(pretty_size, sizeof(pretty_size), size);
782  if (expire != -1)
783  {
784  str = ngettext(
785  /* L10N: If the translation of this string is a multi line string, then
786  each line should start with "[-- " and end with " --]".
787  The first "%s/%s" is a MIME type, e.g. "text/plain". The last %s
788  expands to a date as returned by `mutt_date_parse_date()`.
789 
790  Note: The size argument printed is not the actual number as passed
791  to gettext but the prettified version, e.g. size = 2048 will be
792  printed as 2K. Your language might be sensitive to that: For
793  example although '1K' and '1024' represent the same number your
794  language might inflect the noun 'byte' differently.
795 
796  Sadly, we cannot do anything about that at the moment besides
797  passing the precise size in bytes. If you are interested the
798  function responsible for the prettification is
799  mutt_str_pretty_size() in mutt/string.c.
800  */
801  "[-- This %s/%s attachment (size %s byte) has been deleted --]\n"
802  "[-- on %s --]\n",
803  "[-- This %s/%s attachment (size %s bytes) has been deleted --]\n"
804  "[-- on %s --]\n",
805  size);
806  }
807  else
808  {
809  str = ngettext(
810  /* L10N: If the translation of this string is a multi line string, then
811  each line should start with "[-- " and end with " --]".
812  The first "%s/%s" is a MIME type, e.g. "text/plain".
813 
814  Note: The size argument printed is not the actual number as passed
815  to gettext but the prettified version, e.g. size = 2048 will be
816  printed as 2K. Your language might be sensitive to that: For
817  example although '1K' and '1024' represent the same number your
818  language might inflect the noun 'byte' differently.
819 
820  Sadly, we cannot do anything about that at the moment besides
821  passing the precise size in bytes. If you are interested the
822  function responsible for the prettification is
823  mutt_str_pretty_size() in mutt/string.c.
824  */
825  "[-- This %s/%s attachment (size %s byte) has been deleted --]\n",
826  "[-- This %s/%s attachment (size %s bytes) has been deleted "
827  "--]\n",
828  size);
829  }
830  }
831  else
832  {
833  pretty_size[0] = '\0';
834  if (expire != -1)
835  {
836  /* L10N: If the translation of this string is a multi line string, then
837  each line should start with "[-- " and end with " --]".
838  The first "%s/%s" is a MIME type, e.g. "text/plain". The last %s
839  expands to a date as returned by `mutt_date_parse_date()`.
840 
841  Caution: Argument three %3$ is also defined but should not be used
842  in this translation!
843  */
844  str = _("[-- This %s/%s attachment has been deleted --]\n[-- on %4$s "
845  "--]\n");
846  }
847  else
848  {
849  /* L10N: If the translation of this string is a multi line string, then
850  each line should start with "[-- " and end with " --]".
851  The first "%s/%s" is a MIME type, e.g. "text/plain".
852  */
853  str = _("[-- This %s/%s attachment has been deleted --]\n");
854  }
855  }
856 
857  snprintf(strbuf, sizeof(strbuf), str, TYPE(b->parts), b->parts->subtype,
858  pretty_size, expiration);
859  state_attach_puts(strbuf, s);
860  if (b->parts->filename)
861  {
863  state_printf(s, _("[-- name: %s --]\n"), b->parts->filename);
864  }
865 
866  mutt_copy_hdr(s->fpin, s->fpout, ftello(s->fpin), b->parts->offset,
867  (Weed ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE, NULL);
868  }
869  }
870  else if (expiration && expire < time(NULL))
871  {
872  if (s->flags & MUTT_DISPLAY)
873  {
874  /* L10N: If the translation of this string is a multi line string, then
875  each line should start with "[-- " and end with " --]".
876  The "%s/%s" is a MIME type, e.g. "text/plain".
877  */
878  snprintf(strbuf, sizeof(strbuf), _("[-- This %s/%s attachment is not included, --]\n[-- and the indicated external source has --]\n[-- expired. --]\n"),
879  TYPE(b->parts), b->parts->subtype);
880  state_attach_puts(strbuf, s);
881 
882  mutt_copy_hdr(s->fpin, s->fpout, ftello(s->fpin), b->parts->offset,
883  (Weed ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_DISPLAY, NULL);
884  }
885  }
886  else
887  {
888  if (s->flags & MUTT_DISPLAY)
889  {
890  /* L10N: If the translation of this string is a multi line string, then
891  each line should start with "[-- " and end with " --]".
892  The "%s/%s" is a MIME type, e.g. "text/plain". The %s after
893  access-type is an access-type as defined by the MIME RFCs, e.g. "FTP",
894  "LOCAL-FILE", "MAIL-SERVER".
895  */
896  snprintf(strbuf, sizeof(strbuf), _("[-- This %s/%s attachment is not included, --]\n[-- and the indicated access-type %s is unsupported --]\n"),
897  TYPE(b->parts), b->parts->subtype, access_type);
898  state_attach_puts(strbuf, s);
899 
900  mutt_copy_hdr(s->fpin, s->fpout, ftello(s->fpin), b->parts->offset,
901  (Weed ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_DISPLAY, NULL);
902  }
903  }
904 
905  return 0;
906 }
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:137
#define MUTT_DISPLAY
output is displayed to the user
Definition: state.h:40
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:47
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
#define _(a)
Definition: message.h:28
#define MUTT_PRINTING
are we printing? - MUTT_DISPLAY "light"
Definition: state.h:45
#define LONG_STRING
Definition: string2.h:36
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:443
void state_attach_puts(const char *t, struct State *s)
Write a string to the state.
Definition: state.c:54
int mutt_copy_hdr(FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags, const char *prefix)
Copy header from one file to another.
Definition: copy.c:72
FILE * fpout
Definition: state.h:34
int flags
Definition: state.h:36
#define CH_WEED
weed the headers?
Definition: copy.h:48
bool Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:38
char * subtype
content-type subtype
Definition: body.h:36
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
#define state_puts(x, y)
Definition: state.h:51
#define CH_REORDER
Re-order output of headers.
Definition: copy.h:54
#define CH_DECODE
do RFC1522 decoding?
Definition: copy.h:49
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
#define CH_DISPLAY
display result to user
Definition: copy.h:65
#define TYPE(X)
Definition: mime.h:82
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:41
FILE * fpin
Definition: state.h:33
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:81
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: string.c:1015
struct ParameterList parameter
parameters of the content-type
Definition: body.h:38

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Handler for multipart alternative emails - Implements handler_t.

Definition at line 911 of file handler.c.

912 {
913  struct Body *choice = NULL;
914  struct Body *b = NULL;
915  bool mustfree = false;
916  int rc = 0;
917 
918  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
919  (a->encoding == ENC_UUENCODED))
920  {
921  struct stat st;
922  mustfree = true;
923  fstat(fileno(s->fpin), &st);
924  b = mutt_body_new();
925  b->length = (long) st.st_size;
927  s->fpin, mutt_param_get(&a->parameter, "boundary"), (long) st.st_size,
928  (mutt_str_strcasecmp("digest", a->subtype) == 0));
929  }
930  else
931  b = a;
932 
933  a = b;
934 
935  /* First, search list of preferred types */
936  struct ListNode *np = NULL;
937  STAILQ_FOREACH(np, &AlternativeOrderList, entries)
938  {
939  int btlen; /* length of basetype */
940  bool wild; /* do we have a wildcard to match all subtypes? */
941 
942  char *c = strchr(np->data, '/');
943  if (c)
944  {
945  wild = ((c[1] == '*') && (c[2] == 0));
946  btlen = c - np->data;
947  }
948  else
949  {
950  wild = true;
951  btlen = mutt_str_strlen(np->data);
952  }
953 
954  if (a->parts)
955  b = a->parts;
956  else
957  b = a;
958  while (b)
959  {
960  const char *bt = TYPE(b);
961  if ((mutt_str_strncasecmp(bt, np->data, btlen) == 0) && (bt[btlen] == 0))
962  {
963  /* the basetype matches */
964  if (wild || (mutt_str_strcasecmp(np->data + btlen + 1, b->subtype) == 0))
965  {
966  choice = b;
967  }
968  }
969  b = b->next;
970  }
971 
972  if (choice)
973  break;
974  }
975 
976  /* Next, look for an autoviewable type */
977  if (!choice)
978  {
979  if (a->parts)
980  b = a->parts;
981  else
982  b = a;
983  while (b)
984  {
985  if (is_autoview(b))
986  choice = b;
987  b = b->next;
988  }
989  }
990 
991  /* Then, look for a text entry */
992  if (!choice)
993  {
994  if (a->parts)
995  b = a->parts;
996  else
997  b = a;
998  int type = 0;
999  while (b)
1000  {
1001  if (b->type == TYPE_TEXT)
1002  {
1003  if ((mutt_str_strcasecmp("plain", b->subtype) == 0) && (type <= TXTPLAIN))
1004  {
1005  choice = b;
1006  type = TXTPLAIN;
1007  }
1008  else if ((mutt_str_strcasecmp("enriched", b->subtype) == 0) && (type <= TXTENRICHED))
1009  {
1010  choice = b;
1011  type = TXTENRICHED;
1012  }
1013  else if ((mutt_str_strcasecmp("html", b->subtype) == 0) && (type <= TXTHTML))
1014  {
1015  choice = b;
1016  type = TXTHTML;
1017  }
1018  }
1019  b = b->next;
1020  }
1021  }
1022 
1023  /* Finally, look for other possibilities */
1024  if (!choice)
1025  {
1026  if (a->parts)
1027  b = a->parts;
1028  else
1029  b = a;
1030  while (b)
1031  {
1032  if (mutt_can_decode(b))
1033  choice = b;
1034  b = b->next;
1035  }
1036  }
1037 
1038  if (choice)
1039  {
1040  if (s->flags & MUTT_DISPLAY && !Weed)
1041  {
1042  fseeko(s->fpin, choice->hdr_offset, SEEK_SET);
1043  mutt_file_copy_bytes(s->fpin, s->fpout, choice->offset - choice->hdr_offset);
1044  }
1045 
1046  if (mutt_str_strcmp("info", ShowMultipartAlternative) == 0)
1047  {
1048  print_part_line(s, choice, 0);
1049  }
1050  mutt_body_handler(choice, s);
1051 
1052  if (mutt_str_strcmp("info", ShowMultipartAlternative) == 0)
1053  {
1054  if (a->parts)
1055  b = a->parts;
1056  else
1057  b = a;
1058  int count = 0;
1059  while (b)
1060  {
1061  if (choice != b)
1062  {
1063  count += 1;
1064  if (count == 1)
1065  state_putc('\n', s);
1066 
1067  print_part_line(s, b, count);
1068  }
1069  b = b->next;
1070  }
1071  }
1072  }
1073  else if (s->flags & MUTT_DISPLAY)
1074  {
1075  /* didn't find anything that we could display! */
1076  state_mark_attach(s);
1077  state_puts(_("[-- Error: Could not display any parts of "
1078  "Multipart/Alternative --]\n"),
1079  s);
1080  rc = -1;
1081  }
1082 
1083  if (mustfree)
1084  mutt_body_free(&a);
1085 
1086  return rc;
1087 }
#define MUTT_DISPLAY
output is displayed to the user
Definition: state.h:40
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:482
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
#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:1282
struct Body * next
next attachment in the list
Definition: body.h:57
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
#define TXTPLAIN
Definition: handler.c:75
The body of an email.
Definition: body.h:33
FILE * fpout
Definition: state.h:34
#define state_putc(x, y)
Definition: state.h:52
int flags
Definition: state.h:36
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:42
#define TXTENRICHED
Definition: handler.c:76
bool Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:38
unsigned int encoding
content-transfer-encoding
Definition: body.h:68
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:36
int mutt_str_strncasecmp(const char *a, const char *b, size_t l)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:653
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
#define state_puts(x, y)
Definition: state.h:51
char * ShowMultipartAlternative
Config: How to display &#39;multipart/alternative&#39; MIME parts.
Definition: handler.c:69
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:1687
static void print_part_line(struct State *s, struct Body *b, int n)
Print a separator for the Mime part.
Definition: handler.c:93
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
#define TYPE(X)
Definition: mime.h:82
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:41
FILE * fpin
Definition: state.h:33
unsigned int type
content-type primary type
Definition: body.h:67
#define TXTHTML
Definition: handler.c:74
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:81
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:56
char * data
Definition: list.h:35
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
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:1502
long hdr_offset
offset in stream where the headers begin.
Definition: body.h:41
A List node for strings.
Definition: list.h:33
int mutt_file_copy_bytes(FILE *in, FILE *out, size_t size)
Copy some content from one file to another.
Definition: file.c:237
struct ParameterList parameter
parameters of the content-type
Definition: body.h:38
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:612
UUEncoded text.
Definition: mime.h:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1094 {
1095  struct Body *choice = NULL;
1096  struct Body *b = NULL;
1097  bool mustfree = false;
1098  int rc = 0;
1099  struct Body *first_part = NULL;
1100  struct Body *zxx_part = NULL;
1101  char *lang = NULL;
1102 
1103  mutt_debug(2, "RFC8255 >> entering in handler multilingual handler\n");
1104  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1105  (a->encoding == ENC_UUENCODED))
1106  {
1107  struct stat st;
1108  mustfree = true;
1109  fstat(fileno(s->fpin), &st);
1110  b = mutt_body_new();
1111  b->length = (long) st.st_size;
1113  s->fpin, mutt_param_get(&a->parameter, "boundary"), (long) st.st_size,
1114  (mutt_str_strcasecmp("digest", a->subtype) == 0));
1115  }
1116  else
1117  b = a;
1118 
1119  a = b;
1120 
1121  if (a->parts)
1122  b = a->parts;
1123  else
1124  b = a;
1125 
1126  char *preferred_languages = NULL;
1127  if (PreferredLanguages)
1128  {
1129  mutt_debug(2, "RFC8255 >> preferred_languages set in config to '%s'\n", PreferredLanguages);
1130  preferred_languages = mutt_str_strdup(PreferredLanguages);
1131  lang = strtok(preferred_languages, ",");
1132  }
1133 
1134  while (lang)
1135  {
1136  while (b)
1137  {
1138  if (mutt_can_decode(b))
1139  {
1140  if (!first_part)
1141  first_part = b;
1142 
1143  if (b->language && (mutt_str_strcmp("zxx", b->language) == 0))
1144  zxx_part = b;
1145 
1146  mutt_debug(2, "RFC8255 >> comparing configuration preferred_language='%s' to mail part content-language='%s'\n",
1147  lang, b->language);
1148  if (lang && b->language && (mutt_str_strcmp(lang, b->language) == 0))
1149  {
1150  mutt_debug(2, "RFC8255 >> preferred_language='%s' matches content-language='%s' >> part selected to be displayed\n",
1151  lang, b->language);
1152  choice = b;
1153  break;
1154  }
1155  }
1156 
1157  b = b->next;
1158  }
1159 
1160  if (choice)
1161  break;
1162 
1163  lang = strtok(NULL, ",");
1164 
1165  if (a->parts)
1166  b = a->parts;
1167  else
1168  b = a;
1169  }
1170 
1171  if (choice)
1172  mutt_body_handler(choice, s);
1173  else
1174  {
1175  if (zxx_part)
1176  mutt_body_handler(zxx_part, s);
1177  else
1178  mutt_body_handler(first_part, s);
1179  }
1180 
1181  if (mustfree)
1182  mutt_body_free(&a);
1183 
1184  FREE(&preferred_languages);
1185  return rc;
1186 }
struct Body * mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
parse a multipart structure
Definition: parse.c:1282
struct Body * next
next attachment in the list
Definition: body.h:57
The body of an email.
Definition: body.h:33
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:42
unsigned int encoding
content-transfer-encoding
Definition: body.h:68
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:36
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1687
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
FILE * fpin
Definition: state.h:33
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:81
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:56
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
Quoted-printable text.
Definition: mime.h:51
#define FREE(x)
Definition: memory.h:46
char * language
content-language (RFC8255)
Definition: body.h:37
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1502
char * PreferredLanguages
Config: Preferred languages for multilingual MIME.
Definition: handler.c:67
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
struct ParameterList parameter
parameters of the content-type
Definition: body.h:38
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:612
UUEncoded text.
Definition: mime.h:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Handler for multipart emails - Implements handler_t.

Definition at line 1191 of file handler.c.

1192 {
1193  struct Body *b = NULL, *p = NULL;
1194  struct stat st;
1195  int count;
1196  int rc = 0;
1197 
1198  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1199  (a->encoding == ENC_UUENCODED))
1200  {
1201  fstat(fileno(s->fpin), &st);
1202  b = mutt_body_new();
1203  b->length = (long) st.st_size;
1205  s->fpin, mutt_param_get(&a->parameter, "boundary"), (long) st.st_size,
1206  (mutt_str_strcasecmp("digest", a->subtype) == 0));
1207  }
1208  else
1209  b = a;
1210 
1211  for (p = b->parts, count = 1; p; p = p->next, count++)
1212  {
1213  if (s->flags & MUTT_DISPLAY)
1214  {
1215  state_mark_attach(s);
1216  if (p->description || p->filename || p->form_name)
1217  {
1218  /* L10N: %s is the attachment description, filename or form_name. */
1219  state_printf(s, _("[-- Attachment #%d: %s --]\n"), count,
1220  p->description ? p->description :
1221  p->filename ? p->filename : p->form_name);
1222  }
1223  else
1224  state_printf(s, _("[-- Attachment #%d --]\n"), count);
1225  print_part_line(s, p, 0);
1226  if (!Weed)
1227  {
1228  fseeko(s->fpin, p->hdr_offset, SEEK_SET);
1229  mutt_file_copy_bytes(s->fpin, s->fpout, p->offset - p->hdr_offset);
1230  }
1231  else
1232  state_putc('\n', s);
1233  }
1234 
1235  rc = mutt_body_handler(p, s);
1236  state_putc('\n', s);
1237 
1238  if (rc != 0)
1239  {
1240  mutt_error(_("One or more parts of this message could not be displayed"));
1241  mutt_debug(1, "Failed on attachment #%d, type %s/%s.\n", count, TYPE(p),
1242  NONULL(p->subtype));
1243  }
1244 
1245  if ((s->flags & MUTT_REPLYING) && IncludeOnlyfirst && (s->flags & MUTT_FIRSTDONE))
1246  {
1247  break;
1248  }
1249  }
1250 
1251  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1252  (a->encoding == ENC_UUENCODED))
1253  {
1254  mutt_body_free(&b);
1255  }
1256 
1257  /* make failure of a single part non-fatal */
1258  if (rc < 0)
1259  rc = 1;
1260  return rc;
1261 }
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:137
#define MUTT_DISPLAY
output is displayed to the user
Definition: state.h:40
#define NONULL(x)
Definition: string2.h:39
#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:1282
struct Body * next
next attachment in the list
Definition: body.h:57
The body of an email.
Definition: body.h:33
FILE * fpout
Definition: state.h:34
#define state_putc(x, y)
Definition: state.h:52
int flags
Definition: state.h:36
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:42
bool Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:38
unsigned int encoding
content-transfer-encoding
Definition: body.h:68
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:36
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
static void print_part_line(struct State *s, struct Body *b, int n)
Print a separator for the Mime part.
Definition: handler.c:93
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
#define TYPE(X)
Definition: mime.h:82
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:41
FILE * fpin
Definition: state.h:33
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:81
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:56
#define mutt_error(...)
Definition: logging.h:88
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
Quoted-printable text.
Definition: mime.h:51
#define MUTT_REPLYING
are we replying?
Definition: state.h:46
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1502
#define MUTT_FIRSTDONE
the first attachment has been done
Definition: state.h:47
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int mutt_file_copy_bytes(FILE *in, FILE *out, size_t size)
Copy some content from one file to another.
Definition: file.c:237
struct ParameterList parameter
parameters of the content-type
Definition: body.h:38
UUEncoded text.
Definition: mime.h:54
bool IncludeOnlyfirst
Config: Only include the first attachment when replying.
Definition: handler.c:66

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1274 {
1275  char *save_prefix = NULL;
1276  FILE *fp = NULL;
1277  size_t tmplength = 0;
1278  LOFF_T tmpoffset = 0;
1279  int decode = 0;
1280  int rc = 0;
1281 
1282  fseeko(s->fpin, b->offset, SEEK_SET);
1283 
1284 #ifdef USE_FMEMOPEN
1285  char *temp = NULL;
1286  size_t tempsize = 0;
1287 #endif
1288 
1289  /* see if we need to decode this part before processing it */
1290  if ((b->encoding == ENC_BASE64) || (b->encoding == ENC_QUOTED_PRINTABLE) ||
1291  (b->encoding == ENC_UUENCODED) || (plaintext || mutt_is_text_part(b)))
1292  /* text subtypes may require character set conversion even with 8bit encoding */
1293  {
1294  const int orig_type = b->type;
1295 #ifndef USE_FMEMOPEN
1296  char tempfile[PATH_MAX];
1297 #endif
1298  if (!plaintext)
1299  {
1300  /* decode to a tempfile, saving the original destination */
1301  fp = s->fpout;
1302 #ifdef USE_FMEMOPEN
1303  s->fpout = open_memstream(&temp, &tempsize);
1304  if (!s->fpout)
1305  {
1306  mutt_error(_("Unable to open 'memory stream'"));
1307  mutt_debug(1, "Can't open 'memory stream'.\n");
1308  return -1;
1309  }
1310 #else
1311  mutt_mktemp(tempfile, sizeof(tempfile));
1312  s->fpout = mutt_file_fopen(tempfile, "w");
1313  if (!s->fpout)
1314  {
1315  mutt_error(_("Unable to open temporary file"));
1316  mutt_debug(1, "Can't open %s.\n", tempfile);
1317  return -1;
1318  }
1319 #endif
1320  /* decoding the attachment changes the size and offset, so save a copy
1321  * of the "real" values now, and restore them after processing
1322  */
1323  tmplength = b->length;
1324  tmpoffset = b->offset;
1325 
1326  /* if we are decoding binary bodies, we don't want to prefix each
1327  * line with the prefix or else the data will get corrupted.
1328  */
1329  save_prefix = s->prefix;
1330  s->prefix = NULL;
1331 
1332  decode = 1;
1333  }
1334  else
1335  b->type = TYPE_TEXT;
1336 
1337  mutt_decode_attachment(b, s);
1338 
1339  if (decode)
1340  {
1341  b->length = ftello(s->fpout);
1342  b->offset = 0;
1343 #ifdef USE_FMEMOPEN
1344  /* When running under torify, mutt_file_fclose(&s->fpout) does not seem to
1345  * update tempsize. On the other hand, fflush does. See
1346  * https://github.com/neomutt/neomutt/issues/440 */
1347  fflush(s->fpout);
1348 #endif
1349  mutt_file_fclose(&s->fpout);
1350 
1351  /* restore final destination and substitute the tempfile for input */
1352  s->fpout = fp;
1353  fp = s->fpin;
1354 #ifdef USE_FMEMOPEN
1355  if (tempsize)
1356  {
1357  s->fpin = fmemopen(temp, tempsize, "r");
1358  }
1359  else
1360  { /* fmemopen cannot handle zero-length buffers */
1361  s->fpin = mutt_file_fopen("/dev/null", "r");
1362  }
1363  if (!s->fpin)
1364  {
1365  mutt_perror(_("failed to re-open 'memory stream'"));
1366  return -1;
1367  }
1368 #else
1369  s->fpin = fopen(tempfile, "r");
1370  unlink(tempfile);
1371 #endif
1372  /* restore the prefix */
1373  s->prefix = save_prefix;
1374  }
1375 
1376  b->type = orig_type;
1377  }
1378 
1379  /* process the (decoded) body part */
1380  if (handler)
1381  {
1382  rc = handler(b, s);
1383  if (rc != 0)
1384  {
1385  mutt_debug(1, "Failed on attachment of type %s/%s.\n", TYPE(b), NONULL(b->subtype));
1386  }
1387 
1388  if (decode)
1389  {
1390  b->length = tmplength;
1391  b->offset = tmpoffset;
1392 
1393  /* restore the original source stream */
1394  mutt_file_fclose(&s->fpin);
1395 #ifdef USE_FMEMOPEN
1396  FREE(&temp);
1397 #endif
1398  s->fpin = fp;
1399  }
1400  }
1401  s->flags |= MUTT_FIRSTDONE;
1402 
1403  return rc;
1404 }
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1728
#define NONULL(x)
Definition: string2.h:39
#define mutt_perror(...)
Definition: logging.h:89
char * prefix
Definition: state.h:35
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
#define _(a)
Definition: message.h:28
FILE * fpout
Definition: state.h:34
int flags
Definition: state.h:36
unsigned int encoding
content-transfer-encoding
Definition: body.h:68
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:36
#define mutt_mktemp(a, b)
Definition: muttlib.h:71
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
#define PATH_MAX
Definition: mutt.h:46
Type: &#39;text/*&#39;.
Definition: mime.h:38
#define TYPE(X)
Definition: mime.h:82
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:429
FILE * fpin
Definition: state.h:33
unsigned int type
content-type primary type
Definition: body.h:67
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:548
int mutt_file_fclose(FILE **f)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_error(...)
Definition: logging.h:88
Quoted-printable text.
Definition: mime.h:51
#define FREE(x)
Definition: memory.h:46
#define MUTT_FIRSTDONE
the first attachment has been done
Definition: state.h:47
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
UUEncoded text.
Definition: mime.h:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1410 {
1411  struct Body *octetstream = b->parts->next;
1412  int rc = crypt_pgp_encrypted_handler(octetstream, s);
1413  b->goodsig |= octetstream->goodsig;
1414 
1415  return rc;
1416 }
struct Body * next
next attachment in the list
Definition: body.h:57
The body of an email.
Definition: body.h:33
int crypt_pgp_encrypted_handler(struct Body *a, struct State *s)
Wrapper for CryptModuleSpecs::encrypted_handler()
Definition: cryptglue.c:218
bool goodsig
good cryptographic signature
Definition: body.h:90
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1422 {
1423  struct Body *octetstream = b->parts->next->next;
1424  /* exchange encodes the octet-stream, so re-run it through the decoder */
1425  int rc = run_decode_and_handler(octetstream, s, crypt_pgp_encrypted_handler, false);
1426  b->goodsig |= octetstream->goodsig;
1427 
1428  return rc;
1429 }
struct Body * next
next attachment in the list
Definition: body.h:57
The body of an email.
Definition: body.h:33
int crypt_pgp_encrypted_handler(struct Body *a, struct State *s)
Wrapper for CryptModuleSpecs::encrypted_handler()
Definition: cryptglue.c:218
bool goodsig
good cryptographic signature
Definition: body.h:90
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:1272
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1439 {
1440  char buf[5];
1441  int ch, i;
1442  char bufi[BUFI_SIZE];
1443  size_t l = 0;
1444 
1445  buf[4] = '\0';
1446 
1447  if (istext)
1448  state_set_prefix(s);
1449 
1450  while (len > 0)
1451  {
1452  for (i = 0; (i < 4) && (len > 0); len--)
1453  {
1454  ch = fgetc(s->fpin);
1455  if (ch == EOF)
1456  break;
1457  if ((ch >= 0) && (ch < 128) && (base64val(ch) != -1 || ch == '='))
1458  buf[i++] = ch;
1459  }
1460  if (i != 4)
1461  {
1462  /* "i" may be zero if there is trailing whitespace, which is not an error */
1463  if (i != 0)
1464  mutt_debug(2, "didn't get a multiple of 4 chars.\n");
1465  break;
1466  }
1467 
1468  const int c1 = base64val(buf[0]);
1469  const int c2 = base64val(buf[1]);
1470  ch = (c1 << 2) | (c2 >> 4);
1471  bufi[l++] = ch;
1472 
1473  if (buf[2] == '=')
1474  break;
1475  const int c3 = base64val(buf[2]);
1476  ch = ((c2 & 0xf) << 4) | (c3 >> 2);
1477  bufi[l++] = ch;
1478 
1479  if (buf[3] == '=')
1480  break;
1481  const int c4 = base64val(buf[3]);
1482  ch = ((c3 & 0x3) << 6) | c4;
1483  bufi[l++] = ch;
1484 
1485  if ((l + 8) >= sizeof(bufi))
1486  convert_to_state(cd, bufi, &l, s);
1487  }
1488 
1489  convert_to_state(cd, bufi, &l, s);
1490  convert_to_state(cd, 0, 0, s);
1491 
1492  state_reset_prefix(s);
1493 }
#define state_reset_prefix(s)
Definition: state.h:50
#define state_set_prefix(s)
Definition: state.h:49
#define BUFI_SIZE
Definition: handler.c:71
FILE * fpin
Definition: state.h:33
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:120
#define base64val(c)
Definition: base64.h:28
#define mutt_debug(LEVEL,...)
Definition: logging.h:85

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1503 {
1504  if (!b || !s)
1505  return -1;
1506 
1507  bool plaintext = false;
1508  handler_t handler = NULL;
1509  int rc = 0;
1510 
1511  int oflags = s->flags;
1512 
1513  /* first determine which handler to use to process this part */
1514 
1515  if (is_autoview(b))
1516  {
1517  handler = autoview_handler;
1518  s->flags &= ~MUTT_CHARCONV;
1519  }
1520  else if (b->type == TYPE_TEXT)
1521  {
1522  if (mutt_str_strcasecmp("plain", b->subtype) == 0)
1523  {
1524  /* avoid copying this part twice since removing the transfer-encoding is
1525  * the only operation needed.
1526  */
1527  if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b))
1529  else if (ReflowText &&
1530  (mutt_str_strcasecmp("flowed",
1531  mutt_param_get(&b->parameter, "format")) == 0))
1532  {
1533  handler = rfc3676_handler;
1534  }
1535  else
1536  {
1537  handler = text_plain_handler;
1538  }
1539  }
1540  else if (mutt_str_strcasecmp("enriched", b->subtype) == 0)
1541  handler = text_enriched_handler;
1542  else /* text body type without a handler */
1543  plaintext = false;
1544  }
1545  else if (b->type == TYPE_MESSAGE)
1546  {
1547  if (mutt_is_message_type(b->type, b->subtype))
1548  handler = message_handler;
1549  else if (mutt_str_strcasecmp("delivery-status", b->subtype) == 0)
1550  plaintext = true;
1551  else if (mutt_str_strcasecmp("external-body", b->subtype) == 0)
1552  handler = external_body_handler;
1553  }
1554  else if (b->type == TYPE_MULTIPART)
1555  {
1556  if ((mutt_str_strcmp("inline", ShowMultipartAlternative) != 0) &&
1557  (mutt_str_strcasecmp("alternative", b->subtype) == 0))
1558  {
1559  handler = alternative_handler;
1560  }
1561  else if ((mutt_str_strcmp("inline", ShowMultipartAlternative) != 0) &&
1562  (mutt_str_strcasecmp("multilingual", b->subtype) == 0))
1563  {
1564  handler = multilingual_handler;
1565  }
1566  else if ((WithCrypto != 0) && (mutt_str_strcasecmp("signed", b->subtype) == 0))
1567  {
1568  if (!mutt_param_get(&b->parameter, "protocol"))
1569  mutt_error(_("Error: multipart/signed has no protocol"));
1570  else if (s->flags & MUTT_VERIFY)
1571  handler = mutt_signed_handler;
1572  }
1574  {
1575  handler = valid_pgp_encrypted_handler;
1576  }
1578  {
1580  }
1581 
1582  if (!handler)
1583  handler = multipart_handler;
1584 
1585  if ((b->encoding != ENC_7BIT) && (b->encoding != ENC_8BIT) && (b->encoding != ENC_BINARY))
1586  {
1587  mutt_debug(1, "Bad encoding type %d for multipart entity, assuming 7 bit\n", b->encoding);
1588  b->encoding = ENC_7BIT;
1589  }
1590  }
1591  else if ((WithCrypto != 0) && (b->type == TYPE_APPLICATION))
1592  {
1593  if (OptDontHandlePgpKeys && (mutt_str_strcasecmp("pgp-keys", b->subtype) == 0))
1594  {
1595  /* pass raw part through for key extraction */
1596  plaintext = true;
1597  }
1598  else if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b))
1600  else if (((WithCrypto & APPLICATION_SMIME) != 0) && mutt_is_application_smime(b))
1602  }
1603 
1604  /* only respect disposition == attachment if we're not
1605  displaying from the attachment menu (i.e. pager) */
1606  if ((!HonorDisposition || ((b->disposition != DISP_ATTACH) || OptViewAttach)) &&
1607  (plaintext || handler))
1608  {
1609  rc = run_decode_and_handler(b, s, handler, plaintext);
1610  }
1611  /* print hint to use attachment menu for disposition == attachment
1612  if we're not already being called from there */
1613  else if ((s->flags & MUTT_DISPLAY) || ((b->disposition == DISP_ATTACH) && !OptViewAttach &&
1614  HonorDisposition && (plaintext || handler)))
1615  {
1616  const char *str = NULL;
1617  char keystroke[SHORT_STRING];
1618  keystroke[0] = '\0';
1619 
1620  if (!OptViewAttach)
1621  {
1622  if (km_expand_key(keystroke, sizeof(keystroke),
1623  km_find_func(MENU_PAGER, OP_VIEW_ATTACHMENTS)))
1624  {
1626  {
1627  /* L10N: Caution: Arguments %1$s and %2$s are also defined but should
1628  not be used in this translation!
1629 
1630  %3$s expands to a keystroke/key binding, e.g. 'v'.
1631  */
1632  str = _(
1633  "[-- This is an attachment (use '%3$s' to view this part) --]\n");
1634  }
1635  else
1636  {
1637  /* L10N: %s/%s is a MIME type, e.g. "text/plain".
1638  The last %s expands to a keystroke/key binding, e.g. 'v'.
1639  */
1640  str =
1641  _("[-- %s/%s is unsupported (use '%s' to view this part) --]\n");
1642  }
1643  }
1644  else
1645  {
1646  if (HonorDisposition && (b->disposition == DISP_ATTACH))
1647  {
1648  str = _("[-- This is an attachment (need 'view-attachments' bound to "
1649  "key) --]\n");
1650  }
1651  else
1652  {
1653  /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1654  str = _("[-- %s/%s is unsupported (need 'view-attachments' bound to "
1655  "key) --]\n");
1656  }
1657  }
1658  }
1659  else
1660  {
1661  if (HonorDisposition && (b->disposition == DISP_ATTACH))
1662  str = _("[-- This is an attachment --]\n");
1663  else
1664  {
1665  /* L10N: %s/%s is a MIME type, e.g. "text/plain". */
1666  str = _("[-- %s/%s is unsupported --]\n");
1667  }
1668  }
1669  state_mark_attach(s);
1670  state_printf(s, str, TYPE(b), b->subtype, keystroke);
1671  }
1672 
1673  s->flags = oflags | (s->flags & MUTT_FIRSTDONE);
1674  if (rc != 0)
1675  {
1676  mutt_debug(1, "Bailing on attachment of type %s/%s.\n", TYPE(b), NONULL(b->subtype));
1677  }
1678 
1679  return rc;
1680 }
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:137
#define MUTT_DISPLAY
output is displayed to the user
Definition: state.h:40
#define NONULL(x)
Definition: string2.h:39
#define SHORT_STRING
Definition: string2.h:34
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1214
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:482
static int alternative_handler(struct Body *a, struct State *s)
Handler for multipart alternative emails - Implements handler_t.
Definition: handler.c:911
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:44
int(* handler_t)(struct Body *b, struct State *s)
typedef handler_t - Manage a PGP or S/MIME encrypted MIME part
Definition: handler.c:85
int crypt_pgp_application_handler(struct Body *m, struct State *s)
Wrapper for CryptModuleSpecs::application_handler()
Definition: cryptglue.c:205
7-bit text
Definition: mime.h:49
int mutt_signed_handler(struct Body *a, struct State *s)
Verify a "multipart/signed" body - Implements handler_t.
Definition: crypt.c:1071
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:427
#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:460
8-bit text
Definition: mime.h:50
struct Keymap * km_find_func(int menu, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:798
int crypt_smime_application_handler(struct Body *m, struct State *s)
Wrapper for CryptModuleSpecs::application_handler()
Definition: cryptglue.c:386
int mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:465
unsigned int disposition
content-disposition
Definition: body.h:69
int flags
Definition: state.h:36
static int malformed_pgp_encrypted_handler(struct Body *b, struct State *s)
Handler for invalid pgp-encrypted emails - Implements handler_t.
Definition: handler.c:1421
Content is attached.
Definition: mime.h:63
WHERE bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition: options.h:33
unsigned int encoding
content-transfer-encoding
Definition: body.h:68
static int message_handler(struct Body *a, struct State *s)
Handler for message/rfc822 body parts - Implements handler_t.
Definition: handler.c:693
bool HonorDisposition
Config: Don&#39;t display MIME parts inline if they have a disposition of &#39;attachment&#39;.
Definition: handler.c:64
char * subtype
content-type subtype
Definition: body.h:36
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:770
char * ShowMultipartAlternative
Config: How to display &#39;multipart/alternative&#39; MIME parts.
Definition: handler.c:69
#define MUTT_VERIFY
perform signature verification
Definition: state.h:41
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:1409
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:1272
#define TYPE(X)
Definition: mime.h:82
static int multilingual_handler(struct Body *a, struct State *s)
Handler for multi-lingual emails - Implements handler_t.
Definition: handler.c:1093
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:41
int mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:510
unsigned int type
content-type primary type
Definition: body.h:67
#define APPLICATION_PGP
Definition: ncrypt.h:129
Type: &#39;message/*&#39;.
Definition: mime.h:35
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:81
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
static int autoview_handler(struct Body *a, struct State *s)
Handler for autoviewable attachments - Implements handler_t.
Definition: handler.c:527
#define mutt_error(...)
Definition: logging.h:88
Binary.
Definition: mime.h:53
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
static int multipart_handler(struct Body *a, struct State *s)
Handler for multipart emails - Implements handler_t.
Definition: handler.c:1191
WHERE bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:52
#define MUTT_FIRSTDONE
the first attachment has been done
Definition: state.h:47
int mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:569
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int rfc3676_handler(struct Body *a, struct State *s)
Body handler implementing RFC3676 for format=flowed - Implements handler_t.
Definition: rfc3676.c:317
static int external_body_handler(struct Body *b, struct State *s)
Handler for external-body emails - Implements handler_t.
Definition: handler.c:745
static int text_plain_handler(struct Body *b, struct State *s)
Handler for plain text - Implements handler_t.
Definition: handler.c:667
struct ParameterList parameter
parameters of the content-type
Definition: body.h:38
#define WithCrypto
Definition: ncrypt.h:154
bool ReflowText
Config: Reformat paragraphs of &#39;format=flowed&#39; text.
Definition: handler.c:68
Pager pager (email viewer)
Definition: keymap.h:74
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:612
Type: &#39;application/*&#39;.
Definition: mime.h:33
#define APPLICATION_SMIME
Definition: ncrypt.h:130

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1688 {
1689  if (is_autoview(a))
1690  return true;
1691  else if (a->type == TYPE_TEXT)
1692  return true;
1693  else if (a->type == TYPE_MESSAGE)
1694  return true;
1695  else if (a->type == TYPE_MULTIPART)
1696  {
1697  if (WithCrypto)
1698  {
1699  if ((mutt_str_strcasecmp(a->subtype, "signed") == 0) ||
1700  (mutt_str_strcasecmp(a->subtype, "encrypted") == 0))
1701  {
1702  return true;
1703  }
1704  }
1705 
1706  for (struct Body *b = a->parts; b; b = b->next)
1707  {
1708  if (mutt_can_decode(b))
1709  return true;
1710  }
1711  }
1712  else if ((WithCrypto != 0) && a->type == TYPE_APPLICATION)
1713  {
1714  if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(a))
1715  return true;
1717  return true;
1718  }
1719 
1720  return false;
1721 }
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:482
struct Body * next
next attachment in the list
Definition: body.h:57
The body of an email.
Definition: body.h:33
char * subtype
content-type subtype
Definition: body.h:36
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:1687
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
int mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:510
unsigned int type
content-type primary type
Definition: body.h:67
#define APPLICATION_PGP
Definition: ncrypt.h:129
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
int mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:569
#define WithCrypto
Definition: ncrypt.h:154
Type: &#39;application/*&#39;.
Definition: mime.h:33
#define APPLICATION_SMIME
Definition: ncrypt.h:130

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1729 {
1730  int istext = mutt_is_text_part(b);
1731  iconv_t cd = (iconv_t)(-1);
1732 
1733  if (istext && s->flags & MUTT_CHARCONV)
1734  {
1735  char *charset = mutt_param_get(&b->parameter, "charset");
1736  if (!charset && AssumedCharset && *AssumedCharset)
1737  charset = mutt_ch_get_default_charset();
1738  if (charset && Charset)
1740  }
1741  else if (istext && b->charset)
1743 
1744  fseeko(s->fpin, b->offset, SEEK_SET);
1745  switch (b->encoding)
1746  {
1747  case ENC_QUOTED_PRINTABLE:
1748  decode_quoted(s, b->length,
1749  istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1751  cd);
1752  break;
1753  case ENC_BASE64:
1754  mutt_decode_base64(s, b->length,
1755  istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1757  cd);
1758  break;
1759  case ENC_UUENCODED:
1760  decode_uuencoded(s, b->length,
1761  istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1763  cd);
1764  break;
1765  default:
1766  decode_xbit(s, b->length,
1767  istext || (((WithCrypto & APPLICATION_PGP) != 0) &&
1769  cd);
1770  break;
1771  }
1772 
1773  if (cd != (iconv_t)(-1))
1774  iconv_close(cd);
1775 }
static void decode_xbit(struct State *s, long len, bool istext, iconv_t cd)
Decode xbit-encoded text.
Definition: handler.c:167
static void decode_uuencoded(struct State *s, long len, bool istext, iconv_t cd)
Decode uuencoded text.
Definition: handler.c:371
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:44
char * Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:52
static void decode_quoted(struct State *s, long len, bool istext, iconv_t cd)
Decode an attachment encoded with quoted-printable.
Definition: handler.c:305
LOFF_T offset
offset where the actual data begins
Definition: body.h:45
void mutt_decode_base64(struct State *s, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition: handler.c:1438
int flags
Definition: state.h:36
unsigned int encoding
content-transfer-encoding
Definition: body.h:68
Base-64 encoded text.
Definition: mime.h:52
char * AssumedCharset
Config: If a message is missing a character set, assume this character set.
Definition: charset.c:51
LOFF_T length
length (in bytes) of attachment
Definition: body.h:46
iconv_t mutt_ch_iconv_open(const char *tocode, const char *fromcode, int flags)
Set up iconv for conversions.
Definition: charset.c:529
char * charset
charset of attached file
Definition: body.h:52
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:429
FILE * fpin
Definition: state.h:33
int mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:510
#define APPLICATION_PGP
Definition: ncrypt.h:129
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:81
Quoted-printable text.
Definition: mime.h:51
char * mutt_ch_get_default_charset(void)
Get the default character set.
Definition: charset.c:399
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:81
struct ParameterList parameter
parameters of the content-type
Definition: body.h:38
#define WithCrypto
Definition: ncrypt.h:154
UUEncoded text.
Definition: mime.h:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

bool HonorDisposition

Config: Don't display MIME parts inline if they have a disposition of 'attachment'.

Definition at line 64 of file handler.c.

bool ImplicitAutoview

Config: Display MIME attachments inline if a 'copiousoutput' mailcap entry exists.

Definition at line 65 of file handler.c.

bool IncludeOnlyfirst

Config: Only include the first attachment when replying.

Definition at line 66 of file handler.c.

char* PreferredLanguages

Config: Preferred languages for multilingual MIME.

Definition at line 67 of file handler.c.

bool ReflowText

Config: Reformat paragraphs of 'format=flowed' text.

Definition at line 68 of file handler.c.

char* ShowMultipartAlternative

Config: How to display 'multipart/alternative' MIME parts.

Definition at line 69 of file handler.c.