NeoMutt  2020-06-26-89-g172cd3
Teaching an old dog new tricks
DOXYGEN
parse.c File Reference

Miscellaneous email parsing routines. More...

#include "config.h"
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "mutt.h"
#include "parse.h"
#include "body.h"
#include "email.h"
#include "envelope.h"
#include "from.h"
#include "globals.h"
#include "mime.h"
#include "mutt_globals.h"
#include "parameter.h"
#include "rfc2047.h"
#include "rfc2231.h"
#include "url.h"
#include "autocrypt/lib.h"
+ Include dependency graph for parse.c:

Go to the source code of this file.

Macros

#define CONTENT_TOO_BIG   (1 << 30)
 

Functions

void mutt_auto_subscribe (const char *mailto)
 Check if user is subscribed to mailing list. More...
 
static void parse_parameters (struct ParameterList *pl, const char *s, bool allow_value_spaces)
 Parse a list of Parameters. More...
 
static void parse_content_disposition (const char *s, struct Body *ct)
 Parse a content disposition. More...
 
static void parse_references (struct ListHead *head, const char *s)
 Parse references from an email header. More...
 
static void parse_content_language (const char *s, struct Body *ct)
 Read the content's language. More...
 
bool mutt_matches_ignore (const char *s)
 Does the string match the ignore list. More...
 
enum ContentType mutt_check_mime_type (const char *s)
 Check a MIME type string. More...
 
char * mutt_extract_message_id (const char *s, size_t *len)
 Find a message-id. More...
 
int mutt_check_encoding (const char *c)
 Check the encoding type. More...
 
void mutt_parse_content_type (const char *s, struct Body *ct)
 Parse a content type. More...
 
static struct AutocryptHeaderparse_autocrypt (struct AutocryptHeader *head, const char *s)
 Parse an Autocrypt header line. More...
 
int mutt_rfc822_parse_line (struct Envelope *env, struct Email *e, char *line, char *p, bool user_hdrs, bool weed, bool do_2047)
 Parse an email header. More...
 
char * mutt_rfc822_read_line (FILE *fp, char *line, size_t *linelen)
 Read a header line from a file. More...
 
struct Envelopemutt_rfc822_read_header (FILE *fp, struct Email *e, bool user_hdrs, bool weed)
 parses an RFC822 header More...
 
struct Bodymutt_read_mime_header (FILE *fp, bool digest)
 Parse a MIME header. More...
 
bool mutt_is_message_type (int type, const char *subtype)
 Determine if a mime type matches a message or not. More...
 
void mutt_parse_part (FILE *fp, struct Body *b)
 Parse a MIME part. More...
 
struct Bodymutt_parse_multipart (FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
 parse a multipart structure More...
 
struct Bodymutt_rfc822_parse_message (FILE *fp, struct Body *parent)
 parse a Message/RFC822 body More...
 
bool mutt_parse_mailto (struct Envelope *e, char **body, const char *src)
 Parse a mailto:// url. More...
 

Detailed Description

Miscellaneous email parsing routines.

Authors
  • Richard Russon
  • Pietro Cerutti

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 parse.c.

Macro Definition Documentation

◆ CONTENT_TOO_BIG

#define CONTENT_TOO_BIG   (1 << 30)

Definition at line 58 of file parse.c.

Function Documentation

◆ mutt_auto_subscribe()

void mutt_auto_subscribe ( const char *  mailto)

Check if user is subscribed to mailing list.

Parameters
mailtoURL of mailing list subscribe

Definition at line 64 of file parse.c.

65 {
66  if (!mailto)
67  return;
68 
69  if (!AutoSubscribeCache)
71 
73  return;
74 
76 
77  struct Envelope *lpenv = mutt_env_new(); /* parsed envelope from the List-Post mailto: URL */
78 
79  if (mutt_parse_mailto(lpenv, NULL, mailto) && !TAILQ_EMPTY(&lpenv->to))
80  {
81  const char *mailbox = TAILQ_FIRST(&lpenv->to)->mailbox;
82  if (mailbox && !mutt_regexlist_match(&SubscribedLists, mailbox) &&
83  !mutt_regexlist_match(&UnMailLists, mailbox) &&
85  {
86  /* mutt_regexlist_add() detects duplicates, so it is safe to
87  * try to add here without any checks. */
88  mutt_regexlist_add(&MailLists, mailbox, REG_ICASE, NULL);
89  mutt_regexlist_add(&SubscribedLists, mailbox, REG_ICASE, NULL);
90  }
91  }
92 
93  mutt_env_free(&lpenv);
94 }
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:354
struct RegexList SubscribedLists
List of regexes to match subscribed mailing lists.
Definition: globals.c:52
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition: hash.c:327
#define TAILQ_FIRST(head)
Definition: queue.h:716
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: globals.c:49
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: globals.c:50
struct HashTable * AutoSubscribeCache
Hash Table of auto-subscribed mailing lists.
Definition: globals.c:48
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:98
bool mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1574
int mutt_regexlist_add(struct RegexList *rl, const char *str, int flags, struct Buffer *err)
Compile a regex string and add it to a list.
Definition: regex.c:131
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:190
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: globals.c:51
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:714
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:99
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:251
The header of an Email.
Definition: envelope.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_parameters()

static void parse_parameters ( struct ParameterList *  pl,
const char *  s,
bool  allow_value_spaces 
)
static

Parse a list of Parameters.

Parameters
plParameter list for the results
sString to parse
allow_value_spacesAllow values with spaces

Autocrypt defines an irregular parameter format that doesn't follow the rfc. It splits keydata across multiple lines without parameter continuations. The allow_value_spaces parameter allows parsing those values which are split by spaces when unfolded.

Definition at line 107 of file parse.c.

108 {
109  struct Parameter *pnew = NULL;
110  const char *p = NULL;
111  size_t i;
112 
113  struct Buffer *buf = mutt_buffer_pool_get();
114  /* allow_value_spaces, especially with autocrypt keydata, can result
115  * in quite large parameter values. avoid frequent reallocs by
116  * pre-sizing */
117  if (allow_value_spaces)
119 
120  mutt_debug(LL_DEBUG2, "'%s'\n", s);
121 
122  while (*s)
123  {
124  mutt_buffer_reset(buf);
125 
126  p = strpbrk(s, "=;");
127  if (!p)
128  {
129  mutt_debug(LL_DEBUG1, "malformed parameter: %s\n", s);
130  goto bail;
131  }
132 
133  /* if we hit a ; now the parameter has no value, just skip it */
134  if (*p != ';')
135  {
136  i = p - s;
137  /* remove whitespace from the end of the attribute name */
138  while ((i > 0) && mutt_str_is_email_wsp(s[i - 1]))
139  i--;
140 
141  /* the check for the missing parameter token is here so that we can skip
142  * over any quoted value that may be present. */
143  if (i == 0)
144  {
145  mutt_debug(LL_DEBUG1, "missing attribute: %s\n", s);
146  pnew = NULL;
147  }
148  else
149  {
150  pnew = mutt_param_new();
151  pnew->attribute = mutt_strn_dup(s, i);
152  }
153 
154  do
155  {
156  s = mutt_str_skip_email_wsp(p + 1); /* skip over the =, or space if we loop */
157 
158  if (*s == '"')
159  {
160  bool state_ascii = true;
161  s++;
162  for (; *s; s++)
163  {
164  if (C_AssumedCharset)
165  {
166  // As iso-2022-* has a character of '"' with non-ascii state, ignore it
167  if (*s == 0x1b)
168  {
169  if ((s[1] == '(') && ((s[2] == 'B') || (s[2] == 'J')))
170  state_ascii = true;
171  else
172  state_ascii = false;
173  }
174  }
175  if (state_ascii && (*s == '"'))
176  break;
177  if (*s == '\\')
178  {
179  if (s[1])
180  {
181  s++;
182  /* Quote the next character */
183  mutt_buffer_addch(buf, *s);
184  }
185  }
186  else
187  mutt_buffer_addch(buf, *s);
188  }
189  if (*s)
190  s++; /* skip over the " */
191  }
192  else
193  {
194  for (; *s && *s != ' ' && *s != ';'; s++)
195  mutt_buffer_addch(buf, *s);
196  }
197 
198  p = s;
199  } while (allow_value_spaces && (*s == ' '));
200 
201  /* if the attribute token was missing, 'new' will be NULL */
202  if (pnew)
203  {
204  pnew->value = mutt_buffer_strdup(buf);
205 
206  mutt_debug(LL_DEBUG2, "parse_parameter: '%s' = '%s'\n",
207  pnew->attribute ? pnew->attribute : "", pnew->value ? pnew->value : "");
208 
209  /* Add this parameter to the list */
210  TAILQ_INSERT_HEAD(pl, pnew, entries);
211  }
212  }
213  else
214  {
215  mutt_debug(LL_DEBUG1, "parameter with no value: %s\n", s);
216  s = p;
217  }
218 
219  /* Find the next parameter */
220  if ((*s != ';') && !(s = strchr(s, ';')))
221  break; /* no more parameters */
222 
223  do
224  {
225  /* Move past any leading whitespace. the +1 skips over the semicolon */
226  s = mutt_str_skip_email_wsp(s + 1);
227  } while (*s == ';'); /* skip empty parameters */
228  }
229 
230 bail:
231 
234 }
char * attribute
Parameter name.
Definition: parameter.h:34
char * C_AssumedCharset
Config: If a message is missing a character set, assume this character set.
Definition: charset.c:52
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Parameter * mutt_param_new(void)
Create a new Parameter.
Definition: parameter.c:39
void rfc2231_decode_parameters(struct ParameterList *pl)
Decode a Parameter list.
Definition: rfc2231.c:235
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
String manipulation buffer.
Definition: buffer.h:33
Log at debug level 2.
Definition: logging.h:41
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:553
bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition: string.c:764
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:748
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:789
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
char * value
Parameter value.
Definition: parameter.h:35
Log at debug level 1.
Definition: logging.h:40
Attribute associated with a MIME part.
Definition: parameter.h:32
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_content_disposition()

static void parse_content_disposition ( const char *  s,
struct Body ct 
)
static

Parse a content disposition.

Parameters
sString to parse
ctBody to save the result

e.g. parse a string "inline" and set DISP_INLINE.

Definition at line 243 of file parse.c.

244 {
245  struct ParameterList pl;
246  TAILQ_INIT(&pl);
247 
248  if (mutt_istr_startswith(s, "inline"))
249  ct->disposition = DISP_INLINE;
250  else if (mutt_istr_startswith(s, "form-data"))
252  else
253  ct->disposition = DISP_ATTACH;
254 
255  /* Check to see if a default filename was given */
256  s = strchr(s, ';');
257  if (s)
258  {
259  s = mutt_str_skip_email_wsp(s + 1);
260  parse_parameters(&pl, s, false);
261  s = mutt_param_get(&pl, "filename");
262  if (s)
263  mutt_str_replace(&ct->filename, s);
264  s = mutt_param_get(&pl, "name");
265  if (s)
266  ct->form_name = mutt_str_dup(s);
267  mutt_param_free(&pl);
268  }
269 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:107
char * form_name
Content-Disposition form-data name param.
Definition: body.h:41
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
Content is form-data.
Definition: mime.h:64
Content is attached.
Definition: mime.h:63
#define TAILQ_INIT(head)
Definition: queue.h:758
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:748
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
Content is inline.
Definition: mime.h:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_references()

static void parse_references ( struct ListHead *  head,
const char *  s 
)
static

Parse references from an email header.

Parameters
headList to receive the references
sString to parse

Definition at line 276 of file parse.c.

277 {
278  if (!head)
279  return;
280 
281  char *m = NULL;
282  for (size_t off = 0; (m = mutt_extract_message_id(s, &off)); s += off)
283  {
284  mutt_list_insert_head(head, m);
285  }
286 }
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:356
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_content_language()

static void parse_content_language ( const char *  s,
struct Body ct 
)
static

Read the content's language.

Parameters
sLanguage string
ctBody of the email

Definition at line 293 of file parse.c.

294 {
295  if (!s || !ct)
296  return;
297 
298  mutt_debug(LL_DEBUG2, "RFC8255 >> Content-Language set to %s\n", s);
299  ct->language = mutt_str_dup(s);
300 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
Log at debug level 2.
Definition: logging.h:41
char * language
content-language (RFC8255)
Definition: body.h:38
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_matches_ignore()

bool mutt_matches_ignore ( const char *  s)

Does the string match the ignore list.

Parameters
sString to check
Return values
trueIf string matches

Checks Ignore and UnIgnore using mutt_list_match

Definition at line 309 of file parse.c.

310 {
311  return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
312 }
bool mutt_list_match(const char *s, struct ListHead *h)
Is the string in the list (see notes)
Definition: list.c:195
struct ListHead Ignore
List of header patterns to ignore.
Definition: globals.c:45
struct ListHead UnIgnore
List of header patterns to unignore (see)
Definition: globals.c:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_check_mime_type()

enum ContentType mutt_check_mime_type ( const char *  s)

Check a MIME type string.

Parameters
sString to check
Return values
numMIME type, e.g. TYPE_TEXT

Definition at line 319 of file parse.c.

320 {
321  if (mutt_istr_equal("text", s))
322  return TYPE_TEXT;
323  if (mutt_istr_equal("multipart", s))
324  return TYPE_MULTIPART;
325 #ifdef SUN_ATTACHMENT
326  if (mutt_istr_equal("x-sun-attachment", s))
327  return TYPE_MULTIPART;
328 #endif
329  if (mutt_istr_equal("application", s))
330  return TYPE_APPLICATION;
331  if (mutt_istr_equal("message", s))
332  return TYPE_MESSAGE;
333  if (mutt_istr_equal("image", s))
334  return TYPE_IMAGE;
335  if (mutt_istr_equal("audio", s))
336  return TYPE_AUDIO;
337  if (mutt_istr_equal("video", s))
338  return TYPE_VIDEO;
339  if (mutt_istr_equal("model", s))
340  return TYPE_MODEL;
341  if (mutt_istr_equal("*", s))
342  return TYPE_ANY;
343  if (mutt_istr_equal(".*", s))
344  return TYPE_ANY;
345 
346  return TYPE_OTHER;
347 }
Unknown Content-Type.
Definition: mime.h:31
Type: &#39;audio/*&#39;.
Definition: mime.h:32
Type: &#39;*&#39; or &#39;.*&#39;.
Definition: mime.h:40
Type: &#39;video/*&#39;.
Definition: mime.h:39
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
Type: &#39;text/*&#39;.
Definition: mime.h:38
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Type: &#39;model/*&#39;.
Definition: mime.h:36
Type: &#39;image/*&#39;.
Definition: mime.h:34
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_extract_message_id()

char* mutt_extract_message_id ( const char *  s,
size_t *  len 
)

Find a message-id.

Parameters
[in]sString to parse
[out]lenNumber of bytes of s parsed
Return values
ptrMessage id found
NULLNo more message ids

Definition at line 356 of file parse.c.

357 {
358  if (!s || (*s == '\0'))
359  return NULL;
360 
361  char *decoded = mutt_str_dup(s);
362  rfc2047_decode(&decoded);
363 
364  char *res = NULL;
365 
366  for (const char *p = decoded, *beg = NULL; *p; p++)
367  {
368  if (*p == '<')
369  {
370  beg = p;
371  continue;
372  }
373 
374  if (beg && (*p == '>'))
375  {
376  if (len)
377  *len = p - decoded + 1;
378  res = mutt_strn_dup(beg, (p + 1) - beg);
379  break;
380  }
381  }
382 
383  FREE(&decoded);
384  return res;
385 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:639
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:553
#define FREE(x)
Definition: memory.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_check_encoding()

int mutt_check_encoding ( const char *  c)

Check the encoding type.

Parameters
cString to check
Return values
numEncoding type, e.g. ENC_QUOTED_PRINTABLE

Definition at line 392 of file parse.c.

393 {
394  if (mutt_istr_startswith(c, "7bit"))
395  return ENC_7BIT;
396  if (mutt_istr_startswith(c, "8bit"))
397  return ENC_8BIT;
398  if (mutt_istr_startswith(c, "binary"))
399  return ENC_BINARY;
400  if (mutt_istr_startswith(c, "quoted-printable"))
401  return ENC_QUOTED_PRINTABLE;
402  if (mutt_istr_startswith(c, "base64"))
403  return ENC_BASE64;
404  if (mutt_istr_startswith(c, "x-uuencode"))
405  return ENC_UUENCODED;
406 #ifdef SUN_ATTACHMENT
407  if (mutt_istr_startswith(c, "uuencode"))
408  return ENC_UUENCODED;
409 #endif
410  return ENC_OTHER;
411 }
7-bit text
Definition: mime.h:49
8-bit text
Definition: mime.h:50
Base-64 encoded text.
Definition: mime.h:52
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
Binary.
Definition: mime.h:53
Quoted-printable text.
Definition: mime.h:51
Encoding unknown.
Definition: mime.h:48
UUEncoded text.
Definition: mime.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_content_type()

void mutt_parse_content_type ( const char *  s,
struct Body ct 
)

Parse a content type.

Parameters
sString to parse
ctBody to save the result

e.g. parse a string "inline" and set DISP_INLINE.

Definition at line 420 of file parse.c.

421 {
422  if (!s || !ct)
423  return;
424 
425  FREE(&ct->subtype);
427 
428  /* First extract any existing parameters */
429  char *pc = strchr(s, ';');
430  if (pc)
431  {
432  *pc++ = 0;
433  while (*pc && IS_SPACE(*pc))
434  pc++;
435  parse_parameters(&ct->parameter, pc, false);
436 
437  /* Some pre-RFC1521 gateways still use the "name=filename" convention,
438  * but if a filename has already been set in the content-disposition,
439  * let that take precedence, and don't set it here */
440  pc = mutt_param_get(&ct->parameter, "name");
441  if (pc && !ct->filename)
442  ct->filename = mutt_str_dup(pc);
443 
444 #ifdef SUN_ATTACHMENT
445  /* this is deep and utter perversion */
446  pc = mutt_param_get(&ct->parameter, "conversions");
447  if (pc)
448  ct->encoding = mutt_check_encoding(pc);
449 #endif
450  }
451 
452  /* Now get the subtype */
453  char *subtype = strchr(s, '/');
454  if (subtype)
455  {
456  *subtype++ = '\0';
457  for (pc = subtype; *pc && !IS_SPACE(*pc) && (*pc != ';'); pc++)
458  ; // do nothing
459 
460  *pc = '\0';
461  ct->subtype = mutt_str_dup(subtype);
462  }
463 
464  /* Finally, get the major type */
465  ct->type = mutt_check_mime_type(s);
466 
467 #ifdef SUN_ATTACHMENT
468  if (mutt_istr_equal("x-sun-attachment", s))
469  ct->subtype = mutt_str_dup("x-sun-attachment");
470 #endif
471 
472  if (ct->type == TYPE_OTHER)
473  {
474  mutt_str_replace(&ct->xtype, s);
475  }
476 
477  if (!ct->subtype)
478  {
479  /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type
480  * field, so we can attempt to convert the type to Body here. */
481  if (ct->type == TYPE_TEXT)
482  ct->subtype = mutt_str_dup("plain");
483  else if (ct->type == TYPE_AUDIO)
484  ct->subtype = mutt_str_dup("basic");
485  else if (ct->type == TYPE_MESSAGE)
486  ct->subtype = mutt_str_dup("rfc822");
487  else if (ct->type == TYPE_OTHER)
488  {
489  char buf[128];
490 
491  ct->type = TYPE_APPLICATION;
492  snprintf(buf, sizeof(buf), "x-%s", s);
493  ct->subtype = mutt_str_dup(buf);
494  }
495  else
496  ct->subtype = mutt_str_dup("x-unknown");
497  }
498 
499  /* Default character set for text types. */
500  if (ct->type == TYPE_TEXT)
501  {
502  pc = mutt_param_get(&ct->parameter, "charset");
503  if (pc)
504  {
505  /* Microsoft Outlook seems to think it is necessary to repeat
506  * charset=, strip it off not to confuse ourselves */
507  if (mutt_istrn_equal(pc, "charset=", sizeof("charset=") - 1))
508  mutt_param_set(&ct->parameter, "charset", pc + (sizeof("charset=") - 1));
509  }
510  else
511  {
512  mutt_param_set(&ct->parameter, "charset",
513  (C_AssumedCharset) ? (const char *) mutt_ch_get_default_charset() :
514  "us-ascii");
515  }
516  }
517 }
char * C_AssumedCharset
Config: If a message is missing a character set, assume this character set.
Definition: charset.c:52
Unknown Content-Type.
Definition: mime.h:31
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
Type: &#39;audio/*&#39;.
Definition: mime.h:32
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:107
bool mutt_istrn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:626
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:319
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
char * subtype
content-type subtype
Definition: body.h:37
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:392
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * xtype
content-type if x-unknown
Definition: body.h:36
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
#define IS_SPACE(ch)
Definition: string2.h:38
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
#define FREE(x)
Definition: memory.h:40
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
char * mutt_ch_get_default_charset(void)
Get the default character set.
Definition: charset.c:440
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
Type: &#39;application/*&#39;.
Definition: mime.h:33
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_autocrypt()

static struct AutocryptHeader* parse_autocrypt ( struct AutocryptHeader head,
const char *  s 
)
static

Parse an Autocrypt header line.

Parameters
headAutocrypt header to insert before
sHeader string to parse
Return values
ptrNew AutocryptHeader inserted before head

Definition at line 526 of file parse.c.

527 {
528  struct AutocryptHeader *autocrypt = mutt_autocrypthdr_new();
529  autocrypt->next = head;
530 
531  struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
532  parse_parameters(&pl, s, true);
533  if (TAILQ_EMPTY(&pl))
534  {
535  autocrypt->invalid = true;
536  goto cleanup;
537  }
538 
539  struct Parameter *p = NULL;
540  TAILQ_FOREACH(p, &pl, entries)
541  {
542  if (mutt_istr_equal(p->attribute, "addr"))
543  {
544  if (autocrypt->addr)
545  {
546  autocrypt->invalid = true;
547  goto cleanup;
548  }
549  autocrypt->addr = p->value;
550  p->value = NULL;
551  }
552  else if (mutt_istr_equal(p->attribute, "prefer-encrypt"))
553  {
554  if (mutt_istr_equal(p->value, "mutual"))
555  autocrypt->prefer_encrypt = true;
556  }
557  else if (mutt_istr_equal(p->attribute, "keydata"))
558  {
559  if (autocrypt->keydata)
560  {
561  autocrypt->invalid = true;
562  goto cleanup;
563  }
564  autocrypt->keydata = p->value;
565  p->value = NULL;
566  }
567  else if (p->attribute && (p->attribute[0] != '_'))
568  {
569  autocrypt->invalid = true;
570  goto cleanup;
571  }
572  }
573 
574  /* Checking the addr against From, and for multiple valid headers
575  * occurs later, after all the headers are parsed. */
576  if (!autocrypt->addr || !autocrypt->keydata)
577  autocrypt->invalid = true;
578 
579 cleanup:
580  mutt_param_free(&pl);
581  return autocrypt;
582 }
char * attribute
Parameter name.
Definition: parameter.h:34
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
bool prefer_encrypt
Definition: envelope.h:45
struct AutocryptHeader * mutt_autocrypthdr_new(void)
Create a new AutocryptHeader.
Definition: envelope.c:65
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:107
char * keydata
Definition: envelope.h:44
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
struct AutocryptHeader * next
Definition: envelope.h:47
char * addr
Definition: envelope.h:43
Parse Autocrypt header info.
Definition: envelope.h:41
char * value
Parameter value.
Definition: parameter.h:35
Attribute associated with a MIME part.
Definition: parameter.h:32
#define TAILQ_EMPTY(head)
Definition: queue.h:714
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_rfc822_parse_line()

int mutt_rfc822_parse_line ( struct Envelope env,
struct Email e,
char *  line,
char *  p,
bool  user_hdrs,
bool  weed,
bool  do_2047 
)

Parse an email header.

Parameters
envEnvelope of the email
eEmail
lineHeader field, e.g. 'to'
pHeader value, e.g. 'john@.nosp@m.exam.nosp@m.ple.c.nosp@m.om'
user_hdrsIf true, save into the Envelope's userhdrs
weedIf true, perform header weeding (filtering)
do_2047If true, perform RFC2047 decoding of the field
Return values
1If the field is recognised
0If not

Process a line from an email header. Each line that is recognised is parsed and the information put in the Envelope or Header.

Definition at line 600 of file parse.c.

602 {
603  if (!env || !line)
604  return 0;
605 
606  bool matched = false;
607 
608  switch (tolower(line[0]))
609  {
610  case 'a':
611  if (mutt_istr_equal(line + 1, "pparently-to"))
612  {
613  mutt_addrlist_parse(&env->to, p);
614  matched = true;
615  }
616  else if (mutt_istr_equal(line + 1, "pparently-from"))
617  {
618  mutt_addrlist_parse(&env->from, p);
619  matched = true;
620  }
621  break;
622 
623  case 'b':
624  if (mutt_istr_equal(line + 1, "cc"))
625  {
626  mutt_addrlist_parse(&env->bcc, p);
627  matched = true;
628  }
629  break;
630 
631  case 'c':
632  if (mutt_istr_equal(line + 1, "c"))
633  {
634  mutt_addrlist_parse(&env->cc, p);
635  matched = true;
636  }
637  else
638  {
639  size_t plen = mutt_istr_startswith(line + 1, "ontent-");
640  if (plen != 0)
641  {
642  if (mutt_istr_equal(line + 1 + plen, "type"))
643  {
644  if (e)
646  matched = true;
647  }
648  else if (mutt_istr_equal(line + 1 + plen, "language"))
649  {
650  if (e)
652  matched = true;
653  }
654  else if (mutt_istr_equal(line + 1 + plen, "transfer-encoding"))
655  {
656  if (e)
658  matched = true;
659  }
660  else if (mutt_istr_equal(line + 1 + plen, "length"))
661  {
662  if (e)
663  {
664  int rc = mutt_str_atol(p, (long *) &e->content->length);
665  if ((rc < 0) || (e->content->length < 0))
666  e->content->length = -1;
667  if (e->content->length > CONTENT_TOO_BIG)
669  }
670  matched = true;
671  }
672  else if (mutt_istr_equal(line + 1 + plen, "description"))
673  {
674  if (e)
675  {
678  }
679  matched = true;
680  }
681  else if (mutt_istr_equal(line + 1 + plen, "disposition"))
682  {
683  if (e)
685  matched = true;
686  }
687  }
688  }
689  break;
690 
691  case 'd':
692  if (!mutt_istr_equal("ate", line + 1))
693  break;
694 
695  mutt_str_replace(&env->date, p);
696  if (e)
697  {
698  struct Tz tz;
699  e->date_sent = mutt_date_parse_date(p, &tz);
700  if (e->date_sent > 0)
701  {
702  e->zhours = tz.zhours;
703  e->zminutes = tz.zminutes;
704  e->zoccident = tz.zoccident;
705  }
706  }
707  matched = true;
708  break;
709 
710  case 'e':
711  if (mutt_istr_equal("xpires", line + 1) && e &&
712  (mutt_date_parse_date(p, NULL) < mutt_date_epoch()))
713  {
714  e->expired = true;
715  }
716  break;
717 
718  case 'f':
719  if (mutt_istr_equal("rom", line + 1))
720  {
721  mutt_addrlist_parse(&env->from, p);
722  matched = true;
723  }
724 #ifdef USE_NNTP
725  else if (mutt_istr_equal(line + 1, "ollowup-to"))
726  {
727  if (!env->followup_to)
728  {
731  }
732  matched = true;
733  }
734 #endif
735  break;
736 
737  case 'i':
738  if (!mutt_istr_equal(line + 1, "n-reply-to"))
739  break;
740 
742  parse_references(&env->in_reply_to, p);
743  matched = true;
744  break;
745 
746  case 'l':
747  if (mutt_istr_equal(line + 1, "ines"))
748  {
749  if (e)
750  {
751  /* HACK - neomutt has, for a very short time, produced negative
752  * Lines header values. Ignore them. */
753  if ((mutt_str_atoi(p, &e->lines) < 0) || (e->lines < 0))
754  e->lines = 0;
755  }
756 
757  matched = true;
758  }
759  else if (mutt_istr_equal(line + 1, "ist-Post"))
760  {
761  /* RFC2369. FIXME: We should ignore whitespace, but don't. */
762  if (!mutt_strn_equal(p, "NO", 2))
763  {
764  char *beg = NULL, *end = NULL;
765  for (beg = strchr(p, '<'); beg; beg = strchr(end, ','))
766  {
767  beg++;
768  end = strchr(beg, '>');
769  if (!end)
770  break;
771 
772  char *mlist = mutt_strn_dup(beg, end - beg);
773  /* Take the first mailto URL */
774  if (url_check_scheme(mlist) == U_MAILTO)
775  {
776  FREE(&env->list_post);
777  env->list_post = mlist;
778  if (C_AutoSubscribe)
780 
781  break;
782  }
783  FREE(&mlist);
784  }
785  }
786  matched = true;
787  }
788  break;
789 
790  case 'm':
791  if (mutt_istr_equal(line + 1, "ime-version"))
792  {
793  if (e)
794  e->mime = true;
795  matched = true;
796  }
797  else if (mutt_istr_equal(line + 1, "essage-id"))
798  {
799  /* We add a new "Message-ID:" when building a message */
800  FREE(&env->message_id);
801  env->message_id = mutt_extract_message_id(p, NULL);
802  matched = true;
803  }
804  else
805  {
806  size_t plen = mutt_istr_startswith(line + 1, "ail-");
807  if (plen != 0)
808  {
809  if (mutt_istr_equal(line + 1 + plen, "reply-to"))
810  {
811  /* override the Reply-To: field */
813  mutt_addrlist_parse(&env->reply_to, p);
814  matched = true;
815  }
816  else if (mutt_istr_equal(line + 1 + plen, "followup-to"))
817  {
819  matched = true;
820  }
821  }
822  }
823  break;
824 
825 #ifdef USE_NNTP
826  case 'n':
827  if (mutt_istr_equal(line + 1, "ewsgroups"))
828  {
829  FREE(&env->newsgroups);
832  matched = true;
833  }
834  break;
835 #endif
836 
837  case 'o':
838  /* field 'Organization:' saves only for pager! */
839  if (mutt_istr_equal(line + 1, "rganization"))
840  {
841  if (!env->organization && !mutt_istr_equal(p, "unknown"))
842  env->organization = mutt_str_dup(p);
843  }
844  break;
845 
846  case 'r':
847  if (mutt_istr_equal(line + 1, "eferences"))
848  {
849  mutt_list_free(&env->references);
850  parse_references(&env->references, p);
851  matched = true;
852  }
853  else if (mutt_istr_equal(line + 1, "eply-to"))
854  {
855  mutt_addrlist_parse(&env->reply_to, p);
856  matched = true;
857  }
858  else if (mutt_istr_equal(line + 1, "eturn-path"))
859  {
861  matched = true;
862  }
863  else if (mutt_istr_equal(line + 1, "eceived"))
864  {
865  if (e && !e->received)
866  {
867  char *d = strrchr(p, ';');
868  if (d)
869  {
870  d = mutt_str_skip_email_wsp(d + 1);
871  e->received = mutt_date_parse_date(d, NULL);
872  }
873  }
874  }
875  break;
876 
877  case 's':
878  if (mutt_istr_equal(line + 1, "ubject"))
879  {
880  if (!env->subject)
881  env->subject = mutt_str_dup(p);
882  matched = true;
883  }
884  else if (mutt_istr_equal(line + 1, "ender"))
885  {
886  mutt_addrlist_parse(&env->sender, p);
887  matched = true;
888  }
889  else if (mutt_istr_equal(line + 1, "tatus"))
890  {
891  if (e)
892  {
893  while (*p)
894  {
895  switch (*p)
896  {
897  case 'O':
898  e->old = C_MarkOld;
899  break;
900  case 'R':
901  e->read = true;
902  break;
903  case 'r':
904  e->replied = true;
905  break;
906  }
907  p++;
908  }
909  }
910  matched = true;
911  }
912  else if (e && (mutt_istr_equal("upersedes", line + 1) ||
913  mutt_istr_equal("upercedes", line + 1)))
914  {
915  FREE(&env->supersedes);
916  env->supersedes = mutt_str_dup(p);
917  }
918  break;
919 
920  case 't':
921  if (mutt_istr_equal(line + 1, "o"))
922  {
923  mutt_addrlist_parse(&env->to, p);
924  matched = true;
925  }
926 #ifdef USE_AUTOCRYPT
927  else if (mutt_istr_equal(line + 1, "utocrypt"))
928  {
929  if (C_Autocrypt)
930  {
931  env->autocrypt = parse_autocrypt(env->autocrypt, p);
932  matched = true;
933  }
934  }
935  else if (mutt_istr_equal(line + 1, "utocrypt-gossip"))
936  {
937  if (C_Autocrypt)
938  {
940  matched = true;
941  }
942  }
943 #endif
944  break;
945 
946  case 'x':
947  if (mutt_istr_equal(line + 1, "-status"))
948  {
949  if (e)
950  {
951  while (*p)
952  {
953  switch (*p)
954  {
955  case 'A':
956  e->replied = true;
957  break;
958  case 'D':
959  e->deleted = true;
960  break;
961  case 'F':
962  e->flagged = true;
963  break;
964  default:
965  break;
966  }
967  p++;
968  }
969  }
970  matched = true;
971  }
972  else if (mutt_istr_equal(line + 1, "-label"))
973  {
974  FREE(&env->x_label);
975  env->x_label = mutt_str_dup(p);
976  matched = true;
977  }
978 #ifdef USE_NNTP
979  else if (mutt_istr_equal(line + 1, "-comment-to"))
980  {
981  if (!env->x_comment_to)
982  env->x_comment_to = mutt_str_dup(p);
983  matched = true;
984  }
985  else if (mutt_istr_equal(line + 1, "ref"))
986  {
987  if (!env->xref)
988  env->xref = mutt_str_dup(p);
989  matched = true;
990  }
991 #endif
992  else if (mutt_istr_equal(line + 1, "-original-to"))
993  {
995  matched = true;
996  }
997  break;
998 
999  default:
1000  break;
1001  }
1002 
1003  /* Keep track of the user-defined headers */
1004  if (!matched && user_hdrs)
1005  {
1006  /* restore the original line */
1007  line[strlen(line)] = ':';
1008 
1009  if (!(weed && C_Weed && mutt_matches_ignore(line)))
1010  {
1012  if (do_2047)
1013  rfc2047_decode(&np->data);
1014  }
1015  }
1016 
1017  return matched;
1018 }
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:221
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:414
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:309
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:691
int lines
How many lines in the body of this message?
Definition: email.h:84
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:257
bool C_MarkOld
Config: Mark new emails as old when leaving the mailbox.
Definition: globals.c:36
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
struct AutocryptHeader * autocrypt_gossip
Definition: envelope.h:86
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
char * supersedes
Supersedes header.
Definition: envelope.h:70
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
char * xref
List of cross-references.
Definition: envelope.h:76
bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: config.c:37
char * date
Sent date.
Definition: envelope.h:71
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
struct Body * content
List of MIME parts.
Definition: email.h:90
static void parse_content_disposition(const char *s, struct Body *ct)
Parse a content disposition.
Definition: parse.c:243
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
struct AutocryptHeader * autocrypt
Definition: envelope.h:85
int mutt_str_atol(const char *str, long *dst)
Convert ASCII string to a long.
Definition: string.c:193
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:443
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:65
bool expired
Already expired?
Definition: email.h:52
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
bool C_AutoSubscribe
Config: Automatically check if the user is subscribed to a mailing list.
Definition: globals.c:35
bool read
Email is read.
Definition: email.h:51
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
bool old
Email is seen, but unread.
Definition: email.h:50
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:639
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:553
bool mime
Has a MIME-Version header?
Definition: email.h:42
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
static struct AutocryptHeader * parse_autocrypt(struct AutocryptHeader *head, const char *s)
Parse an Autocrypt header line.
Definition: parse.c:526
static void parse_content_language(const char *s, struct Body *ct)
Read the content&#39;s language.
Definition: parse.c:293
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:81
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:705
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:392
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:356
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:748
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
unsigned int zhours
Hours away from UTC.
Definition: email.h:63
char * description
content-description
Definition: body.h:40
static void parse_references(struct ListHead *head, const char *s)
Parse references from an email header.
Definition: parse.c:276
char * list_post
This stores a mailto URL, or nothing.
Definition: envelope.h:65
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:598
#define CONTENT_TOO_BIG
Definition: parse.c:58
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:420
char * data
String.
Definition: list.h:36
char * subject
Email&#39;s subject.
Definition: envelope.h:66
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:56
List of recognised Timezones.
Definition: date.h:42
bool flagged
Marked important?
Definition: email.h:43
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
bool deleted
Email is deleted.
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:54
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
#define FREE(x)
Definition: memory.h:40
char * organization
Organisation header.
Definition: envelope.h:73
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: globals.c:40
Url is mailto://.
Definition: url.h:44
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
int const char int line
Definition: acutest.h:617
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:34
struct AddressList x_original_to
Email&#39;s &#39;X-Orig-to&#39;.
Definition: envelope.h:64
char * x_label
X-Label.
Definition: envelope.h:72
unsigned int zminutes
Minutes away from UTC.
Definition: email.h:64
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:82
void mutt_auto_subscribe(const char *mailto)
Check if user is subscribed to mailing list.
Definition: parse.c:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_rfc822_read_line()

char* mutt_rfc822_read_line ( FILE *  fp,
char *  line,
size_t *  linelen 
)

Read a header line from a file.

Parameters
fpFile to read from
lineBuffer to store the result
linelenLength of buffer
Return values
ptrLine read from file

Reads an arbitrarily long header field, and looks ahead for continuation lines. "line" must point to a dynamically allocated string; it is increased if more space is required to fit the whole line.

Definition at line 1031 of file parse.c.

1032 {
1033  if (!fp || !line || !linelen)
1034  return NULL;
1035 
1036  char *buf = line;
1037  int ch;
1038  size_t offset = 0;
1039 
1040  while (true)
1041  {
1042  if (!fgets(buf, *linelen - offset, fp) || /* end of file or */
1043  (IS_SPACE(*line) && !offset)) /* end of headers */
1044  {
1045  *line = '\0';
1046  return line;
1047  }
1048 
1049  const size_t len = mutt_str_len(buf);
1050  if (len == 0)
1051  return line;
1052 
1053  buf += len - 1;
1054  if (*buf == '\n')
1055  {
1056  /* we did get a full line. remove trailing space */
1057  while (IS_SPACE(*buf))
1058  {
1059  *buf-- = '\0'; /* we can't come beyond line's beginning because
1060  * it begins with a non-space */
1061  }
1062 
1063  /* check to see if the next line is a continuation line */
1064  ch = fgetc(fp);
1065  if ((ch != ' ') && (ch != '\t'))
1066  {
1067  ungetc(ch, fp);
1068  return line; /* next line is a separate header field or EOH */
1069  }
1070 
1071  /* eat tabs and spaces from the beginning of the continuation line */
1072  while (((ch = fgetc(fp)) == ' ') || (ch == '\t'))
1073  ; // do nothing
1074 
1075  ungetc(ch, fp);
1076  *++buf = ' '; /* string is still terminated because we removed
1077  at least one whitespace char above */
1078  }
1079 
1080  buf++;
1081  offset = buf - line;
1082  if (*linelen < (offset + 256))
1083  {
1084  /* grow the buffer */
1085  *linelen += 256;
1086  mutt_mem_realloc(&line, *linelen);
1087  buf = line + offset;
1088  }
1089  }
1090  /* not reached */
1091 }
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define IS_SPACE(ch)
Definition: string2.h:38
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
int const char int line
Definition: acutest.h:617
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_rfc822_read_header()

struct Envelope* mutt_rfc822_read_header ( FILE *  fp,
struct Email e,
bool  user_hdrs,
bool  weed 
)

parses an RFC822 header

Parameters
fpStream to read from
eCurrent Email (optional)
user_hdrsIf set, store user headers Used for recall-message and postpone modes
weedIf this parameter is set and the user has activated the $weed option, honor the header weed list for user headers. Used for recall-message
Return values
ptrNewly allocated envelope structure

Caller should free the Envelope using mutt_env_free().

Definition at line 1106 of file parse.c.

1107 {
1108  if (!fp)
1109  return NULL;
1110 
1111  struct Envelope *env = mutt_env_new();
1112  char *p = NULL;
1113  LOFF_T loc;
1114  size_t linelen = 1024;
1115  char *line = mutt_mem_malloc(linelen);
1116  char buf[linelen + 1];
1117 
1118  if (e)
1119  {
1120  if (!e->content)
1121  {
1122  e->content = mutt_body_new();
1123 
1124  /* set the defaults from RFC1521 */
1125  e->content->type = TYPE_TEXT;
1126  e->content->subtype = mutt_str_dup("plain");
1127  e->content->encoding = ENC_7BIT;
1128  e->content->length = -1;
1129 
1130  /* RFC2183 says this is arbitrary */
1132  }
1133  }
1134 
1135  while ((loc = ftello(fp)) != -1)
1136  {
1137  line = mutt_rfc822_read_line(fp, line, &linelen);
1138  if (*line == '\0')
1139  break;
1140  p = strpbrk(line, ": \t");
1141  if (!p || (*p != ':'))
1142  {
1143  char return_path[1024];
1144  time_t t;
1145 
1146  /* some bogus MTAs will quote the original "From " line */
1147  if (mutt_str_startswith(line, ">From "))
1148  continue; /* just ignore */
1149  else if (is_from(line, return_path, sizeof(return_path), &t))
1150  {
1151  /* MH sometimes has the From_ line in the middle of the header! */
1152  if (e && !e->received)
1153  e->received = t - mutt_date_local_tz(t);
1154  continue;
1155  }
1156 
1157  fseeko(fp, loc, SEEK_SET);
1158  break; /* end of header */
1159  }
1160 
1161  *buf = '\0';
1162 
1163  if (mutt_replacelist_match(&SpamList, buf, sizeof(buf), line))
1164  {
1165  if (!mutt_regexlist_match(&NoSpamList, line))
1166  {
1167  /* if spam tag already exists, figure out how to amend it */
1168  if ((!mutt_buffer_is_empty(&env->spam)) && (*buf != '\0'))
1169  {
1170  /* If C_SpamSeparator defined, append with separator */
1171  if (C_SpamSeparator)
1172  {
1174  mutt_buffer_addstr(&env->spam, buf);
1175  }
1176  else /* overwrite */
1177  {
1178  mutt_buffer_reset(&env->spam);
1179  mutt_buffer_addstr(&env->spam, buf);
1180  }
1181  }
1182 
1183  /* spam tag is new, and match expr is non-empty; copy */
1184  else if (mutt_buffer_is_empty(&env->spam) && (*buf != '\0'))
1185  {
1186  mutt_buffer_addstr(&env->spam, buf);
1187  }
1188 
1189  /* match expr is empty; plug in null string if no existing tag */
1190  else if (mutt_buffer_is_empty(&env->spam))
1191  {
1192  mutt_buffer_addstr(&env->spam, "");
1193  }
1194 
1195  if (!mutt_buffer_is_empty(&env->spam))
1196  mutt_debug(LL_DEBUG5, "spam = %s\n", env->spam.data);
1197  }
1198  }
1199 
1200  *p = '\0';
1201  p = mutt_str_skip_email_wsp(p + 1);
1202  if (*p == '\0')
1203  continue; /* skip empty header fields */
1204 
1205  mutt_rfc822_parse_line(env, e, line, p, user_hdrs, weed, true);
1206  }
1207 
1208  FREE(&line);
1209 
1210  if (e)
1211  {
1212  e->content->hdr_offset = e->offset;
1213  e->content->offset = ftello(fp);
1214 
1216 
1217  if (env->subject)
1218  {
1219  regmatch_t pmatch[1];
1220 
1221  if (mutt_regex_capture(C_ReplyRegex, env->subject, 1, pmatch))
1222  {
1223  env->real_subj = env->subject + pmatch[0].rm_eo;
1224  }
1225  else
1226  env->real_subj = env->subject;
1227  }
1228 
1229  if (e->received < 0)
1230  {
1231  mutt_debug(LL_DEBUG1, "resetting invalid received time to 0\n");
1232  e->received = 0;
1233  }
1234 
1235  /* check for missing or invalid date */
1236  if (e->date_sent <= 0)
1237  {
1239  "no date found, using received time from msg separator\n");
1240  e->date_sent = e->received;
1241  }
1242 
1243 #ifdef USE_AUTOCRYPT
1244  if (C_Autocrypt)
1245  {
1247  /* No sense in taking up memory after the header is processed */
1249  }
1250 #endif
1251  }
1252 
1253  return env;
1254 }
bool mutt_replacelist_match(struct ReplaceList *rl, char *buf, size_t buflen, const char *str)
Does a string match a pattern?
Definition: regex.c:474
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
int mutt_rfc822_parse_line(struct Envelope *env, struct Email *e, char *line, char *p, bool user_hdrs, bool weed, bool do_2047)
Parse an email header.
Definition: parse.c:600
7-bit text
Definition: mime.h:49
bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: config.c:37
struct Body * content
List of MIME parts.
Definition: email.h:90
struct Regex * C_ReplyRegex
Config: Regex to match message reply subjects like "re: ".
Definition: globals.c:37
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
char * real_subj
Offset of the real subject.
Definition: envelope.h:67
struct AutocryptHeader * autocrypt
Definition: envelope.h:85
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:779
time_t mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:205
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:190
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * subtype
content-type subtype
Definition: body.h:37
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:81
int mutt_autocrypt_process_autocrypt_header(struct Email *e, struct Envelope *env)
Parse an Autocrypt email header.
Definition: autocrypt.c:250
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
struct RegexList NoSpamList
List of regexes to whitelist non-spam emails.
Definition: globals.c:43
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * data
Pointer to data.
Definition: buffer.h:35
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:748
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
match a regex against a string, with provided options
Definition: regex.c:593
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:44
char * subject
Email&#39;s subject.
Definition: envelope.h:66
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:56
void mutt_autocrypthdr_free(struct AutocryptHeader **p)
Free an AutocryptHeader.
Definition: envelope.c:74
Log at debug level 1.
Definition: logging.h:40
#define FREE(x)
Definition: memory.h:40
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:48
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
int const char int line
Definition: acutest.h:617
Log at debug level 5.
Definition: logging.h:44
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Content is inline.
Definition: mime.h:62
char * C_SpamSeparator
Config: Separator for multiple spam headers.
Definition: globals.c:39
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:82
The header of an Email.
Definition: envelope.h:54
struct Buffer spam
Spam header.
Definition: envelope.h:80
char * mutt_rfc822_read_line(FILE *fp, char *line, size_t *linelen)
Read a header line from a file.
Definition: parse.c:1031
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_read_mime_header()

struct Body* mutt_read_mime_header ( FILE *  fp,
bool  digest 
)

Parse a MIME header.

Parameters
fpstream to read from
digesttrue if reading subparts of a multipart/digest
Return values
ptrNew Body containing parsed structure

Definition at line 1262 of file parse.c.

1263 {
1264  if (!fp)
1265  return NULL;
1266 
1267  struct Body *p = mutt_body_new();
1268  struct Envelope *env = mutt_env_new();
1269  char *c = NULL;
1270  size_t linelen = 1024;
1271  char *line = mutt_mem_malloc(linelen);
1272 
1273  p->hdr_offset = ftello(fp);
1274 
1275  p->encoding = ENC_7BIT; /* default from RFC1521 */
1276  p->type = digest ? TYPE_MESSAGE : TYPE_TEXT;
1277  p->disposition = DISP_INLINE;
1278 
1279  while (*(line = mutt_rfc822_read_line(fp, line, &linelen)) != 0)
1280  {
1281  /* Find the value of the current header */
1282  c = strchr(line, ':');
1283  if (c)
1284  {
1285  *c = '\0';
1286  c = mutt_str_skip_email_wsp(c + 1);
1287  if (*c == '\0')
1288  {
1289  mutt_debug(LL_DEBUG1, "skipping empty header field: %s\n", line);
1290  continue;
1291  }
1292  }
1293  else
1294  {
1295  mutt_debug(LL_DEBUG1, "bogus MIME header: %s\n", line);
1296  break;
1297  }
1298 
1299  size_t plen = mutt_istr_startswith(line, "content-");
1300  if (plen != 0)
1301  {
1302  if (mutt_istr_equal("type", line + plen))
1304  else if (mutt_istr_equal("language", line + plen))
1305  parse_content_language(c, p);
1306  else if (mutt_istr_equal("transfer-encoding", line + plen))
1307  p->encoding = mutt_check_encoding(c);
1308  else if (mutt_istr_equal("disposition", line + plen))
1310  else if (mutt_istr_equal("description", line + plen))
1311  {
1312  mutt_str_replace(&p->description, c);
1314  }
1315  }
1316 #ifdef SUN_ATTACHMENT
1317  else if ((plen = mutt_istr_startswith(line, "x-sun-")))
1318  {
1319  if (mutt_istr_equal("data-type", line + plen))
1321  else if (mutt_istr_equal("encoding-info", line + plen))
1322  p->encoding = mutt_check_encoding(c);
1323  else if (mutt_istr_equal("content-lines", line + plen))
1324  mutt_param_set(&p->parameter, "content-lines", c);
1325  else if (mutt_istr_equal("data-description", line + plen))
1326  {
1327  mutt_str_replace(&p->description, c);
1329  }
1330  }
1331 #endif
1332  else
1333  {
1334  if (mutt_rfc822_parse_line(env, NULL, line, c, false, false, false))
1335  p->mime_headers = env;
1336  }
1337  }
1338  p->offset = ftello(fp); /* Mark the start of the real data */
1339  if ((p->type == TYPE_TEXT) && !p->subtype)
1340  p->subtype = mutt_str_dup("plain");
1341  else if ((p->type == TYPE_MESSAGE) && !p->subtype)
1342  p->subtype = mutt_str_dup("rfc822");
1343 
1344  FREE(&line);
1345 
1346  if (p->mime_headers)
1348  else
1349  mutt_env_free(&env);
1350 
1351  return p;
1352 }
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
int mutt_rfc822_parse_line(struct Envelope *env, struct Email *e, char *line, char *p, bool user_hdrs, bool weed, bool do_2047)
Parse an email header.
Definition: parse.c:600
7-bit text
Definition: mime.h:49
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
static void parse_content_disposition(const char *s, struct Body *ct)
Parse a content disposition.
Definition: parse.c:243
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:779
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:639
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
static void parse_content_language(const char *s, struct Body *ct)
Read the content&#39;s language.
Definition: parse.c:293
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
char * subtype
content-type subtype
Definition: body.h:37
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:392
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
Type: &#39;text/*&#39;.
Definition: mime.h:38
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:748
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
char * description
content-description
Definition: body.h:40
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:420
Log at debug level 1.
Definition: logging.h:40
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
int const char int line
Definition: acutest.h:617
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
The header of an Email.
Definition: envelope.h:54
char * mutt_rfc822_read_line(FILE *fp, char *line, size_t *linelen)
Read a header line from a file.
Definition: parse.c:1031
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_message_type()

bool mutt_is_message_type ( int  type,
const char *  subtype 
)

Determine if a mime type matches a message or not.

Parameters
typeMessage type enum value
subtypeMessage subtype
Return values
trueType is message/news or message/rfc822
falseOtherwise

Definition at line 1361 of file parse.c.

1362 {
1363  if (type != TYPE_MESSAGE)
1364  return false;
1365 
1366  subtype = NONULL(subtype);
1367  return mutt_istr_equal(subtype, "rfc822") || mutt_istr_equal(subtype, "news");
1368 }
#define NONULL(x)
Definition: string2.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
Type: &#39;message/*&#39;.
Definition: mime.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_part()

void mutt_parse_part ( FILE *  fp,
struct Body b 
)

Parse a MIME part.

Parameters
fpFile to read from
bBody to store the results in

Definition at line 1375 of file parse.c.

1376 {
1377  if (!fp || !b)
1378  return;
1379 
1380  const char *bound = NULL;
1381  static unsigned short recurse_level = 0;
1382 
1383  if (recurse_level >= 100)
1384  {
1385  mutt_debug(LL_DEBUG1, "recurse level too deep. giving up.\n");
1386  return;
1387  }
1388  recurse_level++;
1389 
1390  switch (b->type)
1391  {
1392  case TYPE_MULTIPART:
1393 #ifdef SUN_ATTACHMENT
1394  if (mutt_istr_equal(b->subtype, "x-sun-attachment"))
1395  bound = "--------";
1396  else
1397 #endif
1398  bound = mutt_param_get(&b->parameter, "boundary");
1399 
1400  fseeko(fp, b->offset, SEEK_SET);
1401  b->parts = mutt_parse_multipart(fp, bound, b->offset + b->length,
1402  mutt_istr_equal("digest", b->subtype));
1403  break;
1404 
1405  case TYPE_MESSAGE:
1406  if (!b->subtype)
1407  break;
1408 
1409  fseeko(fp, b->offset, SEEK_SET);
1410  if (mutt_is_message_type(b->type, b->subtype))
1411  b->parts = mutt_rfc822_parse_message(fp, b);
1412  else if (mutt_istr_equal(b->subtype, "external-body"))
1413  b->parts = mutt_read_mime_header(fp, 0);
1414  else
1415  goto bail;
1416  break;
1417 
1418  default:
1419  goto bail;
1420  }
1421 
1422  /* try to recover from parsing error */
1423  if (!b->parts)
1424  {
1425  b->type = TYPE_TEXT;
1426  mutt_str_replace(&b->subtype, "plain");
1427  }
1428 bail:
1429  recurse_level--;
1430 }
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1361
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
struct Body * mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
parse a multipart structure
Definition: parse.c:1441
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
parse a Message/RFC822 body
Definition: parse.c:1543
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
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
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
Log at debug level 1.
Definition: logging.h:40
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1262
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_multipart()

struct Body* mutt_parse_multipart ( FILE *  fp,
const char *  boundary,
LOFF_T  end_off,
bool  digest 
)

parse a multipart structure

Parameters
fpstream to read from
boundarybody separator
end_offlength of the multipart body (used when the final boundary is missing to avoid reading too far)
digesttrue if reading a multipart/digest
Return values
ptrNew Body containing parsed structure

Definition at line 1441 of file parse.c.

1442 {
1443  if (!fp)
1444  return NULL;
1445 
1446  if (!boundary)
1447  {
1448  mutt_error(_("multipart message has no boundary parameter"));
1449  return NULL;
1450  }
1451 
1452  char buf[1024];
1453  struct Body *head = NULL, *last = NULL, *new_body = NULL;
1454  bool final = false; /* did we see the ending boundary? */
1455 
1456  const size_t blen = mutt_str_len(boundary);
1457  while ((ftello(fp) < end_off) && fgets(buf, sizeof(buf), fp))
1458  {
1459  const size_t len = mutt_str_len(buf);
1460 
1461  const size_t crlf = ((len > 1) && (buf[len - 2] == '\r')) ? 1 : 0;
1462 
1463  if ((buf[0] == '-') && (buf[1] == '-') && mutt_str_startswith(buf + 2, boundary))
1464  {
1465  if (last)
1466  {
1467  last->length = ftello(fp) - last->offset - len - 1 - crlf;
1468  if (last->parts && (last->parts->length == 0))
1469  last->parts->length = ftello(fp) - last->parts->offset - len - 1 - crlf;
1470  /* if the body is empty, we can end up with a -1 length */
1471  if (last->length < 0)
1472  last->length = 0;
1473  }
1474 
1475  if (len > 0)
1476  {
1477  /* Remove any trailing whitespace, up to the length of the boundary */
1478  for (size_t i = len - 1; IS_SPACE(buf[i]) && (i >= (blen + 2)); i--)
1479  buf[i] = '\0';
1480  }
1481 
1482  /* Check for the end boundary */
1483  if (mutt_str_equal(buf + blen + 2, "--"))
1484  {
1485  final = true;
1486  break; /* done parsing */
1487  }
1488  else if (buf[2 + blen] == '\0')
1489  {
1490  new_body = mutt_read_mime_header(fp, digest);
1491 
1492 #ifdef SUN_ATTACHMENT
1493  if (mutt_param_get(&new_body->parameter, "content-lines"))
1494  {
1495  int lines = 0;
1496  if (mutt_str_atoi(
1497  mutt_param_get(&new_body->parameter, "content-lines"), &lines) < 0)
1498  lines = 0;
1499  for (; lines > 0; lines--)
1500  if ((ftello(fp) >= end_off) || !fgets(buf, sizeof(buf), fp))
1501  break;
1502  }
1503 #endif
1504  /* Consistency checking - catch bad attachment end boundaries */
1505  if (new_body->offset > end_off)
1506  {
1507  mutt_body_free(&new_body);
1508  break;
1509  }
1510  if (head)
1511  {
1512  last->next = new_body;
1513  last = new_body;
1514  }
1515  else
1516  {
1517  last = new_body;
1518  head = new_body;
1519  }
1520  }
1521  }
1522  }
1523 
1524  /* in case of missing end boundary, set the length to something reasonable */
1525  if (last && (last->length == 0) && !final)
1526  last->length = end_off - last->offset;
1527 
1528  /* parse recursive MIME parts */
1529  for (last = head; last; last = last->next)
1530  mutt_parse_part(fp, last);
1531 
1532  return head;
1533 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:257
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define IS_SPACE(ch)
Definition: string2.h:38
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1375
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
#define mutt_error(...)
Definition: logging.h:84
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1262
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_rfc822_parse_message()

struct Body* mutt_rfc822_parse_message ( FILE *  fp,
struct Body parent 
)

parse a Message/RFC822 body

Parameters
fpstream to read from
parentinfo about the message/rfc822 body part
Return values
ptrNew Body containing parsed message
Note
This assumes that 'parent->length' has been set!

Definition at line 1543 of file parse.c.

1544 {
1545  if (!fp || !parent)
1546  return NULL;
1547 
1548  parent->email = email_new();
1549  parent->email->offset = ftello(fp);
1550  parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1551  struct Body *msg = parent->email->content;
1552 
1553  /* ignore the length given in the content-length since it could be wrong
1554  * and we already have the info to calculate the correct length */
1555  /* if (msg->length == -1) */
1556  msg->length = parent->length - (msg->offset - parent->offset);
1557 
1558  /* if body of this message is empty, we can end up with a negative length */
1559  if (msg->length < 0)
1560  msg->length = 0;
1561 
1562  mutt_parse_part(fp, msg);
1563  return msg;
1564 }
struct Body * content
List of MIME parts.
Definition: email.h:90
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
The body of an email.
Definition: body.h:34
struct Envelope * env
Envelope information.
Definition: email.h:89
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1375
struct Email * email_new(void)
Create a new Email.
Definition: email.c:68
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1106
struct Email * email
header information for message/rfc822
Definition: body.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_mailto()

bool mutt_parse_mailto ( struct Envelope e,
char **  body,
const char *  src 
)

Parse a mailto:// url.

Parameters
[in]eEnvelope to fill
[out]bodyBody to
[in]srcString to parse
Return values
trueSuccess
falseError

Definition at line 1574 of file parse.c.

1575 {
1576  if (!e || !src)
1577  return false;
1578 
1579  struct Url *url = url_parse(src);
1580  if (!url)
1581  return false;
1582 
1583  if (url->host)
1584  {
1585  /* this is not a path-only URL */
1586  url_free(&url);
1587  return false;
1588  }
1589 
1590  mutt_addrlist_parse(&e->to, url->path);
1591 
1592  struct UrlQuery *np;
1593  STAILQ_FOREACH(np, &url->query_strings, entries)
1594  {
1595  const char *tag = np->name;
1596  char *value = np->value;
1597  /* Determine if this header field is on the allowed list. Since NeoMutt
1598  * interprets some header fields specially (such as
1599  * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
1600  * only safe fields are allowed.
1601  *
1602  * RFC2368, "4. Unsafe headers"
1603  * The user agent interpreting a mailto URL SHOULD choose not to create
1604  * a message if any of the headers are considered dangerous; it may also
1605  * choose to create a message with only a subset of the headers given in
1606  * the URL. */
1607  if (mutt_list_match(tag, &MailToAllow))
1608  {
1609  if (mutt_istr_equal(tag, "body"))
1610  {
1611  if (body)
1612  mutt_str_replace(body, value);
1613  }
1614  else
1615  {
1616  char *scratch = NULL;
1617  size_t taglen = mutt_str_len(tag);
1618 
1619  mutt_str_asprintf(&scratch, "%s: %s", tag, value);
1620  scratch[taglen] = 0; /* overwrite the colon as mutt_rfc822_parse_line expects */
1621  value = mutt_str_skip_email_wsp(&scratch[taglen + 1]);
1622  mutt_rfc822_parse_line(e, NULL, scratch, value, true, false, true);
1623  FREE(&scratch);
1624  }
1625  }
1626  }
1627 
1628  /* RFC2047 decode after the RFC822 parsing */
1630 
1631  url_free(&url);
1632  return true;
1633 }
char * name
Query name.
Definition: url.h:57
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
bool mutt_list_match(const char *s, struct ListHead *h)
Is the string in the list (see notes)
Definition: list.c:195
int mutt_rfc822_parse_line(struct Envelope *env, struct Email *e, char *line, char *p, bool user_hdrs, bool weed, bool do_2047)
Parse an email header.
Definition: parse.c:600
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:66
Parsed Query String.
Definition: url.h:55
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:779
char * value
Query value.
Definition: url.h:58
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
struct UrlQueryList query_strings
List of query strings.
Definition: url.h:74
struct ListHead MailToAllow
List of permitted fields in a mailto: url.
Definition: globals.c:47
char * host
Host.
Definition: url.h:71
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:748
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * path
Path.
Definition: url.h:73
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
#define FREE(x)
Definition: memory.h:40
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1100
char * src
Raw URL string.
Definition: url.h:75
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
+ Here is the call graph for this function:
+ Here is the caller graph for this function: