NeoMutt  2025-12-11-769-g906513
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 "alias/lib.h"
#include "mutt.h"
#include "parse.h"
#include "body.h"
#include "email.h"
#include "envelope.h"
#include "from.h"
#include "mime.h"
#include "module_data.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)
 Maximum reasonable Content-Length value (1 GiB) to prevent overflow.
 

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.
 
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
  • Thomas Klausner

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)

Maximum reasonable Content-Length value (1 GiB) to prevent overflow.

Definition at line 62 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 1483 of file parse.c.

1484{
1485 if (!fp || !b)
1486 return;
1487
1488 const char *bound = NULL;
1489 static unsigned short recurse_level = 0;
1490
1491 if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1492 {
1493 mutt_debug(LL_DEBUG1, "recurse level too deep. giving up\n");
1494 return;
1495 }
1496 recurse_level++;
1497
1498 switch (b->type)
1499 {
1500 case TYPE_MULTIPART:
1501 if (mutt_istr_equal(b->subtype, "x-sun-attachment"))
1502 bound = "--------";
1503 else
1504 bound = mutt_param_get(&b->parameter, "boundary");
1505
1506 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
1507 {
1508 goto bail;
1509 }
1510 b->parts = parse_multipart(fp, bound, b->offset + b->length,
1511 mutt_istr_equal("digest", b->subtype), counter);
1512 break;
1513
1514 case TYPE_MESSAGE:
1515 if (!b->subtype)
1516 break;
1517
1518 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
1519 {
1520 goto bail;
1521 }
1522 if (mutt_is_message_type(b->type, b->subtype))
1523 b->parts = rfc822_parse_message(fp, b, counter);
1524 else if (mutt_istr_equal(b->subtype, "external-body"))
1525 b->parts = mutt_read_mime_header(fp, 0);
1526 else
1527 goto bail;
1528 break;
1529
1530 default:
1531 goto bail;
1532 }
1533
1534 /* try to recover from parsing error */
1535 if (!b->parts)
1536 {
1537 b->type = TYPE_TEXT;
1538 mutt_str_replace(&b->subtype, "plain");
1539 }
1540bail:
1541 recurse_level--;
1542}
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1331
static struct Body * rfc822_parse_message(FILE *fp, struct Body *parent, int *counter)
Parse a Message/RFC822 body.
Definition parse.c:1664
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:1554
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1467
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define MUTT_MIME_MAX_DEPTH
Maximum nesting depth for MIME parts to prevent stack overflow.
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:677
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
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 1664 of file parse.c.

1665{
1666 if (!fp || !parent)
1667 return NULL;
1668
1669 parent->email = email_new();
1670 parent->email->offset = ftello(fp);
1671 parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1672 struct Body *msg = parent->email->body;
1673
1674 /* ignore the length given in the content-length since it could be wrong
1675 * and we already have the info to calculate the correct length */
1676 /* if (msg->length == -1) */
1677 msg->length = parent->length - (msg->offset - parent->offset);
1678
1679 /* if body of this message is empty, we can end up with a negative length */
1680 if (msg->length < 0)
1681 msg->length = 0;
1682
1683 parse_part(fp, msg, counter);
1684 return msg;
1685}
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:1172
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition parse.c:1483
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 1554 of file parse.c.

1556{
1557 if (!fp)
1558 return NULL;
1559
1560 if (!boundary)
1561 {
1562 mutt_error(_("multipart message has no boundary parameter"));
1563 return NULL;
1564 }
1565
1566 char buf[1024] = { 0 };
1567 struct Body *head = NULL, *last = NULL, *new_body = NULL;
1568 bool final = false; /* did we see the ending boundary? */
1569
1570 const size_t blen = mutt_str_len(boundary);
1571 while ((ftello(fp) < end_off) && fgets(buf, sizeof(buf), fp))
1572 {
1573 const size_t len = mutt_str_len(buf);
1574
1575 const size_t crlf = ((len > 1) && (buf[len - 2] == '\r')) ? 1 : 0;
1576
1577 if ((buf[0] == '-') && (buf[1] == '-') && mutt_str_startswith(buf + 2, boundary))
1578 {
1579 if (last)
1580 {
1581 last->length = ftello(fp) - last->offset - len - 1 - crlf;
1582 if (last->parts && (last->parts->length == 0))
1583 last->parts->length = ftello(fp) - last->parts->offset - len - 1 - crlf;
1584 /* if the body is empty, we can end up with a -1 length */
1585 if (last->length < 0)
1586 last->length = 0;
1587 }
1588
1589 if (len > 0)
1590 {
1591 /* Remove any trailing whitespace, up to the length of the boundary */
1592 for (size_t i = len - 1; mutt_isspace(buf[i]) && (i >= (blen + 2)); i--)
1593 buf[i] = '\0';
1594 }
1595
1596 /* Check for the end boundary */
1597 if (mutt_str_equal(buf + blen + 2, "--"))
1598 {
1599 final = true;
1600 break; /* done parsing */
1601 }
1602 else if (buf[2 + blen] == '\0')
1603 {
1604 new_body = mutt_read_mime_header(fp, digest);
1605 if (!new_body)
1606 break;
1607
1608 if (mutt_param_get(&new_body->parameter, "content-lines"))
1609 {
1610 int lines = 0;
1611 mutt_str_atoi(mutt_param_get(&new_body->parameter, "content-lines"), &lines);
1612 for (; lines > 0; lines--)
1613 if ((ftello(fp) >= end_off) || !fgets(buf, sizeof(buf), fp))
1614 break;
1615 }
1616
1617 /* Consistency checking - catch bad attachment end boundaries */
1618 if (new_body->offset > end_off)
1619 {
1620 mutt_body_free(&new_body);
1621 break;
1622 }
1623 if (head)
1624 {
1625 last->next = new_body;
1626 last = new_body;
1627 }
1628 else
1629 {
1630 last = new_body;
1631 head = new_body;
1632 }
1633
1634 /* It seems more intuitive to add the counter increment to
1635 * parse_part(), but we want to stop the case where a multipart
1636 * contains thousands of tiny parts before the memory and data
1637 * structures are allocated. */
1638 if (++(*counter) >= MUTT_MIME_MAX_PARTS)
1639 break;
1640 }
1641 }
1642 }
1643
1644 /* in case of missing end boundary, set the length to something reasonable */
1645 if (last && (last->length == 0) && !final)
1646 last->length = end_off - last->offset;
1647
1648 /* parse recursive MIME parts */
1649 for (last = head; last; last = last->next)
1650 parse_part(fp, last, counter);
1651
1652 return head;
1653}
const char * mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition atoi.c:191
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
#define mutt_error(...)
Definition logging2.h:94
#define MUTT_MIME_MAX_PARTS
Maximum number of MIME parts to process to prevent DoS.
Definition mime.h:71
#define _(a)
Definition message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
+ 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 73 of file parse.c.

74{
75 if (!header)
76 return;
77
78 for (; (*header != '\0'); header++)
79 {
80 if ((*header < 33) || (*header > 126) || (*header == ':'))
81 *header = '?';
82 }
83}
+ 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 93 of file parse.c.

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

117{
118 struct Parameter *pnew = NULL;
119 const char *p = NULL;
120 size_t i;
121
122 struct Buffer *buf = buf_pool_get();
123 /* allow_value_spaces, especially with autocrypt keydata, can result
124 * in quite large parameter values. avoid frequent reallocs by
125 * pre-sizing */
126 if (allow_value_spaces)
127 buf_alloc(buf, mutt_str_len(s));
128
129 mutt_debug(LL_DEBUG2, "'%s'\n", s);
130
131 const bool assumed = !slist_is_empty(cc_assumed_charset());
132 while (*s)
133 {
134 buf_reset(buf);
135
136 p = strpbrk(s, "=;");
137 if (!p)
138 {
139 mutt_debug(LL_DEBUG1, "malformed parameter: %s\n", s);
140 goto bail;
141 }
142
143 /* if we hit a ; now the parameter has no value, just skip it */
144 if (*p != ';')
145 {
146 i = p - s;
147 /* remove whitespace from the end of the attribute name */
148 while ((i > 0) && mutt_str_is_email_wsp(s[i - 1]))
149 i--;
150
151 /* the check for the missing parameter token is here so that we can skip
152 * over any quoted value that may be present. */
153 if (i == 0)
154 {
155 mutt_debug(LL_DEBUG1, "missing attribute: %s\n", s);
156 pnew = NULL;
157 }
158 else
159 {
160 pnew = mutt_param_new();
161 pnew->attribute = mutt_strn_dup(s, i);
162 }
163
164 do
165 {
166 s = mutt_str_skip_email_wsp(p + 1); /* skip over the =, or space if we loop */
167
168 if (*s == '"')
169 {
170 bool state_ascii = true;
171 s++;
172 for (; *s; s++)
173 {
174 if (assumed)
175 {
176 // As iso-2022-* has a character of '"' with non-ascii state, ignore it
177 if (*s == 0x1b)
178 {
179 if ((s[1] == '(') && ((s[2] == 'B') || (s[2] == 'J')))
180 state_ascii = true;
181 else
182 state_ascii = false;
183 }
184 }
185 if (state_ascii && (*s == '"'))
186 break;
187 if (*s == '\\')
188 {
189 if (s[1])
190 {
191 s++;
192 /* Quote the next character */
193 buf_addch(buf, *s);
194 }
195 }
196 else
197 {
198 buf_addch(buf, *s);
199 }
200 }
201 if (*s)
202 s++; /* skip over the " */
203 }
204 else
205 {
206 for (; *s && *s != ' ' && *s != ';'; s++)
207 buf_addch(buf, *s);
208 }
209
210 p = s;
211 } while (allow_value_spaces && (*s == ' '));
212
213 /* if the attribute token was missing, 'new' will be NULL */
214 if (pnew)
215 {
216 pnew->value = buf_strdup(buf);
217
218 mutt_debug(LL_DEBUG2, "parse_parameter: '%s' = '%s'\n",
219 pnew->attribute ? pnew->attribute : "", pnew->value ? pnew->value : "");
220
221 /* Add this parameter to the list */
222 TAILQ_INSERT_HEAD(pl, pnew, entries);
223 }
224 }
225 else
226 {
227 mutt_debug(LL_DEBUG1, "parameter with no value: %s\n", s);
228 s = p;
229 }
230
231 /* Find the next parameter */
232 if ((*s != ';') && !(s = strchr(s, ';')))
233 break; /* no more parameters */
234
235 do
236 {
237 /* Move past any leading whitespace. the +1 skips over the semicolon */
238 s = mutt_str_skip_email_wsp(s + 1);
239 } while (*s == ';'); /* skip empty parameters */
240 }
241
242bail:
243
245 buf_pool_release(&buf);
246}
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.
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
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:384
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition string.c:613
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:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#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:241
static bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition string2.h:111
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 255 of file parse.c.

256{
257 struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
258
259 if (mutt_istr_startswith(s, "inline"))
261 else if (mutt_istr_startswith(s, "form-data"))
263 else
265
266 /* Check to see if a default filename was given */
267 s = strchr(s, ';');
268 if (s)
269 {
270 s = mutt_str_skip_email_wsp(s + 1);
271 parse_parameters(&pl, s, false);
272 s = mutt_param_get(&pl, "filename");
273 if (s)
275 s = mutt_param_get(&pl, "name");
276 if (s)
278 mutt_param_free(&pl);
279 }
280}
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition parse.c:116
@ 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:246
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 287 of file parse.c.

288{
289 if (!head)
290 return;
291
292 char *m = NULL;
293 for (size_t off = 0; (m = mutt_extract_message_id(s, &off)); s += off)
294 {
295 mutt_list_insert_head(head, m);
296 }
297}
char * mutt_extract_message_id(const char *s, size_t *len)
Find a Message-ID.
Definition parse.c:368
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 304 of file parse.c.

305{
306 if (!s || !b)
307 return;
308
309 mutt_debug(LL_DEBUG2, "RFC8255 >> Content-Language set to %s\n", s);
311}
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 320 of file parse.c.

321{
323 ASSERT(mod_data);
324
325 return mutt_list_match(s, &mod_data->ignore) && !mutt_list_match(s, &mod_data->unignore);
326}
bool mutt_list_match(const char *s, struct ListHead *h)
Is the string in the list (see notes)
Definition list.c:194
@ MODULE_ID_EMAIL
ModuleEmail, Email code
Definition module_api.h:64
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:665
#define ASSERT(COND)
Definition signal2.h:59
Email private Module data.
Definition module_data.h:32
struct ListHead unignore
Header patterns to unignore.
Definition module_data.h:43
struct ListHead ignore
Header patterns to ignore.
Definition module_data.h:37
Container for Accounts, Notifications.
Definition neomutt.h:41
+ 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 333 of file parse.c.

334{
335 if (mutt_istr_equal("text", s))
336 return TYPE_TEXT;
337 if (mutt_istr_equal("multipart", s))
338 return TYPE_MULTIPART;
339 if (mutt_istr_equal("x-sun-attachment", s))
340 return TYPE_MULTIPART;
341 if (mutt_istr_equal("application", s))
342 return TYPE_APPLICATION;
343 if (mutt_istr_equal("message", s))
344 return TYPE_MESSAGE;
345 if (mutt_istr_equal("image", s))
346 return TYPE_IMAGE;
347 if (mutt_istr_equal("audio", s))
348 return TYPE_AUDIO;
349 if (mutt_istr_equal("video", s))
350 return TYPE_VIDEO;
351 if (mutt_istr_equal("model", s))
352 return TYPE_MODEL;
353 if (mutt_istr_equal("*", s))
354 return TYPE_ANY;
355 if (mutt_istr_equal(".*", s))
356 return TYPE_ANY;
357
358 return TYPE_OTHER;
359}
@ 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 368 of file parse.c.

369{
370 if (!s || (*s == '\0'))
371 return NULL;
372
373 char *decoded = mutt_str_dup(s);
374 rfc2047_decode(&decoded);
375
376 char *res = NULL;
377
378 for (const char *p = decoded, *beg = NULL; *p; p++)
379 {
380 if (*p == '<')
381 {
382 beg = p;
383 continue;
384 }
385
386 if (beg && (*p == '>'))
387 {
388 if (len)
389 *len = p - decoded + 1;
390 res = mutt_strn_dup(beg, (p + 1) - beg);
391 break;
392 }
393 }
394
395 FREE(&decoded);
396 return res;
397}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:669
+ 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 404 of file parse.c.

405{
406 if (mutt_istr_startswith(c, "7bit"))
407 return ENC_7BIT;
408 if (mutt_istr_startswith(c, "8bit"))
409 return ENC_8BIT;
410 if (mutt_istr_startswith(c, "binary"))
411 return ENC_BINARY;
412 if (mutt_istr_startswith(c, "quoted-printable"))
414 if (mutt_istr_startswith(c, "base64"))
415 return ENC_BASE64;
416 if (mutt_istr_startswith(c, "x-uuencode"))
417 return ENC_UUENCODED;
418 if (mutt_istr_startswith(c, "uuencode"))
419 return ENC_UUENCODED;
420 return ENC_OTHER;
421}
@ 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 430 of file parse.c.

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

540{
541 struct AutocryptHeader *autocrypt = mutt_autocrypthdr_new();
542 autocrypt->next = head;
543
544 struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
545 parse_parameters(&pl, s, true);
546 if (TAILQ_EMPTY(&pl))
547 {
548 autocrypt->invalid = true;
549 goto cleanup;
550 }
551
552 struct Parameter *p = NULL;
553 TAILQ_FOREACH(p, &pl, entries)
554 {
555 if (mutt_istr_equal(p->attribute, "addr"))
556 {
557 if (autocrypt->addr)
558 {
559 autocrypt->invalid = true;
560 goto cleanup;
561 }
562 autocrypt->addr = p->value;
563 p->value = NULL;
564 }
565 else if (mutt_istr_equal(p->attribute, "prefer-encrypt"))
566 {
567 if (mutt_istr_equal(p->value, "mutual"))
568 autocrypt->prefer_encrypt = true;
569 }
570 else if (mutt_istr_equal(p->attribute, "keydata"))
571 {
572 if (autocrypt->keydata)
573 {
574 autocrypt->invalid = true;
575 goto cleanup;
576 }
577 autocrypt->keydata = p->value;
578 p->value = NULL;
579 }
580 else if (p->attribute && (p->attribute[0] != '_'))
581 {
582 autocrypt->invalid = true;
583 goto cleanup;
584 }
585 }
586
587 /* Checking the addr against From, and for multiple valid headers
588 * occurs later, after all the headers are parsed. */
589 if (!autocrypt->addr || !autocrypt->keydata)
590 autocrypt->invalid = true;
591
592cleanup:
593 mutt_param_free(&pl);
594 return autocrypt;
595}
struct AutocryptHeader * mutt_autocrypthdr_new(void)
Create a new AutocryptHeader.
Definition envelope.c:94
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define TAILQ_EMPTY(head)
Definition queue.h:778
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 603 of file parse.c.

604{
605 for (const char *beg = body, *end = NULL; beg; beg = strchr(end, ','))
606 {
607 beg = strchr(beg, '<');
608 if (!beg)
609 {
610 break;
611 }
612 beg++;
613 end = strchr(beg, '>');
614 if (!end)
615 {
616 break;
617 }
618
619 char *mlist = mutt_strn_dup(beg, end - beg);
620 if (url_check_scheme(mlist) == U_MAILTO)
621 {
622 return mlist;
623 }
624 FREE(&mlist);
625 }
626 return NULL;
627}
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition url.c:229
@ 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 645 of file parse.c.

648{
649 if (!env || !name)
650 return 0;
651
652 bool matched = false;
653
654 switch (name[0] | 0x20)
655 {
656 case 'a':
657 if ((name_len == 13) && eqi12(name + 1, "pparently-to"))
658 {
659 mutt_addrlist_parse(&env->to, body);
660 matched = true;
661 }
662 else if ((name_len == 15) && eqi14(name + 1, "pparently-from"))
663 {
664 mutt_addrlist_parse(&env->from, body);
665 matched = true;
666 }
667#ifdef USE_AUTOCRYPT
668 else if ((name_len == 9) && eqi8(name + 1, "utocrypt"))
669 {
670 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
671 if (c_autocrypt)
672 {
673 env->autocrypt = parse_autocrypt(env->autocrypt, body);
674 matched = true;
675 }
676 }
677 else if ((name_len == 16) && eqi15(name + 1, "utocrypt-gossip"))
678 {
679 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
680 if (c_autocrypt)
681 {
683 matched = true;
684 }
685 }
686#endif
687 break;
688
689 case 'b':
690 if ((name_len == 3) && eqi2(name + 1, "cc"))
691 {
692 mutt_addrlist_parse(&env->bcc, body);
693 matched = true;
694 }
695 break;
696
697 case 'c':
698 if ((name_len == 2) && eqi1(name + 1, "c"))
699 {
700 mutt_addrlist_parse(&env->cc, body);
701 matched = true;
702 }
703 else
704 {
705 if ((name_len >= 12) && eqi8(name, "content-"))
706 {
707 if ((name_len == 12) && eqi4(name + 8, "type"))
708 {
709 if (e)
711 matched = true;
712 }
713 else if ((name_len == 16) && eqi8(name + 8, "language"))
714 {
715 if (e)
717 matched = true;
718 }
719 else if ((name_len == 25) && eqi17(name + 8, "transfer-encoding"))
720 {
721 if (e)
723 matched = true;
724 }
725 else if ((name_len == 14) && eqi8(name + 6, "t-length"))
726 {
727 if (e)
728 {
729 unsigned long len = 0;
730 e->body->length = mutt_str_atoul(body, &len) ? MIN(len, CONTENT_TOO_BIG) : -1;
731 }
732 matched = true;
733 }
734 else if ((name_len == 19) && eqi11(name + 8, "description"))
735 {
736 if (e)
737 {
740 }
741 matched = true;
742 }
743 else if ((name_len == 19) && eqi11(name + 8, "disposition"))
744 {
745 if (e)
747 matched = true;
748 }
749 }
750 }
751 break;
752
753 case 'd':
754 if ((name_len != 4) || !eqi4(name, "date"))
755 break;
756
757 mutt_str_replace(&env->date, body);
758 if (e)
759 {
760 struct Tz tz = { 0 };
761 // the caller will check e->date_sent for -1
762 e->date_sent = mutt_date_parse_date(body, &tz);
763 if (e->date_sent > 0)
764 {
765 e->zhours = tz.zhours;
766 e->zminutes = tz.zminutes;
767 e->zoccident = tz.zoccident;
768 }
769 }
770 matched = true;
771 break;
772
773 case 'e':
774 if ((name_len == 7) && eqi6(name + 1, "xpires") && e)
775 {
776 const time_t expired = mutt_date_parse_date(body, NULL);
777 if ((expired != -1) && (expired < mutt_date_now()))
778 {
779 e->expired = true;
780 }
781 }
782 break;
783
784 case 'f':
785 if ((name_len == 4) && eqi4(name, "from"))
786 {
787 mutt_addrlist_parse(&env->from, body);
788 matched = true;
789 }
790 else if ((name_len == 11) && eqi10(name + 1, "ollowup-to"))
791 {
792 if (!env->followup_to)
793 {
796 }
797 matched = true;
798 }
799 break;
800
801 case 'i':
802 if ((name_len != 11) || !eqi10(name + 1, "n-reply-to"))
803 break;
804
806 char *body2 = mutt_str_dup(body); // Create a mutable copy
808 parse_references(&env->in_reply_to, body2);
809 FREE(&body2);
810 matched = true;
811 break;
812
813 case 'l':
814 if ((name_len == 5) && eqi4(name + 1, "ines"))
815 {
816 if (e)
817 {
818 unsigned int ui = 0; // we don't want a negative number of lines
819 mutt_str_atoui(body, &ui);
820 e->lines = ui;
821 }
822
823 matched = true;
824 }
825 else if ((name_len == 9) && eqi8(name + 1, "ist-post"))
826 {
827 /* RFC2369 */
828 if (!mutt_strn_equal(mutt_str_skip_whitespace(body), "NO", 2))
829 {
830 char *mailto = rfc2369_first_mailto(body);
831 if (mailto)
832 {
833 FREE(&env->list_post);
834 env->list_post = mailto;
835 const bool c_auto_subscribe = cs_subset_bool(NeoMutt->sub, "auto_subscribe");
836 if (c_auto_subscribe)
838 }
839 }
840 matched = true;
841 }
842 else if ((name_len == 14) && eqi13(name + 1, "ist-subscribe"))
843 {
844 /* RFC2369 */
845 char *mailto = rfc2369_first_mailto(body);
846 if (mailto)
847 {
848 FREE(&env->list_subscribe);
849 env->list_subscribe = mailto;
850 }
851 matched = true;
852 }
853 else if ((name_len == 16) && eqi15(name + 1, "ist-unsubscribe"))
854 {
855 /* RFC2369 */
856 char *mailto = rfc2369_first_mailto(body);
857 if (mailto)
858 {
859 FREE(&env->list_unsubscribe);
860 env->list_unsubscribe = mailto;
861 }
862 matched = true;
863 }
864 break;
865
866 case 'm':
867 if ((name_len == 12) && eqi11(name + 1, "ime-version"))
868 {
869 if (e)
870 e->mime = true;
871 matched = true;
872 }
873 else if ((name_len == 10) && eqi9(name + 1, "essage-id"))
874 {
875 /* We add a new "Message-ID:" when building a message */
876 FREE(&env->message_id);
877 env->message_id = mutt_extract_message_id(body, NULL);
878 matched = true;
879 }
880 else
881 {
882 if ((name_len >= 13) && eqi4(name + 1, "ail-"))
883 {
884 if ((name_len == 13) && eqi8(name + 5, "reply-to"))
885 {
886 /* override the Reply-To: field */
888 mutt_addrlist_parse(&env->reply_to, body);
889 matched = true;
890 }
891 else if ((name_len == 16) && eqi11(name + 5, "followup-to"))
892 {
894 matched = true;
895 }
896 }
897 }
898 break;
899
900 case 'n':
901 if ((name_len == 10) && eqi9(name + 1, "ewsgroups"))
902 {
903 FREE(&env->newsgroups);
906 matched = true;
907 }
908 break;
909
910 case 'o':
911 /* field 'Organization:' saves only for pager! */
912 if ((name_len == 12) && eqi11(name + 1, "rganization"))
913 {
914 if (!env->organization && !mutt_istr_equal(body, "unknown"))
915 env->organization = mutt_str_dup(body);
916 }
917 break;
918
919 case 'r':
920 if ((name_len == 10) && eqi9(name + 1, "eferences"))
921 {
923 parse_references(&env->references, body);
924 matched = true;
925 }
926 else if ((name_len == 8) && eqi8(name, "reply-to"))
927 {
928 mutt_addrlist_parse(&env->reply_to, body);
929 matched = true;
930 }
931 else if ((name_len == 11) && eqi10(name + 1, "eturn-path"))
932 {
933 mutt_addrlist_parse(&env->return_path, body);
934 matched = true;
935 }
936 else if ((name_len == 8) && eqi8(name, "received"))
937 {
938 if (e && (e->received == 0))
939 {
940 char *d = strrchr(body, ';');
941 if (d)
942 {
943 d = mutt_str_skip_email_wsp(d + 1);
944 // the caller will check e->received for -1
945 e->received = mutt_date_parse_date(d, NULL);
946 }
947 }
948 }
949 break;
950
951 case 's':
952 if ((name_len == 7) && eqi6(name + 1, "ubject"))
953 {
954 if (!env->subject)
955 mutt_env_set_subject(env, body);
956 matched = true;
957 }
958 else if ((name_len == 6) && eqi5(name + 1, "ender"))
959 {
960 mutt_addrlist_parse(&env->sender, body);
961 matched = true;
962 }
963 else if ((name_len == 6) && eqi5(name + 1, "tatus"))
964 {
965 if (e)
966 {
967 while (*body)
968 {
969 switch (*body)
970 {
971 case 'O':
972 {
973 e->old = true;
974 break;
975 }
976 case 'R':
977 e->read = true;
978 break;
979 case 'r':
980 e->replied = true;
981 break;
982 }
983 body++;
984 }
985 }
986 matched = true;
987 }
988 else if (e && (name_len == 10) && eqi1(name + 1, "u") &&
989 (eqi8(name + 2, "persedes") || eqi8(name + 2, "percedes")))
990 {
991 FREE(&env->supersedes);
992 env->supersedes = mutt_str_dup(body);
993 }
994 break;
995
996 case 't':
997 if ((name_len == 2) && eqi1(name + 1, "o"))
998 {
999 mutt_addrlist_parse(&env->to, body);
1000 matched = true;
1001 }
1002 break;
1003
1004 case 'x':
1005 if ((name_len == 8) && eqi8(name, "x-status"))
1006 {
1007 if (e)
1008 {
1009 while (*body)
1010 {
1011 switch (*body)
1012 {
1013 case 'A':
1014 e->replied = true;
1015 break;
1016 case 'D':
1017 e->deleted = true;
1018 break;
1019 case 'F':
1020 e->flagged = true;
1021 break;
1022 default:
1023 break;
1024 }
1025 body++;
1026 }
1027 }
1028 matched = true;
1029 }
1030 else if ((name_len == 7) && eqi6(name + 1, "-label"))
1031 {
1032 FREE(&env->x_label);
1033 env->x_label = mutt_str_dup(body);
1034 matched = true;
1035 }
1036 else if ((name_len == 12) && eqi11(name + 1, "-comment-to"))
1037 {
1038 if (!env->x_comment_to)
1039 env->x_comment_to = mutt_str_dup(body);
1040 matched = true;
1041 }
1042 else if ((name_len == 4) && eqi4(name, "xref"))
1043 {
1044 if (!env->xref)
1045 env->xref = mutt_str_dup(body);
1046 matched = true;
1047 }
1048 else if ((name_len == 13) && eqi12(name + 1, "-original-to"))
1049 {
1051 matched = true;
1052 }
1053 break;
1054
1055 default:
1056 break;
1057 }
1058
1059 /* Keep track of the user-defined headers */
1060 if (!matched && user_hdrs)
1061 {
1062 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1063 char *dup = NULL;
1064 mutt_str_asprintf(&dup, "%s: %s", name, body);
1065
1066 if (!weed || !c_weed || !mutt_matches_ignore(dup))
1067 {
1068 struct ListNode *np = mutt_list_insert_tail(&env->userhdrs, dup);
1069 if (do_2047)
1070 {
1071 rfc2047_decode(&np->data);
1072 }
1073 }
1074 else
1075 {
1076 FREE(&dup);
1077 }
1078 }
1079
1080 return matched;
1081}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
void mutt_auto_subscribe(const char *mailto)
Check if user is subscribed to mailing list.
Definition commands.c:49
const char * mutt_str_atoul(const char *str, unsigned long *dst)
Convert ASCII string to an unsigned long.
Definition atoi.c:243
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition atoi.c:217
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:430
static struct AutocryptHeader * parse_autocrypt(struct AutocryptHeader *head, const char *s)
Parse an Autocrypt header line.
Definition parse.c:539
static void parse_references(struct ListHead *head, const char *s)
Parse references from an email header.
Definition parse.c:287
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition parse.c:320
static char * rfc2369_first_mailto(const char *body)
Extract the first mailto: URL from a RFC2369 list.
Definition parse.c:603
static void parse_content_language(const char *s, struct Body *b)
Read the content's language.
Definition parse.c:304
static void parse_content_disposition(const char *s, struct Body *b)
Parse a content disposition.
Definition parse.c:255
void mutt_filter_commandline_header_value(char *header)
Sanitise characters in a header value.
Definition parse.c:93
#define CONTENT_TOO_BIG
Maximum reasonable Content-Length value (1 GiB) to prevent overflow.
Definition parse.c:62
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition envelope.c:68
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:207
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:159
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:165
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:124
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:171
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:151
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:189
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:183
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:106
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:145
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:177
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:195
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:78
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:90
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)
Return the minimum of two values.
Definition memory.h:40
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition date.c:717
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition string.c:570
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:808
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:429
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition string.c:556
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
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
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
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
List of recognised Timezones.
Definition date.h:53
unsigned char zminutes
Minutes away from UTC.
Definition date.h:56
bool zoccident
True if west of UTC, False if East.
Definition date.h:57
unsigned char zhours
Hours away from UTC.
Definition date.h:55
+ 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 1092 of file parse.c.

1093{
1094 if (!fp || !buf)
1095 return 0;
1096
1097 size_t read = 0;
1098 char line[1024] = { 0 }; /* RFC2822 specifies a maximum line length of 998 */
1099
1100 buf_reset(buf);
1101 while (true)
1102 {
1103 if (!fgets(line, sizeof(line), fp))
1104 {
1105 return 0;
1106 }
1107
1108 const size_t linelen = mutt_str_len(line);
1109 if (linelen == 0)
1110 {
1111 break;
1112 }
1113
1114 if (mutt_str_is_email_wsp(line[0]) && buf_is_empty(buf))
1115 {
1116 read = linelen;
1117 break;
1118 }
1119
1120 read += linelen;
1121
1122 size_t off = linelen - 1;
1123 if (line[off] == '\n')
1124 {
1125 /* We did get a full line: remove trailing space */
1126 do
1127 {
1128 line[off] = '\0';
1129 } while (off && mutt_str_is_email_wsp(line[--off]));
1130
1131 /* check to see if the next line is a continuation line */
1132 int ch = fgetc(fp);
1133 if ((ch != ' ') && (ch != '\t'))
1134 {
1135 /* next line is a separate header field or EOH */
1136 ungetc(ch, fp);
1137 buf_addstr(buf, line);
1138 break;
1139 }
1140 read++;
1141
1142 /* eat tabs and spaces from the beginning of the continuation line */
1143 while (((ch = fgetc(fp)) == ' ') || (ch == '\t'))
1144 {
1145 read++;
1146 }
1147
1148 ungetc(ch, fp);
1149 line[off + 1] = ' '; /* string is still terminated because we removed
1150 at least one whitespace char above */
1151 }
1152
1153 buf_addstr(buf, line);
1154 }
1155
1156 return read;
1157}
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 1172 of file parse.c.

1173{
1174 if (!fp)
1175 return NULL;
1176
1177 struct Envelope *env = mutt_env_new();
1178 char *p = NULL;
1179 LOFF_T loc = e ? e->offset : ftello(fp);
1180 if (loc < 0)
1181 {
1182 mutt_debug(LL_DEBUG1, "ftello: %s (errno %d)\n", strerror(errno), errno);
1183 loc = 0;
1184 }
1185
1186 struct Buffer *line = buf_pool_get();
1187
1188 if (e)
1189 {
1190 if (!e->body)
1191 {
1192 e->body = mutt_body_new();
1193
1194 /* set the defaults from RFC1521 */
1195 e->body->type = TYPE_TEXT;
1196 e->body->subtype = mutt_str_dup("plain");
1197 e->body->encoding = ENC_7BIT;
1198 e->body->length = -1;
1199
1200 /* RFC2183 says this is arbitrary */
1202 }
1203 }
1204
1206 ASSERT(mod_data);
1207
1208 while (true)
1209 {
1210 LOFF_T line_start_loc = loc;
1211 size_t len = mutt_rfc822_read_line(fp, line);
1212 if (buf_is_empty(line))
1213 {
1214 break;
1215 }
1216 loc += len;
1217 const char *lines = buf_string(line);
1218 p = strpbrk(lines, ": \t");
1219 if (!p || (*p != ':'))
1220 {
1221 time_t t = 0;
1222
1223 /* some bogus MTAs will quote the original "From " line */
1224 if (mutt_str_startswith(lines, ">From "))
1225 {
1226 continue; /* just ignore */
1227 }
1228 else if (is_from(lines, NULL, 0, &t))
1229 {
1230 /* MH sometimes has the From_ line in the middle of the header! */
1231 if (e && (e->received == 0))
1232 e->received = t - mutt_date_local_tz(t);
1233 continue;
1234 }
1235
1236 /* We need to seek back to the start of the body. Note that we
1237 * keep track of loc ourselves, since calling ftello() incurs
1238 * a syscall, which can be expensive to do for every single line */
1239 (void) mutt_file_seek(fp, line_start_loc, SEEK_SET);
1240 break; /* end of header */
1241 }
1242 size_t name_len = p - lines;
1243
1244 char buf[1024] = { 0 };
1245 if (mutt_replacelist_match(&mod_data->spam, buf, sizeof(buf), lines))
1246 {
1247 if (!mutt_regexlist_match(&mod_data->no_spam, lines))
1248 {
1249 /* if spam tag already exists, figure out how to amend it */
1250 if ((!buf_is_empty(&env->spam)) && (*buf != '\0'))
1251 {
1252 /* If `$spam_separator` defined, append with separator */
1253 const char *const c_spam_separator = cs_subset_string(NeoMutt->sub, "spam_separator");
1254 if (c_spam_separator)
1255 {
1256 buf_addstr(&env->spam, c_spam_separator);
1257 buf_addstr(&env->spam, buf);
1258 }
1259 else /* overwrite */
1260 {
1261 buf_reset(&env->spam);
1262 buf_addstr(&env->spam, buf);
1263 }
1264 }
1265 else if (buf_is_empty(&env->spam) && (*buf != '\0'))
1266 {
1267 /* spam tag is new, and match expr is non-empty; copy */
1268 buf_addstr(&env->spam, buf);
1269 }
1270 else if (buf_is_empty(&env->spam))
1271 {
1272 /* match expr is empty; plug in null string if no existing tag */
1273 buf_addstr(&env->spam, "");
1274 }
1275
1276 if (!buf_is_empty(&env->spam))
1277 mutt_debug(LL_DEBUG5, "spam = %s\n", env->spam.data);
1278 }
1279 }
1280
1281 *p = '\0';
1282 p = mutt_str_skip_email_wsp(p + 1);
1283 if (*p == '\0')
1284 continue; /* skip empty header fields */
1285
1286 mutt_rfc822_parse_line(env, e, lines, name_len, p, user_hdrs, weed, true);
1287 }
1288
1289 buf_pool_release(&line);
1290
1291 if (e)
1292 {
1293 e->body->hdr_offset = e->offset;
1294 e->body->offset = ftello(fp);
1295
1297
1298 if (e->received < 0)
1299 {
1300 mutt_debug(LL_DEBUG1, "resetting invalid received time to 0\n");
1301 e->received = 0;
1302 }
1303
1304 /* check for missing or invalid date */
1305 if (e->date_sent <= 0)
1306 {
1307 mutt_debug(LL_DEBUG1, "no date found, using received time from msg separator\n");
1308 e->date_sent = e->received;
1309 }
1310
1311#ifdef USE_AUTOCRYPT
1312 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
1313 if (c_autocrypt)
1314 {
1316 /* No sense in taking up memory after the header is processed */
1318 }
1319#endif
1320 }
1321
1322 return env;
1323}
int mutt_autocrypt_process_autocrypt_header(struct Email *e, struct Envelope *env)
Parse an Autocrypt email header.
Definition autocrypt.c:262
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
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
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:645
size_t mutt_rfc822_read_line(FILE *fp, struct Buffer *buf)
Read a header line from a file.
Definition parse.c:1092
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
void mutt_autocrypthdr_free(struct AutocryptHeader **ptr)
Free an AutocryptHeader.
Definition envelope.c:103
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:49
int mutt_date_local_tz(time_t t)
Calculate the local timezone in seconds east of UTC.
Definition date.c:220
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
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition regex.c:200
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition rfc2047.c:840
long hdr_offset
Offset in stream where the headers begin.
Definition body.h:81
char * data
Pointer to data.
Definition buffer.h:37
struct ReplaceList spam
Regexes and patterns to match spam emails.
Definition module_data.h:40
struct RegexList no_spam
Regexes to identify non-spam emails.
Definition module_data.h:39
The header of an Email.
Definition envelope.h:57
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 1331 of file parse.c.

1332{
1333 if (!fp)
1334 return NULL;
1335
1336 struct Body *b = mutt_body_new();
1337 struct Envelope *env = mutt_env_new();
1338 char *c = NULL;
1339 struct Buffer *buf = buf_pool_get();
1340 bool matched = false;
1341
1342 b->hdr_offset = ftello(fp);
1343
1344 b->encoding = ENC_7BIT; /* default from RFC1521 */
1345 b->type = digest ? TYPE_MESSAGE : TYPE_TEXT;
1347
1348 while (mutt_rfc822_read_line(fp, buf) != 0)
1349 {
1350 const char *line = buf_string(buf);
1351 /* Find the value of the current header */
1352 c = strchr(line, ':');
1353 if (c)
1354 {
1355 *c = '\0';
1356 c = mutt_str_skip_email_wsp(c + 1);
1357 if (*c == '\0')
1358 {
1359 mutt_debug(LL_DEBUG1, "skipping empty header field: %s\n", line);
1360 continue;
1361 }
1362 }
1363 else
1364 {
1365 mutt_debug(LL_DEBUG1, "bogus MIME header: %s\n", line);
1366 break;
1367 }
1368
1369 size_t plen = mutt_istr_startswith(line, "content-");
1370 if (plen != 0)
1371 {
1372 if (mutt_istr_equal("type", line + plen))
1373 {
1375 }
1376 else if (mutt_istr_equal("language", line + plen))
1377 {
1379 }
1380 else if (mutt_istr_equal("transfer-encoding", line + plen))
1381 {
1383 }
1384 else if (mutt_istr_equal("disposition", line + plen))
1385 {
1387 }
1388 else if (mutt_istr_equal("description", line + plen))
1389 {
1392 }
1393 else if (mutt_istr_equal("id", line + plen))
1394 {
1395 // strip <angle braces> from Content-ID: header
1396 char *id = c;
1397 int cid_len = mutt_str_len(c);
1398 if (cid_len > 2)
1399 {
1400 if (id[0] == '<')
1401 {
1402 id++;
1403 cid_len--;
1404 }
1405 if (id[cid_len - 1] == '>')
1406 id[cid_len - 1] = '\0';
1407 }
1409 }
1410 }
1411 else if ((plen = mutt_istr_startswith(line, "x-sun-")))
1412 {
1413 if (mutt_istr_equal("data-type", line + plen))
1414 {
1416 }
1417 else if (mutt_istr_equal("encoding-info", line + plen))
1418 {
1420 }
1421 else if (mutt_istr_equal("content-lines", line + plen))
1422 {
1423 mutt_param_set(&b->parameter, "content-lines", c);
1424 }
1425 else if (mutt_istr_equal("data-description", line + plen))
1426 {
1429 }
1430 }
1431 else
1432 {
1433 if (mutt_rfc822_parse_line(env, NULL, line, strlen(line), c, false, false, false))
1434 {
1435 matched = true;
1436 }
1437 }
1438 }
1439 b->offset = ftello(fp); /* Mark the start of the real data */
1440 if ((b->type == TYPE_TEXT) && !b->subtype)
1441 b->subtype = mutt_str_dup("plain");
1442 else if ((b->type == TYPE_MESSAGE) && !b->subtype)
1443 b->subtype = mutt_str_dup("rfc822");
1444
1445 buf_pool_release(&buf);
1446
1447 if (matched)
1448 {
1449 b->mime_headers = env;
1451 }
1452 else
1453 {
1454 mutt_env_free(&env);
1455 }
1456
1457 return b;
1458}
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
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 1467 of file parse.c.

1468{
1469 if (type != TYPE_MESSAGE)
1470 return false;
1471
1472 subtype = NONULL(subtype);
1473 return (mutt_istr_equal(subtype, "rfc822") ||
1474 mutt_istr_equal(subtype, "news") || mutt_istr_equal(subtype, "global"));
1475}
#define NONULL(x)
Definition string2.h:44
+ 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 1701 of file parse.c.

1702{
1703 if (!h)
1704 return false;
1705
1706 struct ListNode *np = NULL;
1707 STAILQ_FOREACH(np, h, entries)
1708 {
1709 if ((*np->data == '*') || mutt_istr_equal(s, np->data))
1710 return true;
1711 }
1712 return false;
1713}
#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 1723 of file parse.c.

1724{
1725 if (!env || !src)
1726 return false;
1727
1728 struct Url *url = url_parse(src);
1729 if (!url)
1730 return false;
1731
1732 if (url->host)
1733 {
1734 /* this is not a path-only URL */
1735 url_free(&url);
1736 return false;
1737 }
1738
1739 mutt_addrlist_parse(&env->to, url->path);
1740
1742 ASSERT(mod_data);
1743
1744 struct UrlQuery *np;
1745 STAILQ_FOREACH(np, &url->query_strings, entries)
1746 {
1748 const char *tag = np->name;
1749 char *value = np->value;
1750 /* Determine if this header field is on the allowed list. Since NeoMutt
1751 * interprets some header fields specially (such as
1752 * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
1753 * only safe fields are allowed.
1754 *
1755 * RFC2368, "4. Unsafe headers"
1756 * The user agent interpreting a mailto URL SHOULD choose not to create
1757 * a message if any of the headers are considered dangerous; it may also
1758 * choose to create a message with only a subset of the headers given in
1759 * the URL. */
1760 if (mailto_header_allowed(tag, &mod_data->mail_to_allow))
1761 {
1762 if (mutt_istr_equal(tag, "body"))
1763 {
1764 if (body)
1765 mutt_str_replace(body, value);
1766 }
1767 else
1768 {
1769 char *scratch = NULL;
1770 size_t taglen = mutt_str_len(tag);
1771
1773 mutt_str_asprintf(&scratch, "%s: %s", tag, value);
1774 scratch[taglen] = 0; /* overwrite the colon as mutt_rfc822_parse_line expects */
1775 value = mutt_str_skip_email_wsp(&scratch[taglen + 1]);
1776 mutt_rfc822_parse_line(env, NULL, scratch, taglen, value, true, false, true);
1777 FREE(&scratch);
1778 }
1779 }
1780 }
1781
1782 /* RFC2047 decode after the RFC822 parsing */
1784
1785 url_free(&url);
1786 return true;
1787}
static bool mailto_header_allowed(const char *s, struct ListHead *h)
Is the string in the list.
Definition parse.c:1701
void mutt_filter_commandline_header_tag(char *header)
Sanitise characters in a header tag.
Definition parse.c:73
struct ListHead mail_to_allow
Permitted fields in a mailto: url.
Definition module_data.h:38
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:242
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition url.c:124
+ 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 1794 of file parse.c.

1795{
1796 int counter = 0;
1797
1798 parse_part(fp, b, &counter);
1799}
+ 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 1809 of file parse.c.

1810{
1811 int counter = 0;
1812
1813 return rfc822_parse_message(fp, b, &counter);
1814}
+ 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 1825 of file parse.c.

1826{
1827 int counter = 0;
1828
1829 return parse_multipart(fp, boundary, end_off, digest, &counter);
1830}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: