NeoMutt  2022-04-29-145-g9b6a0e
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 "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 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...
 
static char * rfc2369_first_mailto (const char *body)
 Extract the first mailto: URL from a RFC2369 list. More...
 
int mutt_rfc822_parse_line (struct Envelope *env, struct Email *e, const char *name, const char *body, 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 *env, 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 56 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 1458 of file parse.c.

1459 {
1460  if (!fp || !b)
1461  return;
1462 
1463  const char *bound = NULL;
1464  static unsigned short recurse_level = 0;
1465 
1466  if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1467  {
1468  mutt_debug(LL_DEBUG1, "recurse level too deep. giving up.\n");
1469  return;
1470  }
1471  recurse_level++;
1472 
1473  switch (b->type)
1474  {
1475  case TYPE_MULTIPART:
1476 #ifdef SUN_ATTACHMENT
1477  if (mutt_istr_equal(b->subtype, "x-sun-attachment"))
1478  bound = "--------";
1479  else
1480 #endif
1481  bound = mutt_param_get(&b->parameter, "boundary");
1482 
1483  if (!mutt_file_seek(fp, b->offset, SEEK_SET))
1484  {
1485  goto bail;
1486  }
1487  b->parts = parse_multipart(fp, bound, b->offset + b->length,
1488  mutt_istr_equal("digest", b->subtype), counter);
1489  break;
1490 
1491  case TYPE_MESSAGE:
1492  if (!b->subtype)
1493  break;
1494 
1495  if (!mutt_file_seek(fp, b->offset, SEEK_SET))
1496  {
1497  goto bail;
1498  }
1499  if (mutt_is_message_type(b->type, b->subtype))
1500  b->parts = rfc822_parse_message(fp, b, counter);
1501  else if (mutt_istr_equal(b->subtype, "external-body"))
1502  b->parts = mutt_read_mime_header(fp, 0);
1503  else
1504  goto bail;
1505  break;
1506 
1507  default:
1508  goto bail;
1509  }
1510 
1511  /* try to recover from parsing error */
1512  if (!b->parts)
1513  {
1514  b->type = TYPE_TEXT;
1515  mutt_str_replace(&b->subtype, "plain");
1516  }
1517 bail:
1518  recurse_level--;
1519 }
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:690
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define MUTT_MIME_MAX_DEPTH
Definition: mime.h:69
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
static struct Body * rfc822_parse_message(FILE *fp, struct Body *parent, int *counter)
Parse a Message/RFC822 body.
Definition: parse.c:1640
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:1531
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1318
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1442
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
+ 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 1640 of file parse.c.

1641 {
1642  if (!fp || !parent)
1643  return NULL;
1644 
1645  parent->email = email_new();
1646  parent->email->offset = ftello(fp);
1647  parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1648  struct Body *msg = parent->email->body;
1649 
1650  /* ignore the length given in the content-length since it could be wrong
1651  * and we already have the info to calculate the correct length */
1652  /* if (msg->length == -1) */
1653  msg->length = parent->length - (msg->offset - parent->offset);
1654 
1655  /* if body of this message is empty, we can end up with a negative length */
1656  if (msg->length < 0)
1657  msg->length = 0;
1658 
1659  parse_part(fp, msg, counter);
1660  return msg;
1661 }
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1158
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1458
The body of an email.
Definition: body.h:36
struct Email * email
header information for message/rfc822
Definition: body.h:73
struct Envelope * env
Envelope information.
Definition: email.h:66
struct Body * body
List of MIME parts.
Definition: email.h:67
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
+ 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 1531 of file parse.c.

1533 {
1534  if (!fp)
1535  return NULL;
1536 
1537  if (!boundary)
1538  {
1539  mutt_error(_("multipart message has no boundary parameter"));
1540  return NULL;
1541  }
1542 
1543  char buf[1024];
1544  struct Body *head = NULL, *last = NULL, *new_body = NULL;
1545  bool final = false; /* did we see the ending boundary? */
1546 
1547  const size_t blen = mutt_str_len(boundary);
1548  while ((ftello(fp) < end_off) && fgets(buf, sizeof(buf), fp))
1549  {
1550  const size_t len = mutt_str_len(buf);
1551 
1552  const size_t crlf = ((len > 1) && (buf[len - 2] == '\r')) ? 1 : 0;
1553 
1554  if ((buf[0] == '-') && (buf[1] == '-') && mutt_str_startswith(buf + 2, boundary))
1555  {
1556  if (last)
1557  {
1558  last->length = ftello(fp) - last->offset - len - 1 - crlf;
1559  if (last->parts && (last->parts->length == 0))
1560  last->parts->length = ftello(fp) - last->parts->offset - len - 1 - crlf;
1561  /* if the body is empty, we can end up with a -1 length */
1562  if (last->length < 0)
1563  last->length = 0;
1564  }
1565 
1566  if (len > 0)
1567  {
1568  /* Remove any trailing whitespace, up to the length of the boundary */
1569  for (size_t i = len - 1; IS_SPACE(buf[i]) && (i >= (blen + 2)); i--)
1570  buf[i] = '\0';
1571  }
1572 
1573  /* Check for the end boundary */
1574  if (mutt_str_equal(buf + blen + 2, "--"))
1575  {
1576  final = true;
1577  break; /* done parsing */
1578  }
1579  else if (buf[2 + blen] == '\0')
1580  {
1581  new_body = mutt_read_mime_header(fp, digest);
1582 
1583 #ifdef SUN_ATTACHMENT
1584  if (mutt_param_get(&new_body->parameter, "content-lines"))
1585  {
1586  int lines = 0;
1587  mutt_str_atoi(mutt_param_get(&new_body->parameter, "content-lines"), &lines);
1588  for (; lines > 0; lines--)
1589  if ((ftello(fp) >= end_off) || !fgets(buf, sizeof(buf), fp))
1590  break;
1591  }
1592 #endif
1593  /* Consistency checking - catch bad attachment end boundaries */
1594  if (new_body->offset > end_off)
1595  {
1596  mutt_body_free(&new_body);
1597  break;
1598  }
1599  if (head)
1600  {
1601  last->next = new_body;
1602  last = new_body;
1603  }
1604  else
1605  {
1606  last = new_body;
1607  head = new_body;
1608  }
1609 
1610  /* It seems more intuitive to add the counter increment to
1611  * parse_part(), but we want to stop the case where a multipart
1612  * contains thousands of tiny parts before the memory and data
1613  * structures are allocated. */
1614  if (++(*counter) >= MUTT_MIME_MAX_PARTS)
1615  break;
1616  }
1617  }
1618  }
1619 
1620  /* in case of missing end boundary, set the length to something reasonable */
1621  if (last && (last->length == 0) && !final)
1622  last->length = end_off - last->offset;
1623 
1624  /* parse recursive MIME parts */
1625  for (last = head; last; last = last->next)
1626  parse_part(fp, last, counter);
1627 
1628  return head;
1629 }
const char * mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: atoi.c:178
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define mutt_error(...)
Definition: logging.h:87
#define MUTT_MIME_MAX_PARTS
Definition: mime.h:70
#define _(a)
Definition: message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
#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_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 67 of file parse.c.

68 {
69  if (!mailto)
70  return;
71 
72  if (!AutoSubscribeCache)
74 
76  return;
77 
79 
80  struct Envelope *lpenv = mutt_env_new(); /* parsed envelope from the List-Post mailto: URL */
81 
82  if (mutt_parse_mailto(lpenv, NULL, mailto) && !TAILQ_EMPTY(&lpenv->to))
83  {
84  const char *mailbox = TAILQ_FIRST(&lpenv->to)->mailbox;
85  if (mailbox && !mutt_regexlist_match(&SubscribedLists, mailbox) &&
86  !mutt_regexlist_match(&UnMailLists, mailbox) &&
88  {
89  /* mutt_regexlist_add() detects duplicates, so it is safe to
90  * try to add here without any checks. */
91  mutt_regexlist_add(&MailLists, mailbox, REG_ICASE, NULL);
92  mutt_regexlist_add(&SubscribedLists, mailbox, REG_ICASE, NULL);
93  }
94  }
95 
96  mutt_env_free(&lpenv);
97 }
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
struct RegexList SubscribedLists
List of regexes to match subscribed mailing lists.
Definition: globals.c:43
struct HashTable * AutoSubscribeCache
Hash Table of auto-subscribed mailing lists.
Definition: globals.c:38
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: globals.c:40
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: globals.c:42
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: globals.c:41
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:335
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:362
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:259
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:111
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:110
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:135
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:195
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1671
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_EMPTY(head)
Definition: queue.h:721
The header of an Email.
Definition: envelope.h:57
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
+ 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 110 of file parse.c.

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

249 {
250  struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
251 
252  if (mutt_istr_startswith(s, "inline"))
253  ct->disposition = DISP_INLINE;
254  else if (mutt_istr_startswith(s, "form-data"))
256  else
257  ct->disposition = DISP_ATTACH;
258 
259  /* Check to see if a default filename was given */
260  s = strchr(s, ';');
261  if (s)
262  {
263  s = mutt_str_skip_email_wsp(s + 1);
264  parse_parameters(&pl, s, false);
265  s = mutt_param_get(&pl, "filename");
266  if (s)
267  mutt_str_replace(&ct->filename, s);
268  s = mutt_param_get(&pl, "name");
269  if (s)
270  mutt_str_replace(&ct->form_name, s);
271  mutt_param_free(&pl);
272  }
273 }
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
@ DISP_FORM_DATA
Content is form-data.
Definition: mime.h:64
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:110
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
char * form_name
Content-Disposition form-data name param.
Definition: body.h:59
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
+ 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 280 of file parse.c.

281 {
282  if (!head)
283  return;
284 
285  char *m = NULL;
286  for (size_t off = 0; (m = mutt_extract_message_id(s, &off)); s += off)
287  {
288  mutt_list_insert_head(head, m);
289  }
290 }
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:360
+ 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 297 of file parse.c.

298 {
299  if (!s || !ct)
300  return;
301 
302  mutt_debug(LL_DEBUG2, "RFC8255 >> Content-Language set to %s\n", s);
303  mutt_str_replace(&ct->language, s);
304 }
char * language
content-language (RFC8255)
Definition: body.h:77
+ 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 313 of file parse.c.

314 {
315  return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
316 }
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
bool mutt_list_match(const char *s, struct ListHead *h)
Is the string in the list (see notes)
Definition: list.c:195
+ 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 313 of file parse.c.

324 {
325  if (mutt_istr_equal("text", s))
326  return TYPE_TEXT;
327  if (mutt_istr_equal("multipart", s))
328  return TYPE_MULTIPART;
329 #ifdef SUN_ATTACHMENT
330  if (mutt_istr_equal("x-sun-attachment", s))
331  return TYPE_MULTIPART;
332 #endif
333  if (mutt_istr_equal("application", s))
334  return TYPE_APPLICATION;
335  if (mutt_istr_equal("message", s))
336  return TYPE_MESSAGE;
337  if (mutt_istr_equal("image", s))
338  return TYPE_IMAGE;
339  if (mutt_istr_equal("audio", s))
340  return TYPE_AUDIO;
341  if (mutt_istr_equal("video", s))
342  return TYPE_VIDEO;
343  if (mutt_istr_equal("model", s))
344  return TYPE_MODEL;
345  if (mutt_istr_equal("*", s))
346  return TYPE_ANY;
347  if (mutt_istr_equal(".*", s))
348  return TYPE_ANY;
349 
350  return TYPE_OTHER;
351 }
@ TYPE_AUDIO
Type: 'audio/*'.
Definition: mime.h:32
@ TYPE_IMAGE
Type: 'image/*'.
Definition: mime.h:34
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MODEL
Type: 'model/*'.
Definition: mime.h:36
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_ANY
Type: '*' or '.*'.
Definition: mime.h:40
@ TYPE_VIDEO
Type: 'video/*'.
Definition: mime.h:39
+ 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 360 of file parse.c.

361 {
362  if (!s || (*s == '\0'))
363  return NULL;
364 
365  char *decoded = mutt_str_dup(s);
366  rfc2047_decode(&decoded);
367 
368  char *res = NULL;
369 
370  for (const char *p = decoded, *beg = NULL; *p; p++)
371  {
372  if (*p == '<')
373  {
374  beg = p;
375  continue;
376  }
377 
378  if (beg && (*p == '>'))
379  {
380  if (len)
381  *len = p - decoded + 1;
382  res = mutt_strn_dup(beg, (p + 1) - beg);
383  break;
384  }
385  }
386 
387  FREE(&decoded);
388  return res;
389 }
#define FREE(x)
Definition: memory.h:43
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:649
+ 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 396 of file parse.c.

397 {
398  if (mutt_istr_startswith(c, "7bit"))
399  return ENC_7BIT;
400  if (mutt_istr_startswith(c, "8bit"))
401  return ENC_8BIT;
402  if (mutt_istr_startswith(c, "binary"))
403  return ENC_BINARY;
404  if (mutt_istr_startswith(c, "quoted-printable"))
405  return ENC_QUOTED_PRINTABLE;
406  if (mutt_istr_startswith(c, "base64"))
407  return ENC_BASE64;
408  if (mutt_istr_startswith(c, "x-uuencode"))
409  return ENC_UUENCODED;
410 #ifdef SUN_ATTACHMENT
411  if (mutt_istr_startswith(c, "uuencode"))
412  return ENC_UUENCODED;
413 #endif
414  return ENC_OTHER;
415 }
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_UUENCODED
UUEncoded text.
Definition: mime.h:54
@ ENC_OTHER
Encoding unknown.
Definition: mime.h:48
@ ENC_BINARY
Binary.
Definition: mime.h:53
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_8BIT
8-bit text
Definition: mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
+ 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 424 of file parse.c.

425 {
426  if (!s || !ct)
427  return;
428 
429  FREE(&ct->subtype);
431 
432  /* First extract any existing parameters */
433  char *pc = strchr(s, ';');
434  if (pc)
435  {
436  *pc++ = 0;
437  while (*pc && IS_SPACE(*pc))
438  pc++;
439  parse_parameters(&ct->parameter, pc, false);
440 
441  /* Some pre-RFC1521 gateways still use the "name=filename" convention,
442  * but if a filename has already been set in the content-disposition,
443  * let that take precedence, and don't set it here */
444  pc = mutt_param_get(&ct->parameter, "name");
445  if (pc && !ct->filename)
446  ct->filename = mutt_str_dup(pc);
447 
448 #ifdef SUN_ATTACHMENT
449  /* this is deep and utter perversion */
450  pc = mutt_param_get(&ct->parameter, "conversions");
451  if (pc)
452  ct->encoding = mutt_check_encoding(pc);
453 #endif
454  }
455 
456  /* Now get the subtype */
457  char *subtype = strchr(s, '/');
458  if (subtype)
459  {
460  *subtype++ = '\0';
461  for (pc = subtype; *pc && !IS_SPACE(*pc) && (*pc != ';'); pc++)
462  ; // do nothing
463 
464  *pc = '\0';
465  mutt_str_replace(&ct->subtype, subtype);
466  }
467 
468  /* Finally, get the major type */
469  ct->type = mutt_check_mime_type(s);
470 
471 #ifdef SUN_ATTACHMENT
472  if (mutt_istr_equal("x-sun-attachment", s))
473  mutt_str_replace(&ct->subtype, "x-sun-attachment");
474 #endif
475 
476  if (ct->type == TYPE_OTHER)
477  {
478  mutt_str_replace(&ct->xtype, s);
479  }
480 
481  if (!ct->subtype)
482  {
483  /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type
484  * field, so we can attempt to convert the type to Body here. */
485  if (ct->type == TYPE_TEXT)
486  ct->subtype = mutt_str_dup("plain");
487  else if (ct->type == TYPE_AUDIO)
488  ct->subtype = mutt_str_dup("basic");
489  else if (ct->type == TYPE_MESSAGE)
490  ct->subtype = mutt_str_dup("rfc822");
491  else if (ct->type == TYPE_OTHER)
492  {
493  char buf[128];
494 
495  ct->type = TYPE_APPLICATION;
496  snprintf(buf, sizeof(buf), "x-%s", s);
497  ct->subtype = mutt_str_dup(buf);
498  }
499  else
500  ct->subtype = mutt_str_dup("x-unknown");
501  }
502 
503  /* Default character set for text types. */
504  if (ct->type == TYPE_TEXT)
505  {
506  pc = mutt_param_get(&ct->parameter, "charset");
507  if (pc)
508  {
509  /* Microsoft Outlook seems to think it is necessary to repeat
510  * charset=, strip it off not to confuse ourselves */
511  if (mutt_istrn_equal(pc, "charset=", sizeof("charset=") - 1))
512  mutt_param_set(&ct->parameter, "charset", pc + (sizeof("charset=") - 1));
513  }
514  else
515  {
516  mutt_param_set(&ct->parameter, "charset",
517  (const char *) mutt_ch_get_default_charset());
518  }
519  }
520 }
char * mutt_ch_get_default_charset(void)
Get the default character set.
Definition: charset.c:439
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:501
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:323
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:396
char * xtype
content-type if x-unknown
Definition: body.h:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
+ 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 529 of file parse.c.

530 {
531  struct AutocryptHeader *autocrypt = mutt_autocrypthdr_new();
532  autocrypt->next = head;
533 
534  struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
535  parse_parameters(&pl, s, true);
536  if (TAILQ_EMPTY(&pl))
537  {
538  autocrypt->invalid = true;
539  goto cleanup;
540  }
541 
542  struct Parameter *p = NULL;
543  TAILQ_FOREACH(p, &pl, entries)
544  {
545  if (mutt_istr_equal(p->attribute, "addr"))
546  {
547  if (autocrypt->addr)
548  {
549  autocrypt->invalid = true;
550  goto cleanup;
551  }
552  autocrypt->addr = p->value;
553  p->value = NULL;
554  }
555  else if (mutt_istr_equal(p->attribute, "prefer-encrypt"))
556  {
557  if (mutt_istr_equal(p->value, "mutual"))
558  autocrypt->prefer_encrypt = true;
559  }
560  else if (mutt_istr_equal(p->attribute, "keydata"))
561  {
562  if (autocrypt->keydata)
563  {
564  autocrypt->invalid = true;
565  goto cleanup;
566  }
567  autocrypt->keydata = p->value;
568  p->value = NULL;
569  }
570  else if (p->attribute && (p->attribute[0] != '_'))
571  {
572  autocrypt->invalid = true;
573  goto cleanup;
574  }
575  }
576 
577  /* Checking the addr against From, and for multiple valid headers
578  * occurs later, after all the headers are parsed. */
579  if (!autocrypt->addr || !autocrypt->keydata)
580  autocrypt->invalid = true;
581 
582 cleanup:
583  mutt_param_free(&pl);
584  return autocrypt;
585 }
struct AutocryptHeader * mutt_autocrypthdr_new(void)
Create a new AutocryptHeader.
Definition: envelope.c:66
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
Parse Autocrypt header info.
Definition: envelope.h:44
bool invalid
Header is invalid.
Definition: envelope.h:48
struct AutocryptHeader * next
Linked list.
Definition: envelope.h:49
char * keydata
PGP Key data.
Definition: envelope.h:46
bool prefer_encrypt
User prefers encryption.
Definition: envelope.h:47
char * addr
Email address.
Definition: envelope.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc2369_first_mailto()

static char* rfc2369_first_mailto ( const char *  body)
static

Extract the first mailto: URL from a RFC2369 list.

Parameters
bodyBody of the header
Return values
ptrFirst mailto: URL found, or NULL if none was found

Definition at line 593 of file parse.c.

594 {
595  for (const char *beg = body, *end = NULL; beg; beg = strchr(end, ','))
596  {
597  beg = strchr(beg, '<');
598  if (!beg)
599  {
600  break;
601  }
602  beg++;
603  end = strchr(beg, '>');
604  if (!end)
605  {
606  break;
607  }
608 
609  char *mlist = mutt_strn_dup(beg, end - beg);
610  if (url_check_scheme(mlist) == U_MAILTO)
611  {
612  return mlist;
613  }
614  FREE(&mlist);
615  }
616  return NULL;
617 }
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:221
@ U_MAILTO
Url is mailto://.
Definition: url.h:45
+ 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,
const char *  name,
const char *  body,
bool  user_hdrs,
bool  weed,
bool  do_2047 
)

Parse an email header.

Parameters
envEnvelope of the email
eEmail
nameHeader field name, e.g. 'to'
bodyHeader field body, 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 634 of file parse.c.

636 {
637  if (!env || !name)
638  return 0;
639 
640  bool matched = false;
641 
642  switch (tolower(name[0]))
643  {
644  case 'a':
645  if (mutt_istr_equal(name + 1, "pparently-to"))
646  {
647  mutt_addrlist_parse(&env->to, body);
648  matched = true;
649  }
650  else if (mutt_istr_equal(name + 1, "pparently-from"))
651  {
652  mutt_addrlist_parse(&env->from, body);
653  matched = true;
654  }
655 #ifdef USE_AUTOCRYPT
656  else if (mutt_istr_equal(name + 1, "utocrypt"))
657  {
658  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
659  if (c_autocrypt)
660  {
661  env->autocrypt = parse_autocrypt(env->autocrypt, body);
662  matched = true;
663  }
664  }
665  else if (mutt_istr_equal(name + 1, "utocrypt-gossip"))
666  {
667  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
668  if (c_autocrypt)
669  {
671  matched = true;
672  }
673  }
674 #endif
675  break;
676 
677  case 'b':
678  if (mutt_istr_equal(name + 1, "cc"))
679  {
680  mutt_addrlist_parse(&env->bcc, body);
681  matched = true;
682  }
683  break;
684 
685  case 'c':
686  if (mutt_istr_equal(name + 1, "c"))
687  {
688  mutt_addrlist_parse(&env->cc, body);
689  matched = true;
690  }
691  else
692  {
693  size_t plen = mutt_istr_startswith(name + 1, "ontent-");
694  if (plen != 0)
695  {
696  if (mutt_istr_equal(name + 1 + plen, "type"))
697  {
698  if (e)
699  mutt_parse_content_type(body, e->body);
700  matched = true;
701  }
702  else if (mutt_istr_equal(name + 1 + plen, "language"))
703  {
704  if (e)
705  parse_content_language(body, e->body);
706  matched = true;
707  }
708  else if (mutt_istr_equal(name + 1 + plen, "transfer-encoding"))
709  {
710  if (e)
711  e->body->encoding = mutt_check_encoding(body);
712  matched = true;
713  }
714  else if (mutt_istr_equal(name + 1 + plen, "length"))
715  {
716  if (e)
717  {
718  unsigned long len = 0;
719  e->body->length = mutt_str_atoul(body, &len) ? MIN(len, CONTENT_TOO_BIG) : -1;
720  }
721  matched = true;
722  }
723  else if (mutt_istr_equal(name + 1 + plen, "description"))
724  {
725  if (e)
726  {
727  mutt_str_replace(&e->body->description, body);
729  }
730  matched = true;
731  }
732  else if (mutt_istr_equal(name + 1 + plen, "disposition"))
733  {
734  if (e)
736  matched = true;
737  }
738  }
739  }
740  break;
741 
742  case 'd':
743  if (!mutt_istr_equal("ate", name + 1))
744  break;
745 
746  mutt_str_replace(&env->date, body);
747  if (e)
748  {
749  struct Tz tz;
750  e->date_sent = mutt_date_parse_date(body, &tz);
751  if (e->date_sent > 0)
752  {
753  e->zhours = tz.zhours;
754  e->zminutes = tz.zminutes;
755  e->zoccident = tz.zoccident;
756  }
757  }
758  matched = true;
759  break;
760 
761  case 'e':
762  if (mutt_istr_equal("xpires", name + 1) && e &&
763  (mutt_date_parse_date(body, NULL) < mutt_date_epoch()))
764  {
765  e->expired = true;
766  }
767  break;
768 
769  case 'f':
770  if (mutt_istr_equal("rom", name + 1))
771  {
772  mutt_addrlist_parse(&env->from, body);
773  matched = true;
774  }
775 #ifdef USE_NNTP
776  else if (mutt_istr_equal(name + 1, "ollowup-to"))
777  {
778  if (!env->followup_to)
779  {
782  }
783  matched = true;
784  }
785 #endif
786  break;
787 
788  case 'i':
789  if (!mutt_istr_equal(name + 1, "n-reply-to"))
790  break;
791 
793  parse_references(&env->in_reply_to, body);
794  matched = true;
795  break;
796 
797  case 'l':
798  if (mutt_istr_equal(name + 1, "ines"))
799  {
800  if (e)
801  {
802  unsigned int ui = 0; // we don't want a negative number of lines
803  mutt_str_atoui(body, &ui);
804  e->lines = ui;
805  }
806 
807  matched = true;
808  }
809  else if (mutt_istr_equal(name + 1, "ist-Post"))
810  {
811  /* RFC2369 */
812  if (!mutt_strn_equal(mutt_str_skip_whitespace(body), "NO", 2))
813  {
814  char *mailto = rfc2369_first_mailto(body);
815  if (mailto)
816  {
817  FREE(&env->list_post);
818  env->list_post = mailto;
819  const bool c_auto_subscribe = cs_subset_bool(NeoMutt->sub, "auto_subscribe");
820  if (c_auto_subscribe)
822  }
823  }
824  matched = true;
825  }
826  else if (mutt_istr_equal(name + 1, "ist-Subscribe"))
827  {
828  /* RFC2369 */
829  char *mailto = rfc2369_first_mailto(body);
830  if (mailto)
831  {
832  FREE(&env->list_subscribe);
833  env->list_subscribe = mailto;
834  }
835  matched = true;
836  }
837  else if (mutt_istr_equal(name + 1, "ist-Unsubscribe"))
838  {
839  /* RFC2369 */
840  char *mailto = rfc2369_first_mailto(body);
841  if (mailto)
842  {
843  FREE(&env->list_unsubscribe);
844  env->list_unsubscribe = mailto;
845  }
846  matched = true;
847  }
848  break;
849 
850  case 'm':
851  if (mutt_istr_equal(name + 1, "ime-version"))
852  {
853  if (e)
854  e->mime = true;
855  matched = true;
856  }
857  else if (mutt_istr_equal(name + 1, "essage-id"))
858  {
859  /* We add a new "Message-ID:" when building a message */
860  FREE(&env->message_id);
861  env->message_id = mutt_extract_message_id(body, NULL);
862  matched = true;
863  }
864  else
865  {
866  size_t plen = mutt_istr_startswith(name + 1, "ail-");
867  if (plen != 0)
868  {
869  if (mutt_istr_equal(name + 1 + plen, "reply-to"))
870  {
871  /* override the Reply-To: field */
873  mutt_addrlist_parse(&env->reply_to, body);
874  matched = true;
875  }
876  else if (mutt_istr_equal(name + 1 + plen, "followup-to"))
877  {
879  matched = true;
880  }
881  }
882  }
883  break;
884 
885 #ifdef USE_NNTP
886  case 'n':
887  if (mutt_istr_equal(name + 1, "ewsgroups"))
888  {
889  FREE(&env->newsgroups);
892  matched = true;
893  }
894  break;
895 #endif
896 
897  case 'o':
898  /* field 'Organization:' saves only for pager! */
899  if (mutt_istr_equal(name + 1, "rganization"))
900  {
901  if (!env->organization && !mutt_istr_equal(body, "unknown"))
902  env->organization = mutt_str_dup(body);
903  }
904  break;
905 
906  case 'r':
907  if (mutt_istr_equal(name + 1, "eferences"))
908  {
909  mutt_list_free(&env->references);
910  parse_references(&env->references, body);
911  matched = true;
912  }
913  else if (mutt_istr_equal(name + 1, "eply-to"))
914  {
915  mutt_addrlist_parse(&env->reply_to, body);
916  matched = true;
917  }
918  else if (mutt_istr_equal(name + 1, "eturn-path"))
919  {
920  mutt_addrlist_parse(&env->return_path, body);
921  matched = true;
922  }
923  else if (mutt_istr_equal(name + 1, "eceived"))
924  {
925  if (e && (e->received == 0))
926  {
927  char *d = strrchr(body, ';');
928  if (d)
929  {
930  d = mutt_str_skip_email_wsp(d + 1);
931  e->received = mutt_date_parse_date(d, NULL);
932  }
933  }
934  }
935  break;
936 
937  case 's':
938  if (mutt_istr_equal(name + 1, "ubject"))
939  {
940  if (!env->subject)
941  env->subject = mutt_str_dup(body);
942  matched = true;
943  }
944  else if (mutt_istr_equal(name + 1, "ender"))
945  {
946  mutt_addrlist_parse(&env->sender, body);
947  matched = true;
948  }
949  else if (mutt_istr_equal(name + 1, "tatus"))
950  {
951  if (e)
952  {
953  while (*body)
954  {
955  switch (*body)
956  {
957  case 'O':
958  {
959  const bool c_mark_old = cs_subset_bool(NeoMutt->sub, "mark_old");
960  e->old = c_mark_old;
961  break;
962  }
963  case 'R':
964  e->read = true;
965  break;
966  case 'r':
967  e->replied = true;
968  break;
969  }
970  body++;
971  }
972  }
973  matched = true;
974  }
975  else if (e && (mutt_istr_equal("upersedes", name + 1) ||
976  mutt_istr_equal("upercedes", name + 1)))
977  {
978  FREE(&env->supersedes);
979  env->supersedes = mutt_str_dup(body);
980  }
981  break;
982 
983  case 't':
984  if (mutt_istr_equal(name + 1, "o"))
985  {
986  mutt_addrlist_parse(&env->to, body);
987  matched = true;
988  }
989  break;
990 
991  case 'x':
992  if (mutt_istr_equal(name + 1, "-status"))
993  {
994  if (e)
995  {
996  while (*body)
997  {
998  switch (*body)
999  {
1000  case 'A':
1001  e->replied = true;
1002  break;
1003  case 'D':
1004  e->deleted = true;
1005  break;
1006  case 'F':
1007  e->flagged = true;
1008  break;
1009  default:
1010  break;
1011  }
1012  body++;
1013  }
1014  }
1015  matched = true;
1016  }
1017  else if (mutt_istr_equal(name + 1, "-label"))
1018  {
1019  FREE(&env->x_label);
1020  env->x_label = mutt_str_dup(body);
1021  matched = true;
1022  }
1023 #ifdef USE_NNTP
1024  else if (mutt_istr_equal(name + 1, "-comment-to"))
1025  {
1026  if (!env->x_comment_to)
1027  env->x_comment_to = mutt_str_dup(body);
1028  matched = true;
1029  }
1030  else if (mutt_istr_equal(name + 1, "ref"))
1031  {
1032  if (!env->xref)
1033  env->xref = mutt_str_dup(body);
1034  matched = true;
1035  }
1036 #endif
1037  else if (mutt_istr_equal(name + 1, "-original-to"))
1038  {
1039  mutt_addrlist_parse(&env->x_original_to, body);
1040  matched = true;
1041  }
1042  break;
1043 
1044  default:
1045  break;
1046  }
1047 
1048  /* Keep track of the user-defined headers */
1049  if (!matched && user_hdrs)
1050  {
1051  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1052  char *dup = NULL;
1053  mutt_str_asprintf(&dup, "%s: %s", name, body);
1054 
1055  if (!weed || !c_weed || !mutt_matches_ignore(dup))
1056  {
1057  struct ListNode *np = mutt_list_insert_tail(&env->userhdrs, dup);
1058  if (do_2047)
1059  {
1060  rfc2047_decode(&np->data);
1061  }
1062  }
1063  else
1064  {
1065  FREE(&dup);
1066  }
1067  }
1068 
1069  return matched;
1070 }
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
const char * mutt_str_atoul(const char *str, unsigned long *dst)
Convert ASCII string to an unsigned long.
Definition: atoi.c:226
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:202
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:456
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define MIN(a, b)
Definition: memory.h:31
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:613
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1008
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:473
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:599
static struct AutocryptHeader * parse_autocrypt(struct AutocryptHeader *head, const char *s)
Parse an Autocrypt header line.
Definition: parse.c:529
void mutt_auto_subscribe(const char *mailto)
Check if user is subscribed to mailing list.
Definition: parse.c:67
static char * rfc2369_first_mailto(const char *body)
Extract the first mailto: URL from a RFC2369 list.
Definition: parse.c:593
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:424
static void parse_references(struct ListHead *head, const char *s)
Parse references from an email header.
Definition: parse.c:280
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:313
static void parse_content_language(const char *s, struct Body *ct)
Read the content's language.
Definition: parse.c:297
static void parse_content_disposition(const char *s, struct Body *ct)
Parse a content disposition.
Definition: parse.c:248
#define CONTENT_TOO_BIG
Definition: parse.c:56
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
char * description
content-description
Definition: body.h:55
bool read
Email is read.
Definition: email.h:48
unsigned int zminutes
Minutes away from UTC.
Definition: email.h:55
bool mime
Has a MIME-Version header?
Definition: email.h:46
int lines
How many lines in the body of this message?
Definition: email.h:60
bool old
Email is seen, but unread.
Definition: email.h:47
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:56
bool flagged
Marked important?
Definition: email.h:45
unsigned int zhours
Hours away from UTC.
Definition: email.h:54
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:58
bool replied
Email has been replied to.
Definition: email.h:49
bool expired
Already expired?
Definition: email.h:44
bool deleted
Email is deleted.
Definition: email.h:76
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
struct ListHead userhdrs
user defined headers
Definition: envelope.h:87
char * supersedes
Supersedes header.
Definition: envelope.h:74
char * list_subscribe
This stores a mailto URL, or nothing.
Definition: envelope.h:68
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:58
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:81
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:64
char * message_id
Message ID.
Definition: envelope.h:73
char * x_comment_to
List of 'X-comment-to' fields.
Definition: envelope.h:82
struct AddressList x_original_to
Email's 'X-Orig-to'.
Definition: envelope.h:66
struct AutocryptHeader * autocrypt_gossip
Autocrypt Gossip header.
Definition: envelope.h:90
char * newsgroups
List of newsgroups.
Definition: envelope.h:79
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:65
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct ListHead references
message references (in reverse order)
Definition: envelope.h:85
struct AutocryptHeader * autocrypt
Autocrypt header.
Definition: envelope.h:89
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:86
char * subject
Email's subject.
Definition: envelope.h:70
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
char * xref
List of cross-references.
Definition: envelope.h:80
char * organization
Organisation header.
Definition: envelope.h:77
char * x_label
X-Label.
Definition: envelope.h:76
char * list_post
This stores a mailto URL, or nothing.
Definition: envelope.h:67
char * date
Sent date.
Definition: envelope.h:75
char * list_unsubscribe
This stores a mailto URL, or nothing.
Definition: envelope.h:69
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
List of recognised Timezones.
Definition: date.h:45
+ 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 1083 of file parse.c.

1084 {
1085  if (!fp || !line || !linelen)
1086  return NULL;
1087 
1088  char *buf = line;
1089  int ch;
1090  size_t offset = 0;
1091 
1092  while (true)
1093  {
1094  if (!fgets(buf, *linelen - offset, fp) || /* end of file or */
1095  (IS_SPACE(*line) && !offset)) /* end of headers */
1096  {
1097  *line = '\0';
1098  return line;
1099  }
1100 
1101  const size_t len = mutt_str_len(buf);
1102  if (len == 0)
1103  return line;
1104 
1105  buf += len - 1;
1106  if (*buf == '\n')
1107  {
1108  /* we did get a full line. remove trailing space */
1109  while (IS_SPACE(*buf))
1110  {
1111  *buf-- = '\0'; /* we can't come beyond line's beginning because
1112  * it begins with a non-space */
1113  }
1114 
1115  /* check to see if the next line is a continuation line */
1116  ch = fgetc(fp);
1117  if ((ch != ' ') && (ch != '\t'))
1118  {
1119  ungetc(ch, fp);
1120  return line; /* next line is a separate header field or EOH */
1121  }
1122 
1123  /* eat tabs and spaces from the beginning of the continuation line */
1124  while (((ch = fgetc(fp)) == ' ') || (ch == '\t'))
1125  ; // do nothing
1126 
1127  ungetc(ch, fp);
1128  *++buf = ' '; /* string is still terminated because we removed
1129  at least one whitespace char above */
1130  }
1131 
1132  buf++;
1133  offset = buf - line;
1134  if (*linelen < (offset + 256))
1135  {
1136  /* grow the buffer */
1137  *linelen += 256;
1138  mutt_mem_realloc(&line, *linelen);
1139  buf = line + offset;
1140  }
1141  }
1142  /* not reached */
1143 }
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
+ 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 1158 of file parse.c.

1159 {
1160  if (!fp)
1161  return NULL;
1162 
1163  struct Envelope *env = mutt_env_new();
1164  char *p = NULL;
1165  LOFF_T loc;
1166  size_t linelen = 1024;
1167  char *line = mutt_mem_malloc(linelen);
1168  char buf[linelen + 1];
1169 
1170  if (e)
1171  {
1172  if (!e->body)
1173  {
1174  e->body = mutt_body_new();
1175 
1176  /* set the defaults from RFC1521 */
1177  e->body->type = TYPE_TEXT;
1178  e->body->subtype = mutt_str_dup("plain");
1179  e->body->encoding = ENC_7BIT;
1180  e->body->length = -1;
1181 
1182  /* RFC2183 says this is arbitrary */
1184  }
1185  }
1186 
1187  while ((loc = ftello(fp)) != -1)
1188  {
1189  line = mutt_rfc822_read_line(fp, line, &linelen);
1190  if (*line == '\0')
1191  break;
1192  p = strpbrk(line, ": \t");
1193  if (!p || (*p != ':'))
1194  {
1195  char return_path[1024];
1196  time_t t = 0;
1197 
1198  /* some bogus MTAs will quote the original "From " line */
1199  if (mutt_str_startswith(line, ">From "))
1200  continue; /* just ignore */
1201  else if (is_from(line, return_path, sizeof(return_path), &t))
1202  {
1203  /* MH sometimes has the From_ line in the middle of the header! */
1204  if (e && (e->received == 0))
1205  e->received = t - mutt_date_local_tz(t);
1206  continue;
1207  }
1208 
1209  (void) mutt_file_seek(fp, loc, SEEK_SET);
1210  break; /* end of header */
1211  }
1212 
1213  *buf = '\0';
1214 
1215  if (mutt_replacelist_match(&SpamList, buf, sizeof(buf), line))
1216  {
1217  if (!mutt_regexlist_match(&NoSpamList, line))
1218  {
1219  /* if spam tag already exists, figure out how to amend it */
1220  if ((!mutt_buffer_is_empty(&env->spam)) && (*buf != '\0'))
1221  {
1222  /* If `$spam_separator` defined, append with separator */
1223  const char *const c_spam_separator = cs_subset_string(NeoMutt->sub, "spam_separator");
1224  if (c_spam_separator)
1225  {
1226  mutt_buffer_addstr(&env->spam, c_spam_separator);
1227  mutt_buffer_addstr(&env->spam, buf);
1228  }
1229  else /* overwrite */
1230  {
1231  mutt_buffer_reset(&env->spam);
1232  mutt_buffer_addstr(&env->spam, buf);
1233  }
1234  }
1235 
1236  /* spam tag is new, and match expr is non-empty; copy */
1237  else if (mutt_buffer_is_empty(&env->spam) && (*buf != '\0'))
1238  {
1239  mutt_buffer_addstr(&env->spam, buf);
1240  }
1241 
1242  /* match expr is empty; plug in null string if no existing tag */
1243  else if (mutt_buffer_is_empty(&env->spam))
1244  {
1245  mutt_buffer_addstr(&env->spam, "");
1246  }
1247 
1248  if (!mutt_buffer_is_empty(&env->spam))
1249  mutt_debug(LL_DEBUG5, "spam = %s\n", env->spam.data);
1250  }
1251  }
1252 
1253  *p = '\0';
1254  p = mutt_str_skip_email_wsp(p + 1);
1255  if (*p == '\0')
1256  continue; /* skip empty header fields */
1257 
1258  mutt_rfc822_parse_line(env, e, line, p, user_hdrs, weed, true);
1259  }
1260 
1261  FREE(&line);
1262 
1263  if (e)
1264  {
1265  e->body->hdr_offset = e->offset;
1266  e->body->offset = ftello(fp);
1267 
1269 
1270  if (env->subject)
1271  {
1272  regmatch_t pmatch[1];
1273 
1274  const struct Regex *c_reply_regex = cs_subset_regex(NeoMutt->sub, "reply_regex");
1275  if (mutt_regex_capture(c_reply_regex, env->subject, 1, pmatch))
1276  {
1277  env->real_subj = env->subject + pmatch[0].rm_eo;
1278  if (env->real_subj[0] == '\0')
1279  env->real_subj = NULL;
1280  }
1281  else
1282  env->real_subj = env->subject;
1283  }
1284 
1285  if (e->received < 0)
1286  {
1287  mutt_debug(LL_DEBUG1, "resetting invalid received time to 0\n");
1288  e->received = 0;
1289  }
1290 
1291  /* check for missing or invalid date */
1292  if (e->date_sent <= 0)
1293  {
1294  mutt_debug(LL_DEBUG1, "no date found, using received time from msg separator\n");
1295  e->date_sent = e->received;
1296  }
1297 
1298 #ifdef USE_AUTOCRYPT
1299  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
1300  if (c_autocrypt)
1301  {
1303  /* No sense in taking up memory after the header is processed */
1305  }
1306 #endif
1307  }
1308 
1309  return env;
1310 }
int mutt_autocrypt_process_autocrypt_header(struct Email *e, struct Envelope *env)
Parse an Autocrypt email header.
Definition: autocrypt.c:265
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:250
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:223
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:243
time_t mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:206
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
void mutt_autocrypthdr_free(struct AutocryptHeader **p)
Free an AutocryptHeader.
Definition: envelope.c:75
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:34
struct RegexList NoSpamList
List of regexes to whitelist non-spam emails.
Definition: globals.c:33
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
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:614
bool mutt_replacelist_match(struct ReplaceList *rl, char *buf, size_t buflen, const char *str)
Does a string match a pattern?
Definition: regex.c:495
int mutt_rfc822_parse_line(struct Envelope *env, struct Email *e, const char *name, const char *body, bool user_hdrs, bool weed, bool do_2047)
Parse an email header.
Definition: parse.c:634
char * mutt_rfc822_read_line(FILE *fp, char *line, size_t *linelen)
Read a header line from a file.
Definition: parse.c:1083
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:793
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:80
char * data
Pointer to data.
Definition: buffer.h:35
struct Buffer spam
Spam header.
Definition: envelope.h:84
char * real_subj
Offset of the real subject.
Definition: envelope.h:71
Cached regular expression.
Definition: regex3.h:89
+ 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 1318 of file parse.c.

1319 {
1320  if (!fp)
1321  return NULL;
1322 
1323  struct Body *p = mutt_body_new();
1324  struct Envelope *env = mutt_env_new();
1325  char *c = NULL;
1326  size_t linelen = 1024;
1327  char *line = mutt_mem_malloc(linelen);
1328  bool matched = false;
1329 
1330  p->hdr_offset = ftello(fp);
1331 
1332  p->encoding = ENC_7BIT; /* default from RFC1521 */
1333  p->type = digest ? TYPE_MESSAGE : TYPE_TEXT;
1334  p->disposition = DISP_INLINE;
1335 
1336  while (*(line = mutt_rfc822_read_line(fp, line, &linelen)) != 0)
1337  {
1338  /* Find the value of the current header */
1339  c = strchr(line, ':');
1340  if (c)
1341  {
1342  *c = '\0';
1343  c = mutt_str_skip_email_wsp(c + 1);
1344  if (*c == '\0')
1345  {
1346  mutt_debug(LL_DEBUG1, "skipping empty header field: %s\n", line);
1347  continue;
1348  }
1349  }
1350  else
1351  {
1352  mutt_debug(LL_DEBUG1, "bogus MIME header: %s\n", line);
1353  break;
1354  }
1355 
1356  size_t plen = mutt_istr_startswith(line, "content-");
1357  if (plen != 0)
1358  {
1359  if (mutt_istr_equal("type", line + plen))
1361  else if (mutt_istr_equal("language", line + plen))
1362  parse_content_language(c, p);
1363  else if (mutt_istr_equal("transfer-encoding", line + plen))
1364  p->encoding = mutt_check_encoding(c);
1365  else if (mutt_istr_equal("disposition", line + plen))
1367  else if (mutt_istr_equal("description", line + plen))
1368  {
1369  mutt_str_replace(&p->description, c);
1371  }
1372  else if (mutt_istr_equal("id", line + plen))
1373  {
1374  // strip <angle braces> from Content-ID: header
1375  char *id = c;
1376  int cid_len = mutt_str_len(c);
1377  if (cid_len > 2)
1378  {
1379  if (id[0] == '<')
1380  {
1381  id++;
1382  cid_len--;
1383  }
1384  if (id[cid_len - 1] == '>')
1385  id[cid_len - 1] = '\0';
1386  }
1387  mutt_param_set(&p->parameter, "content-id", id);
1388  }
1389  }
1390 #ifdef SUN_ATTACHMENT
1391  else if ((plen = mutt_istr_startswith(line, "x-sun-")))
1392  {
1393  if (mutt_istr_equal("data-type", line + plen))
1395  else if (mutt_istr_equal("encoding-info", line + plen))
1396  p->encoding = mutt_check_encoding(c);
1397  else if (mutt_istr_equal("content-lines", line + plen))
1398  mutt_param_set(&p->parameter, "content-lines", c);
1399  else if (mutt_istr_equal("data-description", line + plen))
1400  {
1401  mutt_str_replace(&p->description, c);
1403  }
1404  }
1405 #endif
1406  else
1407  {
1408  if (mutt_rfc822_parse_line(env, NULL, line, c, false, false, false))
1409  {
1410  matched = true;
1411  }
1412  }
1413  }
1414  p->offset = ftello(fp); /* Mark the start of the real data */
1415  if ((p->type == TYPE_TEXT) && !p->subtype)
1416  p->subtype = mutt_str_dup("plain");
1417  else if ((p->type == TYPE_MESSAGE) && !p->subtype)
1418  p->subtype = mutt_str_dup("rfc822");
1419 
1420  FREE(&line);
1421 
1422  if (matched)
1423  {
1424  p->mime_headers = env;
1426  }
1427  else
1428  {
1429  mutt_env_free(&env);
1430  }
1431 
1432  return p;
1433 }
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
+ 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 1442 of file parse.c.

1443 {
1444  if (type != TYPE_MESSAGE)
1445  return false;
1446 
1447  subtype = NONULL(subtype);
1448  return (mutt_istr_equal(subtype, "rfc822") ||
1449  mutt_istr_equal(subtype, "news") || mutt_istr_equal(subtype, "global"));
1450 }
#define NONULL(x)
Definition: string2.h:37
+ 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 env,
char **  body,
const char *  src 
)

Parse a mailto:// url.

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

Definition at line 1671 of file parse.c.

1672 {
1673  if (!env || !src)
1674  return false;
1675 
1676  struct Url *url = url_parse(src);
1677  if (!url)
1678  return false;
1679 
1680  if (url->host)
1681  {
1682  /* this is not a path-only URL */
1683  url_free(&url);
1684  return false;
1685  }
1686 
1687  mutt_addrlist_parse(&env->to, url->path);
1688 
1689  struct UrlQuery *np;
1690  STAILQ_FOREACH(np, &url->query_strings, entries)
1691  {
1692  const char *tag = np->name;
1693  char *value = np->value;
1694  /* Determine if this header field is on the allowed list. Since NeoMutt
1695  * interprets some header fields specially (such as
1696  * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
1697  * only safe fields are allowed.
1698  *
1699  * RFC2368, "4. Unsafe headers"
1700  * The user agent interpreting a mailto URL SHOULD choose not to create
1701  * a message if any of the headers are considered dangerous; it may also
1702  * choose to create a message with only a subset of the headers given in
1703  * the URL. */
1704  if (mutt_list_match(tag, &MailToAllow))
1705  {
1706  if (mutt_istr_equal(tag, "body"))
1707  {
1708  if (body)
1709  mutt_str_replace(body, value);
1710  }
1711  else
1712  {
1713  char *scratch = NULL;
1714  size_t taglen = mutt_str_len(tag);
1715 
1716  mutt_str_asprintf(&scratch, "%s: %s", tag, value);
1717  scratch[taglen] = 0; /* overwrite the colon as mutt_rfc822_parse_line expects */
1718  value = mutt_str_skip_email_wsp(&scratch[taglen + 1]);
1719  mutt_rfc822_parse_line(env, NULL, scratch, value, true, false, true);
1720  FREE(&scratch);
1721  }
1722  }
1723  }
1724 
1725  /* RFC2047 decode after the RFC822 parsing */
1727 
1728  url_free(&url);
1729  return true;
1730 }
struct ListHead MailToAllow
List of permitted fields in a mailto: url.
Definition: globals.c:37
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
Parsed Query String.
Definition: url.h:58
char * name
Query name.
Definition: url.h:59
char * value
Query value.
Definition: url.h:60
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
struct UrlQueryList query_strings
List of query strings.
Definition: url.h:76
char * host
Host.
Definition: url.h:73
char * src
Raw URL string.
Definition: url.h:77
char * path
Path.
Definition: url.h:75
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:234
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
+ 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 1737 of file parse.c.

1738 {
1739  int counter = 0;
1740 
1741  parse_part(fp, b, &counter);
1742 }
+ 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 1752 of file parse.c.

1753 {
1754  int counter = 0;
1755 
1756  return rfc822_parse_message(fp, parent, &counter);
1757 }
+ 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 1768 of file parse.c.

1769 {
1770  int counter = 0;
1771 
1772  return parse_multipart(fp, boundary, end_off, digest, &counter);
1773 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function: