NeoMutt  2023-11-03-85-g512e01
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_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.
 
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

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

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

1664{
1665 if (!fp || !parent)
1666 return NULL;
1667
1668 parent->email = email_new();
1669 parent->email->offset = ftello(fp);
1670 parent->email->env = mutt_rfc822_read_header(fp, parent->email, false, false);
1671 struct Body *msg = parent->email->body;
1672
1673 /* ignore the length given in the content-length since it could be wrong
1674 * and we already have the info to calculate the correct length */
1675 /* if (msg->length == -1) */
1676 msg->length = parent->length - (msg->offset - parent->offset);
1677
1678 /* if body of this message is empty, we can end up with a negative length */
1679 if (msg->length < 0)
1680 msg->length = 0;
1681
1682 parse_part(fp, msg, counter);
1683 return msg;
1684}
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1156
static void parse_part(FILE *fp, struct Body *b, int *counter)
Parse a MIME part.
Definition: parse.c:1482
The body of an email.
Definition: body.h:36
struct Email * email
header information for message/rfc822
Definition: body.h:73
struct Envelope * env
Envelope information.
Definition: email.h:66
struct Body * body
List of MIME parts.
Definition: email.h:67
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_multipart()

static struct Body * parse_multipart ( FILE *  fp,
const char *  boundary,
LOFF_T  end_off,
bool  digest,
int *  counter 
)
static

Parse a multipart structure.

Parameters
fpStream to read from
boundaryBody separator
end_offLength of the multipart body (used when the final boundary is missing to avoid reading too far)
digesttrue if reading a multipart/digest
counterNumber of parts processed so far
Return values
ptrNew Body containing parsed structure

Definition at line 1553 of file parse.c.

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

◆ mutt_auto_subscribe()

void mutt_auto_subscribe ( const char *  mailto)

Check if user is subscribed to mailing list.

Parameters
mailtoURL of mailing list subscribe

Definition at line 68 of file parse.c.

69{
70 if (!mailto)
71 return;
72
75
77 return;
78
80
81 struct Envelope *lpenv = mutt_env_new(); /* parsed envelope from the List-Post mailto: URL */
82
83 if (mutt_parse_mailto(lpenv, NULL, mailto) && !TAILQ_EMPTY(&lpenv->to))
84 {
85 const char *mailbox = buf_string(TAILQ_FIRST(&lpenv->to)->mailbox);
86 if (mailbox && !mutt_regexlist_match(&SubscribedLists, mailbox) &&
89 {
90 /* mutt_regexlist_add() detects duplicates, so it is safe to
91 * try to add here without any checks. */
92 mutt_regexlist_add(&MailLists, mailbox, REG_ICASE, NULL);
93 mutt_regexlist_add(&SubscribedLists, mailbox, REG_ICASE, NULL);
94 }
95 }
96
97 mutt_env_free(&lpenv);
98}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
struct RegexList SubscribedLists
List of header patterns to unignore (see)
Definition: globals.c:47
struct HashTable * AutoSubscribeCache
< Hash Table: "mailto:" -> AutoSubscribeCache
Definition: globals.c:35
struct RegexList UnSubscribedLists
Definition: globals.c:53
struct RegexList UnMailLists
List of regexes to exclude false matches in SubscribedLists.
Definition: globals.c:51
struct RegexList MailLists
List of permitted fields in a mailto: url.
Definition: globals.c:39
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1694
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
struct 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:112
#define MUTT_HASH_STRCASECMP
use strcasecmp() to compare keys
Definition: hash.h:111
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:136
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:196
#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 111 of file parse.c.

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

251{
252 struct ParameterList pl = TAILQ_HEAD_INITIALIZER(pl);
253
254 if (mutt_istr_startswith(s, "inline"))
256 else if (mutt_istr_startswith(s, "form-data"))
258 else
260
261 /* Check to see if a default filename was given */
262 s = strchr(s, ';');
263 if (s)
264 {
265 s = mutt_str_skip_email_wsp(s + 1);
266 parse_parameters(&pl, s, false);
267 s = mutt_param_get(&pl, "filename");
268 if (s)
270 s = mutt_param_get(&pl, "name");
271 if (s)
273 mutt_param_free(&pl);
274 }
275}
static void parse_parameters(struct ParameterList *pl, const char *s, bool allow_value_spaces)
Parse a list of Parameters.
Definition: parse.c:111
@ 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:240
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
#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 282 of file parse.c.

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

300{
301 if (!s || !b)
302 return;
303
304 mutt_debug(LL_DEBUG2, "RFC8255 >> Content-Language set to %s\n", s);
306}
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 315 of file parse.c.

316{
317 return mutt_list_match(s, &Ignore) && !mutt_list_match(s, &UnIgnore);
318}
struct ListHead Ignore
List of regexes to match mailing lists.
Definition: globals.c:37
struct ListHead UnIgnore
List of regexes to exclude false matches in MailLists.
Definition: globals.c:49
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 325 of file parse.c.

326{
327 if (mutt_istr_equal("text", s))
328 return TYPE_TEXT;
329 if (mutt_istr_equal("multipart", s))
330 return TYPE_MULTIPART;
331 if (mutt_istr_equal("x-sun-attachment", s))
332 return TYPE_MULTIPART;
333 if (mutt_istr_equal("application", s))
334 return TYPE_APPLICATION;
335 if (mutt_istr_equal("message", s))
336 return TYPE_MESSAGE;
337 if (mutt_istr_equal("image", s))
338 return TYPE_IMAGE;
339 if (mutt_istr_equal("audio", s))
340 return TYPE_AUDIO;
341 if (mutt_istr_equal("video", s))
342 return TYPE_VIDEO;
343 if (mutt_istr_equal("model", s))
344 return TYPE_MODEL;
345 if (mutt_istr_equal("*", s))
346 return TYPE_ANY;
347 if (mutt_istr_equal(".*", s))
348 return TYPE_ANY;
349
350 return TYPE_OTHER;
351}
@ TYPE_AUDIO
Type: 'audio/*'.
Definition: mime.h:32
@ TYPE_IMAGE
Type: 'image/*'.
Definition: mime.h:34
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MODEL
Type: 'model/*'.
Definition: mime.h:36
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_ANY
Type: '*' or '.*'.
Definition: mime.h:40
@ TYPE_VIDEO
Type: 'video/*'.
Definition: mime.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_extract_message_id()

char * mutt_extract_message_id ( const char *  s,
size_t *  len 
)

Find a message-id.

Parameters
[in]sString to parse
[out]lenNumber of bytes of s parsed
Return values
ptrMessage id found
NULLNo more message ids

Definition at line 360 of file parse.c.

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

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

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

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

◆ rfc2369_first_mailto()

static char * rfc2369_first_mailto ( const char *  body)
static

Extract the first mailto: URL from a RFC2369 list.

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

Definition at line 595 of file parse.c.

596{
597 for (const char *beg = body, *end = NULL; beg; beg = strchr(end, ','))
598 {
599 beg = strchr(beg, '<');
600 if (!beg)
601 {
602 break;
603 }
604 beg++;
605 end = strchr(beg, '>');
606 if (!end)
607 {
608 break;
609 }
610
611 char *mlist = mutt_strn_dup(beg, end - beg);
612 if (url_check_scheme(mlist) == U_MAILTO)
613 {
614 return mlist;
615 }
616 FREE(&mlist);
617 }
618 return NULL;
619}
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:225
@ U_MAILTO
Url is mailto://.
Definition: url.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_rfc822_parse_line()

int mutt_rfc822_parse_line ( struct Envelope env,
struct Email e,
const char *  name,
size_t  name_len,
const char *  body,
bool  user_hdrs,
bool  weed,
bool  do_2047 
)

Parse an email header.

Parameters
envEnvelope of the email
eEmail
nameHeader field name, e.g. 'to'
name_lenMust be equivalent to strlen(name)
bodyHeader field body, e.g. 'john@.nosp@m.exam.nosp@m.ple.c.nosp@m.om'
user_hdrsIf true, save into the Envelope's userhdrs
weedIf true, perform header weeding (filtering)
do_2047If true, perform RFC2047 decoding of the field
Return values
1The field is recognised
0The field is not recognised

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

Definition at line 637 of file parse.c.

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

1077{
1078 if (!fp || !buf)
1079 return 0;
1080
1081 size_t read = 0;
1082 char line[1024] = { 0 }; /* RFC2822 specifies a maximum line length of 998 */
1083
1084 buf_reset(buf);
1085 while (true)
1086 {
1087 if (!fgets(line, sizeof(line), fp))
1088 {
1089 return 0;
1090 }
1091
1092 const size_t linelen = mutt_str_len(line);
1093 if (linelen == 0)
1094 {
1095 break;
1096 }
1097
1098 if (isspace(line[0]) && buf_is_empty(buf))
1099 {
1100 read = linelen;
1101 break;
1102 }
1103
1104 read += linelen;
1105
1106 size_t off = linelen - 1;
1107 if (line[off] == '\n')
1108 {
1109 /* We did get a full line: remove trailing space */
1110 do
1111 {
1112 line[off] = '\0';
1113 } while (off && isspace(line[--off]));
1114
1115 /* check to see if the next line is a continuation line */
1116 int ch = fgetc(fp);
1117 if ((ch != ' ') && (ch != '\t'))
1118 {
1119 /* next line is a separate header field or EOH */
1120 ungetc(ch, fp);
1121 buf_addstr(buf, line);
1122 break;
1123 }
1124 read++;
1125
1126 /* eat tabs and spaces from the beginning of the continuation line */
1127 while (((ch = fgetc(fp)) == ' ') || (ch == '\t'))
1128 {
1129 read++;
1130 }
1131
1132 ungetc(ch, fp);
1133 line[off + 1] = ' '; /* string is still terminated because we removed
1134 at least one whitespace char above */
1135 }
1136
1137 buf_addstr(buf, line);
1138 }
1139
1140 return read;
1141}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
+ 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 1156 of file parse.c.

1157{
1158 if (!fp)
1159 return NULL;
1160
1161 struct Envelope *env = mutt_env_new();
1162 char *p = NULL;
1163 LOFF_T loc = e ? e->offset : ftello(fp);
1164 if (loc < 0)
1165 {
1166 mutt_debug(LL_DEBUG1, "ftello: %s (errno %d)\n", strerror(errno), errno);
1167 loc = 0;
1168 }
1169
1170 struct Buffer *line = buf_pool_get();
1171
1172 if (e)
1173 {
1174 if (!e->body)
1175 {
1176 e->body = mutt_body_new();
1177
1178 /* set the defaults from RFC1521 */
1179 e->body->type = TYPE_TEXT;
1180 e->body->subtype = mutt_str_dup("plain");
1181 e->body->encoding = ENC_7BIT;
1182 e->body->length = -1;
1183
1184 /* RFC2183 says this is arbitrary */
1186 }
1187 }
1188
1189 while (true)
1190 {
1191 LOFF_T line_start_loc = loc;
1192 size_t len = mutt_rfc822_read_line(fp, line);
1193 if (buf_len(line) == 0)
1194 {
1195 break;
1196 }
1197 loc += len;
1198 const char *lines = buf_string(line);
1199 p = strpbrk(lines, ": \t");
1200 if (!p || (*p != ':'))
1201 {
1202 char return_path[1024] = { 0 };
1203 time_t t = 0;
1204
1205 /* some bogus MTAs will quote the original "From " line */
1206 if (mutt_str_startswith(lines, ">From "))
1207 {
1208 continue; /* just ignore */
1209 }
1210 else if (is_from(lines, return_path, sizeof(return_path), &t))
1211 {
1212 /* MH sometimes has the From_ line in the middle of the header! */
1213 if (e && (e->received == 0))
1214 e->received = t - mutt_date_local_tz(t);
1215 continue;
1216 }
1217
1218 /* We need to seek back to the start of the body. Note that we
1219 * keep track of loc ourselves, since calling ftello() incurs
1220 * a syscall, which can be expensive to do for every single line */
1221 (void) mutt_file_seek(fp, line_start_loc, SEEK_SET);
1222 break; /* end of header */
1223 }
1224 size_t name_len = p - lines;
1225
1226 char buf[1024] = { 0 };
1227 if (mutt_replacelist_match(&SpamList, buf, sizeof(buf), lines))
1228 {
1229 if (!mutt_regexlist_match(&NoSpamList, lines))
1230 {
1231 /* if spam tag already exists, figure out how to amend it */
1232 if ((!buf_is_empty(&env->spam)) && (*buf != '\0'))
1233 {
1234 /* If `$spam_separator` defined, append with separator */
1235 const char *const c_spam_separator = cs_subset_string(NeoMutt->sub, "spam_separator");
1236 if (c_spam_separator)
1237 {
1238 buf_addstr(&env->spam, c_spam_separator);
1239 buf_addstr(&env->spam, buf);
1240 }
1241 else /* overwrite */
1242 {
1243 buf_reset(&env->spam);
1244 buf_addstr(&env->spam, buf);
1245 }
1246 }
1247 else if (buf_is_empty(&env->spam) && (*buf != '\0'))
1248 {
1249 /* spam tag is new, and match expr is non-empty; copy */
1250 buf_addstr(&env->spam, buf);
1251 }
1252 else if (buf_is_empty(&env->spam))
1253 {
1254 /* match expr is empty; plug in null string if no existing tag */
1255 buf_addstr(&env->spam, "");
1256 }
1257
1258 if (!buf_is_empty(&env->spam))
1259 mutt_debug(LL_DEBUG5, "spam = %s\n", env->spam.data);
1260 }
1261 }
1262
1263 *p = '\0';
1264 p = mutt_str_skip_email_wsp(p + 1);
1265 if (*p == '\0')
1266 continue; /* skip empty header fields */
1267
1268 mutt_rfc822_parse_line(env, e, lines, name_len, p, user_hdrs, weed, true);
1269 }
1270
1271 buf_pool_release(&line);
1272
1273 if (e)
1274 {
1275 e->body->hdr_offset = e->offset;
1276 e->body->offset = ftello(fp);
1277
1279
1280 if (env->subject)
1281 {
1282 regmatch_t pmatch[1];
1283
1284 const struct Regex *c_reply_regex = cs_subset_regex(NeoMutt->sub, "reply_regex");
1285 if (mutt_regex_capture(c_reply_regex, env->subject, 1, pmatch))
1286 {
1287 env->real_subj = env->subject + pmatch[0].rm_eo;
1288 if (env->real_subj[0] == '\0')
1289 env->real_subj = NULL;
1290 }
1291 else
1292 {
1293 env->real_subj = env->subject;
1294 }
1295 }
1296
1297 if (e->received < 0)
1298 {
1299 mutt_debug(LL_DEBUG1, "resetting invalid received time to 0\n");
1300 e->received = 0;
1301 }
1302
1303 /* check for missing or invalid date */
1304 if (e->date_sent <= 0)
1305 {
1306 mutt_debug(LL_DEBUG1, "no date found, using received time from msg separator\n");
1307 e->date_sent = e->received;
1308 }
1309
1310#ifdef USE_AUTOCRYPT
1311 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
1312 if (c_autocrypt)
1313 {
1315 /* No sense in taking up memory after the header is processed */
1317 }
1318#endif
1319 }
1320
1321 return env;
1322}
int mutt_autocrypt_process_autocrypt_header(struct Email *e, struct Envelope *env)
Parse an Autocrypt email header.
Definition: autocrypt.c:255
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:218
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:43
struct ReplaceList SpamList
List of regexes to match subscribed mailing lists.
Definition: globals.c:45
struct RegexList NoSpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:43
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:637
size_t mutt_rfc822_read_line(FILE *fp, struct Buffer *buf)
Read a header line from a file.
Definition: parse.c:1076
void mutt_autocrypthdr_free(struct AutocryptHeader **ptr)
Free an AutocryptHeader.
Definition: envelope.c:75
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
@ 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:209
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
Match a regex against a string, with provided options.
Definition: regex.c:619
bool mutt_replacelist_match(struct ReplaceList *rl, char *buf, size_t buflen, const char *str)
Does a string match a pattern?
Definition: regex.c:500
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:828
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:80
char * data
Pointer to data.
Definition: buffer.h:35
struct Buffer spam
Spam header.
Definition: envelope.h:82
char * real_subj
Offset of the real subject.
Definition: envelope.h:71
Cached regular expression.
Definition: regex3.h:89
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_read_mime_header()

struct Body * mutt_read_mime_header ( FILE *  fp,
bool  digest 
)

Parse a MIME header.

Parameters
fpstream to read from
digesttrue if reading subparts of a multipart/digest
Return values
ptrNew Body containing parsed structure

Definition at line 1330 of file parse.c.

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

1467{
1468 if (type != TYPE_MESSAGE)
1469 return false;
1470
1471 subtype = NONULL(subtype);
1472 return (mutt_istr_equal(subtype, "rfc822") ||
1473 mutt_istr_equal(subtype, "news") || mutt_istr_equal(subtype, "global"));
1474}
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_mailto()

bool mutt_parse_mailto ( struct Envelope env,
char **  body,
const char *  src 
)

Parse a mailto:// url.

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

Definition at line 1694 of file parse.c.

1695{
1696 if (!env || !src)
1697 return false;
1698
1699 struct Url *url = url_parse(src);
1700 if (!url)
1701 return false;
1702
1703 if (url->host)
1704 {
1705 /* this is not a path-only URL */
1706 url_free(&url);
1707 return false;
1708 }
1709
1710 mutt_addrlist_parse(&env->to, url->path);
1711
1712 struct UrlQuery *np;
1713 STAILQ_FOREACH(np, &url->query_strings, entries)
1714 {
1715 const char *tag = np->name;
1716 char *value = np->value;
1717 /* Determine if this header field is on the allowed list. Since NeoMutt
1718 * interprets some header fields specially (such as
1719 * "Attach: ~/.gnupg/secring.gpg"), care must be taken to ensure that
1720 * only safe fields are allowed.
1721 *
1722 * RFC2368, "4. Unsafe headers"
1723 * The user agent interpreting a mailto URL SHOULD choose not to create
1724 * a message if any of the headers are considered dangerous; it may also
1725 * choose to create a message with only a subset of the headers given in
1726 * the URL. */
1727 if (mutt_list_match(tag, &MailToAllow))
1728 {
1729 if (mutt_istr_equal(tag, "body"))
1730 {
1731 if (body)
1732 mutt_str_replace(body, value);
1733 }
1734 else
1735 {
1736 char *scratch = NULL;
1737 size_t taglen = mutt_str_len(tag);
1738
1739 mutt_str_asprintf(&scratch, "%s: %s", tag, value);
1740 scratch[taglen] = 0; /* overwrite the colon as mutt_rfc822_parse_line expects */
1741 value = mutt_str_skip_email_wsp(&scratch[taglen + 1]);
1742 mutt_rfc822_parse_line(env, NULL, scratch, taglen, value, true, false, true);
1743 FREE(&scratch);
1744 }
1745 }
1746 }
1747
1748 /* RFC2047 decode after the RFC822 parsing */
1750
1751 url_free(&url);
1752 return true;
1753}
struct ListHead MailToAllow
List of regexes to identify non-spam emails.
Definition: globals.c:41
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
Parsed Query String.
Definition: url.h:58
char * name
Query name.
Definition: url.h:59
char * value
Query value.
Definition: url.h:60
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
struct UrlQueryList query_strings
List of query strings.
Definition: url.h:76
char * host
Host.
Definition: url.h:73
char * src
Raw URL string.
Definition: url.h:77
char * path
Path.
Definition: url.h:75
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:238
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_part()

void mutt_parse_part ( FILE *  fp,
struct Body b 
)

Parse a MIME part.

Parameters
fpFile to read from
bBody to store the results in

Definition at line 1760 of file parse.c.

1761{
1762 int counter = 0;
1763
1764 parse_part(fp, b, &counter);
1765}
+ 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 1775 of file parse.c.

1776{
1777 int counter = 0;
1778
1779 return rfc822_parse_message(fp, b, &counter);
1780}
+ 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 1791 of file parse.c.

1792{
1793 int counter = 0;
1794
1795 return parse_multipart(fp, boundary, end_off, digest, &counter);
1796}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: