NeoMutt  2025-09-05-2-g4bf191
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
parse.c File Reference

Miscellaneous email parsing routines. More...

#include "config.h"
#include <errno.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.
 
static struct Bodyrfc822_parse_message (FILE *fp, struct Body *parent, int *counter)
 Parse a Message/RFC822 body.
 
static struct Bodyparse_multipart (FILE *fp, const char *boundary, LOFF_T end_off, bool digest, int *counter)
 Parse a multipart structure.
 
void mutt_filter_commandline_header_tag (char *header)
 Sanitise characters in a header tag.
 
void mutt_filter_commandline_header_value (char *header)
 Sanitise characters in a header value.
 
void mutt_auto_subscribe (const char *mailto)
 Check if user is subscribed to mailing list.
 
static void parse_parameters (struct ParameterList *pl, const char *s, bool allow_value_spaces)
 Parse a list of Parameters.
 
static void parse_content_disposition (const char *s, struct Body *b)
 Parse a content disposition.
 
static void parse_references (struct ListHead *head, const char *s)
 Parse references from an email header.
 
static void parse_content_language (const char *s, struct Body *b)
 Read the content's language.
 
bool mutt_matches_ignore (const char *s)
 Does the string match the ignore list.
 
enum ContentType mutt_check_mime_type (const char *s)
 Check a MIME type string.
 
char * mutt_extract_message_id (const char *s, size_t *len)
 Find a message-id.
 
int mutt_check_encoding (const char *c)
 Check the encoding type.
 
void mutt_parse_content_type (const char *s, struct Body *b)
 Parse a content type.
 
static struct AutocryptHeaderparse_autocrypt (struct AutocryptHeader *head, const char *s)
 Parse an Autocrypt header line.
 
static char * rfc2369_first_mailto (const char *body)
 Extract the first mailto: URL from a RFC2369 list.
 
int mutt_rfc822_parse_line (struct Envelope *env, struct Email *e, const char *name, size_t name_len, const char *body, bool user_hdrs, bool weed, bool do_2047)
 Parse an email header.
 
size_t mutt_rfc822_read_line (FILE *fp, struct Buffer *buf)
 Read a header line from a file.
 
struct Envelopemutt_rfc822_read_header (FILE *fp, struct Email *e, bool user_hdrs, bool weed)
 Parses an RFC822 header.
 
struct Bodymutt_read_mime_header (FILE *fp, bool digest)
 Parse a MIME header.
 
bool mutt_is_message_type (int type, const char *subtype)
 Determine if a mime type matches a message or not.
 
static bool mailto_header_allowed (const char *s, struct ListHead *h)
 Is the string in the list.
 
bool mutt_parse_mailto (struct Envelope *env, char **body, const char *src)
 Parse a mailto:// url.
 
void mutt_parse_part (FILE *fp, struct Body *b)
 Parse a MIME part.
 
struct Bodymutt_rfc822_parse_message (FILE *fp, struct Body *b)
 Parse a Message/RFC822 body.
 
struct Bodymutt_parse_multipart (FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
 Parse a multipart structure.
 

Detailed Description

Miscellaneous email parsing routines.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Federico Kircheis
  • Ian Zimmerman
  • Christian Ludwig
  • David Purton
  • Steinar H Gunderson

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

1514{
1515 if (!fp || !b)
1516 return;
1517
1518 const char *bound = NULL;
1519 static unsigned short recurse_level = 0;
1520
1521 if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1522 {
1523 mutt_debug(LL_DEBUG1, "recurse level too deep. giving up\n");
1524 return;
1525 }
1526 recurse_level++;
1527
1528 switch (b->type)
1529 {
1530 case TYPE_MULTIPART:
1531 if (mutt_istr_equal(b->subtype, "x-sun-attachment"))
1532 bound = "--------";
1533 else
1534 bound = mutt_param_get(&b->parameter, "boundary");
1535
1536 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
1537 {
1538 goto bail;
1539 }
1540 b->parts = parse_multipart(fp, bound, b->offset + b->length,
1541 mutt_istr_equal("digest", b->subtype), counter);
1542 break;
1543
1544 case TYPE_MESSAGE:
1545 if (!b->subtype)
1546 break;
1547
1548 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
1549 {
1550 goto bail;
1551 }
1552 if (mutt_is_message_type(b->type, b->subtype))
1553 b->parts = rfc822_parse_message(fp, b, counter);
1554 else if (mutt_istr_equal(b->subtype, "external-body"))
1555 b->parts = mutt_read_mime_header(fp, 0);
1556 else
1557 goto bail;
1558 break;
1559
1560 default:
1561 goto bail;
1562 }
1563
1564 /* try to recover from parsing error */
1565 if (!b->parts)
1566 {
1567 b->type = TYPE_TEXT;
1568 mutt_str_replace(&b->subtype, "plain");
1569 }
1570bail:
1571 recurse_level--;
1572}
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1361
static struct Body * rfc822_parse_message(FILE *fp, struct Body *parent, int *counter)
Parse a Message/RFC822 body.
Definition: parse.c:1694
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:1584
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1497
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:655
#define mutt_debug(LEVEL,...)
Definition: logging2.h:90
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:44
#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:671
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:281
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:85
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:73
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:63
char * subtype
content-type subtype
Definition: body.h:61
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 1694 of file parse.c.

1695{
1696 if (!fp || !parent)
1697 return NULL;
1698
1699 parent->email = email_new();
1700 parent->email->offset = ftello(fp);
1701 parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1702 struct Body *msg = parent->email->body;
1703
1704 /* ignore the length given in the content-length since it could be wrong
1705 * and we already have the info to calculate the correct length */
1706 /* if (msg->length == -1) */
1707 msg->length = parent->length - (msg->offset - parent->offset);
1708
1709 /* if body of this message is empty, we can end up with a negative length */
1710 if (msg->length < 0)
1711 msg->length = 0;
1712
1713 parse_part(fp, msg, counter);
1714 return msg;
1715}
struct Email * email_new(void)
Create a new Email.
Definition: email.c:77
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1204
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1513
The body of an email.
Definition: body.h:36
struct Email * email
header information for message/rfc822
Definition: body.h:74
struct Envelope * env
Envelope information.
Definition: email.h:68
struct Body * body
List of MIME parts.
Definition: email.h:69
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:71
+ 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 1584 of file parse.c.

1586{
1587 if (!fp)
1588 return NULL;
1589
1590 if (!boundary)
1591 {
1592 mutt_error(_("multipart message has no boundary parameter"));
1593 return NULL;
1594 }
1595
1596 char buf[1024] = { 0 };
1597 struct Body *head = NULL, *last = NULL, *new_body = NULL;
1598 bool final = false; /* did we see the ending boundary? */
1599
1600 const size_t blen = mutt_str_len(boundary);
1601 while ((ftello(fp) < end_off) && fgets(buf, sizeof(buf), fp))
1602 {
1603 const size_t len = mutt_str_len(buf);
1604
1605 const size_t crlf = ((len > 1) && (buf[len - 2] == '\r')) ? 1 : 0;
1606
1607 if ((buf[0] == '-') && (buf[1] == '-') && mutt_str_startswith(buf + 2, boundary))
1608 {
1609 if (last)
1610 {
1611 last->length = ftello(fp) - last->offset - len - 1 - crlf;
1612 if (last->parts && (last->parts->length == 0))
1613 last->parts->length = ftello(fp) - last->parts->offset - len - 1 - crlf;
1614 /* if the body is empty, we can end up with a -1 length */
1615 if (last->length < 0)
1616 last->length = 0;
1617 }
1618
1619 if (len > 0)
1620 {
1621 /* Remove any trailing whitespace, up to the length of the boundary */
1622 for (size_t i = len - 1; mutt_isspace(buf[i]) && (i >= (blen + 2)); i--)
1623 buf[i] = '\0';
1624 }
1625
1626 /* Check for the end boundary */
1627 if (mutt_str_equal(buf + blen + 2, "--"))
1628 {
1629 final = true;
1630 break; /* done parsing */
1631 }
1632 else if (buf[2 + blen] == '\0')
1633 {
1634 new_body = mutt_read_mime_header(fp, digest);
1635 if (!new_body)
1636 break;
1637
1638 if (mutt_param_get(&new_body->parameter, "content-lines"))
1639 {
1640 int lines = 0;
1641 mutt_str_atoi(mutt_param_get(&new_body->parameter, "content-lines"), &lines);
1642 for (; lines > 0; lines--)
1643 if ((ftello(fp) >= end_off) || !fgets(buf, sizeof(buf), fp))
1644 break;
1645 }
1646
1647 /* Consistency checking - catch bad attachment end boundaries */
1648 if (new_body->offset > end_off)
1649 {
1650 mutt_body_free(&new_body);
1651 break;
1652 }
1653 if (head)
1654 {
1655 last->next = new_body;
1656 last = new_body;
1657 }
1658 else
1659 {
1660 last = new_body;
1661 head = new_body;
1662 }
1663
1664 /* It seems more intuitive to add the counter increment to
1665 * parse_part(), but we want to stop the case where a multipart
1666 * contains thousands of tiny parts before the memory and data
1667 * structures are allocated. */
1668 if (++(*counter) >= MUTT_MIME_MAX_PARTS)
1669 break;
1670 }
1671 }
1672 }
1673
1674 /* in case of missing end boundary, set the length to something reasonable */
1675 if (last && (last->length == 0) && !final)
1676 last->length = end_off - last->offset;
1677
1678 /* parse recursive MIME parts */
1679 for (last = head; last; last = last->next)
1680 parse_part(fp, last, counter);
1681
1682 return head;
1683}
const char * mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: atoi.c:192
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition: ctype.c:95
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
#define mutt_error(...)
Definition: logging2.h:93
#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:659
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:231
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:497
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_filter_commandline_header_tag()

void mutt_filter_commandline_header_tag ( char *  header)

Sanitise characters in a header tag.

Parameters
headerString to sanitise

Definition at line 72 of file parse.c.

73{
74 if (!header)
75 return;
76
77 for (; (*header != '\0'); header++)
78 {
79 if ((*header < 33) || (*header > 126) || (*header == ':'))
80 *header = '?';
81 }
82}
+ Here is the caller graph for this function:

◆ mutt_filter_commandline_header_value()

void mutt_filter_commandline_header_value ( char *  header)

Sanitise characters in a header value.

Parameters
headerString to sanitise

It might be preferable to use mutt_filter_unprintable() instead. This filter is being lax, but preventing a header injection via an embedded newline.

Definition at line 92 of file parse.c.

93{
94 if (!header)
95 return;
96
97 for (; (*header != '\0'); header++)
98 {
99 if ((*header == '\n') || (*header == '\r'))
100 *header = ' ';
101 }
102}
+ 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 108 of file parse.c.

109{
110 if (!mailto)
111 return;
112
115
117 return;
118
120
121 struct Envelope *lpenv = mutt_env_new(); /* parsed envelope from the List-Post mailto: URL */
122
123 if (mutt_parse_mailto(lpenv, NULL, mailto) && !TAILQ_EMPTY(&lpenv->to))
124 {
125 const char *mailbox = buf_string(TAILQ_FIRST(&lpenv->to)->mailbox);
126 if (mailbox && !mutt_regexlist_match(&SubscribedLists, mailbox) &&
127 !mutt_regexlist_match(&UnMailLists, mailbox) &&
129 {
130 /* mutt_regexlist_add() detects duplicates, so it is safe to
131 * try to add here without any checks. */
132 mutt_regexlist_add(&MailLists, mailbox, REG_ICASE, NULL);
133 mutt_regexlist_add(&SubscribedLists, mailbox, REG_ICASE, NULL);
134 }
135 }
136
137 mutt_env_free(&lpenv);
138}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
struct RegexList SubscribedLists
List of header patterns to unignore (see)
Definition: globals.c:48
struct HashTable * AutoSubscribeCache
< Hash Table: "mailto:" -> AutoSubscribeCache
Definition: globals.c:36
struct RegexList UnSubscribedLists
Definition: globals.c:54
struct RegexList UnMailLists
List of regexes to exclude false matches in SubscribedLists.
Definition: globals.c:52
struct RegexList MailLists
List of permitted fields in a mailto: url.
Definition: globals.c:40
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1753
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:126
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:46
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:113
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:112
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:140
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:200
#define TAILQ_FIRST(head)
Definition: queue.h:780
#define TAILQ_EMPTY(head)
Definition: queue.h:778
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 151 of file parse.c.

152{
153 struct Parameter *pnew = NULL;
154 const char *p = NULL;
155 size_t i;
156
157 struct Buffer *buf = buf_pool_get();
158 /* allow_value_spaces, especially with autocrypt keydata, can result
159 * in quite large parameter values. avoid frequent reallocs by
160 * pre-sizing */
161 if (allow_value_spaces)
162 buf_alloc(buf, mutt_str_len(s));
163
164 mutt_debug(LL_DEBUG2, "'%s'\n", s);
165
166 const bool assumed = !slist_is_empty(cc_assumed_charset());
167 while (*s)
168 {
169 buf_reset(buf);
170
171 p = strpbrk(s, "=;");
172 if (!p)
173 {
174 mutt_debug(LL_DEBUG1, "malformed parameter: %s\n", s);
175 goto bail;
176 }
177
178 /* if we hit a ; now the parameter has no value, just skip it */
179 if (*p != ';')
180 {
181 i = p - s;
182 /* remove whitespace from the end of the attribute name */
183 while ((i > 0) && mutt_str_is_email_wsp(s[i - 1]))
184 i--;
185
186 /* the check for the missing parameter token is here so that we can skip
187 * over any quoted value that may be present. */
188 if (i == 0)
189 {
190 mutt_debug(LL_DEBUG1, "missing attribute: %s\n", s);
191 pnew = NULL;
192 }
193 else
194 {
195 pnew = mutt_param_new();
196 pnew->attribute = mutt_strn_dup(s, i);
197 }
198
199 do
200 {
201 s = mutt_str_skip_email_wsp(p + 1); /* skip over the =, or space if we loop */
202
203 if (*s == '"')
204 {
205 bool state_ascii = true;
206 s++;
207 for (; *s; s++)
208 {
209 if (assumed)
210 {
211 // As iso-2022-* has a character of '"' with non-ascii state, ignore it
212 if (*s == 0x1b)
213 {
214 if ((s[1] == '(') && ((s[2] == 'B') || (s[2] == 'J')))
215 state_ascii = true;
216 else
217 state_ascii = false;
218 }
219 }
220 if (state_ascii && (*s == '"'))
221 break;
222 if (*s == '\\')
223 {
224 if (s[1])
225 {
226 s++;
227 /* Quote the next character */
228 buf_addch(buf, *s);
229 }
230 }
231 else
232 {
233 buf_addch(buf, *s);
234 }
235 }
236 if (*s)
237 s++; /* skip over the " */
238 }
239 else
240 {
241 for (; *s && *s != ' ' && *s != ';'; s++)
242 buf_addch(buf, *s);
243 }
244
245 p = s;
246 } while (allow_value_spaces && (*s == ' '));
247
248 /* if the attribute token was missing, 'new' will be NULL */
249 if (pnew)
250 {
251 pnew->value = buf_strdup(buf);
252
253 mutt_debug(LL_DEBUG2, "parse_parameter: '%s' = '%s'\n",
254 pnew->attribute ? pnew->attribute : "", pnew->value ? pnew->value : "");
255
256 /* Add this parameter to the list */
257 TAILQ_INSERT_HEAD(pl, pnew, entries);
258 }
259 }
260 else
261 {
262 mutt_debug(LL_DEBUG1, "parameter with no value: %s\n", s);
263 s = p;
264 }
265
266 /* Find the next parameter */
267 if ((*s != ';') && !(s = strchr(s, ';')))
268 break; /* no more parameters */
269
270 do
271 {
272 /* Move past any leading whitespace. the +1 skips over the semicolon */
273 s = mutt_str_skip_email_wsp(s + 1);
274 } while (*s == ';'); /* skip empty parameters */
275 }
276
277bail:
278
280 buf_pool_release(&buf);
281}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:337
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
Definition: config_cache.c:101
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:45
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:140
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:381
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:607
struct Parameter * mutt_param_new(void)
Create a new Parameter.
Definition: parameter.c:40
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:853
void rfc2231_decode_parameters(struct ParameterList *pl)
Decode a Parameter list.
Definition: rfc2231.c:240
static bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition: string2.h:103
String manipulation buffer.
Definition: buffer.h:36
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
+ 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 b 
)
static

Parse a content disposition.

Parameters
sString to parse
bBody to save the result

e.g. parse a string "inline" and set DISP_INLINE.

Definition at line 290 of file parse.c.

291{
292 struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
293
294 if (mutt_istr_startswith(s, "inline"))
296 else if (mutt_istr_startswith(s, "form-data"))
298 else
300
301 /* Check to see if a default filename was given */
302 s = strchr(s, ';');
303 if (s)
304 {
305 s = mutt_str_skip_email_wsp(s + 1);
306 parse_parameters(&pl, s, false);
307 s = mutt_param_get(&pl, "filename");
308 if (s)
310 s = mutt_param_get(&pl, "name");
311 if (s)
313 mutt_param_free(&pl);
314 }
315}
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:151
@ 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:243
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:62
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:694
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
char * form_name
Content-Disposition form-data name param.
Definition: body.h:60
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:59
+ 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 322 of file parse.c.

323{
324 if (!head)
325 return;
326
327 char *m = NULL;
328 for (size_t off = 0; (m = mutt_extract_message_id(s, &off)); s += off)
329 {
330 mutt_list_insert_head(head, m);
331 }
332}
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:400
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:46
+ 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 b 
)
static

Read the content's language.

Parameters
sLanguage string
bBody of the email

Definition at line 339 of file parse.c.

340{
341 if (!s || !b)
342 return;
343
344 mutt_debug(LL_DEBUG2, "RFC8255 >> Content-Language set to %s\n", s);
346}
char * language
content-language (RFC8255)
Definition: body.h:78
+ 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 355 of file parse.c.

356{
357 return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
358}
struct ListHead Ignore
List of regexes to match mailing lists.
Definition: globals.c:38
struct ListHead UnIgnore
List of regexes to exclude false matches in MailLists.
Definition: globals.c:50
bool mutt_list_match(const char *s, struct ListHead *h)
Is the string in the list (see notes)
Definition: list.c:194
+ 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
enumContentType, e.g. TYPE_TEXT

Definition at line 365 of file parse.c.

366{
367 if (mutt_istr_equal("text", s))
368 return TYPE_TEXT;
369 if (mutt_istr_equal("multipart", s))
370 return TYPE_MULTIPART;
371 if (mutt_istr_equal("x-sun-attachment", s))
372 return TYPE_MULTIPART;
373 if (mutt_istr_equal("application", s))
374 return TYPE_APPLICATION;
375 if (mutt_istr_equal("message", s))
376 return TYPE_MESSAGE;
377 if (mutt_istr_equal("image", s))
378 return TYPE_IMAGE;
379 if (mutt_istr_equal("audio", s))
380 return TYPE_AUDIO;
381 if (mutt_istr_equal("video", s))
382 return TYPE_VIDEO;
383 if (mutt_istr_equal("model", s))
384 return TYPE_MODEL;
385 if (mutt_istr_equal("*", s))
386 return TYPE_ANY;
387 if (mutt_istr_equal(".*", s))
388 return TYPE_ANY;
389
390 return TYPE_OTHER;
391}
@ 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 400 of file parse.c.

401{
402 if (!s || (*s == '\0'))
403 return NULL;
404
405 char *decoded = mutt_str_dup(s);
406 rfc2047_decode(&decoded);
407
408 char *res = NULL;
409
410 for (const char *p = decoded, *beg = NULL; *p; p++)
411 {
412 if (*p == '<')
413 {
414 beg = p;
415 continue;
416 }
417
418 if (beg && (*p == '>'))
419 {
420 if (len)
421 *len = p - decoded + 1;
422 res = mutt_strn_dup(beg, (p + 1) - beg);
423 break;
424 }
425 }
426
427 FREE(&decoded);
428 return res;
429}
#define FREE(x)
Definition: memory.h:62
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:254
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:661
+ 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
enumContentEncoding, e.g. ENC_QUOTED_PRINTABLE

Definition at line 436 of file parse.c.

437{
438 if (mutt_istr_startswith(c, "7bit"))
439 return ENC_7BIT;
440 if (mutt_istr_startswith(c, "8bit"))
441 return ENC_8BIT;
442 if (mutt_istr_startswith(c, "binary"))
443 return ENC_BINARY;
444 if (mutt_istr_startswith(c, "quoted-printable"))
446 if (mutt_istr_startswith(c, "base64"))
447 return ENC_BASE64;
448 if (mutt_istr_startswith(c, "x-uuencode"))
449 return ENC_UUENCODED;
450 if (mutt_istr_startswith(c, "uuencode"))
451 return ENC_UUENCODED;
452 return ENC_OTHER;
453}
@ 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 b 
)

Parse a content type.

Parameters
sString to parse
bBody to save the result

e.g. parse a string "inline" and set DISP_INLINE.

Definition at line 462 of file parse.c.

463{
464 if (!s || !b)
465 return;
466
467 FREE(&b->subtype);
469
470 /* First extract any existing parameters */
471 char *pc = strchr(s, ';');
472 if (pc)
473 {
474 *pc++ = 0;
475 while (*pc && mutt_isspace(*pc))
476 pc++;
477 parse_parameters(&b->parameter, pc, false);
478
479 /* Some pre-RFC1521 gateways still use the "name=filename" convention,
480 * but if a filename has already been set in the content-disposition,
481 * let that take precedence, and don't set it here */
482 pc = mutt_param_get(&b->parameter, "name");
483 if (pc && !b->filename)
484 b->filename = mutt_str_dup(pc);
485
486 /* this is deep and utter perversion */
487 pc = mutt_param_get(&b->parameter, "conversions");
488 if (pc)
490 }
491
492 /* Now get the subtype */
493 char *subtype = strchr(s, '/');
494 if (subtype)
495 {
496 *subtype++ = '\0';
497 for (pc = subtype; *pc && !mutt_isspace(*pc) && (*pc != ';'); pc++)
498 ; // do nothing
499
500 *pc = '\0';
501 mutt_str_replace(&b->subtype, subtype);
502 }
503
504 /* Finally, get the major type */
506
507 if (mutt_istr_equal("x-sun-attachment", s))
508 mutt_str_replace(&b->subtype, "x-sun-attachment");
509
510 if (b->type == TYPE_OTHER)
511 {
512 mutt_str_replace(&b->xtype, s);
513 }
514
515 if (!b->subtype)
516 {
517 /* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type
518 * field, so we can attempt to convert the type to Body here. */
519 if (b->type == TYPE_TEXT)
520 {
521 b->subtype = mutt_str_dup("plain");
522 }
523 else if (b->type == TYPE_AUDIO)
524 {
525 b->subtype = mutt_str_dup("basic");
526 }
527 else if (b->type == TYPE_MESSAGE)
528 {
529 b->subtype = mutt_str_dup("rfc822");
530 }
531 else if (b->type == TYPE_OTHER)
532 {
533 char buf[128] = { 0 };
534
536 snprintf(buf, sizeof(buf), "x-%s", s);
537 b->subtype = mutt_str_dup(buf);
538 }
539 else
540 {
541 b->subtype = mutt_str_dup("x-unknown");
542 }
543 }
544
545 /* Default character set for text types. */
546 if (b->type == TYPE_TEXT)
547 {
548 pc = mutt_param_get(&b->parameter, "charset");
549 if (pc)
550 {
551 /* Microsoft Outlook seems to think it is necessary to repeat
552 * charset=, strip it off not to confuse ourselves */
553 if (mutt_istrn_equal(pc, "charset=", sizeof("charset=") - 1))
554 mutt_param_set(&b->parameter, "charset", pc + (sizeof("charset=") - 1));
555 }
556 else
557 {
558 mutt_param_set(&b->parameter, "charset",
560 }
561 }
562}
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:365
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:436
const char * mutt_ch_get_default_charset(const struct Slist *const assumed_charset)
Get the default character set.
Definition: charset.c:465
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:454
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:111
char * xtype
content-type if x-unknown
Definition: body.h:62
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 571 of file parse.c.

572{
573 struct AutocryptHeader *autocrypt = mutt_autocrypthdr_new();
574 autocrypt->next = head;
575
576 struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
577 parse_parameters(&pl, s, true);
578 if (TAILQ_EMPTY(&pl))
579 {
580 autocrypt->invalid = true;
581 goto cleanup;
582 }
583
584 struct Parameter *p = NULL;
585 TAILQ_FOREACH(p, &pl, entries)
586 {
587 if (mutt_istr_equal(p->attribute, "addr"))
588 {
589 if (autocrypt->addr)
590 {
591 autocrypt->invalid = true;
592 goto cleanup;
593 }
594 autocrypt->addr = p->value;
595 p->value = NULL;
596 }
597 else if (mutt_istr_equal(p->attribute, "prefer-encrypt"))
598 {
599 if (mutt_istr_equal(p->value, "mutual"))
600 autocrypt->prefer_encrypt = true;
601 }
602 else if (mutt_istr_equal(p->attribute, "keydata"))
603 {
604 if (autocrypt->keydata)
605 {
606 autocrypt->invalid = true;
607 goto cleanup;
608 }
609 autocrypt->keydata = p->value;
610 p->value = NULL;
611 }
612 else if (p->attribute && (p->attribute[0] != '_'))
613 {
614 autocrypt->invalid = true;
615 goto cleanup;
616 }
617 }
618
619 /* Checking the addr against From, and for multiple valid headers
620 * occurs later, after all the headers are parsed. */
621 if (!autocrypt->addr || !autocrypt->keydata)
622 autocrypt->invalid = true;
623
624cleanup:
625 mutt_param_free(&pl);
626 return autocrypt;
627}
struct AutocryptHeader * mutt_autocrypthdr_new(void)
Create a new AutocryptHeader.
Definition: envelope.c:95
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:782
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 635 of file parse.c.

636{
637 for (const char *beg = body, *end = NULL; beg; beg = strchr(end, ','))
638 {
639 beg = strchr(beg, '<');
640 if (!beg)
641 {
642 break;
643 }
644 beg++;
645 end = strchr(beg, '>');
646 if (!end)
647 {
648 break;
649 }
650
651 char *mlist = mutt_strn_dup(beg, end - beg);
652 if (url_check_scheme(mlist) == U_MAILTO)
653 {
654 return mlist;
655 }
656 FREE(&mlist);
657 }
658 return NULL;
659}
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:225
@ 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,
size_t  name_len,
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'
name_lenMust be equivalent to strlen(name)
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 677 of file parse.c.

680{
681 if (!env || !name)
682 return 0;
683
684 bool matched = false;
685
686 switch (name[0] | 0x20)
687 {
688 case 'a':
689 if ((name_len == 13) && eqi12(name + 1, "pparently-to"))
690 {
691 mutt_addrlist_parse(&env->to, body);
692 matched = true;
693 }
694 else if ((name_len == 15) && eqi14(name + 1, "pparently-from"))
695 {
696 mutt_addrlist_parse(&env->from, body);
697 matched = true;
698 }
699#ifdef USE_AUTOCRYPT
700 else if ((name_len == 9) && eqi8(name + 1, "utocrypt"))
701 {
702 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
703 if (c_autocrypt)
704 {
705 env->autocrypt = parse_autocrypt(env->autocrypt, body);
706 matched = true;
707 }
708 }
709 else if ((name_len == 16) && eqi15(name + 1, "utocrypt-gossip"))
710 {
711 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
712 if (c_autocrypt)
713 {
715 matched = true;
716 }
717 }
718#endif
719 break;
720
721 case 'b':
722 if ((name_len == 3) && eqi2(name + 1, "cc"))
723 {
724 mutt_addrlist_parse(&env->bcc, body);
725 matched = true;
726 }
727 break;
728
729 case 'c':
730 if ((name_len == 2) && eqi1(name + 1, "c"))
731 {
732 mutt_addrlist_parse(&env->cc, body);
733 matched = true;
734 }
735 else
736 {
737 if ((name_len >= 12) && eqi8(name, "content-"))
738 {
739 if ((name_len == 12) && eqi4(name + 8, "type"))
740 {
741 if (e)
743 matched = true;
744 }
745 else if ((name_len == 16) && eqi8(name + 8, "language"))
746 {
747 if (e)
749 matched = true;
750 }
751 else if ((name_len == 25) && eqi17(name + 8, "transfer-encoding"))
752 {
753 if (e)
755 matched = true;
756 }
757 else if ((name_len == 14) && eqi8(name + 6, "t-length"))
758 {
759 if (e)
760 {
761 unsigned long len = 0;
762 e->body->length = mutt_str_atoul(body, &len) ? MIN(len, CONTENT_TOO_BIG) : -1;
763 }
764 matched = true;
765 }
766 else if ((name_len == 19) && eqi11(name + 8, "description"))
767 {
768 if (e)
769 {
772 }
773 matched = true;
774 }
775 else if ((name_len == 19) && eqi11(name + 8, "disposition"))
776 {
777 if (e)
779 matched = true;
780 }
781 }
782 }
783 break;
784
785 case 'd':
786 if ((name_len != 4) || !eqi4(name, "date"))
787 break;
788
789 mutt_str_replace(&env->date, body);
790 if (e)
791 {
792 struct Tz tz = { 0 };
793 // the caller will check e->date_sent for -1
794 e->date_sent = mutt_date_parse_date(body, &tz);
795 if (e->date_sent > 0)
796 {
797 e->zhours = tz.zhours;
798 e->zminutes = tz.zminutes;
799 e->zoccident = tz.zoccident;
800 }
801 }
802 matched = true;
803 break;
804
805 case 'e':
806 if ((name_len == 7) && eqi6(name + 1, "xpires") && e)
807 {
808 const time_t expired = mutt_date_parse_date(body, NULL);
809 if ((expired != -1) && (expired < mutt_date_now()))
810 {
811 e->expired = true;
812 }
813 }
814 break;
815
816 case 'f':
817 if ((name_len == 4) && eqi4(name, "from"))
818 {
819 mutt_addrlist_parse(&env->from, body);
820 matched = true;
821 }
822 else if ((name_len == 11) && eqi10(name + 1, "ollowup-to"))
823 {
824 if (!env->followup_to)
825 {
828 }
829 matched = true;
830 }
831 break;
832
833 case 'i':
834 if ((name_len != 11) || !eqi10(name + 1, "n-reply-to"))
835 break;
836
838 char *body2 = mutt_str_dup(body); // Create a mutable copy
840 parse_references(&env->in_reply_to, body2);
841 FREE(&body2);
842 matched = true;
843 break;
844
845 case 'l':
846 if ((name_len == 5) && eqi4(name + 1, "ines"))
847 {
848 if (e)
849 {
850 unsigned int ui = 0; // we don't want a negative number of lines
851 mutt_str_atoui(body, &ui);
852 e->lines = ui;
853 }
854
855 matched = true;
856 }
857 else if ((name_len == 9) && eqi8(name + 1, "ist-post"))
858 {
859 /* RFC2369 */
860 if (!mutt_strn_equal(mutt_str_skip_whitespace(body), "NO", 2))
861 {
862 char *mailto = rfc2369_first_mailto(body);
863 if (mailto)
864 {
865 FREE(&env->list_post);
866 env->list_post = mailto;
867 const bool c_auto_subscribe = cs_subset_bool(NeoMutt->sub, "auto_subscribe");
868 if (c_auto_subscribe)
870 }
871 }
872 matched = true;
873 }
874 else if ((name_len == 14) && eqi13(name + 1, "ist-subscribe"))
875 {
876 /* RFC2369 */
877 char *mailto = rfc2369_first_mailto(body);
878 if (mailto)
879 {
880 FREE(&env->list_subscribe);
881 env->list_subscribe = mailto;
882 }
883 matched = true;
884 }
885 else if ((name_len == 16) && eqi15(name + 1, "ist-unsubscribe"))
886 {
887 /* RFC2369 */
888 char *mailto = rfc2369_first_mailto(body);
889 if (mailto)
890 {
891 FREE(&env->list_unsubscribe);
892 env->list_unsubscribe = mailto;
893 }
894 matched = true;
895 }
896 break;
897
898 case 'm':
899 if ((name_len == 12) && eqi11(name + 1, "ime-version"))
900 {
901 if (e)
902 e->mime = true;
903 matched = true;
904 }
905 else if ((name_len == 10) && eqi9(name + 1, "essage-id"))
906 {
907 /* We add a new "Message-ID:" when building a message */
908 FREE(&env->message_id);
909 env->message_id = mutt_extract_message_id(body, NULL);
910 matched = true;
911 }
912 else
913 {
914 if ((name_len >= 13) && eqi4(name + 1, "ail-"))
915 {
916 if ((name_len == 13) && eqi8(name + 5, "reply-to"))
917 {
918 /* override the Reply-To: field */
920 mutt_addrlist_parse(&env->reply_to, body);
921 matched = true;
922 }
923 else if ((name_len == 16) && eqi11(name + 5, "followup-to"))
924 {
926 matched = true;
927 }
928 }
929 }
930 break;
931
932 case 'n':
933 if ((name_len == 10) && eqi9(name + 1, "ewsgroups"))
934 {
935 FREE(&env->newsgroups);
938 matched = true;
939 }
940 break;
941
942 case 'o':
943 /* field 'Organization:' saves only for pager! */
944 if ((name_len == 12) && eqi11(name + 1, "rganization"))
945 {
946 if (!env->organization && !mutt_istr_equal(body, "unknown"))
947 env->organization = mutt_str_dup(body);
948 }
949 break;
950
951 case 'r':
952 if ((name_len == 10) && eqi9(name + 1, "eferences"))
953 {
955 parse_references(&env->references, body);
956 matched = true;
957 }
958 else if ((name_len == 8) && eqi8(name, "reply-to"))
959 {
960 mutt_addrlist_parse(&env->reply_to, body);
961 matched = true;
962 }
963 else if ((name_len == 11) && eqi10(name + 1, "eturn-path"))
964 {
965 mutt_addrlist_parse(&env->return_path, body);
966 matched = true;
967 }
968 else if ((name_len == 8) && eqi8(name, "received"))
969 {
970 if (e && (e->received == 0))
971 {
972 char *d = strrchr(body, ';');
973 if (d)
974 {
975 d = mutt_str_skip_email_wsp(d + 1);
976 // the caller will check e->received for -1
977 e->received = mutt_date_parse_date(d, NULL);
978 }
979 }
980 }
981 break;
982
983 case 's':
984 if ((name_len == 7) && eqi6(name + 1, "ubject"))
985 {
986 if (!env->subject)
987 mutt_env_set_subject(env, body);
988 matched = true;
989 }
990 else if ((name_len == 6) && eqi5(name + 1, "ender"))
991 {
992 mutt_addrlist_parse(&env->sender, body);
993 matched = true;
994 }
995 else if ((name_len == 6) && eqi5(name + 1, "tatus"))
996 {
997 if (e)
998 {
999 while (*body)
1000 {
1001 switch (*body)
1002 {
1003 case 'O':
1004 {
1005 e->old = true;
1006 break;
1007 }
1008 case 'R':
1009 e->read = true;
1010 break;
1011 case 'r':
1012 e->replied = true;
1013 break;
1014 }
1015 body++;
1016 }
1017 }
1018 matched = true;
1019 }
1020 else if (e && (name_len == 10) && eqi1(name + 1, "u") &&
1021 (eqi8(name + 2, "persedes") || eqi8(name + 2, "percedes")))
1022 {
1023 FREE(&env->supersedes);
1024 env->supersedes = mutt_str_dup(body);
1025 }
1026 break;
1027
1028 case 't':
1029 if ((name_len == 2) && eqi1(name + 1, "o"))
1030 {
1031 mutt_addrlist_parse(&env->to, body);
1032 matched = true;
1033 }
1034 break;
1035
1036 case 'x':
1037 if ((name_len == 8) && eqi8(name, "x-status"))
1038 {
1039 if (e)
1040 {
1041 while (*body)
1042 {
1043 switch (*body)
1044 {
1045 case 'A':
1046 e->replied = true;
1047 break;
1048 case 'D':
1049 e->deleted = true;
1050 break;
1051 case 'F':
1052 e->flagged = true;
1053 break;
1054 default:
1055 break;
1056 }
1057 body++;
1058 }
1059 }
1060 matched = true;
1061 }
1062 else if ((name_len == 7) && eqi6(name + 1, "-label"))
1063 {
1064 FREE(&env->x_label);
1065 env->x_label = mutt_str_dup(body);
1066 matched = true;
1067 }
1068 else if ((name_len == 12) && eqi11(name + 1, "-comment-to"))
1069 {
1070 if (!env->x_comment_to)
1071 env->x_comment_to = mutt_str_dup(body);
1072 matched = true;
1073 }
1074 else if ((name_len == 4) && eqi4(name, "xref"))
1075 {
1076 if (!env->xref)
1077 env->xref = mutt_str_dup(body);
1078 matched = true;
1079 }
1080 else if ((name_len == 13) && eqi12(name + 1, "-original-to"))
1081 {
1083 matched = true;
1084 }
1085 break;
1086
1087 default:
1088 break;
1089 }
1090
1091 /* Keep track of the user-defined headers */
1092 if (!matched && user_hdrs)
1093 {
1094 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1095 char *dup = NULL;
1096 mutt_str_asprintf(&dup, "%s: %s", name, body);
1097
1098 if (!weed || !c_weed || !mutt_matches_ignore(dup))
1099 {
1100 struct ListNode *np = mutt_list_insert_tail(&env->userhdrs, dup);
1101 if (do_2047)
1102 {
1103 rfc2047_decode(&np->data);
1104 }
1105 }
1106 else
1107 {
1108 FREE(&dup);
1109 }
1110 }
1111
1112 return matched;
1113}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:480
const char * mutt_str_atoul(const char *str, unsigned long *dst)
Convert ASCII string to an unsigned long.
Definition: atoi.c:244
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:218
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition: parse.c:462
void mutt_auto_subscribe(const char *mailto)
Check if user is subscribed to mailing list.
Definition: parse.c:108
static struct AutocryptHeader * parse_autocrypt(struct AutocryptHeader *head, const char *s)
Parse an Autocrypt header line.
Definition: parse.c:571
static void parse_references(struct ListHead *head, const char *s)
Parse references from an email header.
Definition: parse.c:322
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:355
static char * rfc2369_first_mailto(const char *body)
Extract the first mailto: URL from a RFC2369 list.
Definition: parse.c:635
static void parse_content_language(const char *s, struct Body *b)
Read the content's language.
Definition: parse.c:339
static void parse_content_disposition(const char *s, struct Body *b)
Parse a content disposition.
Definition: parse.c:290
void mutt_filter_commandline_header_value(char *header)
Sanitise characters in a header value.
Definition: parse.c:92
#define CONTENT_TOO_BIG
Definition: parse.c:61
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition: envelope.c:69
static bool eqi17(const char *a, const char b[17])
eqi17 - Compare two 17-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:205
static bool eqi9(const char *a, const char b[9])
eqi9 - Compare two 9-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:157
static bool eqi10(const char *a, const char b[10])
eqi10 - Compare two 10-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:163
static bool eqi8(const char *a, const char b[8])
Compare two 8-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons.
Definition: eqi.h:122
static bool eqi11(const char *a, const char b[11])
eqi11 - Compare two 11-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:169
static bool eqi6(const char *a, const char b[6])
eqi6 - Compare two 6-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:149
static bool eqi14(const char *a, const char b[14])
eqi14 - Compare two 14-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:187
static bool eqi13(const char *a, const char b[13])
eqi13 - Compare two 13-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:181
static bool eqi4(const char *a, const char b[4])
Compare two 4-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons.
Definition: eqi.h:104
static bool eqi5(const char *a, const char b[5])
eqi5 - Compare two 5-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:143
static bool eqi12(const char *a, const char b[12])
eqi12 - Compare two 12-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:175
static bool eqi15(const char *a, const char b[15])
eqi15 - Compare two 15-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons
Definition: eqi.h:193
static bool eqi1(const char *a, const char b[1])
Compare two 1-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons.
Definition: eqi.h:76
static bool eqi2(const char *a, const char b[2])
Compare two 2-byte strings, ignoring case - See: Case-insensitive fixed-chunk comparisons.
Definition: eqi.h:88
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
#define MIN(a, b)
Definition: memory.h:37
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:716
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:564
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:802
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:426
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:550
char * description
content-description
Definition: body.h:55
bool read
Email is read.
Definition: email.h:50
unsigned int zminutes
Minutes away from UTC.
Definition: email.h:57
bool mime
Has a MIME-Version header?
Definition: email.h:48
int lines
How many lines in the body of this message?
Definition: email.h:62
bool old
Email is seen, but unread.
Definition: email.h:49
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:58
bool flagged
Marked important?
Definition: email.h:47
unsigned int zhours
Hours away from UTC.
Definition: email.h:56
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:60
bool replied
Email has been replied to.
Definition: email.h:51
bool expired
Already expired?
Definition: email.h:46
bool deleted
Email is deleted.
Definition: email.h:78
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:61
struct ListHead userhdrs
user defined headers
Definition: envelope.h:85
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 *const subject
Email's subject.
Definition: envelope.h:70
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:80
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:81
struct AddressList x_original_to
Email's 'X-Original-to'.
Definition: envelope.h:66
struct AutocryptHeader * autocrypt_gossip
Autocrypt Gossip header.
Definition: envelope.h:88
char * newsgroups
List of newsgroups.
Definition: envelope.h:78
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:83
struct AutocryptHeader * autocrypt
Autocrypt header.
Definition: envelope.h:87
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:84
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
char * xref
List of cross-references.
Definition: envelope.h:79
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:37
char * data
String.
Definition: list.h:38
Container for Accounts, Notifications.
Definition: neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:47
List of recognised Timezones.
Definition: date.h:50
unsigned char zminutes
Minutes away from UTC.
Definition: date.h:53
bool zoccident
True if west of UTC, False if East.
Definition: date.h:54
unsigned char zhours
Hours away from UTC.
Definition: date.h:52
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_rfc822_read_line()

size_t mutt_rfc822_read_line ( FILE *  fp,
struct Buffer buf 
)

Read a header line from a file.

Parameters
fpFile to read from
bufBuffer to store the result
Return values
numNumber of bytes read from fp

Reads an arbitrarily long header field, and looks ahead for continuation lines.

Definition at line 1124 of file parse.c.

1125{
1126 if (!fp || !buf)
1127 return 0;
1128
1129 size_t read = 0;
1130 char line[1024] = { 0 }; /* RFC2822 specifies a maximum line length of 998 */
1131
1132 buf_reset(buf);
1133 while (true)
1134 {
1135 if (!fgets(line, sizeof(line), fp))
1136 {
1137 return 0;
1138 }
1139
1140 const size_t linelen = mutt_str_len(line);
1141 if (linelen == 0)
1142 {
1143 break;
1144 }
1145
1146 if (mutt_str_is_email_wsp(line[0]) && buf_is_empty(buf))
1147 {
1148 read = linelen;
1149 break;
1150 }
1151
1152 read += linelen;
1153
1154 size_t off = linelen - 1;
1155 if (line[off] == '\n')
1156 {
1157 /* We did get a full line: remove trailing space */
1158 do
1159 {
1160 line[off] = '\0';
1161 } while (off && mutt_str_is_email_wsp(line[--off]));
1162
1163 /* check to see if the next line is a continuation line */
1164 int ch = fgetc(fp);
1165 if ((ch != ' ') && (ch != '\t'))
1166 {
1167 /* next line is a separate header field or EOH */
1168 ungetc(ch, fp);
1169 buf_addstr(buf, line);
1170 break;
1171 }
1172 read++;
1173
1174 /* eat tabs and spaces from the beginning of the continuation line */
1175 while (((ch = fgetc(fp)) == ' ') || (ch == '\t'))
1176 {
1177 read++;
1178 }
1179
1180 ungetc(ch, fp);
1181 line[off + 1] = ' '; /* string is still terminated because we removed
1182 at least one whitespace char above */
1183 }
1184
1185 buf_addstr(buf, line);
1186 }
1187
1188 return read;
1189}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
+ 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 1204 of file parse.c.

1205{
1206 if (!fp)
1207 return NULL;
1208
1209 struct Envelope *env = mutt_env_new();
1210 char *p = NULL;
1211 LOFF_T loc = e ? e->offset : ftello(fp);
1212 if (loc < 0)
1213 {
1214 mutt_debug(LL_DEBUG1, "ftello: %s (errno %d)\n", strerror(errno), errno);
1215 loc = 0;
1216 }
1217
1218 struct Buffer *line = buf_pool_get();
1219
1220 if (e)
1221 {
1222 if (!e->body)
1223 {
1224 e->body = mutt_body_new();
1225
1226 /* set the defaults from RFC1521 */
1227 e->body->type = TYPE_TEXT;
1228 e->body->subtype = mutt_str_dup("plain");
1229 e->body->encoding = ENC_7BIT;
1230 e->body->length = -1;
1231
1232 /* RFC2183 says this is arbitrary */
1234 }
1235 }
1236
1237 while (true)
1238 {
1239 LOFF_T line_start_loc = loc;
1240 size_t len = mutt_rfc822_read_line(fp, line);
1241 if (buf_is_empty(line))
1242 {
1243 break;
1244 }
1245 loc += len;
1246 const char *lines = buf_string(line);
1247 p = strpbrk(lines, ": \t");
1248 if (!p || (*p != ':'))
1249 {
1250 char return_path[1024] = { 0 };
1251 time_t t = 0;
1252
1253 /* some bogus MTAs will quote the original "From " line */
1254 if (mutt_str_startswith(lines, ">From "))
1255 {
1256 continue; /* just ignore */
1257 }
1258 else if (is_from(lines, return_path, sizeof(return_path), &t))
1259 {
1260 /* MH sometimes has the From_ line in the middle of the header! */
1261 if (e && (e->received == 0))
1262 e->received = t - mutt_date_local_tz(t);
1263 continue;
1264 }
1265
1266 /* We need to seek back to the start of the body. Note that we
1267 * keep track of loc ourselves, since calling ftello() incurs
1268 * a syscall, which can be expensive to do for every single line */
1269 (void) mutt_file_seek(fp, line_start_loc, SEEK_SET);
1270 break; /* end of header */
1271 }
1272 size_t name_len = p - lines;
1273
1274 char buf[1024] = { 0 };
1275 if (mutt_replacelist_match(&SpamList, buf, sizeof(buf), lines))
1276 {
1277 if (!mutt_regexlist_match(&NoSpamList, lines))
1278 {
1279 /* if spam tag already exists, figure out how to amend it */
1280 if ((!buf_is_empty(&env->spam)) && (*buf != '\0'))
1281 {
1282 /* If `$spam_separator` defined, append with separator */
1283 const char *const c_spam_separator = cs_subset_string(NeoMutt->sub, "spam_separator");
1284 if (c_spam_separator)
1285 {
1286 buf_addstr(&env->spam, c_spam_separator);
1287 buf_addstr(&env->spam, buf);
1288 }
1289 else /* overwrite */
1290 {
1291 buf_reset(&env->spam);
1292 buf_addstr(&env->spam, buf);
1293 }
1294 }
1295 else if (buf_is_empty(&env->spam) && (*buf != '\0'))
1296 {
1297 /* spam tag is new, and match expr is non-empty; copy */
1298 buf_addstr(&env->spam, buf);
1299 }
1300 else if (buf_is_empty(&env->spam))
1301 {
1302 /* match expr is empty; plug in null string if no existing tag */
1303 buf_addstr(&env->spam, "");
1304 }
1305
1306 if (!buf_is_empty(&env->spam))
1307 mutt_debug(LL_DEBUG5, "spam = %s\n", env->spam.data);
1308 }
1309 }
1310
1311 *p = '\0';
1312 p = mutt_str_skip_email_wsp(p + 1);
1313 if (*p == '\0')
1314 continue; /* skip empty header fields */
1315
1316 mutt_rfc822_parse_line(env, e, lines, name_len, p, user_hdrs, weed, true);
1317 }
1318
1319 buf_pool_release(&line);
1320
1321 if (e)
1322 {
1323 e->body->hdr_offset = e->offset;
1324 e->body->offset = ftello(fp);
1325
1327
1328 if (e->received < 0)
1329 {
1330 mutt_debug(LL_DEBUG1, "resetting invalid received time to 0\n");
1331 e->received = 0;
1332 }
1333
1334 /* check for missing or invalid date */
1335 if (e->date_sent <= 0)
1336 {
1337 mutt_debug(LL_DEBUG1, "no date found, using received time from msg separator\n");
1338 e->date_sent = e->received;
1339 }
1340
1341#ifdef USE_AUTOCRYPT
1342 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
1343 if (c_autocrypt)
1344 {
1346 /* No sense in taking up memory after the header is processed */
1348 }
1349#endif
1350 }
1351
1352 return env;
1353}
int mutt_autocrypt_process_autocrypt_header(struct Email *e, struct Envelope *env)
Parse an Autocrypt email header.
Definition: autocrypt.c:256
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:44
struct ReplaceList SpamList
List of regexes to match subscribed mailing lists.
Definition: globals.c:46
struct RegexList NoSpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:44
int mutt_rfc822_parse_line(struct Envelope *env, struct Email *e, const char *name, size_t name_len, const char *body, bool user_hdrs, bool weed, bool do_2047)
Parse an email header.
Definition: parse.c:677
size_t mutt_rfc822_read_line(FILE *fp, struct Buffer *buf)
Read a header line from a file.
Definition: parse.c:1124
void mutt_autocrypthdr_free(struct AutocryptHeader **ptr)
Free an AutocryptHeader.
Definition: envelope.c:104
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:49
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:48
int mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition: date.c:219
bool mutt_replacelist_match(struct ReplaceList *rl, char *buf, size_t buflen, const char *str)
Does a string match a pattern?
Definition: regex.c:478
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:832
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:81
char * data
Pointer to data.
Definition: buffer.h:37
struct Buffer spam
Spam header.
Definition: envelope.h:82
+ 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 1361 of file parse.c.

1362{
1363 if (!fp)
1364 return NULL;
1365
1366 struct Body *b = mutt_body_new();
1367 struct Envelope *env = mutt_env_new();
1368 char *c = NULL;
1369 struct Buffer *buf = buf_pool_get();
1370 bool matched = false;
1371
1372 b->hdr_offset = ftello(fp);
1373
1374 b->encoding = ENC_7BIT; /* default from RFC1521 */
1375 b->type = digest ? TYPE_MESSAGE : TYPE_TEXT;
1377
1378 while (mutt_rfc822_read_line(fp, buf) != 0)
1379 {
1380 const char *line = buf_string(buf);
1381 /* Find the value of the current header */
1382 c = strchr(line, ':');
1383 if (c)
1384 {
1385 *c = '\0';
1386 c = mutt_str_skip_email_wsp(c + 1);
1387 if (*c == '\0')
1388 {
1389 mutt_debug(LL_DEBUG1, "skipping empty header field: %s\n", line);
1390 continue;
1391 }
1392 }
1393 else
1394 {
1395 mutt_debug(LL_DEBUG1, "bogus MIME header: %s\n", line);
1396 break;
1397 }
1398
1399 size_t plen = mutt_istr_startswith(line, "content-");
1400 if (plen != 0)
1401 {
1402 if (mutt_istr_equal("type", line + plen))
1403 {
1405 }
1406 else if (mutt_istr_equal("language", line + plen))
1407 {
1409 }
1410 else if (mutt_istr_equal("transfer-encoding", line + plen))
1411 {
1413 }
1414 else if (mutt_istr_equal("disposition", line + plen))
1415 {
1417 }
1418 else if (mutt_istr_equal("description", line + plen))
1419 {
1422 }
1423 else if (mutt_istr_equal("id", line + plen))
1424 {
1425 // strip <angle braces> from Content-ID: header
1426 char *id = c;
1427 int cid_len = mutt_str_len(c);
1428 if (cid_len > 2)
1429 {
1430 if (id[0] == '<')
1431 {
1432 id++;
1433 cid_len--;
1434 }
1435 if (id[cid_len - 1] == '>')
1436 id[cid_len - 1] = '\0';
1437 }
1439 }
1440 }
1441 else if ((plen = mutt_istr_startswith(line, "x-sun-")))
1442 {
1443 if (mutt_istr_equal("data-type", line + plen))
1444 {
1446 }
1447 else if (mutt_istr_equal("encoding-info", line + plen))
1448 {
1450 }
1451 else if (mutt_istr_equal("content-lines", line + plen))
1452 {
1453 mutt_param_set(&b->parameter, "content-lines", c);
1454 }
1455 else if (mutt_istr_equal("data-description", line + plen))
1456 {
1459 }
1460 }
1461 else
1462 {
1463 if (mutt_rfc822_parse_line(env, NULL, line, strlen(line), c, false, false, false))
1464 {
1465 matched = true;
1466 }
1467 }
1468 }
1469 b->offset = ftello(fp); /* Mark the start of the real data */
1470 if ((b->type == TYPE_TEXT) && !b->subtype)
1471 b->subtype = mutt_str_dup("plain");
1472 else if ((b->type == TYPE_MESSAGE) && !b->subtype)
1473 b->subtype = mutt_str_dup("rfc822");
1474
1475 buf_pool_release(&buf);
1476
1477 if (matched)
1478 {
1479 b->mime_headers = env;
1481 }
1482 else
1483 {
1484 mutt_env_free(&env);
1485 }
1486
1487 return b;
1488}
char * content_id
Content-Id (RFC2392)
Definition: body.h:58
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:76
+ 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 1497 of file parse.c.

1498{
1499 if (type != TYPE_MESSAGE)
1500 return false;
1501
1502 subtype = NONULL(subtype);
1503 return (mutt_istr_equal(subtype, "rfc822") ||
1504 mutt_istr_equal(subtype, "news") || mutt_istr_equal(subtype, "global"));
1505}
#define NONULL(x)
Definition: string2.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mailto_header_allowed()

static bool mailto_header_allowed ( const char *  s,
struct ListHead *  h 
)
static

Is the string in the list.

Parameters
sString to match
hHead of the List
Return values
trueString matches a List item (or List contains "*")

This is a very specific function. It searches a List of strings looking for a match. If the list contains a string "*", then it match any input string.

This is similar to mutt_list_match(), except that it doesn't allow prefix matches.

Note
The case of the strings is ignored.

Definition at line 1731 of file parse.c.

1732{
1733 if (!h)
1734 return false;
1735
1736 struct ListNode *np = NULL;
1737 STAILQ_FOREACH(np, h, entries)
1738 {
1739 if ((*np->data == '*') || mutt_istr_equal(s, np->data))
1740 return true;
1741 }
1742 return false;
1743}
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:390
+ 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 1753 of file parse.c.

1754{
1755 if (!env || !src)
1756 return false;
1757
1758 struct Url *url = url_parse(src);
1759 if (!url)
1760 return false;
1761
1762 if (url->host)
1763 {
1764 /* this is not a path-only URL */
1765 url_free(&url);
1766 return false;
1767 }
1768
1769 mutt_addrlist_parse(&env->to, url->path);
1770
1771 struct UrlQuery *np;
1772 STAILQ_FOREACH(np, &url->query_strings, entries)
1773 {
1775 const char *tag = np->name;
1776 char *value = np->value;
1777 /* Determine if this header field is on the allowed list. Since NeoMutt
1778 * interprets some header fields specially (such as
1779 * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
1780 * only safe fields are allowed.
1781 *
1782 * RFC2368, "4. Unsafe headers"
1783 * The user agent interpreting a mailto URL SHOULD choose not to create
1784 * a message if any of the headers are considered dangerous; it may also
1785 * choose to create a message with only a subset of the headers given in
1786 * the URL. */
1788 {
1789 if (mutt_istr_equal(tag, "body"))
1790 {
1791 if (body)
1792 mutt_str_replace(body, value);
1793 }
1794 else
1795 {
1796 char *scratch = NULL;
1797 size_t taglen = mutt_str_len(tag);
1798
1800 mutt_str_asprintf(&scratch, "%s: %s", tag, value);
1801 scratch[taglen] = 0; /* overwrite the colon as mutt_rfc822_parse_line expects */
1802 value = mutt_str_skip_email_wsp(&scratch[taglen + 1]);
1803 mutt_rfc822_parse_line(env, NULL, scratch, taglen, value, true, false, true);
1804 FREE(&scratch);
1805 }
1806 }
1807 }
1808
1809 /* RFC2047 decode after the RFC822 parsing */
1811
1812 url_free(&url);
1813 return true;
1814}
struct ListHead MailToAllow
List of regexes to identify non-spam emails.
Definition: globals.c:42
static bool mailto_header_allowed(const char *s, struct ListHead *h)
Is the string in the list.
Definition: parse.c:1731
void mutt_filter_commandline_header_tag(char *header)
Sanitise characters in a header tag.
Definition: parse.c:72
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:238
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 1821 of file parse.c.

1822{
1823 int counter = 0;
1824
1825 parse_part(fp, b, &counter);
1826}
+ 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 b 
)

Parse a Message/RFC822 body.

Parameters
fpStream to read from
bInfo about the message/rfc822 body part
Return values
ptrNew Body containing parsed message
Note
This assumes that 'b->length' has been set!

Definition at line 1836 of file parse.c.

1837{
1838 int counter = 0;
1839
1840 return rfc822_parse_message(fp, b, &counter);
1841}
+ 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 1852 of file parse.c.

1853{
1854 int counter = 0;
1855
1856 return parse_multipart(fp, boundary, end_off, digest, &counter);
1857}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: