NeoMutt  2021-02-05-329-g9e03b7
Teaching an old dog new tricks
DOXYGEN
parse.c File Reference

Miscellaneous email parsing routines. More...

#include "config.h"
#include <ctype.h>
#include <string.h>
#include <time.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "parse.h"
#include "body.h"
#include "context.h"
#include "email.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/lib.h"
#include "mutt_globals.h"
+ Include dependency graph for parse.c:

Go to the source code of this file.

Macros

#define CONTENT_TOO_BIG   (1 << 30)
 

Functions

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

◆ parse_part()

static void parse_part ( FILE *  fp,
struct Body b,
int *  counter 
)
static

Parse a MIME part.

Parameters
fpFile to read from
bBody to store the results in
counterNumber of parts processed so far

Definition at line 1401 of file parse.c.

1402 {
1403  if (!fp || !b)
1404  return;
1405 
1406  const char *bound = NULL;
1407  static unsigned short recurse_level = 0;
1408 
1409  if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1410  {
1411  mutt_debug(LL_DEBUG1, "recurse level too deep. giving up.\n");
1412  return;
1413  }
1414  recurse_level++;
1415 
1416  switch (b->type)
1417  {
1418  case TYPE_MULTIPART:
1419 #ifdef SUN_ATTACHMENT
1420  if (mutt_istr_equal(b->subtype, "x-sun-attachment"))
1421  bound = "--------";
1422  else
1423 #endif
1424  bound = mutt_param_get(&b->parameter, "boundary");
1425 
1426  fseeko(fp, b->offset, SEEK_SET);
1427  b->parts = parse_multipart(fp, bound, b->offset + b->length,
1428  mutt_istr_equal("digest", b->subtype), counter);
1429  break;
1430 
1431  case TYPE_MESSAGE:
1432  if (!b->subtype)
1433  break;
1434 
1435  fseeko(fp, b->offset, SEEK_SET);
1436  if (mutt_is_message_type(b->type, b->subtype))
1437  b->parts = rfc822_parse_message(fp, b, counter);
1438  else if (mutt_istr_equal(b->subtype, "external-body"))
1439  b->parts = mutt_read_mime_header(fp, 0);
1440  else
1441  goto bail;
1442  break;
1443 
1444  default:
1445  goto bail;
1446  }
1447 
1448  /* try to recover from parsing error */
1449  if (!b->parts)
1450  {
1451  b->type = TYPE_TEXT;
1452  mutt_str_replace(&b->subtype, "plain");
1453  }
1454 bail:
1455  recurse_level--;
1456 }
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1385
static struct Body * parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest, int *counter)
Parse a multipart structure.
Definition: parse.c:1468
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
static struct Body * rfc822_parse_message(FILE *fp, struct Body *parent, int *counter)
parse a Message/RFC822 body
Definition: parse.c:1579
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * subtype
content-type subtype
Definition: body.h:37
#define MUTT_MIME_MAX_DEPTH
Definition: mime.h:69
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Type: &#39;text/*&#39;.
Definition: mime.h:38
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:40
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1286
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc822_parse_message()

static struct Body * rfc822_parse_message ( FILE *  fp,
struct Body parent,
int *  counter 
)
static

parse a Message/RFC822 body

Parameters
fpStream to read from
parentInfo about the message/rfc822 body part
counterNumber of parts processed so far
Return values
ptrNew Body containing parsed message
Note
This assumes that 'parent->length' has been set!

Definition at line 1579 of file parse.c.

1580 {
1581  if (!fp || !parent)
1582  return NULL;
1583 
1584  parent->email = email_new();
1585  parent->email->offset = ftello(fp);
1586  parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1587  struct Body *msg = parent->email->body;
1588 
1589  /* ignore the length given in the content-length since it could be wrong
1590  * and we already have the info to calculate the correct length */
1591  /* if (msg->length == -1) */
1592  msg->length = parent->length - (msg->offset - parent->offset);
1593 
1594  /* if body of this message is empty, we can end up with a negative length */
1595  if (msg->length < 0)
1596  msg->length = 0;
1597 
1598  parse_part(fp, msg, counter);
1599  return msg;
1600 }
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1401
struct Body * body
List of MIME parts.
Definition: email.h:91
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
The body of an email.
Definition: body.h:34
struct Email * email_new(void)
Create a new Email.
Definition: email.c:77
struct Envelope * env
Envelope information.
Definition: email.h:90
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:84
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1124
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:

◆ parse_multipart()

static struct Body * parse_multipart ( FILE *  fp,
const char *  boundary,
LOFF_T  end_off,
bool  digest,
int *  counter 
)
static

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
counterNumber of parts processed so far
Return values
ptrNew Body containing parsed structure

Definition at line 1468 of file parse.c.

1470 {
1471  if (!fp)
1472  return NULL;
1473 
1474  if (!boundary)
1475  {
1476  mutt_error(_("multipart message has no boundary parameter"));
1477  return NULL;
1478  }
1479 
1480  char buf[1024];
1481  struct Body *head = NULL, *last = NULL, *new_body = NULL;
1482  bool final = false; /* did we see the ending boundary? */
1483 
1484  const size_t blen = mutt_str_len(boundary);
1485  while ((ftello(fp) < end_off) && fgets(buf, sizeof(buf), fp))
1486  {
1487  const size_t len = mutt_str_len(buf);
1488 
1489  const size_t crlf = ((len > 1) && (buf[len - 2] == '\r')) ? 1 : 0;
1490 
1491  if ((buf[0] == '-') && (buf[1] == '-') && mutt_str_startswith(buf + 2, boundary))
1492  {
1493  if (last)
1494  {
1495  last->length = ftello(fp) - last->offset - len - 1 - crlf;
1496  if (last->parts && (last->parts->length == 0))
1497  last->parts->length = ftello(fp) - last->parts->offset - len - 1 - crlf;
1498  /* if the body is empty, we can end up with a -1 length */
1499  if (last->length < 0)
1500  last->length = 0;
1501  }
1502 
1503  if (len > 0)
1504  {
1505  /* Remove any trailing whitespace, up to the length of the boundary */
1506  for (size_t i = len - 1; IS_SPACE(buf[i]) && (i >= (blen + 2)); i--)
1507  buf[i] = '\0';
1508  }
1509 
1510  /* Check for the end boundary */
1511  if (mutt_str_equal(buf + blen + 2, "--"))
1512  {
1513  final = true;
1514  break; /* done parsing */
1515  }
1516  else if (buf[2 + blen] == '\0')
1517  {
1518  new_body = mutt_read_mime_header(fp, digest);
1519 
1520 #ifdef SUN_ATTACHMENT
1521  if (mutt_param_get(&new_body->parameter, "content-lines"))
1522  {
1523  int lines = 0;
1524  if (mutt_str_atoi(
1525  mutt_param_get(&new_body->parameter, "content-lines"), &lines) < 0)
1526  lines = 0;
1527  for (; lines > 0; lines--)
1528  if ((ftello(fp) >= end_off) || !fgets(buf, sizeof(buf), fp))
1529  break;
1530  }
1531 #endif
1532  /* Consistency checking - catch bad attachment end boundaries */
1533  if (new_body->offset > end_off)
1534  {
1535  mutt_body_free(&new_body);
1536  break;
1537  }
1538  if (head)
1539  {
1540  last->next = new_body;
1541  last = new_body;
1542  }
1543  else
1544  {
1545  last = new_body;
1546  head = new_body;
1547  }
1548 
1549  /* It seems more intuitive to add the counter increment to
1550  * parse_part(), but we want to stop the case where a multipart
1551  * contains thousands of tiny parts before the memory and data
1552  * structures are allocated. */
1553  if (++(*counter) >= MUTT_MIME_MAX_PARTS)
1554  break;
1555  }
1556  }
1557  }
1558 
1559  /* in case of missing end boundary, set the length to something reasonable */
1560  if (last && (last->length == 0) && !final)
1561  last->length = end_off - last->offset;
1562 
1563  /* parse recursive MIME parts */
1564  for (last = head; last; last = last->next)
1565  parse_part(fp, last, counter);
1566 
1567  return head;
1568 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1401
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:252
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define IS_SPACE(ch)
Definition: string2.h:38
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
#define MUTT_MIME_MAX_PARTS
Definition: mime.h:70
#define mutt_error(...)
Definition: logging.h:84
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1286
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_auto_subscribe()

void mutt_auto_subscribe ( const char *  mailto)

Check if user is subscribed to mailing list.

Parameters
mailtoURL of mailing list subscribe

Definition at line 69 of file parse.c.

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

◆ parse_parameters()

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

Parse a list of Parameters.

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

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

Definition at line 112 of file parse.c.

113 {
114  struct Parameter *pnew = NULL;
115  const char *p = NULL;
116  size_t i;
117 
118  struct Buffer *buf = mutt_buffer_pool_get();
119  /* allow_value_spaces, especially with autocrypt keydata, can result
120  * in quite large parameter values. avoid frequent reallocs by
121  * pre-sizing */
122  if (allow_value_spaces)
124 
125  mutt_debug(LL_DEBUG2, "'%s'\n", s);
126 
127  while (*s)
128  {
129  mutt_buffer_reset(buf);
130 
131  p = strpbrk(s, "=;");
132  if (!p)
133  {
134  mutt_debug(LL_DEBUG1, "malformed parameter: %s\n", s);
135  goto bail;
136  }
137 
138  /* if we hit a ; now the parameter has no value, just skip it */
139  if (*p != ';')
140  {
141  i = p - s;
142  /* remove whitespace from the end of the attribute name */
143  while ((i > 0) && mutt_str_is_email_wsp(s[i - 1]))
144  i--;
145 
146  /* the check for the missing parameter token is here so that we can skip
147  * over any quoted value that may be present. */
148  if (i == 0)
149  {
150  mutt_debug(LL_DEBUG1, "missing attribute: %s\n", s);
151  pnew = NULL;
152  }
153  else
154  {
155  pnew = mutt_param_new();
156  pnew->attribute = mutt_strn_dup(s, i);
157  }
158 
159  do
160  {
161  s = mutt_str_skip_email_wsp(p + 1); /* skip over the =, or space if we loop */
162 
163  if (*s == '"')
164  {
165  bool state_ascii = true;
166  s++;
167  for (; *s; s++)
168  {
169  const char *const c_assumed_charset =
170  cs_subset_string(NeoMutt->sub, "assumed_charset");
171  if (c_assumed_charset)
172  {
173  // As iso-2022-* has a character of '"' with non-ascii state, ignore it
174  if (*s == 0x1b)
175  {
176  if ((s[1] == '(') && ((s[2] == 'B') || (s[2] == 'J')))
177  state_ascii = true;
178  else
179  state_ascii = false;
180  }
181  }
182  if (state_ascii && (*s == '"'))
183  break;
184  if (*s == '\\')
185  {
186  if (s[1])
187  {
188  s++;
189  /* Quote the next character */
190  mutt_buffer_addch(buf, *s);
191  }
192  }
193  else
194  mutt_buffer_addch(buf, *s);
195  }
196  if (*s)
197  s++; /* skip over the " */
198  }
199  else
200  {
201  for (; *s && *s != ' ' && *s != ';'; s++)
202  mutt_buffer_addch(buf, *s);
203  }
204 
205  p = s;
206  } while (allow_value_spaces && (*s == ' '));
207 
208  /* if the attribute token was missing, 'new' will be NULL */
209  if (pnew)
210  {
211  pnew->value = mutt_buffer_strdup(buf);
212 
213  mutt_debug(LL_DEBUG2, "parse_parameter: '%s' = '%s'\n",
214  pnew->attribute ? pnew->attribute : "", pnew->value ? pnew->value : "");
215 
216  /* Add this parameter to the list */
217  TAILQ_INSERT_HEAD(pl, pnew, entries);
218  }
219  }
220  else
221  {
222  mutt_debug(LL_DEBUG1, "parameter with no value: %s\n", s);
223  s = p;
224  }
225 
226  /* Find the next parameter */
227  if ((*s != ';') && !(s = strchr(s, ';')))
228  break; /* no more parameters */
229 
230  do
231  {
232  /* Move past any leading whitespace. the +1 skips over the semicolon */
233  s = mutt_str_skip_email_wsp(s + 1);
234  } while (*s == ';'); /* skip empty parameters */
235  }
236 
237 bail:
238 
241 }
char * attribute
Parameter name.
Definition: parameter.h:34
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
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
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:233
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
Container for Accounts, Notifications.
Definition: neomutt.h:36
Log at debug level 2.
Definition: logging.h:41
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:548
bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition: string.c:759
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:295
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:743
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:789
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
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
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
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 250 of file parse.c.

251 {
252  struct ParameterList pl;
253  TAILQ_INIT(&pl);
254 
255  if (mutt_istr_startswith(s, "inline"))
256  ct->disposition = DISP_INLINE;
257  else if (mutt_istr_startswith(s, "form-data"))
259  else
260  ct->disposition = DISP_ATTACH;
261 
262  /* Check to see if a default filename was given */
263  s = strchr(s, ';');
264  if (s)
265  {
266  s = mutt_str_skip_email_wsp(s + 1);
267  parse_parameters(&pl, s, false);
268  s = mutt_param_get(&pl, "filename");
269  if (s)
270  mutt_str_replace(&ct->filename, s);
271  s = mutt_param_get(&pl, "name");
272  if (s)
273  ct->form_name = mutt_str_dup(s);
274  mutt_param_free(&pl);
275  }
276 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:112
char * form_name
Content-Disposition form-data name param.
Definition: body.h:41
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
Content is form-data.
Definition: mime.h:64
Content is attached.
Definition: mime.h:63
#define TAILQ_INIT(head)
Definition: queue.h:758
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:743
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
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 283 of file parse.c.

284 {
285  if (!head)
286  return;
287 
288  char *m = NULL;
289  for (size_t off = 0; (m = mutt_extract_message_id(s, &off)); s += off)
290  {
291  mutt_list_insert_head(head, m);
292  }
293 }
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:363
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_content_language()

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

Read the content's language.

Parameters
sLanguage string
ctBody of the email

Definition at line 300 of file parse.c.

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

◆ mutt_matches_ignore()

bool mutt_matches_ignore ( const char *  s)

Does the string match the ignore list.

Parameters
sString to check
Return values
trueString matches

Checks Ignore and UnIgnore using mutt_list_match

Definition at line 316 of file parse.c.

317 {
318  return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
319 }
bool mutt_list_match(const char *s, struct ListHead *h)
Is the string in the list (see notes)
Definition: list.c:195
struct ListHead Ignore
List of header patterns to ignore.
Definition: globals.c:35
struct ListHead UnIgnore
List of header patterns to unignore (see)
Definition: globals.c:36
+ 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 326 of file parse.c.

327 {
328  if (mutt_istr_equal("text", s))
329  return TYPE_TEXT;
330  if (mutt_istr_equal("multipart", s))
331  return TYPE_MULTIPART;
332 #ifdef SUN_ATTACHMENT
333  if (mutt_istr_equal("x-sun-attachment", s))
334  return TYPE_MULTIPART;
335 #endif
336  if (mutt_istr_equal("application", s))
337  return TYPE_APPLICATION;
338  if (mutt_istr_equal("message", s))
339  return TYPE_MESSAGE;
340  if (mutt_istr_equal("image", s))
341  return TYPE_IMAGE;
342  if (mutt_istr_equal("audio", s))
343  return TYPE_AUDIO;
344  if (mutt_istr_equal("video", s))
345  return TYPE_VIDEO;
346  if (mutt_istr_equal("model", s))
347  return TYPE_MODEL;
348  if (mutt_istr_equal("*", s))
349  return TYPE_ANY;
350  if (mutt_istr_equal(".*", s))
351  return TYPE_ANY;
352 
353  return TYPE_OTHER;
354 }
Unknown Content-Type.
Definition: mime.h:31
Type: &#39;audio/*&#39;.
Definition: mime.h:32
Type: &#39;*&#39; or &#39;.*&#39;.
Definition: mime.h:40
Type: &#39;video/*&#39;.
Definition: mime.h:39
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
Type: &#39;text/*&#39;.
Definition: mime.h:38
Type: &#39;message/*&#39;.
Definition: mime.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Type: &#39;model/*&#39;.
Definition: mime.h:36
Type: &#39;image/*&#39;.
Definition: mime.h:34
Type: &#39;application/*&#39;.
Definition: mime.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_extract_message_id()

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

Find a message-id.

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

Definition at line 363 of file parse.c.

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

◆ mutt_check_encoding()

int mutt_check_encoding ( const char *  c)

Check the encoding type.

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

Definition at line 399 of file parse.c.

400 {
401  if (mutt_istr_startswith(c, "7bit"))
402  return ENC_7BIT;
403  if (mutt_istr_startswith(c, "8bit"))
404  return ENC_8BIT;
405  if (mutt_istr_startswith(c, "binary"))
406  return ENC_BINARY;
407  if (mutt_istr_startswith(c, "quoted-printable"))
408  return ENC_QUOTED_PRINTABLE;
409  if (mutt_istr_startswith(c, "base64"))
410  return ENC_BASE64;
411  if (mutt_istr_startswith(c, "x-uuencode"))
412  return ENC_UUENCODED;
413 #ifdef SUN_ATTACHMENT
414  if (mutt_istr_startswith(c, "uuencode"))
415  return ENC_UUENCODED;
416 #endif
417  return ENC_OTHER;
418 }
7-bit text
Definition: mime.h:49
8-bit text
Definition: mime.h:50
Base-64 encoded text.
Definition: mime.h:52
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
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 427 of file parse.c.

428 {
429  if (!s || !ct)
430  return;
431 
432  FREE(&ct->subtype);
434 
435  /* First extract any existing parameters */
436  char *pc = strchr(s, ';');
437  if (pc)
438  {
439  *pc++ = 0;
440  while (*pc && IS_SPACE(*pc))
441  pc++;
442  parse_parameters(&ct->parameter, pc, false);
443 
444  /* Some pre-RFC1521 gateways still use the "name=filename" convention,
445  * but if a filename has already been set in the content-disposition,
446  * let that take precedence, and don't set it here */
447  pc = mutt_param_get(&ct->parameter, "name");
448  if (pc && !ct->filename)
449  ct->filename = mutt_str_dup(pc);
450 
451 #ifdef SUN_ATTACHMENT
452  /* this is deep and utter perversion */
453  pc = mutt_param_get(&ct->parameter, "conversions");
454  if (pc)
455  ct->encoding = mutt_check_encoding(pc);
456 #endif
457  }
458 
459  /* Now get the subtype */
460  char *subtype = strchr(s, '/');
461  if (subtype)
462  {
463  *subtype++ = '\0';
464  for (pc = subtype; *pc && !IS_SPACE(*pc) && (*pc != ';'); pc++)
465  ; // do nothing
466 
467  *pc = '\0';
468  ct->subtype = mutt_str_dup(subtype);
469  }
470 
471  /* Finally, get the major type */
472  ct->type = mutt_check_mime_type(s);
473 
474 #ifdef SUN_ATTACHMENT
475  if (mutt_istr_equal("x-sun-attachment", s))
476  ct->subtype = mutt_str_dup("x-sun-attachment");
477 #endif
478 
479  if (ct->type == TYPE_OTHER)
480  {
481  mutt_str_replace(&ct->xtype, s);
482  }
483 
484  if (!ct->subtype)
485  {
486  /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type
487  * field, so we can attempt to convert the type to Body here. */
488  if (ct->type == TYPE_TEXT)
489  ct->subtype = mutt_str_dup("plain");
490  else if (ct->type == TYPE_AUDIO)
491  ct->subtype = mutt_str_dup("basic");
492  else if (ct->type == TYPE_MESSAGE)
493  ct->subtype = mutt_str_dup("rfc822");
494  else if (ct->type == TYPE_OTHER)
495  {
496  char buf[128];
497 
498  ct->type = TYPE_APPLICATION;
499  snprintf(buf, sizeof(buf), "x-%s", s);
500  ct->subtype = mutt_str_dup(buf);
501  }
502  else
503  ct->subtype = mutt_str_dup("x-unknown");
504  }
505 
506  /* Default character set for text types. */
507  if (ct->type == TYPE_TEXT)
508  {
509  pc = mutt_param_get(&ct->parameter, "charset");
510  if (pc)
511  {
512  /* Microsoft Outlook seems to think it is necessary to repeat
513  * charset=, strip it off not to confuse ourselves */
514  if (mutt_istrn_equal(pc, "charset=", sizeof("charset=") - 1))
515  mutt_param_set(&ct->parameter, "charset", pc + (sizeof("charset=") - 1));
516  }
517  else
518  {
519  const char *const c_assumed_charset =
520  cs_subset_string(NeoMutt->sub, "assumed_charset");
521  mutt_param_set(&ct->parameter, "charset",
522  (c_assumed_charset) ? (const char *) mutt_ch_get_default_charset() :
523  "us-ascii");
524  }
525  }
526 }
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
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:621
Type: &#39;audio/*&#39;.
Definition: mime.h:32
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:112
Container for Accounts, Notifications.
Definition: neomutt.h:36
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:326
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
char * mutt_ch_get_default_charset(void)
Get the default character set.
Definition: charset.c:442
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * subtype
content-type subtype
Definition: body.h:37
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:399
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * xtype
content-type if x-unknown
Definition: body.h:36
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:295
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
#define IS_SPACE(ch)
Definition: string2.h:38
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
#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
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
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 535 of file parse.c.

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

◆ mutt_rfc822_parse_line()

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

Parse an email header.

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

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 609 of file parse.c.

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

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

1125 {
1126  if (!fp)
1127  return NULL;
1128 
1129  struct Envelope *env = mutt_env_new();
1130  char *p = NULL;
1131  LOFF_T loc;
1132  size_t linelen = 1024;
1133  char *line = mutt_mem_malloc(linelen);
1134  char buf[linelen + 1];
1135 
1136  if (e)
1137  {
1138  if (!e->body)
1139  {
1140  e->body = mutt_body_new();
1141 
1142  /* set the defaults from RFC1521 */
1143  e->body->type = TYPE_TEXT;
1144  e->body->subtype = mutt_str_dup("plain");
1145  e->body->encoding = ENC_7BIT;
1146  e->body->length = -1;
1147 
1148  /* RFC2183 says this is arbitrary */
1150  }
1151  }
1152 
1153  while ((loc = ftello(fp)) != -1)
1154  {
1155  line = mutt_rfc822_read_line(fp, line, &linelen);
1156  if (*line == '\0')
1157  break;
1158  p = strpbrk(line, ": \t");
1159  if (!p || (*p != ':'))
1160  {
1161  char return_path[1024];
1162  time_t t;
1163 
1164  /* some bogus MTAs will quote the original "From " line */
1165  if (mutt_str_startswith(line, ">From "))
1166  continue; /* just ignore */
1167  else if (is_from(line, return_path, sizeof(return_path), &t))
1168  {
1169  /* MH sometimes has the From_ line in the middle of the header! */
1170  if (e && !e->received)
1171  e->received = t - mutt_date_local_tz(t);
1172  continue;
1173  }
1174 
1175  fseeko(fp, loc, SEEK_SET);
1176  break; /* end of header */
1177  }
1178 
1179  *buf = '\0';
1180 
1181  if (mutt_replacelist_match(&SpamList, buf, sizeof(buf), line))
1182  {
1183  if (!mutt_regexlist_match(&NoSpamList, line))
1184  {
1185  /* if spam tag already exists, figure out how to amend it */
1186  if ((!mutt_buffer_is_empty(&env->spam)) && (*buf != '\0'))
1187  {
1188  /* If `$spam_separator` defined, append with separator */
1189  const char *const c_spam_separator =
1190  cs_subset_string(NeoMutt->sub, "spam_separator");
1191  if (c_spam_separator)
1192  {
1193  mutt_buffer_addstr(&env->spam, c_spam_separator);
1194  mutt_buffer_addstr(&env->spam, buf);
1195  }
1196  else /* overwrite */
1197  {
1198  mutt_buffer_reset(&env->spam);
1199  mutt_buffer_addstr(&env->spam, buf);
1200  }
1201  }
1202 
1203  /* spam tag is new, and match expr is non-empty; copy */
1204  else if (mutt_buffer_is_empty(&env->spam) && (*buf != '\0'))
1205  {
1206  mutt_buffer_addstr(&env->spam, buf);
1207  }
1208 
1209  /* match expr is empty; plug in null string if no existing tag */
1210  else if (mutt_buffer_is_empty(&env->spam))
1211  {
1212  mutt_buffer_addstr(&env->spam, "");
1213  }
1214 
1215  if (!mutt_buffer_is_empty(&env->spam))
1216  mutt_debug(LL_DEBUG5, "spam = %s\n", env->spam.data);
1217  }
1218  }
1219 
1220  *p = '\0';
1221  p = mutt_str_skip_email_wsp(p + 1);
1222  if (*p == '\0')
1223  continue; /* skip empty header fields */
1224 
1225  mutt_rfc822_parse_line(env, e, line, p, user_hdrs, weed, true);
1226  }
1227 
1228  FREE(&line);
1229 
1230  if (e)
1231  {
1232  e->body->hdr_offset = e->offset;
1233  e->body->offset = ftello(fp);
1234 
1236 
1237  if (env->subject)
1238  {
1239  regmatch_t pmatch[1];
1240 
1241  const struct Regex *c_reply_regex =
1242  cs_subset_regex(NeoMutt->sub, "reply_regex");
1243  if (mutt_regex_capture(c_reply_regex, 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  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
1267  if (c_autocrypt)
1268  {
1269  struct Mailbox *m = ctx_mailbox(Context);
1271  /* No sense in taking up memory after the header is processed */
1273  }
1274 #endif
1275  }
1276 
1277  return env;
1278 }
The "current" mailbox.
Definition: context.h:37
bool mutt_replacelist_match(struct ReplaceList *rl, char *buf, size_t buflen, const char *str)
Does a string match a pattern?
Definition: regex.c:476
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:71
struct Body * body
List of MIME parts.
Definition: email.h:91
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:440
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:609
7-bit text
Definition: mime.h:49
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
char * real_subj
Offset of the real subject.
Definition: envelope.h:67
struct AutocryptHeader * autocrypt
Definition: envelope.h:85
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:787
time_t mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:206
Container for Accounts, Notifications.
Definition: neomutt.h:36
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:227
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:192
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * subtype
content-type subtype
Definition: body.h:37
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
int mutt_autocrypt_process_autocrypt_header(struct Mailbox *m, struct Email *e, struct Envelope *env)
Parse an Autocrypt email header.
Definition: autocrypt.c:263
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
struct RegexList NoSpamList
List of regexes to whitelist non-spam emails.
Definition: globals.c:33
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:81
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
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:295
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:743
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:84
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:596
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:34
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
Cached regular expression.
Definition: regex3.h:89
#define FREE(x)
Definition: memory.h:40
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:48
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
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
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
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:1049
+ 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 1286 of file parse.c.

1287 {
1288  if (!fp)
1289  return NULL;
1290 
1291  struct Body *p = mutt_body_new();
1292  struct Envelope *env = mutt_env_new();
1293  char *c = NULL;
1294  size_t linelen = 1024;
1295  char *line = mutt_mem_malloc(linelen);
1296 
1297  p->hdr_offset = ftello(fp);
1298 
1299  p->encoding = ENC_7BIT; /* default from RFC1521 */
1300  p->type = digest ? TYPE_MESSAGE : TYPE_TEXT;
1301  p->disposition = DISP_INLINE;
1302 
1303  while (*(line = mutt_rfc822_read_line(fp, line, &linelen)) != 0)
1304  {
1305  /* Find the value of the current header */
1306  c = strchr(line, ':');
1307  if (c)
1308  {
1309  *c = '\0';
1310  c = mutt_str_skip_email_wsp(c + 1);
1311  if (*c == '\0')
1312  {
1313  mutt_debug(LL_DEBUG1, "skipping empty header field: %s\n", line);
1314  continue;
1315  }
1316  }
1317  else
1318  {
1319  mutt_debug(LL_DEBUG1, "bogus MIME header: %s\n", line);
1320  break;
1321  }
1322 
1323  size_t plen = mutt_istr_startswith(line, "content-");
1324  if (plen != 0)
1325  {
1326  if (mutt_istr_equal("type", line + plen))
1328  else if (mutt_istr_equal("language", line + plen))
1329  parse_content_language(c, p);
1330  else if (mutt_istr_equal("transfer-encoding", line + plen))
1331  p->encoding = mutt_check_encoding(c);
1332  else if (mutt_istr_equal("disposition", line + plen))
1334  else if (mutt_istr_equal("description", line + plen))
1335  {
1336  mutt_str_replace(&p->description, c);
1338  }
1339  }
1340 #ifdef SUN_ATTACHMENT
1341  else if ((plen = mutt_istr_startswith(line, "x-sun-")))
1342  {
1343  if (mutt_istr_equal("data-type", line + plen))
1345  else if (mutt_istr_equal("encoding-info", line + plen))
1346  p->encoding = mutt_check_encoding(c);
1347  else if (mutt_istr_equal("content-lines", line + plen))
1348  mutt_param_set(&p->parameter, "content-lines", c);
1349  else if (mutt_istr_equal("data-description", line + plen))
1350  {
1351  mutt_str_replace(&p->description, c);
1353  }
1354  }
1355 #endif
1356  else
1357  {
1358  if (mutt_rfc822_parse_line(env, NULL, line, c, false, false, false))
1359  p->mime_headers = env;
1360  }
1361  }
1362  p->offset = ftello(fp); /* Mark the start of the real data */
1363  if ((p->type == TYPE_TEXT) && !p->subtype)
1364  p->subtype = mutt_str_dup("plain");
1365  else if ((p->type == TYPE_MESSAGE) && !p->subtype)
1366  p->subtype = mutt_str_dup("rfc822");
1367 
1368  FREE(&line);
1369 
1370  if (p->mime_headers)
1372  else
1373  mutt_env_free(&env);
1374 
1375  return p;
1376 }
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:609
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:250
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
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:787
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:641
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
static void parse_content_language(const char *s, struct Body *ct)
Read the content&#39;s language.
Definition: parse.c:300
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * subtype
content-type subtype
Definition: body.h:37
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:399
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
Type: &#39;text/*&#39;.
Definition: mime.h:38
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:743
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
char * description
content-description
Definition: body.h:40
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:427
Log at debug level 1.
Definition: logging.h:40
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
#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:1049
+ 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 1385 of file parse.c.

1386 {
1387  if (type != TYPE_MESSAGE)
1388  return false;
1389 
1390  subtype = NONULL(subtype);
1391  return (mutt_istr_equal(subtype, "rfc822") ||
1392  mutt_istr_equal(subtype, "news") || mutt_istr_equal(subtype, "global"));
1393 }
#define NONULL(x)
Definition: string2.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
Type: &#39;message/*&#39;.
Definition: mime.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_mailto()

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

Parse a mailto:// url.

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

Definition at line 1610 of file parse.c.

1611 {
1612  if (!e || !src)
1613  return false;
1614 
1615  struct Url *url = url_parse(src);
1616  if (!url)
1617  return false;
1618 
1619  if (url->host)
1620  {
1621  /* this is not a path-only URL */
1622  url_free(&url);
1623  return false;
1624  }
1625 
1626  mutt_addrlist_parse(&e->to, url->path);
1627 
1628  struct UrlQuery *np;
1629  STAILQ_FOREACH(np, &url->query_strings, entries)
1630  {
1631  const char *tag = np->name;
1632  char *value = np->value;
1633  /* Determine if this header field is on the allowed list. Since NeoMutt
1634  * interprets some header fields specially (such as
1635  * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
1636  * only safe fields are allowed.
1637  *
1638  * RFC2368, "4. Unsafe headers"
1639  * The user agent interpreting a mailto URL SHOULD choose not to create
1640  * a message if any of the headers are considered dangerous; it may also
1641  * choose to create a message with only a subset of the headers given in
1642  * the URL. */
1643  if (mutt_list_match(tag, &MailToAllow))
1644  {
1645  if (mutt_istr_equal(tag, "body"))
1646  {
1647  if (body)
1648  mutt_str_replace(body, value);
1649  }
1650  else
1651  {
1652  char *scratch = NULL;
1653  size_t taglen = mutt_str_len(tag);
1654 
1655  mutt_str_asprintf(&scratch, "%s: %s", tag, value);
1656  scratch[taglen] = 0; /* overwrite the colon as mutt_rfc822_parse_line expects */
1657  value = mutt_str_skip_email_wsp(&scratch[taglen + 1]);
1658  mutt_rfc822_parse_line(e, NULL, scratch, value, true, false, true);
1659  FREE(&scratch);
1660  }
1661  }
1662  }
1663 
1664  /* RFC2047 decode after the RFC822 parsing */
1666 
1667  url_free(&url);
1668  return true;
1669 }
char * name
Query name.
Definition: url.h:59
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
bool mutt_list_match(const char *s, struct ListHead *h)
Is the string in the list (see notes)
Definition: list.c:195
int mutt_rfc822_parse_line(struct Envelope *env, struct Email *e, char *line, char *p, bool user_hdrs, bool weed, bool do_2047)
Parse an email header.
Definition: parse.c:609
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:68
Parsed Query String.
Definition: url.h:57
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:787
char * value
Query value.
Definition: url.h:60
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
struct UrlQueryList query_strings
List of query strings.
Definition: url.h:76
struct ListHead MailToAllow
List of permitted fields in a mailto: url.
Definition: globals.c:37
char * host
Host.
Definition: url.h:73
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:743
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * path
Path.
Definition: url.h:75
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
#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:1095
char * src
Raw URL string.
Definition: url.h:77
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 1676 of file parse.c.

1677 {
1678  int counter = 0;
1679 
1680  parse_part(fp, b, &counter);
1681 }
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1401
+ 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 1691 of file parse.c.

1692 {
1693  int counter = 0;
1694 
1695  return rfc822_parse_message(fp, parent, &counter);
1696 }
static struct Body * rfc822_parse_message(FILE *fp, struct Body *parent, int *counter)
parse a Message/RFC822 body
Definition: parse.c:1579
+ 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 1707 of file parse.c.

1708 {
1709  int counter = 0;
1710 
1711  return parse_multipart(fp, boundary, end_off, digest, &counter);
1712 }
static struct Body * parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest, int *counter)
Parse a multipart structure.
Definition: parse.c:1468
+ Here is the call graph for this function:
+ Here is the caller graph for this function: