NeoMutt  2020-11-20
Teaching an old dog new tricks
DOXYGEN
parse.c File Reference

Miscellaneous email parsing routines. More...

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

Go to the source code of this file.

Macros

#define CONTENT_TOO_BIG   (1 << 30)
 

Functions

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

1383 {
1384  if (!fp || !b)
1385  return;
1386 
1387  const char *bound = NULL;
1388  static unsigned short recurse_level = 0;
1389 
1390  if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1391  {
1392  mutt_debug(LL_DEBUG1, "recurse level too deep. giving up.\n");
1393  return;
1394  }
1395  recurse_level++;
1396 
1397  switch (b->type)
1398  {
1399  case TYPE_MULTIPART:
1400 #ifdef SUN_ATTACHMENT
1401  if (mutt_istr_equal(b->subtype, "x-sun-attachment"))
1402  bound = "--------";
1403  else
1404 #endif
1405  bound = mutt_param_get(&b->parameter, "boundary");
1406 
1407  fseeko(fp, b->offset, SEEK_SET);
1408  b->parts = parse_multipart(fp, bound, b->offset + b->length,
1409  mutt_istr_equal("digest", b->subtype), counter);
1410  break;
1411 
1412  case TYPE_MESSAGE:
1413  if (!b->subtype)
1414  break;
1415 
1416  fseeko(fp, b->offset, SEEK_SET);
1417  if (mutt_is_message_type(b->type, b->subtype))
1418  b->parts = rfc822_parse_message(fp, b, counter);
1419  else if (mutt_istr_equal(b->subtype, "external-body"))
1420  b->parts = mutt_read_mime_header(fp, 0);
1421  else
1422  goto bail;
1423  break;
1424 
1425  default:
1426  goto bail;
1427  }
1428 
1429  /* try to recover from parsing error */
1430  if (!b->parts)
1431  {
1432  b->type = TYPE_TEXT;
1433  mutt_str_replace(&b->subtype, "plain");
1434  }
1435 bail:
1436  recurse_level--;
1437 }
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1366
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:1449
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:1560
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:1267
+ 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 1560 of file parse.c.

1561 {
1562  if (!fp || !parent)
1563  return NULL;
1564 
1565  parent->email = email_new();
1566  parent->email->offset = ftello(fp);
1567  parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1568  struct Body *msg = parent->email->body;
1569 
1570  /* ignore the length given in the content-length since it could be wrong
1571  * and we already have the info to calculate the correct length */
1572  /* if (msg->length == -1) */
1573  msg->length = parent->length - (msg->offset - parent->offset);
1574 
1575  /* if body of this message is empty, we can end up with a negative length */
1576  if (msg->length < 0)
1577  msg->length = 0;
1578 
1579  parse_part(fp, msg, counter);
1580  return msg;
1581 }
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1382
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 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 Email * email_new(void)
Create a new Email.
Definition: email.c:72
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1111
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 1449 of file parse.c.

1451 {
1452  if (!fp)
1453  return NULL;
1454 
1455  if (!boundary)
1456  {
1457  mutt_error(_("multipart message has no boundary parameter"));
1458  return NULL;
1459  }
1460 
1461  char buf[1024];
1462  struct Body *head = NULL, *last = NULL, *new_body = NULL;
1463  bool final = false; /* did we see the ending boundary? */
1464 
1465  const size_t blen = mutt_str_len(boundary);
1466  while ((ftello(fp) < end_off) && fgets(buf, sizeof(buf), fp))
1467  {
1468  const size_t len = mutt_str_len(buf);
1469 
1470  const size_t crlf = ((len > 1) && (buf[len - 2] == '\r')) ? 1 : 0;
1471 
1472  if ((buf[0] == '-') && (buf[1] == '-') && mutt_str_startswith(buf + 2, boundary))
1473  {
1474  if (last)
1475  {
1476  last->length = ftello(fp) - last->offset - len - 1 - crlf;
1477  if (last->parts && (last->parts->length == 0))
1478  last->parts->length = ftello(fp) - last->parts->offset - len - 1 - crlf;
1479  /* if the body is empty, we can end up with a -1 length */
1480  if (last->length < 0)
1481  last->length = 0;
1482  }
1483 
1484  if (len > 0)
1485  {
1486  /* Remove any trailing whitespace, up to the length of the boundary */
1487  for (size_t i = len - 1; IS_SPACE(buf[i]) && (i >= (blen + 2)); i--)
1488  buf[i] = '\0';
1489  }
1490 
1491  /* Check for the end boundary */
1492  if (mutt_str_equal(buf + blen + 2, "--"))
1493  {
1494  final = true;
1495  break; /* done parsing */
1496  }
1497  else if (buf[2 + blen] == '\0')
1498  {
1499  new_body = mutt_read_mime_header(fp, digest);
1500 
1501 #ifdef SUN_ATTACHMENT
1502  if (mutt_param_get(&new_body->parameter, "content-lines"))
1503  {
1504  int lines = 0;
1505  if (mutt_str_atoi(
1506  mutt_param_get(&new_body->parameter, "content-lines"), &lines) < 0)
1507  lines = 0;
1508  for (; lines > 0; lines--)
1509  if ((ftello(fp) >= end_off) || !fgets(buf, sizeof(buf), fp))
1510  break;
1511  }
1512 #endif
1513  /* Consistency checking - catch bad attachment end boundaries */
1514  if (new_body->offset > end_off)
1515  {
1516  mutt_body_free(&new_body);
1517  break;
1518  }
1519  if (head)
1520  {
1521  last->next = new_body;
1522  last = new_body;
1523  }
1524  else
1525  {
1526  last = new_body;
1527  head = new_body;
1528  }
1529 
1530  /* It seems more intuitive to add the counter increment to
1531  * parse_part(), but we want to stop the case where a multipart
1532  * contains thousands of tiny parts before the memory and data
1533  * structures are allocated. */
1534  if (++(*counter) >= MUTT_MIME_MAX_PARTS)
1535  break;
1536  }
1537  }
1538  }
1539 
1540  /* in case of missing end boundary, set the length to something reasonable */
1541  if (last && (last->length == 0) && !final)
1542  last->length = end_off - last->offset;
1543 
1544  /* parse recursive MIME parts */
1545  for (last = head; last; last = last->next)
1546  parse_part(fp, last, counter);
1547 
1548  return head;
1549 }
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:1382
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:1267
+ 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:52
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition: hash.c:327
#define TAILQ_FIRST(head)
Definition: queue.h:716
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: globals.c:49
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: globals.c:50
struct HashTable * AutoSubscribeCache
Hash Table of auto-subscribed mailing lists.
Definition: globals.c:48
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:98
bool mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1591
int mutt_regexlist_add(struct RegexList *rl, const char *str, int flags, struct Buffer *err)
Compile a regex string and add it to a list.
Definition: regex.c:131
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:190
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: globals.c:51
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:714
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:99
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:251
The header of an Email.
Definition: envelope.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_parameters()

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

Parse a list of Parameters.

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

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

Definition at line 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  if (C_AssumedCharset)
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 }
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:235
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
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
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
char * C_AssumedCharset
Config: If a message is missing a character set, assume this character set.
Definition: charset.c:52
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 248 of file parse.c.

249 {
250  struct ParameterList pl;
251  TAILQ_INIT(&pl);
252 
253  if (mutt_istr_startswith(s, "inline"))
254  ct->disposition = DISP_INLINE;
255  else if (mutt_istr_startswith(s, "form-data"))
257  else
258  ct->disposition = DISP_ATTACH;
259 
260  /* Check to see if a default filename was given */
261  s = strchr(s, ';');
262  if (s)
263  {
264  s = mutt_str_skip_email_wsp(s + 1);
265  parse_parameters(&pl, s, false);
266  s = mutt_param_get(&pl, "filename");
267  if (s)
268  mutt_str_replace(&ct->filename, s);
269  s = mutt_param_get(&pl, "name");
270  if (s)
271  ct->form_name = mutt_str_dup(s);
272  mutt_param_free(&pl);
273  }
274 }
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 281 of file parse.c.

282 {
283  if (!head)
284  return;
285 
286  char *m = NULL;
287  for (size_t off = 0; (m = mutt_extract_message_id(s, &off)); s += off)
288  {
289  mutt_list_insert_head(head, m);
290  }
291 }
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:361
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 298 of file parse.c.

299 {
300  if (!s || !ct)
301  return;
302 
303  mutt_debug(LL_DEBUG2, "RFC8255 >> Content-Language set to %s\n", s);
304  ct->language = mutt_str_dup(s);
305 }
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
trueIf string matches

Checks Ignore and UnIgnore using mutt_list_match

Definition at line 314 of file parse.c.

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

◆ mutt_check_mime_type()

enum ContentType mutt_check_mime_type ( const char *  s)

Check a MIME type string.

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

Definition at line 324 of file parse.c.

325 {
326  if (mutt_istr_equal("text", s))
327  return TYPE_TEXT;
328  if (mutt_istr_equal("multipart", s))
329  return TYPE_MULTIPART;
330 #ifdef SUN_ATTACHMENT
331  if (mutt_istr_equal("x-sun-attachment", s))
332  return TYPE_MULTIPART;
333 #endif
334  if (mutt_istr_equal("application", s))
335  return TYPE_APPLICATION;
336  if (mutt_istr_equal("message", s))
337  return TYPE_MESSAGE;
338  if (mutt_istr_equal("image", s))
339  return TYPE_IMAGE;
340  if (mutt_istr_equal("audio", s))
341  return TYPE_AUDIO;
342  if (mutt_istr_equal("video", s))
343  return TYPE_VIDEO;
344  if (mutt_istr_equal("model", s))
345  return TYPE_MODEL;
346  if (mutt_istr_equal("*", s))
347  return TYPE_ANY;
348  if (mutt_istr_equal(".*", s))
349  return TYPE_ANY;
350 
351  return TYPE_OTHER;
352 }
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 361 of file parse.c.

362 {
363  if (!s || (*s == '\0'))
364  return NULL;
365 
366  char *decoded = mutt_str_dup(s);
367  rfc2047_decode(&decoded);
368 
369  char *res = NULL;
370 
371  for (const char *p = decoded, *beg = NULL; *p; p++)
372  {
373  if (*p == '<')
374  {
375  beg = p;
376  continue;
377  }
378 
379  if (beg && (*p == '>'))
380  {
381  if (len)
382  *len = p - decoded + 1;
383  res = mutt_strn_dup(beg, (p + 1) - beg);
384  break;
385  }
386  }
387 
388  FREE(&decoded);
389  return res;
390 }
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:639
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 397 of file parse.c.

398 {
399  if (mutt_istr_startswith(c, "7bit"))
400  return ENC_7BIT;
401  if (mutt_istr_startswith(c, "8bit"))
402  return ENC_8BIT;
403  if (mutt_istr_startswith(c, "binary"))
404  return ENC_BINARY;
405  if (mutt_istr_startswith(c, "quoted-printable"))
406  return ENC_QUOTED_PRINTABLE;
407  if (mutt_istr_startswith(c, "base64"))
408  return ENC_BASE64;
409  if (mutt_istr_startswith(c, "x-uuencode"))
410  return ENC_UUENCODED;
411 #ifdef SUN_ATTACHMENT
412  if (mutt_istr_startswith(c, "uuencode"))
413  return ENC_UUENCODED;
414 #endif
415  return ENC_OTHER;
416 }
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 425 of file parse.c.

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

532 {
533  struct AutocryptHeader *autocrypt = mutt_autocrypthdr_new();
534  autocrypt->next = head;
535 
536  struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
537  parse_parameters(&pl, s, true);
538  if (TAILQ_EMPTY(&pl))
539  {
540  autocrypt->invalid = true;
541  goto cleanup;
542  }
543 
544  struct Parameter *p = NULL;
545  TAILQ_FOREACH(p, &pl, entries)
546  {
547  if (mutt_istr_equal(p->attribute, "addr"))
548  {
549  if (autocrypt->addr)
550  {
551  autocrypt->invalid = true;
552  goto cleanup;
553  }
554  autocrypt->addr = p->value;
555  p->value = NULL;
556  }
557  else if (mutt_istr_equal(p->attribute, "prefer-encrypt"))
558  {
559  if (mutt_istr_equal(p->value, "mutual"))
560  autocrypt->prefer_encrypt = true;
561  }
562  else if (mutt_istr_equal(p->attribute, "keydata"))
563  {
564  if (autocrypt->keydata)
565  {
566  autocrypt->invalid = true;
567  goto cleanup;
568  }
569  autocrypt->keydata = p->value;
570  p->value = NULL;
571  }
572  else if (p->attribute && (p->attribute[0] != '_'))
573  {
574  autocrypt->invalid = true;
575  goto cleanup;
576  }
577  }
578 
579  /* Checking the addr against From, and for multiple valid headers
580  * occurs later, after all the headers are parsed. */
581  if (!autocrypt->addr || !autocrypt->keydata)
582  autocrypt->invalid = true;
583 
584 cleanup:
585  mutt_param_free(&pl);
586  return autocrypt;
587 }
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
1If the field is recognised
0If not

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

Definition at line 605 of file parse.c.

607 {
608  if (!env || !line)
609  return 0;
610 
611  bool matched = false;
612 
613  switch (tolower(line[0]))
614  {
615  case 'a':
616  if (mutt_istr_equal(line + 1, "pparently-to"))
617  {
618  mutt_addrlist_parse(&env->to, p);
619  matched = true;
620  }
621  else if (mutt_istr_equal(line + 1, "pparently-from"))
622  {
623  mutt_addrlist_parse(&env->from, p);
624  matched = true;
625  }
626  break;
627 
628  case 'b':
629  if (mutt_istr_equal(line + 1, "cc"))
630  {
631  mutt_addrlist_parse(&env->bcc, p);
632  matched = true;
633  }
634  break;
635 
636  case 'c':
637  if (mutt_istr_equal(line + 1, "c"))
638  {
639  mutt_addrlist_parse(&env->cc, p);
640  matched = true;
641  }
642  else
643  {
644  size_t plen = mutt_istr_startswith(line + 1, "ontent-");
645  if (plen != 0)
646  {
647  if (mutt_istr_equal(line + 1 + plen, "type"))
648  {
649  if (e)
651  matched = true;
652  }
653  else if (mutt_istr_equal(line + 1 + plen, "language"))
654  {
655  if (e)
657  matched = true;
658  }
659  else if (mutt_istr_equal(line + 1 + plen, "transfer-encoding"))
660  {
661  if (e)
663  matched = true;
664  }
665  else if (mutt_istr_equal(line + 1 + plen, "length"))
666  {
667  if (e)
668  {
669  int rc = mutt_str_atol(p, (long *) &e->body->length);
670  if ((rc < 0) || (e->body->length < 0))
671  e->body->length = -1;
672  if (e->body->length > CONTENT_TOO_BIG)
674  }
675  matched = true;
676  }
677  else if (mutt_istr_equal(line + 1 + plen, "description"))
678  {
679  if (e)
680  {
683  }
684  matched = true;
685  }
686  else if (mutt_istr_equal(line + 1 + plen, "disposition"))
687  {
688  if (e)
690  matched = true;
691  }
692  }
693  }
694  break;
695 
696  case 'd':
697  if (!mutt_istr_equal("ate", line + 1))
698  break;
699 
700  mutt_str_replace(&env->date, p);
701  if (e)
702  {
703  struct Tz tz;
704  e->date_sent = mutt_date_parse_date(p, &tz);
705  if (e->date_sent > 0)
706  {
707  e->zhours = tz.zhours;
708  e->zminutes = tz.zminutes;
709  e->zoccident = tz.zoccident;
710  }
711  }
712  matched = true;
713  break;
714 
715  case 'e':
716  if (mutt_istr_equal("xpires", line + 1) && e &&
717  (mutt_date_parse_date(p, NULL) < mutt_date_epoch()))
718  {
719  e->expired = true;
720  }
721  break;
722 
723  case 'f':
724  if (mutt_istr_equal("rom", line + 1))
725  {
726  mutt_addrlist_parse(&env->from, p);
727  matched = true;
728  }
729 #ifdef USE_NNTP
730  else if (mutt_istr_equal(line + 1, "ollowup-to"))
731  {
732  if (!env->followup_to)
733  {
736  }
737  matched = true;
738  }
739 #endif
740  break;
741 
742  case 'i':
743  if (!mutt_istr_equal(line + 1, "n-reply-to"))
744  break;
745 
747  parse_references(&env->in_reply_to, p);
748  matched = true;
749  break;
750 
751  case 'l':
752  if (mutt_istr_equal(line + 1, "ines"))
753  {
754  if (e)
755  {
756  /* HACK - neomutt has, for a very short time, produced negative
757  * Lines header values. Ignore them. */
758  if ((mutt_str_atoi(p, &e->lines) < 0) || (e->lines < 0))
759  e->lines = 0;
760  }
761 
762  matched = true;
763  }
764  else if (mutt_istr_equal(line + 1, "ist-Post"))
765  {
766  /* RFC2369. FIXME: We should ignore whitespace, but don't. */
767  if (!mutt_strn_equal(p, "NO", 2))
768  {
769  char *beg = NULL, *end = NULL;
770  for (beg = strchr(p, '<'); beg; beg = strchr(end, ','))
771  {
772  beg++;
773  end = strchr(beg, '>');
774  if (!end)
775  break;
776 
777  char *mlist = mutt_strn_dup(beg, end - beg);
778  /* Take the first mailto URL */
779  if (url_check_scheme(mlist) == U_MAILTO)
780  {
781  FREE(&env->list_post);
782  env->list_post = mlist;
783  if (C_AutoSubscribe)
785 
786  break;
787  }
788  FREE(&mlist);
789  }
790  }
791  matched = true;
792  }
793  break;
794 
795  case 'm':
796  if (mutt_istr_equal(line + 1, "ime-version"))
797  {
798  if (e)
799  e->mime = true;
800  matched = true;
801  }
802  else if (mutt_istr_equal(line + 1, "essage-id"))
803  {
804  /* We add a new "Message-ID:" when building a message */
805  FREE(&env->message_id);
806  env->message_id = mutt_extract_message_id(p, NULL);
807  matched = true;
808  }
809  else
810  {
811  size_t plen = mutt_istr_startswith(line + 1, "ail-");
812  if (plen != 0)
813  {
814  if (mutt_istr_equal(line + 1 + plen, "reply-to"))
815  {
816  /* override the Reply-To: field */
818  mutt_addrlist_parse(&env->reply_to, p);
819  matched = true;
820  }
821  else if (mutt_istr_equal(line + 1 + plen, "followup-to"))
822  {
824  matched = true;
825  }
826  }
827  }
828  break;
829 
830 #ifdef USE_NNTP
831  case 'n':
832  if (mutt_istr_equal(line + 1, "ewsgroups"))
833  {
834  FREE(&env->newsgroups);
837  matched = true;
838  }
839  break;
840 #endif
841 
842  case 'o':
843  /* field 'Organization:' saves only for pager! */
844  if (mutt_istr_equal(line + 1, "rganization"))
845  {
846  if (!env->organization && !mutt_istr_equal(p, "unknown"))
847  env->organization = mutt_str_dup(p);
848  }
849  break;
850 
851  case 'r':
852  if (mutt_istr_equal(line + 1, "eferences"))
853  {
854  mutt_list_free(&env->references);
855  parse_references(&env->references, p);
856  matched = true;
857  }
858  else if (mutt_istr_equal(line + 1, "eply-to"))
859  {
860  mutt_addrlist_parse(&env->reply_to, p);
861  matched = true;
862  }
863  else if (mutt_istr_equal(line + 1, "eturn-path"))
864  {
866  matched = true;
867  }
868  else if (mutt_istr_equal(line + 1, "eceived"))
869  {
870  if (e && !e->received)
871  {
872  char *d = strrchr(p, ';');
873  if (d)
874  {
875  d = mutt_str_skip_email_wsp(d + 1);
876  e->received = mutt_date_parse_date(d, NULL);
877  }
878  }
879  }
880  break;
881 
882  case 's':
883  if (mutt_istr_equal(line + 1, "ubject"))
884  {
885  if (!env->subject)
886  env->subject = mutt_str_dup(p);
887  matched = true;
888  }
889  else if (mutt_istr_equal(line + 1, "ender"))
890  {
891  mutt_addrlist_parse(&env->sender, p);
892  matched = true;
893  }
894  else if (mutt_istr_equal(line + 1, "tatus"))
895  {
896  if (e)
897  {
898  while (*p)
899  {
900  switch (*p)
901  {
902  case 'O':
903  e->old = C_MarkOld;
904  break;
905  case 'R':
906  e->read = true;
907  break;
908  case 'r':
909  e->replied = true;
910  break;
911  }
912  p++;
913  }
914  }
915  matched = true;
916  }
917  else if (e && (mutt_istr_equal("upersedes", line + 1) ||
918  mutt_istr_equal("upercedes", line + 1)))
919  {
920  FREE(&env->supersedes);
921  env->supersedes = mutt_str_dup(p);
922  }
923  break;
924 
925  case 't':
926  if (mutt_istr_equal(line + 1, "o"))
927  {
928  mutt_addrlist_parse(&env->to, p);
929  matched = true;
930  }
931 #ifdef USE_AUTOCRYPT
932  else if (mutt_istr_equal(line + 1, "utocrypt"))
933  {
934  if (C_Autocrypt)
935  {
936  env->autocrypt = parse_autocrypt(env->autocrypt, p);
937  matched = true;
938  }
939  }
940  else if (mutt_istr_equal(line + 1, "utocrypt-gossip"))
941  {
942  if (C_Autocrypt)
943  {
945  matched = true;
946  }
947  }
948 #endif
949  break;
950 
951  case 'x':
952  if (mutt_istr_equal(line + 1, "-status"))
953  {
954  if (e)
955  {
956  while (*p)
957  {
958  switch (*p)
959  {
960  case 'A':
961  e->replied = true;
962  break;
963  case 'D':
964  e->deleted = true;
965  break;
966  case 'F':
967  e->flagged = true;
968  break;
969  default:
970  break;
971  }
972  p++;
973  }
974  }
975  matched = true;
976  }
977  else if (mutt_istr_equal(line + 1, "-label"))
978  {
979  FREE(&env->x_label);
980  env->x_label = mutt_str_dup(p);
981  matched = true;
982  }
983 #ifdef USE_NNTP
984  else if (mutt_istr_equal(line + 1, "-comment-to"))
985  {
986  if (!env->x_comment_to)
987  env->x_comment_to = mutt_str_dup(p);
988  matched = true;
989  }
990  else if (mutt_istr_equal(line + 1, "ref"))
991  {
992  if (!env->xref)
993  env->xref = mutt_str_dup(p);
994  matched = true;
995  }
996 #endif
997  else if (mutt_istr_equal(line + 1, "-original-to"))
998  {
1000  matched = true;
1001  }
1002  break;
1003 
1004  default:
1005  break;
1006  }
1007 
1008  /* Keep track of the user-defined headers */
1009  if (!matched && user_hdrs)
1010  {
1011  /* restore the original line */
1012  line[strlen(line)] = ':';
1013 
1014  if (!(weed && C_Weed && mutt_matches_ignore(line)))
1015  {
1016  struct ListNode *np = mutt_list_insert_tail(&env->userhdrs, mutt_str_dup(line));
1017  if (do_2047)
1018  rfc2047_decode(&np->data);
1019  }
1020  }
1021 
1022  return matched;
1023 }
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:314
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
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:252
bool C_MarkOld
Config: Mark new emails as old when leaving the mailbox.
Definition: globals.c:36
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
struct 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:1468
char * xref
List of cross-references.
Definition: envelope.h:76
bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: config.c:37
char * date
Sent date.
Definition: envelope.h:71
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
static void parse_content_disposition(const char *s, struct Body *ct)
Parse a content disposition.
Definition: parse.c:248
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
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
bool C_AutoSubscribe
Config: Automatically check if the user is subscribed to a mailing list.
Definition: globals.c:35
bool read
Email is read.
Definition: email.h:51
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
bool old
Email is seen, but unread.
Definition: email.h:50
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:639
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c: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:531
static void parse_content_language(const char *s, struct Body *ct)
Read the content&#39;s language.
Definition: parse.c:298
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:397
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:361
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:281
char * list_post
This stores a mailto URL, or nothing.
Definition: envelope.h:65
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
#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:425
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
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
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: globals.c:40
Url is mailto://.
Definition: url.h:44
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
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 1036 of file parse.c.

1037 {
1038  if (!fp || !line || !linelen)
1039  return NULL;
1040 
1041  char *buf = line;
1042  int ch;
1043  size_t offset = 0;
1044 
1045  while (true)
1046  {
1047  if (!fgets(buf, *linelen - offset, fp) || /* end of file or */
1048  (IS_SPACE(*line) && !offset)) /* end of headers */
1049  {
1050  *line = '\0';
1051  return line;
1052  }
1053 
1054  const size_t len = mutt_str_len(buf);
1055  if (len == 0)
1056  return line;
1057 
1058  buf += len - 1;
1059  if (*buf == '\n')
1060  {
1061  /* we did get a full line. remove trailing space */
1062  while (IS_SPACE(*buf))
1063  {
1064  *buf-- = '\0'; /* we can't come beyond line's beginning because
1065  * it begins with a non-space */
1066  }
1067 
1068  /* check to see if the next line is a continuation line */
1069  ch = fgetc(fp);
1070  if ((ch != ' ') && (ch != '\t'))
1071  {
1072  ungetc(ch, fp);
1073  return line; /* next line is a separate header field or EOH */
1074  }
1075 
1076  /* eat tabs and spaces from the beginning of the continuation line */
1077  while (((ch = fgetc(fp)) == ' ') || (ch == '\t'))
1078  ; // do nothing
1079 
1080  ungetc(ch, fp);
1081  *++buf = ' '; /* string is still terminated because we removed
1082  at least one whitespace char above */
1083  }
1084 
1085  buf++;
1086  offset = buf - line;
1087  if (*linelen < (offset + 256))
1088  {
1089  /* grow the buffer */
1090  *linelen += 256;
1091  mutt_mem_realloc(&line, *linelen);
1092  buf = line + offset;
1093  }
1094  }
1095  /* not reached */
1096 }
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 1111 of file parse.c.

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

1268 {
1269  if (!fp)
1270  return NULL;
1271 
1272  struct Body *p = mutt_body_new();
1273  struct Envelope *env = mutt_env_new();
1274  char *c = NULL;
1275  size_t linelen = 1024;
1276  char *line = mutt_mem_malloc(linelen);
1277 
1278  p->hdr_offset = ftello(fp);
1279 
1280  p->encoding = ENC_7BIT; /* default from RFC1521 */
1281  p->type = digest ? TYPE_MESSAGE : TYPE_TEXT;
1282  p->disposition = DISP_INLINE;
1283 
1284  while (*(line = mutt_rfc822_read_line(fp, line, &linelen)) != 0)
1285  {
1286  /* Find the value of the current header */
1287  c = strchr(line, ':');
1288  if (c)
1289  {
1290  *c = '\0';
1291  c = mutt_str_skip_email_wsp(c + 1);
1292  if (*c == '\0')
1293  {
1294  mutt_debug(LL_DEBUG1, "skipping empty header field: %s\n", line);
1295  continue;
1296  }
1297  }
1298  else
1299  {
1300  mutt_debug(LL_DEBUG1, "bogus MIME header: %s\n", line);
1301  break;
1302  }
1303 
1304  size_t plen = mutt_istr_startswith(line, "content-");
1305  if (plen != 0)
1306  {
1307  if (mutt_istr_equal("type", line + plen))
1309  else if (mutt_istr_equal("language", line + plen))
1310  parse_content_language(c, p);
1311  else if (mutt_istr_equal("transfer-encoding", line + plen))
1312  p->encoding = mutt_check_encoding(c);
1313  else if (mutt_istr_equal("disposition", line + plen))
1315  else if (mutt_istr_equal("description", line + plen))
1316  {
1317  mutt_str_replace(&p->description, c);
1319  }
1320  }
1321 #ifdef SUN_ATTACHMENT
1322  else if ((plen = mutt_istr_startswith(line, "x-sun-")))
1323  {
1324  if (mutt_istr_equal("data-type", line + plen))
1326  else if (mutt_istr_equal("encoding-info", line + plen))
1327  p->encoding = mutt_check_encoding(c);
1328  else if (mutt_istr_equal("content-lines", line + plen))
1329  mutt_param_set(&p->parameter, "content-lines", c);
1330  else if (mutt_istr_equal("data-description", line + plen))
1331  {
1332  mutt_str_replace(&p->description, c);
1334  }
1335  }
1336 #endif
1337  else
1338  {
1339  if (mutt_rfc822_parse_line(env, NULL, line, c, false, false, false))
1340  p->mime_headers = env;
1341  }
1342  }
1343  p->offset = ftello(fp); /* Mark the start of the real data */
1344  if ((p->type == TYPE_TEXT) && !p->subtype)
1345  p->subtype = mutt_str_dup("plain");
1346  else if ((p->type == TYPE_MESSAGE) && !p->subtype)
1347  p->subtype = mutt_str_dup("rfc822");
1348 
1349  FREE(&line);
1350 
1351  if (p->mime_headers)
1353  else
1354  mutt_env_free(&env);
1355 
1356  return p;
1357 }
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:605
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:248
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:779
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:639
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
static void parse_content_language(const char *s, struct Body *ct)
Read the content&#39;s language.
Definition: parse.c:298
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:397
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:425
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:1036
+ 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 1366 of file parse.c.

1367 {
1368  if (type != TYPE_MESSAGE)
1369  return false;
1370 
1371  subtype = NONULL(subtype);
1372  return (mutt_istr_equal(subtype, "rfc822") ||
1373  mutt_istr_equal(subtype, "news") || mutt_istr_equal(subtype, "global"));
1374 }
#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 1591 of file parse.c.

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

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

1658 {
1659  int counter = 0;
1660 
1661  parse_part(fp, b, &counter);
1662 }
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1382
+ 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 1672 of file parse.c.

1673 {
1674  int counter = 0;
1675 
1676  return rfc822_parse_message(fp, parent, &counter);
1677 }
static struct Body * rfc822_parse_message(FILE *fp, struct Body *parent, int *counter)
parse a Message/RFC822 body
Definition: parse.c:1560
+ 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 1688 of file parse.c.

1689 {
1690  int counter = 0;
1691 
1692  return parse_multipart(fp, boundary, end_off, digest, &counter);
1693 }
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:1449
+ Here is the call graph for this function:
+ Here is the caller graph for this function: