NeoMutt  2018-07-16 +2481-68dcde
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 "globals.h"
#include "mime.h"
#include "parameter.h"
#include "rfc2047.h"
#include "rfc2231.h"
#include "url.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 56 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 62 of file parse.c.

63 {
64  if (!mailto)
65  return;
66 
67  if (!AutoSubscribeCache)
69 
71  return;
72 
74 
75  struct Envelope *lpenv = mutt_env_new(); /* parsed envelope from the List-Post mailto: URL */
76 
77  if ((mutt_parse_mailto(lpenv, NULL, mailto) != -1) && !TAILQ_EMPTY(&lpenv->to))
78  {
79  const char *mailbox = TAILQ_FIRST(&lpenv->to)->mailbox;
80  if (mailbox && !mutt_regexlist_match(&SubscribedLists, mailbox) &&
81  !mutt_regexlist_match(&UnMailLists, mailbox) &&
83  {
84  /* mutt_regexlist_add() detects duplicates, so it is safe to
85  * try to add here without any checks. */
86  mutt_regexlist_add(&MailLists, mailbox, REG_ICASE, NULL);
87  mutt_regexlist_add(&SubscribedLists, mailbox, REG_ICASE, NULL);
88  }
89  }
90 
91  mutt_env_free(&lpenv);
92 }
#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:1587
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:379
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:276
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:352
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 105 of file parse.c.

106 {
107  struct Parameter *pnew = NULL;
108  const char *p = NULL;
109  size_t i;
110 
111  struct Buffer *buf = mutt_buffer_pool_get();
112  /* allow_value_spaces, especially with autocrypt keydata, can result
113  * in quite large parameter values. avoid frequent reallocs by
114  * pre-sizing */
115  if (allow_value_spaces)
117 
118  mutt_debug(LL_DEBUG2, "'%s'\n", s);
119 
120  while (*s)
121  {
122  mutt_buffer_reset(buf);
123 
124  p = strpbrk(s, "=;");
125  if (!p)
126  {
127  mutt_debug(LL_DEBUG1, "malformed parameter: %s\n", s);
128  goto bail;
129  }
130 
131  /* if we hit a ; now the parameter has no value, just skip it */
132  if (*p != ';')
133  {
134  i = p - s;
135  /* remove whitespace from the end of the attribute name */
136  while ((i > 0) && mutt_str_is_email_wsp(s[i - 1]))
137  i--;
138 
139  /* the check for the missing parameter token is here so that we can skip
140  * over any quoted value that may be present. */
141  if (i == 0)
142  {
143  mutt_debug(LL_DEBUG1, "missing attribute: %s\n", s);
144  pnew = NULL;
145  }
146  else
147  {
148  pnew = mutt_param_new();
149  pnew->attribute = mutt_str_substr_dup(s, s + i);
150  }
151 
152  do
153  {
154  s = mutt_str_skip_email_wsp(p + 1); /* skip over the =, or space if we loop */
155 
156  if (*s == '"')
157  {
158  bool state_ascii = true;
159  s++;
160  for (; *s; s++)
161  {
162  if (C_AssumedCharset)
163  {
164  // As iso-2022-* has a character of '"' with non-ascii state, ignore it
165  if (*s == 0x1b)
166  {
167  if ((s[1] == '(') && ((s[2] == 'B') || (s[2] == 'J')))
168  state_ascii = true;
169  else
170  state_ascii = false;
171  }
172  }
173  if (state_ascii && (*s == '"'))
174  break;
175  if (*s == '\\')
176  {
177  if (s[1])
178  {
179  s++;
180  /* Quote the next character */
181  mutt_buffer_addch(buf, *s);
182  }
183  }
184  else
185  mutt_buffer_addch(buf, *s);
186  }
187  if (*s)
188  s++; /* skip over the " */
189  }
190  else
191  {
192  for (; *s && *s != ' ' && *s != ';'; s++)
193  mutt_buffer_addch(buf, *s);
194  }
195 
196  p = s;
197  } while (allow_value_spaces && (*s == ' '));
198 
199  /* if the attribute token was missing, 'new' will be NULL */
200  if (pnew)
201  {
202  pnew->value = mutt_str_strdup(mutt_b2s(buf));
203 
204  mutt_debug(LL_DEBUG2, "parse_parameter: '%s' = '%s'\n",
205  pnew->attribute ? pnew->attribute : "", pnew->value ? pnew->value : "");
206 
207  /* Add this parameter to the list */
208  TAILQ_INSERT_HEAD(pl, pnew, entries);
209  }
210  }
211  else
212  {
213  mutt_debug(LL_DEBUG1, "parameter with no value: %s\n", s);
214  s = p;
215  }
216 
217  /* Find the next parameter */
218  if ((*s != ';') && !(s = strchr(s, ';')))
219  break; /* no more parameters */
220 
221  do
222  {
223  /* Move past any leading whitespace. the +1 skips over the semicolon */
224  s = mutt_str_skip_email_wsp(s + 1);
225  } while (*s == ';'); /* skip empty parameters */
226  }
227 
228 bail:
229 
232 }
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:100
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:236
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
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:57
#define mutt_b2s(buf)
Definition: buffer.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:56
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
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 241 of file parse.c.

242 {
243  struct ParameterList pl;
244  TAILQ_INIT(&pl);
245 
246  if (mutt_str_startswith(s, "inline", CASE_IGNORE))
247  ct->disposition = DISP_INLINE;
248  else if (mutt_str_startswith(s, "form-data", CASE_IGNORE))
250  else
251  ct->disposition = DISP_ATTACH;
252 
253  /* Check to see if a default filename was given */
254  s = strchr(s, ';');
255  if (s)
256  {
257  s = mutt_str_skip_email_wsp(s + 1);
258  parse_parameters(&pl, s, false);
259  s = mutt_param_get(&pl, "filename");
260  if (s)
261  mutt_str_replace(&ct->filename, s);
262  s = mutt_param_get(&pl, "name");
263  if (s)
264  ct->form_name = mutt_str_strdup(s);
265  mutt_param_free(&pl);
266  }
267 }
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:105
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 274 of file parse.c.

275 {
276  char *m = NULL;
277  const char *sp = NULL;
278 
279  while ((m = mutt_extract_message_id(s, &sp)))
280  {
281  mutt_list_insert_head(head, m);
282  s = NULL;
283  }
284 }
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:357
+ 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 291 of file parse.c.

292 {
293  if (!s || !ct)
294  return;
295 
296  mutt_debug(LL_DEBUG2, "RFC8255 >> Content-Language set to %s\n", s);
297  ct->language = mutt_str_strdup(s);
298 }
Log at debug level 2.
Definition: logging.h:57
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 307 of file parse.c.

308 {
309  return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
310 }
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 317 of file parse.c.

318 {
319  if (mutt_str_strcasecmp("text", s) == 0)
320  return TYPE_TEXT;
321  else if (mutt_str_strcasecmp("multipart", s) == 0)
322  return TYPE_MULTIPART;
323 #ifdef SUN_ATTACHMENT
324  else if (mutt_str_strcasecmp("x-sun-attachment", s) == 0)
325  return TYPE_MULTIPART;
326 #endif
327  else if (mutt_str_strcasecmp("application", s) == 0)
328  return TYPE_APPLICATION;
329  else if (mutt_str_strcasecmp("message", s) == 0)
330  return TYPE_MESSAGE;
331  else if (mutt_str_strcasecmp("image", s) == 0)
332  return TYPE_IMAGE;
333  else if (mutt_str_strcasecmp("audio", s) == 0)
334  return TYPE_AUDIO;
335  else if (mutt_str_strcasecmp("video", s) == 0)
336  return TYPE_VIDEO;
337  else if (mutt_str_strcasecmp("model", s) == 0)
338  return TYPE_MODEL;
339  else if (mutt_str_strcasecmp("*", s) == 0)
340  return TYPE_ANY;
341  else if (mutt_str_strcasecmp(".*", s) == 0)
342  return TYPE_ANY;
343  else
344  return TYPE_OTHER;
345 }
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 357 of file parse.c.

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

427 {
428  if (mutt_str_startswith(c, "7bit", CASE_IGNORE))
429  return ENC_7BIT;
430  else if (mutt_str_startswith(c, "8bit", CASE_IGNORE))
431  return ENC_8BIT;
432  else if (mutt_str_startswith(c, "binary", CASE_IGNORE))
433  return ENC_BINARY;
434  else if (mutt_str_startswith(c, "quoted-printable", CASE_IGNORE))
435  return ENC_QUOTED_PRINTABLE;
436  else if (mutt_str_startswith(c, "base64", CASE_IGNORE))
437  return ENC_BASE64;
438  else if (mutt_str_startswith(c, "x-uuencode", CASE_IGNORE))
439  return ENC_UUENCODED;
440 #ifdef SUN_ATTACHMENT
441  else if (mutt_str_startswith(c, "uuencode", CASE_IGNORE))
442  return ENC_UUENCODED;
443 #endif
444  else
445  return ENC_OTHER;
446 }
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 455 of file parse.c.

456 {
457  if (!s || !ct)
458  return;
459 
460  FREE(&ct->subtype);
462 
463  /* First extract any existing parameters */
464  char *pc = strchr(s, ';');
465  if (pc)
466  {
467  *pc++ = 0;
468  while (*pc && IS_SPACE(*pc))
469  pc++;
470  parse_parameters(&ct->parameter, pc, false);
471 
472  /* Some pre-RFC1521 gateways still use the "name=filename" convention,
473  * but if a filename has already been set in the content-disposition,
474  * let that take precedence, and don't set it here */
475  pc = mutt_param_get(&ct->parameter, "name");
476  if (pc && !ct->filename)
477  ct->filename = mutt_str_strdup(pc);
478 
479 #ifdef SUN_ATTACHMENT
480  /* this is deep and utter perversion */
481  pc = mutt_param_get(&ct->parameter, "conversions");
482  if (pc)
483  ct->encoding = mutt_check_encoding(pc);
484 #endif
485  }
486 
487  /* Now get the subtype */
488  char *subtype = strchr(s, '/');
489  if (subtype)
490  {
491  *subtype++ = '\0';
492  for (pc = subtype; *pc && !IS_SPACE(*pc) && (*pc != ';'); pc++)
493  ;
494  *pc = '\0';
495  ct->subtype = mutt_str_strdup(subtype);
496  }
497 
498  /* Finally, get the major type */
499  ct->type = mutt_check_mime_type(s);
500 
501 #ifdef SUN_ATTACHMENT
502  if (mutt_str_strcasecmp("x-sun-attachment", s) == 0)
503  ct->subtype = mutt_str_strdup("x-sun-attachment");
504 #endif
505 
506  if (ct->type == TYPE_OTHER)
507  {
508  mutt_str_replace(&ct->xtype, s);
509  }
510 
511  if (!ct->subtype)
512  {
513  /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type
514  * field, so we can attempt to convert the type to Body here. */
515  if (ct->type == TYPE_TEXT)
516  ct->subtype = mutt_str_strdup("plain");
517  else if (ct->type == TYPE_AUDIO)
518  ct->subtype = mutt_str_strdup("basic");
519  else if (ct->type == TYPE_MESSAGE)
520  ct->subtype = mutt_str_strdup("rfc822");
521  else if (ct->type == TYPE_OTHER)
522  {
523  char buf[128];
524 
525  ct->type = TYPE_APPLICATION;
526  snprintf(buf, sizeof(buf), "x-%s", s);
527  ct->subtype = mutt_str_strdup(buf);
528  }
529  else
530  ct->subtype = mutt_str_strdup("x-unknown");
531  }
532 
533  /* Default character set for text types. */
534  if (ct->type == TYPE_TEXT)
535  {
536  pc = mutt_param_get(&ct->parameter, "charset");
537  if (!pc)
538  {
539  mutt_param_set(&ct->parameter, "charset",
540  (C_AssumedCharset) ? (const char *) mutt_ch_get_default_charset() :
541  "us-ascii");
542  }
543  }
544 }
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:105
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:317
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_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:426
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 553 of file parse.c.

554 {
555  struct AutocryptHeader *autocrypt = mutt_autocrypthdr_new();
556  autocrypt->next = head;
557 
558  struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
559  parse_parameters(&pl, s, true);
560  if (TAILQ_EMPTY(&pl))
561  {
562  autocrypt->invalid = true;
563  goto cleanup;
564  }
565 
566  struct Parameter *p = NULL;
567  TAILQ_FOREACH(p, &pl, entries)
568  {
569  if (mutt_str_strcasecmp(p->attribute, "addr") == 0)
570  {
571  if (autocrypt->addr)
572  {
573  autocrypt->invalid = true;
574  goto cleanup;
575  }
576  autocrypt->addr = p->value;
577  p->value = NULL;
578  }
579  else if (mutt_str_strcasecmp(p->attribute, "prefer-encrypt") == 0)
580  {
581  if (mutt_str_strcasecmp(p->value, "mutual") == 0)
582  autocrypt->prefer_encrypt = true;
583  }
584  else if (mutt_str_strcasecmp(p->attribute, "keydata") == 0)
585  {
586  if (autocrypt->keydata)
587  {
588  autocrypt->invalid = true;
589  goto cleanup;
590  }
591  autocrypt->keydata = p->value;
592  p->value = NULL;
593  }
594  else if (p->attribute && (p->attribute[0] != '_'))
595  {
596  autocrypt->invalid = true;
597  goto cleanup;
598  }
599  }
600 
601  /* Checking the addr against From, and for multiple valid headers
602  * occurs later, after all the headers are parsed. */
603  if (!autocrypt->addr || !autocrypt->keydata)
604  autocrypt->invalid = true;
605 
606 cleanup:
607  mutt_param_free(&pl);
608  return autocrypt;
609 }
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:105
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 627 of file parse.c.

629 {
630  if (!env || !line)
631  return 0;
632 
633  bool matched = false;
634 
635  switch (tolower(line[0]))
636  {
637  case 'a':
638  if (mutt_str_strcasecmp(line + 1, "pparently-to") == 0)
639  {
640  mutt_addrlist_parse(&env->to, p);
641  matched = true;
642  }
643  else if (mutt_str_strcasecmp(line + 1, "pparently-from") == 0)
644  {
645  mutt_addrlist_parse(&env->from, p);
646  matched = true;
647  }
648  break;
649 
650  case 'b':
651  if (mutt_str_strcasecmp(line + 1, "cc") == 0)
652  {
653  mutt_addrlist_parse(&env->bcc, p);
654  matched = true;
655  }
656  break;
657 
658  case 'c':
659  if (mutt_str_strcasecmp(line + 1, "c") == 0)
660  {
661  mutt_addrlist_parse(&env->cc, p);
662  matched = true;
663  }
664  else
665  {
666  size_t plen = mutt_str_startswith(line + 1, "ontent-", CASE_IGNORE);
667  if (plen != 0)
668  {
669  if (mutt_str_strcasecmp(line + 1 + plen, "type") == 0)
670  {
671  if (e)
673  matched = true;
674  }
675  else if (mutt_str_strcasecmp(line + 1 + plen, "language") == 0)
676  {
677  if (e)
679  matched = true;
680  }
681  else if (mutt_str_strcasecmp(line + 1 + plen, "transfer-encoding") == 0)
682  {
683  if (e)
685  matched = true;
686  }
687  else if (mutt_str_strcasecmp(line + 1 + plen, "length") == 0)
688  {
689  if (e)
690  {
691  int rc = mutt_str_atol(p, &e->content->length);
692  if ((rc < 0) || (e->content->length < 0))
693  e->content->length = -1;
694  if (e->content->length > CONTENT_TOO_BIG)
696  }
697  matched = true;
698  }
699  else if (mutt_str_strcasecmp(line + 1 + plen, "description") == 0)
700  {
701  if (e)
702  {
705  }
706  matched = true;
707  }
708  else if (mutt_str_strcasecmp(line + 1 + plen, "disposition") == 0)
709  {
710  if (e)
712  matched = true;
713  }
714  }
715  }
716  break;
717 
718  case 'd':
719  if (mutt_str_strcasecmp("ate", line + 1) == 0)
720  {
721  mutt_str_replace(&env->date, p);
722  if (e)
723  {
724  struct Tz tz;
725  e->date_sent = mutt_date_parse_date(p, &tz);
726  if (e->date_sent > 0)
727  {
728  e->zhours = tz.zhours;
729  e->zminutes = tz.zminutes;
730  e->zoccident = tz.zoccident;
731  }
732  }
733  matched = true;
734  }
735  break;
736 
737  case 'e':
738  if ((mutt_str_strcasecmp("xpires", line + 1) == 0) && e &&
739  (mutt_date_parse_date(p, NULL) < mutt_date_epoch()))
740  {
741  e->expired = true;
742  }
743  break;
744 
745  case 'f':
746  if (mutt_str_strcasecmp("rom", line + 1) == 0)
747  {
748  mutt_addrlist_parse(&env->from, p);
749  matched = true;
750  }
751 #ifdef USE_NNTP
752  else if (mutt_str_strcasecmp(line + 1, "ollowup-to") == 0)
753  {
754  if (!env->followup_to)
755  {
758  }
759  matched = true;
760  }
761 #endif
762  break;
763 
764  case 'i':
765  if (mutt_str_strcasecmp(line + 1, "n-reply-to") == 0)
766  {
768  parse_references(&env->in_reply_to, p);
769  matched = true;
770  }
771  break;
772 
773  case 'l':
774  if (mutt_str_strcasecmp(line + 1, "ines") == 0)
775  {
776  if (e)
777  {
778  /* HACK - neomutt has, for a very short time, produced negative
779  * Lines header values. Ignore them. */
780  if ((mutt_str_atoi(p, &e->lines) < 0) || (e->lines < 0))
781  e->lines = 0;
782  }
783 
784  matched = true;
785  }
786  else if (mutt_str_strcasecmp(line + 1, "ist-Post") == 0)
787  {
788  /* RFC2369. FIXME: We should ignore whitespace, but don't. */
789  if (strncmp(p, "NO", 2) != 0)
790  {
791  char *beg = NULL, *end = NULL;
792  for (beg = strchr(p, '<'); beg; beg = strchr(end, ','))
793  {
794  beg++;
795  end = strchr(beg, '>');
796  if (!end)
797  break;
798 
799  /* Take the first mailto URL */
800  if (url_check_scheme(beg) == U_MAILTO)
801  {
802  FREE(&env->list_post);
803  env->list_post = mutt_str_substr_dup(beg, end);
804  if (C_AutoSubscribe)
806 
807  break;
808  }
809  }
810  }
811  matched = true;
812  }
813  break;
814 
815  case 'm':
816  if (mutt_str_strcasecmp(line + 1, "ime-version") == 0)
817  {
818  if (e)
819  e->mime = true;
820  matched = true;
821  }
822  else if (mutt_str_strcasecmp(line + 1, "essage-id") == 0)
823  {
824  /* We add a new "Message-ID:" when building a message */
825  FREE(&env->message_id);
826  env->message_id = mutt_extract_message_id(p, NULL);
827  matched = true;
828  }
829  else
830  {
831  size_t plen = mutt_str_startswith(line + 1, "ail-", CASE_IGNORE);
832  if (plen != 0)
833  {
834  if (mutt_str_strcasecmp(line + 1 + plen, "reply-to") == 0)
835  {
836  /* override the Reply-To: field */
838  mutt_addrlist_parse(&env->reply_to, p);
839  matched = true;
840  }
841  else if (mutt_str_strcasecmp(line + 1 + plen, "followup-to") == 0)
842  {
844  matched = true;
845  }
846  }
847  }
848  break;
849 
850 #ifdef USE_NNTP
851  case 'n':
852  if (mutt_str_strcasecmp(line + 1, "ewsgroups") == 0)
853  {
854  FREE(&env->newsgroups);
857  matched = true;
858  }
859  break;
860 #endif
861 
862  case 'o':
863  /* field 'Organization:' saves only for pager! */
864  if (mutt_str_strcasecmp(line + 1, "rganization") == 0)
865  {
866  if (!env->organization && (mutt_str_strcasecmp(p, "unknown") != 0))
867  env->organization = mutt_str_strdup(p);
868  }
869  break;
870 
871  case 'r':
872  if (mutt_str_strcasecmp(line + 1, "eferences") == 0)
873  {
874  mutt_list_free(&env->references);
875  parse_references(&env->references, p);
876  matched = true;
877  }
878  else if (mutt_str_strcasecmp(line + 1, "eply-to") == 0)
879  {
880  mutt_addrlist_parse(&env->reply_to, p);
881  matched = true;
882  }
883  else if (mutt_str_strcasecmp(line + 1, "eturn-path") == 0)
884  {
886  matched = true;
887  }
888  else if (mutt_str_strcasecmp(line + 1, "eceived") == 0)
889  {
890  if (e && !e->received)
891  {
892  char *d = strrchr(p, ';');
893 
894  if (d)
895  e->received = mutt_date_parse_date(d + 1, NULL);
896  }
897  }
898  break;
899 
900  case 's':
901  if (mutt_str_strcasecmp(line + 1, "ubject") == 0)
902  {
903  if (!env->subject)
904  env->subject = mutt_str_strdup(p);
905  matched = true;
906  }
907  else if (mutt_str_strcasecmp(line + 1, "ender") == 0)
908  {
909  mutt_addrlist_parse(&env->sender, p);
910  matched = true;
911  }
912  else if (mutt_str_strcasecmp(line + 1, "tatus") == 0)
913  {
914  if (e)
915  {
916  while (*p)
917  {
918  switch (*p)
919  {
920  case 'O':
921  e->old = C_MarkOld;
922  break;
923  case 'R':
924  e->read = true;
925  break;
926  case 'r':
927  e->replied = true;
928  break;
929  }
930  p++;
931  }
932  }
933  matched = true;
934  }
935  else if (((mutt_str_strcasecmp("upersedes", line + 1) == 0) ||
936  (mutt_str_strcasecmp("upercedes", line + 1) == 0)) &&
937  e)
938  {
939  FREE(&env->supersedes);
940  env->supersedes = mutt_str_strdup(p);
941  }
942  break;
943 
944  case 't':
945  if (mutt_str_strcasecmp(line + 1, "o") == 0)
946  {
947  mutt_addrlist_parse(&env->to, p);
948  matched = true;
949  }
950 #ifdef USE_AUTOCRYPT
951  else if (mutt_str_strcasecmp(line + 1, "utocrypt") == 0)
952  {
953  if (C_Autocrypt)
954  {
955  env->autocrypt = parse_autocrypt(env->autocrypt, p);
956  matched = true;
957  }
958  }
959  else if (mutt_str_strcasecmp(line + 1, "utocrypt-gossip") == 0)
960  {
961  if (C_Autocrypt)
962  {
964  matched = true;
965  }
966  }
967 #endif
968  break;
969 
970  case 'x':
971  if (mutt_str_strcasecmp(line + 1, "-status") == 0)
972  {
973  if (e)
974  {
975  while (*p)
976  {
977  switch (*p)
978  {
979  case 'A':
980  e->replied = true;
981  break;
982  case 'D':
983  e->deleted = true;
984  break;
985  case 'F':
986  e->flagged = true;
987  break;
988  default:
989  break;
990  }
991  p++;
992  }
993  }
994  matched = true;
995  }
996  else if (mutt_str_strcasecmp(line + 1, "-label") == 0)
997  {
998  FREE(&env->x_label);
999  env->x_label = mutt_str_strdup(p);
1000  matched = true;
1001  }
1002 #ifdef USE_NNTP
1003  else if (mutt_str_strcasecmp(line + 1, "-comment-to") == 0)
1004  {
1005  if (!env->x_comment_to)
1006  env->x_comment_to = mutt_str_strdup(p);
1007  matched = true;
1008  }
1009  else if (mutt_str_strcasecmp(line + 1, "ref") == 0)
1010  {
1011  if (!env->xref)
1012  env->xref = mutt_str_strdup(p);
1013  matched = true;
1014  }
1015 #endif
1016  else if (mutt_str_strcasecmp(line + 1, "-original-to") == 0)
1017  {
1019  matched = true;
1020  }
1021 
1022  default:
1023  break;
1024  }
1025 
1026  /* Keep track of the user-defined headers */
1027  if (!matched && user_hdrs)
1028  {
1029  /* restore the original line */
1030  line[strlen(line)] = ':';
1031 
1032  if (!(weed && C_Weed && mutt_matches_ignore(line)))
1033  {
1035  if (do_2047)
1036  rfc2047_decode(&np->data);
1037  }
1038  }
1039 
1040  return matched;
1041 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:410
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:307
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:86
WHERE bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: globals.h:205
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:38
struct Body * content
List of MIME parts.
Definition: email.h:92
static void parse_content_disposition(const char *s, struct Body *ct)
Parse a content disposition.
Definition: parse.c:241
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:459
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:67
bool expired
Already expired?
Definition: email.h:54
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:53
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:52
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:649
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
bool mime
Has a MIME-Version header?
Definition: email.h:44
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:553
static void parse_content_language(const char *s, struct Body *ct)
Read the content&#39;s language.
Definition: parse.c:291
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:83
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:426
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:65
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:274
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:56
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:455
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:41
bool flagged
Marked important?
Definition: email.h:45
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:47
bool replied
Email has been replied to.
Definition: email.h:56
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:357
unsigned int zminutes
Minutes away from UTC.
Definition: email.h:66
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:84
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:62
+ 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 1054 of file parse.c.

1055 {
1056  if (!fp || !line || !linelen)
1057  return NULL;
1058 
1059  char *buf = line;
1060  int ch;
1061  size_t offset = 0;
1062 
1063  while (true)
1064  {
1065  if (!fgets(buf, *linelen - offset, fp) || /* end of file or */
1066  (IS_SPACE(*line) && !offset)) /* end of headers */
1067  {
1068  *line = '\0';
1069  return line;
1070  }
1071 
1072  const size_t len = mutt_str_strlen(buf);
1073  if (len == 0)
1074  return line;
1075 
1076  buf += len - 1;
1077  if (*buf == '\n')
1078  {
1079  /* we did get a full line. remove trailing space */
1080  while (IS_SPACE(*buf))
1081  {
1082  *buf-- = '\0'; /* we can't come beyond line's beginning because
1083  * it begins with a non-space */
1084  }
1085 
1086  /* check to see if the next line is a continuation line */
1087  ch = fgetc(fp);
1088  if ((ch != ' ') && (ch != '\t'))
1089  {
1090  ungetc(ch, fp);
1091  return line; /* next line is a separate header field or EOH */
1092  }
1093 
1094  /* eat tabs and spaces from the beginning of the continuation line */
1095  while (((ch = fgetc(fp)) == ' ') || (ch == '\t'))
1096  ;
1097  ungetc(ch, fp);
1098  *++buf = ' '; /* string is still terminated because we removed
1099  at least one whitespace char above */
1100  }
1101 
1102  buf++;
1103  offset = buf - line;
1104  if (*linelen < (offset + 256))
1105  {
1106  /* grow the buffer */
1107  *linelen += 256;
1108  mutt_mem_realloc(&line, *linelen);
1109  buf = line + offset;
1110  }
1111  }
1112  /* not reached */
1113 }
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 1128 of file parse.c.

1129 {
1130  if (!fp)
1131  return NULL;
1132 
1133  struct Envelope *env = mutt_env_new();
1134  char *p = NULL;
1135  LOFF_T loc;
1136  size_t linelen = 1024;
1137  char *line = mutt_mem_malloc(linelen);
1138  char buf[linelen + 1];
1139 
1140  if (e)
1141  {
1142  if (!e->content)
1143  {
1144  e->content = mutt_body_new();
1145 
1146  /* set the defaults from RFC1521 */
1147  e->content->type = TYPE_TEXT;
1148  e->content->subtype = mutt_str_strdup("plain");
1149  e->content->encoding = ENC_7BIT;
1150  e->content->length = -1;
1151 
1152  /* RFC2183 says this is arbitrary */
1154  }
1155  }
1156 
1157  while ((loc = ftello(fp)) != -1)
1158  {
1159  line = mutt_rfc822_read_line(fp, line, &linelen);
1160  if (*line == '\0')
1161  break;
1162  p = strpbrk(line, ": \t");
1163  if (!p || (*p != ':'))
1164  {
1165  char return_path[1024];
1166  time_t t;
1167 
1168  /* some bogus MTAs will quote the original "From " line */
1169  if (mutt_str_startswith(line, ">From ", CASE_MATCH))
1170  continue; /* just ignore */
1171  else if (is_from(line, return_path, sizeof(return_path), &t))
1172  {
1173  /* MH sometimes has the From_ line in the middle of the header! */
1174  if (e && !e->received)
1175  e->received = t - mutt_date_local_tz(t);
1176  continue;
1177  }
1178 
1179  fseeko(fp, loc, SEEK_SET);
1180  break; /* end of header */
1181  }
1182 
1183  *buf = '\0';
1184 
1185  if (mutt_replacelist_match(&SpamList, buf, sizeof(buf), line))
1186  {
1187  if (!mutt_regexlist_match(&NoSpamList, line))
1188  {
1189  /* if spam tag already exists, figure out how to amend it */
1190  if ((!mutt_buffer_is_empty(&env->spam)) && (*buf != '\0'))
1191  {
1192  /* If C_SpamSeparator defined, append with separator */
1193  if (C_SpamSeparator)
1194  {
1196  mutt_buffer_addstr(&env->spam, buf);
1197  }
1198  else /* overwrite */
1199  {
1200  mutt_buffer_reset(&env->spam);
1201  mutt_buffer_addstr(&env->spam, buf);
1202  }
1203  }
1204 
1205  /* spam tag is new, and match expr is non-empty; copy */
1206  else if (mutt_buffer_is_empty(&env->spam) && (*buf != '\0'))
1207  {
1208  mutt_buffer_addstr(&env->spam, buf);
1209  }
1210 
1211  /* match expr is empty; plug in null string if no existing tag */
1212  else if (mutt_buffer_is_empty(&env->spam))
1213  {
1214  mutt_buffer_addstr(&env->spam, "");
1215  }
1216 
1217  if (!mutt_buffer_is_empty(&env->spam))
1218  mutt_debug(LL_DEBUG5, "spam = %s\n", env->spam.data);
1219  }
1220  }
1221 
1222  *p = '\0';
1223  p = mutt_str_skip_email_wsp(p + 1);
1224  if (!*p)
1225  continue; /* skip empty header fields */
1226 
1227  mutt_rfc822_parse_line(env, e, line, p, user_hdrs, weed, true);
1228  }
1229 
1230  FREE(&line);
1231 
1232  if (e)
1233  {
1234  e->content->hdr_offset = e->offset;
1235  e->content->offset = ftello(fp);
1236 
1238 
1239  if (env->subject)
1240  {
1241  regmatch_t pmatch[1];
1242 
1243  if (mutt_regex_capture(C_ReplyRegex, env->subject, 1, pmatch))
1244  {
1245  env->real_subj = env->subject + pmatch[0].rm_eo;
1246  }
1247  else
1248  env->real_subj = env->subject;
1249  }
1250 
1251  if (e->received < 0)
1252  {
1253  mutt_debug(LL_DEBUG1, "resetting invalid received time to 0\n");
1254  e->received = 0;
1255  }
1256 
1257  /* check for missing or invalid date */
1258  if (e->date_sent <= 0)
1259  {
1261  "no date found, using received time from msg separator\n");
1262  e->date_sent = e->received;
1263  }
1264 
1265 #ifdef USE_AUTOCRYPT
1266  if (C_Autocrypt)
1267  {
1269  /* No sense in taking up memory after the header is processed */
1271  }
1272 #endif
1273  }
1274 
1275  return env;
1276 }
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:205
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:627
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:92
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:789
time_t mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:201
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:83
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:259
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:85
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:56
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:49
#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:60
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:84
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:1054
+ 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 1284 of file parse.c.

1285 {
1286  if (!fp)
1287  return NULL;
1288 
1289  struct Body *p = mutt_body_new();
1290  struct Envelope *env = mutt_env_new();
1291  char *c = NULL;
1292  size_t linelen = 1024;
1293  char *line = mutt_mem_malloc(linelen);
1294 
1295  p->hdr_offset = ftello(fp);
1296 
1297  p->encoding = ENC_7BIT; /* default from RFC1521 */
1298  p->type = digest ? TYPE_MESSAGE : TYPE_TEXT;
1299  p->disposition = DISP_INLINE;
1300 
1301  while (*(line = mutt_rfc822_read_line(fp, line, &linelen)) != 0)
1302  {
1303  /* Find the value of the current header */
1304  c = strchr(line, ':');
1305  if (c)
1306  {
1307  *c = '\0';
1308  c = mutt_str_skip_email_wsp(c + 1);
1309  if (!*c)
1310  {
1311  mutt_debug(LL_DEBUG1, "skipping empty header field: %s\n", line);
1312  continue;
1313  }
1314  }
1315  else
1316  {
1317  mutt_debug(LL_DEBUG1, "bogus MIME header: %s\n", line);
1318  break;
1319  }
1320 
1321  size_t plen = mutt_str_startswith(line, "content-", CASE_IGNORE);
1322  if (plen != 0)
1323  {
1324  if (mutt_str_strcasecmp("type", line + plen) == 0)
1326  else if (mutt_str_strcasecmp("language", line + plen) == 0)
1327  parse_content_language(c, p);
1328  else if (mutt_str_strcasecmp("transfer-encoding", line + plen) == 0)
1329  p->encoding = mutt_check_encoding(c);
1330  else if (mutt_str_strcasecmp("disposition", line + plen) == 0)
1332  else if (mutt_str_strcasecmp("description", line + plen) == 0)
1333  {
1334  mutt_str_replace(&p->description, c);
1336  }
1337  }
1338 #ifdef SUN_ATTACHMENT
1339  else if ((plen = mutt_str_startswith(line, "x-sun-", CASE_IGNORE)))
1340  {
1341  if (mutt_str_strcasecmp("data-type", line + plen) == 0)
1343  else if (mutt_str_strcasecmp("encoding-info", line + plen) == 0)
1344  p->encoding = mutt_check_encoding(c);
1345  else if (mutt_str_strcasecmp("content-lines", line + plen) == 0)
1346  mutt_param_set(&p->parameter, "content-lines", c);
1347  else if (mutt_str_strcasecmp("data-description", line + plen) == 0)
1348  {
1349  mutt_str_replace(&p->description, c);
1351  }
1352  }
1353 #endif
1354  else
1355  {
1356  if (mutt_rfc822_parse_line(env, NULL, line, c, false, false, false))
1357  p->mime_headers = env;
1358  }
1359  }
1360  p->offset = ftello(fp); /* Mark the start of the real data */
1361  if ((p->type == TYPE_TEXT) && !p->subtype)
1362  p->subtype = mutt_str_strdup("plain");
1363  else if ((p->type == TYPE_MESSAGE) && !p->subtype)
1364  p->subtype = mutt_str_strdup("rfc822");
1365 
1366  FREE(&line);
1367 
1368  if (p->mime_headers)
1370  else
1371  mutt_env_free(&env);
1372 
1373  return p;
1374 }
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:627
7-bit text
Definition: mime.h:49
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
static void parse_content_disposition(const char *s, struct Body *ct)
Parse a content disposition.
Definition: parse.c:241
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:789
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:649
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:291
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:426
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:455
Log at debug level 1.
Definition: logging.h:56
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:1054
+ 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 1383 of file parse.c.

1384 {
1385  if (type != TYPE_MESSAGE)
1386  return false;
1387 
1388  subtype = NONULL(subtype);
1389  return (mutt_str_strcasecmp(subtype, "rfc822") == 0) ||
1390  (mutt_str_strcasecmp(subtype, "news") == 0);
1391 }
#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 1398 of file parse.c.

1399 {
1400  if (!fp || !b)
1401  return;
1402 
1403  const char *bound = NULL;
1404 
1405  switch (b->type)
1406  {
1407  case TYPE_MULTIPART:
1408 #ifdef SUN_ATTACHMENT
1409  if (mutt_str_strcasecmp(b->subtype, "x-sun-attachment") == 0)
1410  bound = "--------";
1411  else
1412 #endif
1413  bound = mutt_param_get(&b->parameter, "boundary");
1414 
1415  fseeko(fp, b->offset, SEEK_SET);
1416  b->parts = mutt_parse_multipart(fp, bound, b->offset + b->length,
1417  (mutt_str_strcasecmp("digest", b->subtype) == 0));
1418  break;
1419 
1420  case TYPE_MESSAGE:
1421  if (b->subtype)
1422  {
1423  fseeko(fp, b->offset, SEEK_SET);
1424  if (mutt_is_message_type(b->type, b->subtype))
1425  b->parts = mutt_rfc822_parse_message(fp, b);
1426  else if (mutt_str_strcasecmp(b->subtype, "external-body") == 0)
1427  b->parts = mutt_read_mime_header(fp, 0);
1428  else
1429  return;
1430  }
1431  break;
1432 
1433  default:
1434  return;
1435  }
1436 
1437  /* try to recover from parsing error */
1438  if (!b->parts)
1439  {
1440  b->type = TYPE_TEXT;
1441  mutt_str_replace(&b->subtype, "plain");
1442  }
1443 }
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1383
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:1454
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
parse a Message/RFC822 body
Definition: parse.c:1556
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:1284
+ 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 1454 of file parse.c.

1455 {
1456  if (!fp)
1457  return NULL;
1458 
1459  if (!boundary)
1460  {
1461  mutt_error(_("multipart message has no boundary parameter"));
1462  return NULL;
1463  }
1464 
1465  char buf[1024];
1466  struct Body *head = NULL, *last = NULL, *new_body = NULL;
1467  bool final = false; /* did we see the ending boundary? */
1468 
1469  const size_t blen = mutt_str_strlen(boundary);
1470  while ((ftello(fp) < end_off) && fgets(buf, sizeof(buf), fp))
1471  {
1472  const size_t len = mutt_str_strlen(buf);
1473 
1474  const size_t crlf = ((len > 1) && (buf[len - 2] == '\r')) ? 1 : 0;
1475 
1476  if ((buf[0] == '-') && (buf[1] == '-') && mutt_str_startswith(buf + 2, boundary, CASE_MATCH))
1477  {
1478  if (last)
1479  {
1480  last->length = ftello(fp) - last->offset - len - 1 - crlf;
1481  if (last->parts && (last->parts->length == 0))
1482  last->parts->length = ftello(fp) - last->parts->offset - len - 1 - crlf;
1483  /* if the body is empty, we can end up with a -1 length */
1484  if (last->length < 0)
1485  last->length = 0;
1486  }
1487 
1488  if (len > 0)
1489  {
1490  /* Remove any trailing whitespace, up to the length of the boundary */
1491  for (size_t i = len - 1; IS_SPACE(buf[i]) && (i >= (blen + 2)); i--)
1492  buf[i] = '\0';
1493  }
1494 
1495  /* Check for the end boundary */
1496  if (mutt_str_strcmp(buf + blen + 2, "--") == 0)
1497  {
1498  final = true;
1499  break; /* done parsing */
1500  }
1501  else if (buf[2 + blen] == '\0')
1502  {
1503  new_body = mutt_read_mime_header(fp, digest);
1504 
1505 #ifdef SUN_ATTACHMENT
1506  if (mutt_param_get(&new_body->parameter, "content-lines"))
1507  {
1508  int lines = 0;
1509  if (mutt_str_atoi(
1510  mutt_param_get(&new_body->parameter, "content-lines"), &lines) < 0)
1511  lines = 0;
1512  for (; lines > 0; lines--)
1513  if ((ftello(fp) >= end_off) || !fgets(buf, sizeof(buf), fp))
1514  break;
1515  }
1516 #endif
1517  /* Consistency checking - catch bad attachment end boundaries */
1518  if (new_body->offset > end_off)
1519  {
1520  mutt_body_free(&new_body);
1521  break;
1522  }
1523  if (head)
1524  {
1525  last->next = new_body;
1526  last = new_body;
1527  }
1528  else
1529  {
1530  last = new_body;
1531  head = new_body;
1532  }
1533  }
1534  }
1535  }
1536 
1537  /* in case of missing end boundary, set the length to something reasonable */
1538  if (last && (last->length == 0) && !final)
1539  last->length = end_off - last->offset;
1540 
1541  /* parse recursive MIME parts */
1542  for (last = head; last; last = last->next)
1543  mutt_parse_part(fp, last);
1544 
1545  return head;
1546 }
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:1398
#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:1284
+ 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 1556 of file parse.c.

1557 {
1558  if (!fp || !parent)
1559  return NULL;
1560 
1561  parent->email = email_new();
1562  parent->email->offset = ftello(fp);
1563  parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1564  struct Body *msg = parent->email->content;
1565 
1566  /* ignore the length given in the content-length since it could be wrong
1567  * and we already have the info to calculate the correct length */
1568  /* if (msg->length == -1) */
1569  msg->length = parent->length - (msg->offset - parent->offset);
1570 
1571  /* if body of this message is empty, we can end up with a negative length */
1572  if (msg->length < 0)
1573  msg->length = 0;
1574 
1575  mutt_parse_part(fp, msg);
1576  return msg;
1577 }
struct Body * content
List of MIME parts.
Definition: email.h:92
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:91
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:85
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1398
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:1128
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 1587 of file parse.c.

1588 {
1589  if (!e || !src)
1590  return -1;
1591 
1592  char *p = NULL;
1593  char *tag = NULL, *value = NULL;
1594 
1595  int rc = -1;
1596 
1597  char *t = strchr(src, ':');
1598  if (!t)
1599  return -1;
1600 
1601  /* copy string for safe use of strtok() */
1602  char *tmp = mutt_str_strdup(t + 1);
1603  if (!tmp)
1604  return -1;
1605 
1606  char *headers = strchr(tmp, '?');
1607  if (headers)
1608  *headers++ = '\0';
1609 
1610  if (url_pct_decode(tmp) < 0)
1611  goto out;
1612 
1613  mutt_addrlist_parse(&e->to, tmp);
1614 
1615  tag = headers ? strtok_r(headers, "&", &p) : NULL;
1616 
1617  for (; tag; tag = strtok_r(NULL, "&", &p))
1618  {
1619  value = strchr(tag, '=');
1620  if (value)
1621  *value++ = '\0';
1622  if (!value || !*value)
1623  continue;
1624 
1625  if (url_pct_decode(tag) < 0)
1626  goto out;
1627  if (url_pct_decode(value) < 0)
1628  goto out;
1629 
1630  /* Determine if this header field is on the allowed list. Since NeoMutt
1631  * interprets some header fields specially (such as
1632  * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
1633  * only safe fields are allowed.
1634  *
1635  * RFC2368, "4. Unsafe headers"
1636  * The user agent interpreting a mailto URL SHOULD choose not to create
1637  * a message if any of the headers are considered dangerous; it may also
1638  * choose to create a message with only a subset of the headers given in
1639  * the URL. */
1640  if (mutt_list_match(tag, &MailToAllow))
1641  {
1642  if (mutt_str_strcasecmp(tag, "body") == 0)
1643  {
1644  if (body)
1645  mutt_str_replace(body, value);
1646  }
1647  else
1648  {
1649  char *scratch = NULL;
1650  size_t taglen = mutt_str_strlen(tag);
1651 
1652  mutt_str_asprintf(&scratch, "%s: %s", tag, value);
1653  scratch[taglen] = 0; /* overwrite the colon as mutt_rfc822_parse_line expects */
1654  value = mutt_str_skip_email_wsp(&scratch[taglen + 1]);
1655  mutt_rfc822_parse_line(e, NULL, scratch, value, true, false, true);
1656  FREE(&scratch);
1657  }
1658  }
1659  }
1660 
1661  /* RFC2047 decode after the RFC822 parsing */
1663 
1664  rc = 0;
1665 
1666 out:
1667  FREE(&tmp);
1668  return rc;
1669 }
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:627
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:789
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:1195
+ Here is the call graph for this function:
+ Here is the caller graph for this function: