NeoMutt  2024-04-16-36-g75b6fb
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
parse.c File Reference

Miscellaneous email parsing routines. More...

#include "config.h"
#include <ctype.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 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 1509 of file parse.c.

1510{
1511 if (!fp || !b)
1512 return;
1513
1514 const char *bound = NULL;
1515 static unsigned short recurse_level = 0;
1516
1517 if (recurse_level >= MUTT_MIME_MAX_DEPTH)
1518 {
1519 mutt_debug(LL_DEBUG1, "recurse level too deep. giving up\n");
1520 return;
1521 }
1522 recurse_level++;
1523
1524 switch (b->type)
1525 {
1526 case TYPE_MULTIPART:
1527 if (mutt_istr_equal(b->subtype, "x-sun-attachment"))
1528 bound = "--------";
1529 else
1530 bound = mutt_param_get(&b->parameter, "boundary");
1531
1532 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
1533 {
1534 goto bail;
1535 }
1536 b->parts = parse_multipart(fp, bound, b->offset + b->length,
1537 mutt_istr_equal("digest", b->subtype), counter);
1538 break;
1539
1540 case TYPE_MESSAGE:
1541 if (!b->subtype)
1542 break;
1543
1544 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
1545 {
1546 goto bail;
1547 }
1548 if (mutt_is_message_type(b->type, b->subtype))
1549 b->parts = rfc822_parse_message(fp, b, counter);
1550 else if (mutt_istr_equal(b->subtype, "external-body"))
1551 b->parts = mutt_read_mime_header(fp, 0);
1552 else
1553 goto bail;
1554 break;
1555
1556 default:
1557 goto bail;
1558 }
1559
1560 /* try to recover from parsing error */
1561 if (!b->parts)
1562 {
1563 b->type = TYPE_TEXT;
1564 mutt_str_replace(&b->subtype, "plain");
1565 }
1566bail:
1567 recurse_level--;
1568}
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1357
static struct Body * rfc822_parse_message(FILE *fp, struct Body *parent, int *counter)
Parse a Message/RFC822 body.
Definition: parse.c:1690
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:1580
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1493
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:775
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#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:666
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:274
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:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc822_parse_message()

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

Parse a Message/RFC822 body.

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

Definition at line 1690 of file parse.c.

1691{
1692 if (!fp || !parent)
1693 return NULL;
1694
1695 parent->email = email_new();
1696 parent->email->offset = ftello(fp);
1697 parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1698 struct Body *msg = parent->email->body;
1699
1700 /* ignore the length given in the content-length since it could be wrong
1701 * and we already have the info to calculate the correct length */
1702 /* if (msg->length == -1) */
1703 msg->length = parent->length - (msg->offset - parent->offset);
1704
1705 /* if body of this message is empty, we can end up with a negative length */
1706 if (msg->length < 0)
1707 msg->length = 0;
1708
1709 parse_part(fp, msg, counter);
1710 return msg;
1711}
struct Email * email_new(void)
Create a new Email.
Definition: email.c:80
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1200
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1509
The body of an email.
Definition: body.h:36
struct Email * email
header information for message/rfc822
Definition: body.h:73
struct Envelope * env
Envelope information.
Definition: email.h: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 1580 of file parse.c.

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

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

110{
111 if (!mailto)
112 return;
113
116
118 return;
119
121
122 struct Envelope *lpenv = mutt_env_new(); /* parsed envelope from the List-Post mailto: URL */
123
124 if (mutt_parse_mailto(lpenv, NULL, mailto) && !TAILQ_EMPTY(&lpenv->to))
125 {
126 const char *mailbox = buf_string(TAILQ_FIRST(&lpenv->to)->mailbox);
127 if (mailbox && !mutt_regexlist_match(&SubscribedLists, mailbox) &&
128 !mutt_regexlist_match(&UnMailLists, mailbox) &&
130 {
131 /* mutt_regexlist_add() detects duplicates, so it is safe to
132 * try to add here without any checks. */
133 mutt_regexlist_add(&MailLists, mailbox, REG_ICASE, NULL);
134 mutt_regexlist_add(&SubscribedLists, mailbox, REG_ICASE, NULL);
135 }
136 }
137
138 mutt_env_free(&lpenv);
139}
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:1749
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:111
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:110
int mutt_regexlist_add(struct RegexList *rl, const char *str, uint16_t flags, struct Buffer *err)
Compile a regex string and add it to a list.
Definition: regex.c: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:723
#define TAILQ_EMPTY(head)
Definition: queue.h:721
The header of an Email.
Definition: envelope.h:57
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_parameters()

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

Parse a list of Parameters.

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

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

Definition at line 152 of file parse.c.

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

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

◆ parse_references()

static void parse_references ( struct ListHead *  head,
const char *  s 
)
static

Parse references from an email header.

Parameters
headList to receive the references
sString to parse

Definition at line 323 of file parse.c.

324{
325 if (!head)
326 return;
327
328 char *m = NULL;
329 for (size_t off = 0; (m = mutt_extract_message_id(s, &off)); s += off)
330 {
331 mutt_list_insert_head(head, m);
332 }
333}
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:401
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_content_language()

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

Read the content's language.

Parameters
sLanguage string
bBody of the email

Definition at line 340 of file parse.c.

341{
342 if (!s || !b)
343 return;
344
345 mutt_debug(LL_DEBUG2, "RFC8255 >> Content-Language set to %s\n", s);
347}
char * language
content-language (RFC8255)
Definition: body.h:77
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_matches_ignore()

bool mutt_matches_ignore ( const char *  s)

Does the string match the ignore list.

Parameters
sString to check
Return values
trueString matches

Checks Ignore and UnIgnore using mutt_list_match

Definition at line 356 of file parse.c.

357{
358 return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
359}
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:195
+ 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 366 of file parse.c.

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

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

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

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

◆ parse_autocrypt()

static struct AutocryptHeader * parse_autocrypt ( struct AutocryptHeader head,
const char *  s 
)
static

Parse an Autocrypt header line.

Parameters
headAutocrypt header to insert before
sHeader string to parse
Return values
ptrNew AutocryptHeader inserted before head

Definition at line 572 of file parse.c.

573{
574 struct AutocryptHeader *autocrypt = mutt_autocrypthdr_new();
575 autocrypt->next = head;
576
577 struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
578 parse_parameters(&pl, s, true);
579 if (TAILQ_EMPTY(&pl))
580 {
581 autocrypt->invalid = true;
582 goto cleanup;
583 }
584
585 struct Parameter *p = NULL;
586 TAILQ_FOREACH(p, &pl, entries)
587 {
588 if (mutt_istr_equal(p->attribute, "addr"))
589 {
590 if (autocrypt->addr)
591 {
592 autocrypt->invalid = true;
593 goto cleanup;
594 }
595 autocrypt->addr = p->value;
596 p->value = NULL;
597 }
598 else if (mutt_istr_equal(p->attribute, "prefer-encrypt"))
599 {
600 if (mutt_istr_equal(p->value, "mutual"))
601 autocrypt->prefer_encrypt = true;
602 }
603 else if (mutt_istr_equal(p->attribute, "keydata"))
604 {
605 if (autocrypt->keydata)
606 {
607 autocrypt->invalid = true;
608 goto cleanup;
609 }
610 autocrypt->keydata = p->value;
611 p->value = NULL;
612 }
613 else if (p->attribute && (p->attribute[0] != '_'))
614 {
615 autocrypt->invalid = true;
616 goto cleanup;
617 }
618 }
619
620 /* Checking the addr against From, and for multiple valid headers
621 * occurs later, after all the headers are parsed. */
622 if (!autocrypt->addr || !autocrypt->keydata)
623 autocrypt->invalid = true;
624
625cleanup:
626 mutt_param_free(&pl);
627 return autocrypt;
628}
struct AutocryptHeader * mutt_autocrypthdr_new(void)
Create a new AutocryptHeader.
Definition: envelope.c:95
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
Parse Autocrypt header info.
Definition: envelope.h:44
bool invalid
Header is invalid.
Definition: envelope.h:48
struct AutocryptHeader * next
Linked list.
Definition: envelope.h:49
char * keydata
PGP Key data.
Definition: envelope.h:46
bool prefer_encrypt
User prefers encryption.
Definition: envelope.h:47
char * addr
Email address.
Definition: envelope.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc2369_first_mailto()

static char * rfc2369_first_mailto ( const char *  body)
static

Extract the first mailto: URL from a RFC2369 list.

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

Definition at line 636 of file parse.c.

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

681{
682 if (!env || !name)
683 return 0;
684
685 bool matched = false;
686
687 switch (name[0] | 0x20)
688 {
689 case 'a':
690 if ((name_len == 13) && eqi12(name + 1, "pparently-to"))
691 {
692 mutt_addrlist_parse(&env->to, body);
693 matched = true;
694 }
695 else if ((name_len == 15) && eqi14(name + 1, "pparently-from"))
696 {
697 mutt_addrlist_parse(&env->from, body);
698 matched = true;
699 }
700#ifdef USE_AUTOCRYPT
701 else if ((name_len == 9) && eqi8(name + 1, "utocrypt"))
702 {
703 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
704 if (c_autocrypt)
705 {
706 env->autocrypt = parse_autocrypt(env->autocrypt, body);
707 matched = true;
708 }
709 }
710 else if ((name_len == 16) && eqi15(name + 1, "utocrypt-gossip"))
711 {
712 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
713 if (c_autocrypt)
714 {
716 matched = true;
717 }
718 }
719#endif
720 break;
721
722 case 'b':
723 if ((name_len == 3) && eqi2(name + 1, "cc"))
724 {
725 mutt_addrlist_parse(&env->bcc, body);
726 matched = true;
727 }
728 break;
729
730 case 'c':
731 if ((name_len == 2) && eqi1(name + 1, "c"))
732 {
733 mutt_addrlist_parse(&env->cc, body);
734 matched = true;
735 }
736 else
737 {
738 if ((name_len >= 12) && eqi8(name, "content-"))
739 {
740 if ((name_len == 12) && eqi4(name + 8, "type"))
741 {
742 if (e)
744 matched = true;
745 }
746 else if ((name_len == 16) && eqi8(name + 8, "language"))
747 {
748 if (e)
750 matched = true;
751 }
752 else if ((name_len == 25) && eqi17(name + 8, "transfer-encoding"))
753 {
754 if (e)
756 matched = true;
757 }
758 else if ((name_len == 14) && eqi8(name + 6, "t-length"))
759 {
760 if (e)
761 {
762 unsigned long len = 0;
763 e->body->length = mutt_str_atoul(body, &len) ? MIN(len, CONTENT_TOO_BIG) : -1;
764 }
765 matched = true;
766 }
767 else if ((name_len == 19) && eqi11(name + 8, "description"))
768 {
769 if (e)
770 {
773 }
774 matched = true;
775 }
776 else if ((name_len == 19) && eqi11(name + 8, "disposition"))
777 {
778 if (e)
780 matched = true;
781 }
782 }
783 }
784 break;
785
786 case 'd':
787 if ((name_len != 4) || !eqi4(name, "date"))
788 break;
789
790 mutt_str_replace(&env->date, body);
791 if (e)
792 {
793 struct Tz tz = { 0 };
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 (mutt_date_parse_date(body, NULL) < mutt_date_now()))
808 {
809 e->expired = true;
810 }
811 break;
812
813 case 'f':
814 if ((name_len == 4) && eqi4(name, "from"))
815 {
816 mutt_addrlist_parse(&env->from, body);
817 matched = true;
818 }
819 else if ((name_len == 11) && eqi10(name + 1, "ollowup-to"))
820 {
821 if (!env->followup_to)
822 {
825 }
826 matched = true;
827 }
828 break;
829
830 case 'i':
831 if ((name_len != 11) || !eqi10(name + 1, "n-reply-to"))
832 break;
833
835 char *body2 = mutt_str_dup(body); // Create a mutable copy
837 parse_references(&env->in_reply_to, body2);
838 FREE(&body2);
839 matched = true;
840 break;
841
842 case 'l':
843 if ((name_len == 5) && eqi4(name + 1, "ines"))
844 {
845 if (e)
846 {
847 unsigned int ui = 0; // we don't want a negative number of lines
848 mutt_str_atoui(body, &ui);
849 e->lines = ui;
850 }
851
852 matched = true;
853 }
854 else if ((name_len == 9) && eqi8(name + 1, "ist-post"))
855 {
856 /* RFC2369 */
857 if (!mutt_strn_equal(mutt_str_skip_whitespace(body), "NO", 2))
858 {
859 char *mailto = rfc2369_first_mailto(body);
860 if (mailto)
861 {
862 FREE(&env->list_post);
863 env->list_post = mailto;
864 const bool c_auto_subscribe = cs_subset_bool(NeoMutt->sub, "auto_subscribe");
865 if (c_auto_subscribe)
867 }
868 }
869 matched = true;
870 }
871 else if ((name_len == 14) && eqi13(name + 1, "ist-subscribe"))
872 {
873 /* RFC2369 */
874 char *mailto = rfc2369_first_mailto(body);
875 if (mailto)
876 {
877 FREE(&env->list_subscribe);
878 env->list_subscribe = mailto;
879 }
880 matched = true;
881 }
882 else if ((name_len == 16) && eqi15(name + 1, "ist-unsubscribe"))
883 {
884 /* RFC2369 */
885 char *mailto = rfc2369_first_mailto(body);
886 if (mailto)
887 {
888 FREE(&env->list_unsubscribe);
889 env->list_unsubscribe = mailto;
890 }
891 matched = true;
892 }
893 break;
894
895 case 'm':
896 if ((name_len == 12) && eqi11(name + 1, "ime-version"))
897 {
898 if (e)
899 e->mime = true;
900 matched = true;
901 }
902 else if ((name_len == 10) && eqi9(name + 1, "essage-id"))
903 {
904 /* We add a new "Message-ID:" when building a message */
905 FREE(&env->message_id);
906 env->message_id = mutt_extract_message_id(body, NULL);
907 matched = true;
908 }
909 else
910 {
911 if ((name_len >= 13) && eqi4(name + 1, "ail-"))
912 {
913 if ((name_len == 13) && eqi8(name + 5, "reply-to"))
914 {
915 /* override the Reply-To: field */
917 mutt_addrlist_parse(&env->reply_to, body);
918 matched = true;
919 }
920 else if ((name_len == 16) && eqi11(name + 5, "followup-to"))
921 {
923 matched = true;
924 }
925 }
926 }
927 break;
928
929 case 'n':
930 if ((name_len == 10) && eqi9(name + 1, "ewsgroups"))
931 {
932 FREE(&env->newsgroups);
935 matched = true;
936 }
937 break;
938
939 case 'o':
940 /* field 'Organization:' saves only for pager! */
941 if ((name_len == 12) && eqi11(name + 1, "rganization"))
942 {
943 if (!env->organization && !mutt_istr_equal(body, "unknown"))
944 env->organization = mutt_str_dup(body);
945 }
946 break;
947
948 case 'r':
949 if ((name_len == 10) && eqi9(name + 1, "eferences"))
950 {
952 parse_references(&env->references, body);
953 matched = true;
954 }
955 else if ((name_len == 8) && eqi8(name, "reply-to"))
956 {
957 mutt_addrlist_parse(&env->reply_to, body);
958 matched = true;
959 }
960 else if ((name_len == 11) && eqi10(name + 1, "eturn-path"))
961 {
962 mutt_addrlist_parse(&env->return_path, body);
963 matched = true;
964 }
965 else if ((name_len == 8) && eqi8(name, "received"))
966 {
967 if (e && (e->received == 0))
968 {
969 char *d = strrchr(body, ';');
970 if (d)
971 {
972 d = mutt_str_skip_email_wsp(d + 1);
973 e->received = mutt_date_parse_date(d, NULL);
974 }
975 }
976 }
977 break;
978
979 case 's':
980 if ((name_len == 7) && eqi6(name + 1, "ubject"))
981 {
982 if (!env->subject)
983 mutt_env_set_subject(env, body);
984 matched = true;
985 }
986 else if ((name_len == 6) && eqi5(name + 1, "ender"))
987 {
988 mutt_addrlist_parse(&env->sender, body);
989 matched = true;
990 }
991 else if ((name_len == 6) && eqi5(name + 1, "tatus"))
992 {
993 if (e)
994 {
995 while (*body)
996 {
997 switch (*body)
998 {
999 case 'O':
1000 {
1001 e->old = true;
1002 break;
1003 }
1004 case 'R':
1005 e->read = true;
1006 break;
1007 case 'r':
1008 e->replied = true;
1009 break;
1010 }
1011 body++;
1012 }
1013 }
1014 matched = true;
1015 }
1016 else if (e && (name_len == 10) && eqi1(name + 1, "u") &&
1017 (eqi8(name + 2, "persedes") || eqi8(name + 2, "percedes")))
1018 {
1019 FREE(&env->supersedes);
1020 env->supersedes = mutt_str_dup(body);
1021 }
1022 break;
1023
1024 case 't':
1025 if ((name_len == 2) && eqi1(name + 1, "o"))
1026 {
1027 mutt_addrlist_parse(&env->to, body);
1028 matched = true;
1029 }
1030 break;
1031
1032 case 'x':
1033 if ((name_len == 8) && eqi8(name, "x-status"))
1034 {
1035 if (e)
1036 {
1037 while (*body)
1038 {
1039 switch (*body)
1040 {
1041 case 'A':
1042 e->replied = true;
1043 break;
1044 case 'D':
1045 e->deleted = true;
1046 break;
1047 case 'F':
1048 e->flagged = true;
1049 break;
1050 default:
1051 break;
1052 }
1053 body++;
1054 }
1055 }
1056 matched = true;
1057 }
1058 else if ((name_len == 7) && eqi6(name + 1, "-label"))
1059 {
1060 FREE(&env->x_label);
1061 env->x_label = mutt_str_dup(body);
1062 matched = true;
1063 }
1064 else if ((name_len == 12) && eqi11(name + 1, "-comment-to"))
1065 {
1066 if (!env->x_comment_to)
1067 env->x_comment_to = mutt_str_dup(body);
1068 matched = true;
1069 }
1070 else if ((name_len == 4) && eqi4(name, "xref"))
1071 {
1072 if (!env->xref)
1073 env->xref = mutt_str_dup(body);
1074 matched = true;
1075 }
1076 else if ((name_len == 13) && eqi12(name + 1, "-original-to"))
1077 {
1079 matched = true;
1080 }
1081 break;
1082
1083 default:
1084 break;
1085 }
1086
1087 /* Keep track of the user-defined headers */
1088 if (!matched && user_hdrs)
1089 {
1090 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1091 char *dup = NULL;
1092 mutt_str_asprintf(&dup, "%s: %s", name, body);
1093
1094 if (!weed || !c_weed || !mutt_matches_ignore(dup))
1095 {
1096 struct ListNode *np = mutt_list_insert_tail(&env->userhdrs, dup);
1097 if (do_2047)
1098 {
1099 rfc2047_decode(&np->data);
1100 }
1101 }
1102 else
1103 {
1104 FREE(&dup);
1105 }
1106 }
1107
1108 return matched;
1109}
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:240
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:214
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition: parse.c:463
void mutt_auto_subscribe(const char *mailto)
Check if user is subscribed to mailing list.
Definition: parse.c:109
static struct AutocryptHeader * parse_autocrypt(struct AutocryptHeader *head, const char *s)
Parse an Autocrypt header line.
Definition: parse.c:572
static void parse_references(struct ListHead *head, const char *s)
Parse references from an email header.
Definition: parse.c:323
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:356
static char * rfc2369_first_mailto(const char *body)
Extract the first mailto: URL from a RFC2369 list.
Definition: parse.c:636
static void parse_content_language(const char *s, struct Body *b)
Read the content's language.
Definition: parse.c:340
static void parse_content_disposition(const char *s, struct Body *b)
Parse a content disposition.
Definition: parse.c:291
void mutt_filter_commandline_header_value(char *header)
Sanitise characters in a header value.
Definition: parse.c:93
#define CONTENT_TOO_BIG
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: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:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
#define MIN(a, b)
Definition: memory.h:32
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:715
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:559
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:797
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:419
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:545
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:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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 1120 of file parse.c.

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

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

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

◆ mutt_is_message_type()

bool mutt_is_message_type ( int  type,
const char *  subtype 
)

Determine if a mime type matches a message or not.

Parameters
typeMessage type enum value
subtypeMessage subtype
Return values
trueType is message/news or message/rfc822
falseOtherwise

Definition at line 1493 of file parse.c.

1494{
1495 if (type != TYPE_MESSAGE)
1496 return false;
1497
1498 subtype = NONULL(subtype);
1499 return (mutt_istr_equal(subtype, "rfc822") ||
1500 mutt_istr_equal(subtype, "news") || mutt_istr_equal(subtype, "global"));
1501}
#define NONULL(x)
Definition: string2.h:37
+ 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 1727 of file parse.c.

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

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

1818{
1819 int counter = 0;
1820
1821 parse_part(fp, b, &counter);
1822}
+ 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 1832 of file parse.c.

1833{
1834 int counter = 0;
1835
1836 return rfc822_parse_message(fp, b, &counter);
1837}
+ 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 1848 of file parse.c.

1849{
1850 int counter = 0;
1851
1852 return parse_multipart(fp, boundary, end_off, digest, &counter);
1853}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: