NeoMutt  2019-12-07
Teaching an old dog new tricks
DOXYGEN
parse.c File Reference

Miscellaneous email parsing routines. More...

#include "config.h"
#include <ctype.h>
#include <regex.h>
#include <string.h>
#include <time.h>
#include "mutt/mutt.h"
#include "address/lib.h"
#include "mutt.h"
#include "parse.h"
#include "body.h"
#include "email.h"
#include "email_globals.h"
#include "envelope.h"
#include "from.h"
#include "mime.h"
#include "parameter.h"
#include "rfc2047.h"
#include "rfc2231.h"
#include "url.h"
#include "globals.h"
#include "autocrypt/autocrypt.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, const char **saveptr)
 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...
 
int 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
mailtoURI 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) != -1) && !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 }
#define TAILQ_FIRST(head)
Definition: queue.h:717
int mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1595
void * mutt_hash_find(const struct Hash *table, const char *strkey)
Find the HashElem data in a Hash table element using a key.
Definition: hash.c:378
struct Hash * AutoSubscribeCache
Hash table of auto-subscribed mailing lists.
Definition: email_globals.c:48
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:75
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:132
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:191
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: email_globals.c:50
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
struct Hash * mutt_hash_new(size_t nelem, HashFlags flags)
Create a new Hash table (with string keys)
Definition: hash.c:275
struct RegexList SubscribedLists
List of regexes to match subscribed mailing lists.
Definition: email_globals.c:52
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: email_globals.c:51
#define TAILQ_EMPTY(head)
Definition: queue.h:715
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:76
struct HashElem * mutt_hash_insert(struct Hash *table, const char *strkey, void *data)
Add a new element to the Hash table (with string keys)
Definition: hash.c:351
The header of an Email.
Definition: envelope.h:54
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: email_globals.c:49
+ 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_str_substr_dup(s, 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:53
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
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
Log at debug level 2.
Definition: logging.h:41
bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition: string.c:788
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
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:790
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
char * mutt_str_substr_dup(const char *begin, const char *end)
Duplicate a sub-string.
Definition: string.c:579
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_str_startswith(s, "inline", CASE_IGNORE))
249  ct->disposition = DISP_INLINE;
250  else if (mutt_str_startswith(s, "form-data", CASE_IGNORE))
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_strdup(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
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
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:759
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
Ignore case when comparing strings.
Definition: string2.h:68
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
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:168
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
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  char *m = NULL;
279  const char *sp = NULL;
280 
281  while ((m = mutt_extract_message_id(s, &sp)))
282  {
283  mutt_list_insert_head(head, m);
284  s = NULL;
285  }
286 }
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:46
char * mutt_extract_message_id(const char *s, const char **saveptr)
Find a message-id.
Definition: parse.c:359
+ 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_strdup(s);
300 }
Log at debug level 2.
Definition: logging.h:41
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
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:196
struct ListHead UnIgnore
List of header patterns to unignore (see)
Definition: email_globals.c:46
struct ListHead Ignore
List of header patterns to ignore.
Definition: email_globals.c:45
+ 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_str_strcasecmp("text", s) == 0)
322  return TYPE_TEXT;
323  if (mutt_str_strcasecmp("multipart", s) == 0)
324  return TYPE_MULTIPART;
325 #ifdef SUN_ATTACHMENT
326  if (mutt_str_strcasecmp("x-sun-attachment", s) == 0)
327  return TYPE_MULTIPART;
328 #endif
329  if (mutt_str_strcasecmp("application", s) == 0)
330  return TYPE_APPLICATION;
331  if (mutt_str_strcasecmp("message", s) == 0)
332  return TYPE_MESSAGE;
333  if (mutt_str_strcasecmp("image", s) == 0)
334  return TYPE_IMAGE;
335  if (mutt_str_strcasecmp("audio", s) == 0)
336  return TYPE_AUDIO;
337  if (mutt_str_strcasecmp("video", s) == 0)
338  return TYPE_VIDEO;
339  if (mutt_str_strcasecmp("model", s) == 0)
340  return TYPE_MODEL;
341  if (mutt_str_strcasecmp("*", s) == 0)
342  return TYPE_ANY;
343  if (mutt_str_strcasecmp(".*", s) == 0)
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
Type: &#39;text/*&#39;.
Definition: mime.h:38
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:628
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,
const char **  saveptr 
)

Find a message-id.

Parameters
[in]sString to parse
[out]saveptrSave result here
Return values
ptrFirst character after message-id
NULLNo more message ids

Extract the first substring that looks like a message-id. Call back with NULL for more (like strtok).

Definition at line 359 of file parse.c.

360 {
361  const char *o = NULL, *onull = NULL, *p = NULL;
362  char *ret = NULL;
363 
364  if (s)
365  p = s;
366  else if (saveptr && *saveptr)
367  p = *saveptr;
368  else
369  return NULL;
370 
371  for (s = NULL, o = NULL, onull = NULL; (p = strpbrk(p, "<> \t;")); p++)
372  {
373  if (*p == '<')
374  {
375  s = p;
376  o = NULL;
377  onull = NULL;
378  continue;
379  }
380 
381  if (!s)
382  continue;
383 
384  if (*p == '>')
385  {
386  size_t olen = onull - o;
387  size_t slen = p - s + 1;
388  ret = mutt_mem_malloc(olen + slen + 1);
389  if (o)
390  memcpy(ret, o, olen);
391  memcpy(ret + olen, s, slen);
392  ret[olen + slen] = '\0';
393  if (saveptr)
394  *saveptr = p + 1; /* next call starts after '>' */
395  return ret;
396  }
397 
398  /* some idiotic clients break their message-ids between lines */
399  if (s == p)
400  {
401  /* step past another whitespace */
402  s = p + 1;
403  }
404  else if (o)
405  {
406  /* more than two lines, give up */
407  s = NULL;
408  o = NULL;
409  onull = NULL;
410  }
411  else
412  {
413  /* remember the first line, start looking for the second */
414  o = s;
415  onull = p;
416  s = p + 1;
417  }
418  }
419 
420  return NULL;
421 }
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
+ 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 428 of file parse.c.

429 {
430  if (mutt_str_startswith(c, "7bit", CASE_IGNORE))
431  return ENC_7BIT;
432  if (mutt_str_startswith(c, "8bit", CASE_IGNORE))
433  return ENC_8BIT;
434  if (mutt_str_startswith(c, "binary", CASE_IGNORE))
435  return ENC_BINARY;
436  if (mutt_str_startswith(c, "quoted-printable", CASE_IGNORE))
437  return ENC_QUOTED_PRINTABLE;
438  if (mutt_str_startswith(c, "base64", CASE_IGNORE))
439  return ENC_BASE64;
440  if (mutt_str_startswith(c, "x-uuencode", CASE_IGNORE))
441  return ENC_UUENCODED;
442 #ifdef SUN_ATTACHMENT
443  if (mutt_str_startswith(c, "uuencode", CASE_IGNORE))
444  return ENC_UUENCODED;
445 #endif
446  return ENC_OTHER;
447 }
7-bit text
Definition: mime.h:49
8-bit text
Definition: mime.h:50
Base-64 encoded text.
Definition: mime.h:52
Ignore case when comparing strings.
Definition: string2.h:68
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:168
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 456 of file parse.c.

457 {
458  if (!s || !ct)
459  return;
460 
461  FREE(&ct->subtype);
463 
464  /* First extract any existing parameters */
465  char *pc = strchr(s, ';');
466  if (pc)
467  {
468  *pc++ = 0;
469  while (*pc && IS_SPACE(*pc))
470  pc++;
471  parse_parameters(&ct->parameter, pc, false);
472 
473  /* Some pre-RFC1521 gateways still use the "name=filename" convention,
474  * but if a filename has already been set in the content-disposition,
475  * let that take precedence, and don't set it here */
476  pc = mutt_param_get(&ct->parameter, "name");
477  if (pc && !ct->filename)
478  ct->filename = mutt_str_strdup(pc);
479 
480 #ifdef SUN_ATTACHMENT
481  /* this is deep and utter perversion */
482  pc = mutt_param_get(&ct->parameter, "conversions");
483  if (pc)
484  ct->encoding = mutt_check_encoding(pc);
485 #endif
486  }
487 
488  /* Now get the subtype */
489  char *subtype = strchr(s, '/');
490  if (subtype)
491  {
492  *subtype++ = '\0';
493  for (pc = subtype; *pc && !IS_SPACE(*pc) && (*pc != ';'); pc++)
494  ;
495  *pc = '\0';
496  ct->subtype = mutt_str_strdup(subtype);
497  }
498 
499  /* Finally, get the major type */
500  ct->type = mutt_check_mime_type(s);
501 
502 #ifdef SUN_ATTACHMENT
503  if (mutt_str_strcasecmp("x-sun-attachment", s) == 0)
504  ct->subtype = mutt_str_strdup("x-sun-attachment");
505 #endif
506 
507  if (ct->type == TYPE_OTHER)
508  {
509  mutt_str_replace(&ct->xtype, s);
510  }
511 
512  if (!ct->subtype)
513  {
514  /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type
515  * field, so we can attempt to convert the type to Body here. */
516  if (ct->type == TYPE_TEXT)
517  ct->subtype = mutt_str_strdup("plain");
518  else if (ct->type == TYPE_AUDIO)
519  ct->subtype = mutt_str_strdup("basic");
520  else if (ct->type == TYPE_MESSAGE)
521  ct->subtype = mutt_str_strdup("rfc822");
522  else if (ct->type == TYPE_OTHER)
523  {
524  char buf[128];
525 
526  ct->type = TYPE_APPLICATION;
527  snprintf(buf, sizeof(buf), "x-%s", s);
528  ct->subtype = mutt_str_strdup(buf);
529  }
530  else
531  ct->subtype = mutt_str_strdup("x-unknown");
532  }
533 
534  /* Default character set for text types. */
535  if (ct->type == TYPE_TEXT)
536  {
537  pc = mutt_param_get(&ct->parameter, "charset");
538  if (pc)
539  {
540  /* Microsoft Outlook seems to think it is necessary to repeat
541  * charset=, strip it off not to confuse ourselves */
542  if (mutt_str_strncasecmp(pc, "charset=", sizeof("charset=") - 1) == 0)
543  mutt_param_set(&ct->parameter, "charset", pc + (sizeof("charset=") - 1));
544  }
545  else
546  {
547  mutt_param_set(&ct->parameter, "charset",
548  (C_AssumedCharset) ? (const char *) mutt_ch_get_default_charset() :
549  "us-ascii");
550  }
551  }
552 }
char * C_AssumedCharset
Config: If a message is missing a character set, assume this character set.
Definition: charset.c:53
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
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:107
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
Definition: body.h:66
char * subtype
content-type subtype
Definition: body.h:37
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:656
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:428
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * xtype
content-type if x-unknown
Definition: body.h:36
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
unsigned int type
content-type primary type
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
#define IS_SPACE(ch)
Definition: string2.h:38
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#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:434
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 561 of file parse.c.

562 {
563  struct AutocryptHeader *autocrypt = mutt_autocrypthdr_new();
564  autocrypt->next = head;
565 
566  struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
567  parse_parameters(&pl, s, true);
568  if (TAILQ_EMPTY(&pl))
569  {
570  autocrypt->invalid = true;
571  goto cleanup;
572  }
573 
574  struct Parameter *p = NULL;
575  TAILQ_FOREACH(p, &pl, entries)
576  {
577  if (mutt_str_strcasecmp(p->attribute, "addr") == 0)
578  {
579  if (autocrypt->addr)
580  {
581  autocrypt->invalid = true;
582  goto cleanup;
583  }
584  autocrypt->addr = p->value;
585  p->value = NULL;
586  }
587  else if (mutt_str_strcasecmp(p->attribute, "prefer-encrypt") == 0)
588  {
589  if (mutt_str_strcasecmp(p->value, "mutual") == 0)
590  autocrypt->prefer_encrypt = true;
591  }
592  else if (mutt_str_strcasecmp(p->attribute, "keydata") == 0)
593  {
594  if (autocrypt->keydata)
595  {
596  autocrypt->invalid = true;
597  goto cleanup;
598  }
599  autocrypt->keydata = p->value;
600  p->value = NULL;
601  }
602  else if (p->attribute && (p->attribute[0] != '_'))
603  {
604  autocrypt->invalid = true;
605  goto cleanup;
606  }
607  }
608 
609  /* Checking the addr against From, and for multiple valid headers
610  * occurs later, after all the headers are parsed. */
611  if (!autocrypt->addr || !autocrypt->keydata)
612  autocrypt->invalid = true;
613 
614 cleanup:
615  mutt_param_free(&pl);
616  return autocrypt;
617 }
char * attribute
Parameter name.
Definition: parameter.h:34
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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
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
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
Attribute associated with a MIME part.
Definition: parameter.h:32
#define TAILQ_EMPTY(head)
Definition: queue.h:715
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:631
+ 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 635 of file parse.c.

637 {
638  if (!env || !line)
639  return 0;
640 
641  bool matched = false;
642 
643  switch (tolower(line[0]))
644  {
645  case 'a':
646  if (mutt_str_strcasecmp(line + 1, "pparently-to") == 0)
647  {
648  mutt_addrlist_parse(&env->to, p);
649  matched = true;
650  }
651  else if (mutt_str_strcasecmp(line + 1, "pparently-from") == 0)
652  {
653  mutt_addrlist_parse(&env->from, p);
654  matched = true;
655  }
656  break;
657 
658  case 'b':
659  if (mutt_str_strcasecmp(line + 1, "cc") == 0)
660  {
661  mutt_addrlist_parse(&env->bcc, p);
662  matched = true;
663  }
664  break;
665 
666  case 'c':
667  if (mutt_str_strcasecmp(line + 1, "c") == 0)
668  {
669  mutt_addrlist_parse(&env->cc, p);
670  matched = true;
671  }
672  else
673  {
674  size_t plen = mutt_str_startswith(line + 1, "ontent-", CASE_IGNORE);
675  if (plen != 0)
676  {
677  if (mutt_str_strcasecmp(line + 1 + plen, "type") == 0)
678  {
679  if (e)
681  matched = true;
682  }
683  else if (mutt_str_strcasecmp(line + 1 + plen, "language") == 0)
684  {
685  if (e)
687  matched = true;
688  }
689  else if (mutt_str_strcasecmp(line + 1 + plen, "transfer-encoding") == 0)
690  {
691  if (e)
693  matched = true;
694  }
695  else if (mutt_str_strcasecmp(line + 1 + plen, "length") == 0)
696  {
697  if (e)
698  {
699  int rc = mutt_str_atol(p, (long *) &e->content->length);
700  if ((rc < 0) || (e->content->length < 0))
701  e->content->length = -1;
702  if (e->content->length > CONTENT_TOO_BIG)
704  }
705  matched = true;
706  }
707  else if (mutt_str_strcasecmp(line + 1 + plen, "description") == 0)
708  {
709  if (e)
710  {
713  }
714  matched = true;
715  }
716  else if (mutt_str_strcasecmp(line + 1 + plen, "disposition") == 0)
717  {
718  if (e)
720  matched = true;
721  }
722  }
723  }
724  break;
725 
726  case 'd':
727  if (mutt_str_strcasecmp("ate", line + 1) == 0)
728  {
729  mutt_str_replace(&env->date, p);
730  if (e)
731  {
732  struct Tz tz;
733  e->date_sent = mutt_date_parse_date(p, &tz);
734  if (e->date_sent > 0)
735  {
736  e->zhours = tz.zhours;
737  e->zminutes = tz.zminutes;
738  e->zoccident = tz.zoccident;
739  }
740  }
741  matched = true;
742  }
743  break;
744 
745  case 'e':
746  if ((mutt_str_strcasecmp("xpires", line + 1) == 0) && e &&
747  (mutt_date_parse_date(p, NULL) < mutt_date_epoch()))
748  {
749  e->expired = true;
750  }
751  break;
752 
753  case 'f':
754  if (mutt_str_strcasecmp("rom", line + 1) == 0)
755  {
756  mutt_addrlist_parse(&env->from, p);
757  matched = true;
758  }
759 #ifdef USE_NNTP
760  else if (mutt_str_strcasecmp(line + 1, "ollowup-to") == 0)
761  {
762  if (!env->followup_to)
763  {
766  }
767  matched = true;
768  }
769 #endif
770  break;
771 
772  case 'i':
773  if (mutt_str_strcasecmp(line + 1, "n-reply-to") == 0)
774  {
776  parse_references(&env->in_reply_to, p);
777  matched = true;
778  }
779  break;
780 
781  case 'l':
782  if (mutt_str_strcasecmp(line + 1, "ines") == 0)
783  {
784  if (e)
785  {
786  /* HACK - neomutt has, for a very short time, produced negative
787  * Lines header values. Ignore them. */
788  if ((mutt_str_atoi(p, &e->lines) < 0) || (e->lines < 0))
789  e->lines = 0;
790  }
791 
792  matched = true;
793  }
794  else if (mutt_str_strcasecmp(line + 1, "ist-Post") == 0)
795  {
796  /* RFC2369. FIXME: We should ignore whitespace, but don't. */
797  if (strncmp(p, "NO", 2) != 0)
798  {
799  char *beg = NULL, *end = NULL;
800  for (beg = strchr(p, '<'); beg; beg = strchr(end, ','))
801  {
802  beg++;
803  end = strchr(beg, '>');
804  if (!end)
805  break;
806 
807  /* Take the first mailto URL */
808  if (url_check_scheme(beg) == U_MAILTO)
809  {
810  FREE(&env->list_post);
811  env->list_post = mutt_str_substr_dup(beg, end);
812  if (C_AutoSubscribe)
814 
815  break;
816  }
817  }
818  }
819  matched = true;
820  }
821  break;
822 
823  case 'm':
824  if (mutt_str_strcasecmp(line + 1, "ime-version") == 0)
825  {
826  if (e)
827  e->mime = true;
828  matched = true;
829  }
830  else if (mutt_str_strcasecmp(line + 1, "essage-id") == 0)
831  {
832  /* We add a new "Message-ID:" when building a message */
833  FREE(&env->message_id);
834  env->message_id = mutt_extract_message_id(p, NULL);
835  matched = true;
836  }
837  else
838  {
839  size_t plen = mutt_str_startswith(line + 1, "ail-", CASE_IGNORE);
840  if (plen != 0)
841  {
842  if (mutt_str_strcasecmp(line + 1 + plen, "reply-to") == 0)
843  {
844  /* override the Reply-To: field */
846  mutt_addrlist_parse(&env->reply_to, p);
847  matched = true;
848  }
849  else if (mutt_str_strcasecmp(line + 1 + plen, "followup-to") == 0)
850  {
852  matched = true;
853  }
854  }
855  }
856  break;
857 
858 #ifdef USE_NNTP
859  case 'n':
860  if (mutt_str_strcasecmp(line + 1, "ewsgroups") == 0)
861  {
862  FREE(&env->newsgroups);
865  matched = true;
866  }
867  break;
868 #endif
869 
870  case 'o':
871  /* field 'Organization:' saves only for pager! */
872  if (mutt_str_strcasecmp(line + 1, "rganization") == 0)
873  {
874  if (!env->organization && (mutt_str_strcasecmp(p, "unknown") != 0))
875  env->organization = mutt_str_strdup(p);
876  }
877  break;
878 
879  case 'r':
880  if (mutt_str_strcasecmp(line + 1, "eferences") == 0)
881  {
882  mutt_list_free(&env->references);
883  parse_references(&env->references, p);
884  matched = true;
885  }
886  else if (mutt_str_strcasecmp(line + 1, "eply-to") == 0)
887  {
888  mutt_addrlist_parse(&env->reply_to, p);
889  matched = true;
890  }
891  else if (mutt_str_strcasecmp(line + 1, "eturn-path") == 0)
892  {
894  matched = true;
895  }
896  else if (mutt_str_strcasecmp(line + 1, "eceived") == 0)
897  {
898  if (e && !e->received)
899  {
900  char *d = strrchr(p, ';');
901 
902  if (d)
903  e->received = mutt_date_parse_date(d + 1, NULL);
904  }
905  }
906  break;
907 
908  case 's':
909  if (mutt_str_strcasecmp(line + 1, "ubject") == 0)
910  {
911  if (!env->subject)
912  env->subject = mutt_str_strdup(p);
913  matched = true;
914  }
915  else if (mutt_str_strcasecmp(line + 1, "ender") == 0)
916  {
917  mutt_addrlist_parse(&env->sender, p);
918  matched = true;
919  }
920  else if (mutt_str_strcasecmp(line + 1, "tatus") == 0)
921  {
922  if (e)
923  {
924  while (*p)
925  {
926  switch (*p)
927  {
928  case 'O':
929  e->old = C_MarkOld;
930  break;
931  case 'R':
932  e->read = true;
933  break;
934  case 'r':
935  e->replied = true;
936  break;
937  }
938  p++;
939  }
940  }
941  matched = true;
942  }
943  else if (((mutt_str_strcasecmp("upersedes", line + 1) == 0) ||
944  (mutt_str_strcasecmp("upercedes", line + 1) == 0)) &&
945  e)
946  {
947  FREE(&env->supersedes);
948  env->supersedes = mutt_str_strdup(p);
949  }
950  break;
951 
952  case 't':
953  if (mutt_str_strcasecmp(line + 1, "o") == 0)
954  {
955  mutt_addrlist_parse(&env->to, p);
956  matched = true;
957  }
958 #ifdef USE_AUTOCRYPT
959  else if (mutt_str_strcasecmp(line + 1, "utocrypt") == 0)
960  {
961  if (C_Autocrypt)
962  {
963  env->autocrypt = parse_autocrypt(env->autocrypt, p);
964  matched = true;
965  }
966  }
967  else if (mutt_str_strcasecmp(line + 1, "utocrypt-gossip") == 0)
968  {
969  if (C_Autocrypt)
970  {
972  matched = true;
973  }
974  }
975 #endif
976  break;
977 
978  case 'x':
979  if (mutt_str_strcasecmp(line + 1, "-status") == 0)
980  {
981  if (e)
982  {
983  while (*p)
984  {
985  switch (*p)
986  {
987  case 'A':
988  e->replied = true;
989  break;
990  case 'D':
991  e->deleted = true;
992  break;
993  case 'F':
994  e->flagged = true;
995  break;
996  default:
997  break;
998  }
999  p++;
1000  }
1001  }
1002  matched = true;
1003  }
1004  else if (mutt_str_strcasecmp(line + 1, "-label") == 0)
1005  {
1006  FREE(&env->x_label);
1007  env->x_label = mutt_str_strdup(p);
1008  matched = true;
1009  }
1010 #ifdef USE_NNTP
1011  else if (mutt_str_strcasecmp(line + 1, "-comment-to") == 0)
1012  {
1013  if (!env->x_comment_to)
1014  env->x_comment_to = mutt_str_strdup(p);
1015  matched = true;
1016  }
1017  else if (mutt_str_strcasecmp(line + 1, "ref") == 0)
1018  {
1019  if (!env->xref)
1020  env->xref = mutt_str_strdup(p);
1021  matched = true;
1022  }
1023 #endif
1024  else if (mutt_str_strcasecmp(line + 1, "-original-to") == 0)
1025  {
1027  matched = true;
1028  }
1029 
1030  default:
1031  break;
1032  }
1033 
1034  /* Keep track of the user-defined headers */
1035  if (!matched && user_hdrs)
1036  {
1037  /* restore the original line */
1038  line[strlen(line)] = ':';
1039 
1040  if (!(weed && C_Weed && mutt_matches_ignore(line)))
1041  {
1043  if (do_2047)
1044  rfc2047_decode(&np->data);
1045  }
1046  }
1047 
1048  return matched;
1049 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:411
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:720
int lines
How many lines in the body of this message?
Definition: email.h:84
WHERE bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: globals.h:202
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:262
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:457
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:1381
char * xref
List of cross-references.
Definition: envelope.h:76
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
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:198
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:460
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:65
bool expired
Already expired?
Definition: email.h:52
enum UrlScheme url_check_scheme(const char *s)
Check the protocol of a URL.
Definition: url.c:132
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
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:651
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
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
Definition: body.h:66
static struct AutocryptHeader * parse_autocrypt(struct AutocryptHeader *head, const char *s)
Parse an Autocrypt header line.
Definition: parse.c:561
static void parse_content_language(const char *s, struct Body *ct)
Read the content&#39;s language.
Definition: parse.c:293
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:65
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:734
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
const char * line
Definition: common.c:36
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:428
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Ignore case when comparing strings.
Definition: string2.h:68
unsigned int zhours
Hours away from UTC.
Definition: email.h:63
char * description
content-description
Definition: body.h:40
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
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
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:168
#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:456
bool C_MarkOld
Config: Mark new emails as old when leaving the mailbox.
Definition: email_globals.c:36
char * data
String.
Definition: list.h:35
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_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
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
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
bool C_AutoSubscribe
Config: Automatically check if the user is subscribed to a mailing list.
Definition: email_globals.c:35
#define FREE(x)
Definition: memory.h:40
char * organization
Organisation header.
Definition: envelope.h:73
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
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:33
char * mutt_str_substr_dup(const char *begin, const char *end)
Duplicate a sub-string.
Definition: string.c:579
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
char * mutt_extract_message_id(const char *s, const char **saveptr)
Find a message-id.
Definition: parse.c:359
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
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:40
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 1062 of file parse.c.

1063 {
1064  if (!fp || !line || !linelen)
1065  return NULL;
1066 
1067  char *buf = line;
1068  int ch;
1069  size_t offset = 0;
1070 
1071  while (true)
1072  {
1073  if (!fgets(buf, *linelen - offset, fp) || /* end of file or */
1074  (IS_SPACE(*line) && !offset)) /* end of headers */
1075  {
1076  *line = '\0';
1077  return line;
1078  }
1079 
1080  const size_t len = mutt_str_strlen(buf);
1081  if (len == 0)
1082  return line;
1083 
1084  buf += len - 1;
1085  if (*buf == '\n')
1086  {
1087  /* we did get a full line. remove trailing space */
1088  while (IS_SPACE(*buf))
1089  {
1090  *buf-- = '\0'; /* we can't come beyond line's beginning because
1091  * it begins with a non-space */
1092  }
1093 
1094  /* check to see if the next line is a continuation line */
1095  ch = fgetc(fp);
1096  if ((ch != ' ') && (ch != '\t'))
1097  {
1098  ungetc(ch, fp);
1099  return line; /* next line is a separate header field or EOH */
1100  }
1101 
1102  /* eat tabs and spaces from the beginning of the continuation line */
1103  while (((ch = fgetc(fp)) == ' ') || (ch == '\t'))
1104  ;
1105  ungetc(ch, fp);
1106  *++buf = ' '; /* string is still terminated because we removed
1107  at least one whitespace char above */
1108  }
1109 
1110  buf++;
1111  offset = buf - line;
1112  if (*linelen < (offset + 256))
1113  {
1114  /* grow the buffer */
1115  *linelen += 256;
1116  mutt_mem_realloc(&line, *linelen);
1117  buf = line + offset;
1118  }
1119  }
1120  /* not reached */
1121 }
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
const char * line
Definition: common.c:36
#define IS_SPACE(ch)
Definition: string2.h:38
+ 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 1136 of file parse.c.

1137 {
1138  if (!fp)
1139  return NULL;
1140 
1141  struct Envelope *env = mutt_env_new();
1142  char *p = NULL;
1143  LOFF_T loc;
1144  size_t linelen = 1024;
1145  char *line = mutt_mem_malloc(linelen);
1146  char buf[linelen + 1];
1147 
1148  if (e)
1149  {
1150  if (!e->content)
1151  {
1152  e->content = mutt_body_new();
1153 
1154  /* set the defaults from RFC1521 */
1155  e->content->type = TYPE_TEXT;
1156  e->content->subtype = mutt_str_strdup("plain");
1157  e->content->encoding = ENC_7BIT;
1158  e->content->length = -1;
1159 
1160  /* RFC2183 says this is arbitrary */
1162  }
1163  }
1164 
1165  while ((loc = ftello(fp)) != -1)
1166  {
1167  line = mutt_rfc822_read_line(fp, line, &linelen);
1168  if (*line == '\0')
1169  break;
1170  p = strpbrk(line, ": \t");
1171  if (!p || (*p != ':'))
1172  {
1173  char return_path[1024];
1174  time_t t;
1175 
1176  /* some bogus MTAs will quote the original "From " line */
1177  if (mutt_str_startswith(line, ">From ", CASE_MATCH))
1178  continue; /* just ignore */
1179  else if (is_from(line, return_path, sizeof(return_path), &t))
1180  {
1181  /* MH sometimes has the From_ line in the middle of the header! */
1182  if (e && !e->received)
1183  e->received = t - mutt_date_local_tz(t);
1184  continue;
1185  }
1186 
1187  fseeko(fp, loc, SEEK_SET);
1188  break; /* end of header */
1189  }
1190 
1191  *buf = '\0';
1192 
1193  if (mutt_replacelist_match(&SpamList, buf, sizeof(buf), line))
1194  {
1195  if (!mutt_regexlist_match(&NoSpamList, line))
1196  {
1197  /* if spam tag already exists, figure out how to amend it */
1198  if ((!mutt_buffer_is_empty(&env->spam)) && (*buf != '\0'))
1199  {
1200  /* If C_SpamSeparator defined, append with separator */
1201  if (C_SpamSeparator)
1202  {
1204  mutt_buffer_addstr(&env->spam, buf);
1205  }
1206  else /* overwrite */
1207  {
1208  mutt_buffer_reset(&env->spam);
1209  mutt_buffer_addstr(&env->spam, buf);
1210  }
1211  }
1212 
1213  /* spam tag is new, and match expr is non-empty; copy */
1214  else if (mutt_buffer_is_empty(&env->spam) && (*buf != '\0'))
1215  {
1216  mutt_buffer_addstr(&env->spam, buf);
1217  }
1218 
1219  /* match expr is empty; plug in null string if no existing tag */
1220  else if (mutt_buffer_is_empty(&env->spam))
1221  {
1222  mutt_buffer_addstr(&env->spam, "");
1223  }
1224 
1225  if (!mutt_buffer_is_empty(&env->spam))
1226  mutt_debug(LL_DEBUG5, "spam = %s\n", env->spam.data);
1227  }
1228  }
1229 
1230  *p = '\0';
1231  p = mutt_str_skip_email_wsp(p + 1);
1232  if (!*p)
1233  continue; /* skip empty header fields */
1234 
1235  mutt_rfc822_parse_line(env, e, line, p, user_hdrs, weed, true);
1236  }
1237 
1238  FREE(&line);
1239 
1240  if (e)
1241  {
1242  e->content->hdr_offset = e->offset;
1243  e->content->offset = ftello(fp);
1244 
1246 
1247  if (env->subject)
1248  {
1249  regmatch_t pmatch[1];
1250 
1251  if (mutt_regex_capture(C_ReplyRegex, env->subject, 1, pmatch))
1252  {
1253  env->real_subj = env->subject + pmatch[0].rm_eo;
1254  }
1255  else
1256  env->real_subj = env->subject;
1257  }
1258 
1259  if (e->received < 0)
1260  {
1261  mutt_debug(LL_DEBUG1, "resetting invalid received time to 0\n");
1262  e->received = 0;
1263  }
1264 
1265  /* check for missing or invalid date */
1266  if (e->date_sent <= 0)
1267  {
1269  "no date found, using received time from msg separator\n");
1270  e->date_sent = e->received;
1271  }
1272 
1273 #ifdef USE_AUTOCRYPT
1274  if (C_Autocrypt)
1275  {
1277  /* No sense in taking up memory after the header is processed */
1279  }
1280 #endif
1281  }
1282 
1283  return env;
1284 }
bool mutt_replacelist_match(struct ReplaceList *rl, char *buf, size_t buflen, const char *str)
Does a string match a pattern?
Definition: regex.c:475
WHERE bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: globals.h:202
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:635
7-bit text
Definition: mime.h:49
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: email_globals.c:44
struct Body * content
List of MIME parts.
Definition: email.h:90
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
Match case when comparing strings.
Definition: string2.h:67
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:791
time_t mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:202
unsigned int disposition
content-disposition
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:191
unsigned int encoding
content-transfer-encoding
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
struct Regex * C_ReplyRegex
Config: Regex to match message reply subjects like "re: ".
Definition: email_globals.c:37
char * subtype
content-type subtype
Definition: body.h:37
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:81
const char * line
Definition: common.c:36
int mutt_autocrypt_process_autocrypt_header(struct Email *e, struct Envelope *env)
Parse an Autocrypt email header.
Definition: autocrypt.c:258
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:776
char * C_SpamSeparator
Config: Separator for multiple spam headers.
Definition: email_globals.c:39
unsigned int type
content-type primary type
Definition: body.h:65
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
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:168
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:594
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
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#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:50
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
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
struct RegexList NoSpamList
List of regexes to whitelist non-spam emails.
Definition: email_globals.c:43
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:1062
+ 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 1292 of file parse.c.

1293 {
1294  if (!fp)
1295  return NULL;
1296 
1297  struct Body *p = mutt_body_new();
1298  struct Envelope *env = mutt_env_new();
1299  char *c = NULL;
1300  size_t linelen = 1024;
1301  char *line = mutt_mem_malloc(linelen);
1302 
1303  p->hdr_offset = ftello(fp);
1304 
1305  p->encoding = ENC_7BIT; /* default from RFC1521 */
1306  p->type = digest ? TYPE_MESSAGE : TYPE_TEXT;
1307  p->disposition = DISP_INLINE;
1308 
1309  while (*(line = mutt_rfc822_read_line(fp, line, &linelen)) != 0)
1310  {
1311  /* Find the value of the current header */
1312  c = strchr(line, ':');
1313  if (c)
1314  {
1315  *c = '\0';
1316  c = mutt_str_skip_email_wsp(c + 1);
1317  if (!*c)
1318  {
1319  mutt_debug(LL_DEBUG1, "skipping empty header field: %s\n", line);
1320  continue;
1321  }
1322  }
1323  else
1324  {
1325  mutt_debug(LL_DEBUG1, "bogus MIME header: %s\n", line);
1326  break;
1327  }
1328 
1329  size_t plen = mutt_str_startswith(line, "content-", CASE_IGNORE);
1330  if (plen != 0)
1331  {
1332  if (mutt_str_strcasecmp("type", line + plen) == 0)
1334  else if (mutt_str_strcasecmp("language", line + plen) == 0)
1335  parse_content_language(c, p);
1336  else if (mutt_str_strcasecmp("transfer-encoding", line + plen) == 0)
1337  p->encoding = mutt_check_encoding(c);
1338  else if (mutt_str_strcasecmp("disposition", line + plen) == 0)
1340  else if (mutt_str_strcasecmp("description", line + plen) == 0)
1341  {
1342  mutt_str_replace(&p->description, c);
1344  }
1345  }
1346 #ifdef SUN_ATTACHMENT
1347  else if ((plen = mutt_str_startswith(line, "x-sun-", CASE_IGNORE)))
1348  {
1349  if (mutt_str_strcasecmp("data-type", line + plen) == 0)
1351  else if (mutt_str_strcasecmp("encoding-info", line + plen) == 0)
1352  p->encoding = mutt_check_encoding(c);
1353  else if (mutt_str_strcasecmp("content-lines", line + plen) == 0)
1354  mutt_param_set(&p->parameter, "content-lines", c);
1355  else if (mutt_str_strcasecmp("data-description", line + plen) == 0)
1356  {
1357  mutt_str_replace(&p->description, c);
1359  }
1360  }
1361 #endif
1362  else
1363  {
1364  if (mutt_rfc822_parse_line(env, NULL, line, c, false, false, false))
1365  p->mime_headers = env;
1366  }
1367  }
1368  p->offset = ftello(fp); /* Mark the start of the real data */
1369  if ((p->type == TYPE_TEXT) && !p->subtype)
1370  p->subtype = mutt_str_strdup("plain");
1371  else if ((p->type == TYPE_MESSAGE) && !p->subtype)
1372  p->subtype = mutt_str_strdup("rfc822");
1373 
1374  FREE(&line);
1375 
1376  if (p->mime_headers)
1378  else
1379  mutt_env_free(&env);
1380 
1381  return p;
1382 }
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:635
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
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:791
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition
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:651
unsigned int encoding
content-transfer-encoding
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
char * subtype
content-type subtype
Definition: body.h:37
const char * line
Definition: common.c:36
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:428
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
Ignore case when comparing strings.
Definition: string2.h:68
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
char * description
content-description
Definition: body.h:40
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
unsigned int type
content-type primary type
Definition: body.h:65
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:168
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:456
Log at debug level 1.
Definition: logging.h:40
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#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
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:1062
+ 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 1391 of file parse.c.

1392 {
1393  if (type != TYPE_MESSAGE)
1394  return false;
1395 
1396  subtype = NONULL(subtype);
1397  return (mutt_str_strcasecmp(subtype, "rfc822") == 0) ||
1398  (mutt_str_strcasecmp(subtype, "news") == 0);
1399 }
#define NONULL(x)
Definition: string2.h:37
Type: &#39;message/*&#39;.
Definition: mime.h:35
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
+ 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 1406 of file parse.c.

1407 {
1408  if (!fp || !b)
1409  return;
1410 
1411  const char *bound = NULL;
1412 
1413  switch (b->type)
1414  {
1415  case TYPE_MULTIPART:
1416 #ifdef SUN_ATTACHMENT
1417  if (mutt_str_strcasecmp(b->subtype, "x-sun-attachment") == 0)
1418  bound = "--------";
1419  else
1420 #endif
1421  bound = mutt_param_get(&b->parameter, "boundary");
1422 
1423  fseeko(fp, b->offset, SEEK_SET);
1424  b->parts = mutt_parse_multipart(fp, bound, b->offset + b->length,
1425  (mutt_str_strcasecmp("digest", b->subtype) == 0));
1426  break;
1427 
1428  case TYPE_MESSAGE:
1429  if (b->subtype)
1430  {
1431  fseeko(fp, b->offset, SEEK_SET);
1432  if (mutt_is_message_type(b->type, b->subtype))
1433  b->parts = mutt_rfc822_parse_message(fp, b);
1434  else if (mutt_str_strcasecmp(b->subtype, "external-body") == 0)
1435  b->parts = mutt_read_mime_header(fp, 0);
1436  else
1437  return;
1438  }
1439  break;
1440 
1441  default:
1442  return;
1443  }
1444 
1445  /* try to recover from parsing error */
1446  if (!b->parts)
1447  {
1448  b->type = TYPE_TEXT;
1449  mutt_str_replace(&b->subtype, "plain");
1450  }
1451 }
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1391
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:1462
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
parse a Message/RFC822 body
Definition: parse.c:1564
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
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
unsigned int type
content-type primary type
Definition: body.h:65
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:628
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1292
+ 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 1462 of file parse.c.

1463 {
1464  if (!fp)
1465  return NULL;
1466 
1467  if (!boundary)
1468  {
1469  mutt_error(_("multipart message has no boundary parameter"));
1470  return NULL;
1471  }
1472 
1473  char buf[1024];
1474  struct Body *head = NULL, *last = NULL, *new_body = NULL;
1475  bool final = false; /* did we see the ending boundary? */
1476 
1477  const size_t blen = mutt_str_strlen(boundary);
1478  while ((ftello(fp) < end_off) && fgets(buf, sizeof(buf), fp))
1479  {
1480  const size_t len = mutt_str_strlen(buf);
1481 
1482  const size_t crlf = ((len > 1) && (buf[len - 2] == '\r')) ? 1 : 0;
1483 
1484  if ((buf[0] == '-') && (buf[1] == '-') && mutt_str_startswith(buf + 2, boundary, CASE_MATCH))
1485  {
1486  if (last)
1487  {
1488  last->length = ftello(fp) - last->offset - len - 1 - crlf;
1489  if (last->parts && (last->parts->length == 0))
1490  last->parts->length = ftello(fp) - last->parts->offset - len - 1 - crlf;
1491  /* if the body is empty, we can end up with a -1 length */
1492  if (last->length < 0)
1493  last->length = 0;
1494  }
1495 
1496  if (len > 0)
1497  {
1498  /* Remove any trailing whitespace, up to the length of the boundary */
1499  for (size_t i = len - 1; IS_SPACE(buf[i]) && (i >= (blen + 2)); i--)
1500  buf[i] = '\0';
1501  }
1502 
1503  /* Check for the end boundary */
1504  if (mutt_str_strcmp(buf + blen + 2, "--") == 0)
1505  {
1506  final = true;
1507  break; /* done parsing */
1508  }
1509  else if (buf[2 + blen] == '\0')
1510  {
1511  new_body = mutt_read_mime_header(fp, digest);
1512 
1513 #ifdef SUN_ATTACHMENT
1514  if (mutt_param_get(&new_body->parameter, "content-lines"))
1515  {
1516  int lines = 0;
1517  if (mutt_str_atoi(
1518  mutt_param_get(&new_body->parameter, "content-lines"), &lines) < 0)
1519  lines = 0;
1520  for (; lines > 0; lines--)
1521  if ((ftello(fp) >= end_off) || !fgets(buf, sizeof(buf), fp))
1522  break;
1523  }
1524 #endif
1525  /* Consistency checking - catch bad attachment end boundaries */
1526  if (new_body->offset > end_off)
1527  {
1528  mutt_body_free(&new_body);
1529  break;
1530  }
1531  if (head)
1532  {
1533  last->next = new_body;
1534  last = new_body;
1535  }
1536  else
1537  {
1538  last = new_body;
1539  head = new_body;
1540  }
1541  }
1542  }
1543  }
1544 
1545  /* in case of missing end boundary, set the length to something reasonable */
1546  if (last && (last->length == 0) && !final)
1547  last->length = end_off - last->offset;
1548 
1549  /* parse recursive MIME parts */
1550  for (last = head; last; last = last->next)
1551  mutt_parse_part(fp, last);
1552 
1553  return head;
1554 }
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:262
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
Match case when comparing strings.
Definition: string2.h:67
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
The body of an email.
Definition: body.h:34
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
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:168
#define IS_SPACE(ch)
Definition: string2.h:38
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1406
#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
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1292
+ 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 1564 of file parse.c.

1565 {
1566  if (!fp || !parent)
1567  return NULL;
1568 
1569  parent->email = email_new();
1570  parent->email->offset = ftello(fp);
1571  parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1572  struct Body *msg = parent->email->content;
1573 
1574  /* ignore the length given in the content-length since it could be wrong
1575  * and we already have the info to calculate the correct length */
1576  /* if (msg->length == -1) */
1577  msg->length = parent->length - (msg->offset - parent->offset);
1578 
1579  /* if body of this message is empty, we can end up with a negative length */
1580  if (msg->length < 0)
1581  msg->length = 0;
1582 
1583  mutt_parse_part(fp, msg);
1584  return msg;
1585 }
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:1406
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:1136
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()

int 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
0Success
-1Error

Definition at line 1595 of file parse.c.

1596 {
1597  if (!e || !src)
1598  return -1;
1599 
1600  char *p = NULL;
1601  char *tag = NULL, *value = NULL;
1602 
1603  int rc = -1;
1604 
1605  char *t = strchr(src, ':');
1606  if (!t)
1607  return -1;
1608 
1609  /* copy string for safe use of strtok() */
1610  char *tmp = mutt_str_strdup(t + 1);
1611  if (!tmp)
1612  return -1;
1613 
1614  char *headers = strchr(tmp, '?');
1615  if (headers)
1616  *headers++ = '\0';
1617 
1618  if (url_pct_decode(tmp) < 0)
1619  goto out;
1620 
1621  mutt_addrlist_parse(&e->to, tmp);
1622 
1623  tag = headers ? strtok_r(headers, "&", &p) : NULL;
1624 
1625  for (; tag; tag = strtok_r(NULL, "&", &p))
1626  {
1627  value = strchr(tag, '=');
1628  if (value)
1629  *value++ = '\0';
1630  if (!value || !*value)
1631  continue;
1632 
1633  if (url_pct_decode(tag) < 0)
1634  goto out;
1635  if (url_pct_decode(value) < 0)
1636  goto out;
1637 
1638  /* Determine if this header field is on the allowed list. Since NeoMutt
1639  * interprets some header fields specially (such as
1640  * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
1641  * only safe fields are allowed.
1642  *
1643  * RFC2368, "4. Unsafe headers"
1644  * The user agent interpreting a mailto URL SHOULD choose not to create
1645  * a message if any of the headers are considered dangerous; it may also
1646  * choose to create a message with only a subset of the headers given in
1647  * the URL. */
1648  if (mutt_list_match(tag, &MailToAllow))
1649  {
1650  if (mutt_str_strcasecmp(tag, "body") == 0)
1651  {
1652  if (body)
1653  mutt_str_replace(body, value);
1654  }
1655  else
1656  {
1657  char *scratch = NULL;
1658  size_t taglen = mutt_str_strlen(tag);
1659 
1660  mutt_str_asprintf(&scratch, "%s: %s", tag, value);
1661  scratch[taglen] = 0; /* overwrite the colon as mutt_rfc822_parse_line expects */
1662  value = mutt_str_skip_email_wsp(&scratch[taglen + 1]);
1663  mutt_rfc822_parse_line(e, NULL, scratch, value, true, false, true);
1664  FREE(&scratch);
1665  }
1666  }
1667  }
1668 
1669  /* RFC2047 decode after the RFC822 parsing */
1671 
1672  rc = 0;
1673 
1674 out:
1675  FREE(&tmp);
1676  return rc;
1677 }
int url_pct_decode(char *s)
Decode a percent-encoded string.
Definition: url.c:100
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:457
bool mutt_list_match(const char *s, struct ListHead *h)
Is the string in the list (see notes)
Definition: list.c:196
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:635
struct ListHead MailToAllow
List of permitted fields in a mailto: uri.
Definition: email_globals.c:47
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:791
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#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:1194
+ Here is the call graph for this function:
+ Here is the caller graph for this function: