NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
address.c File Reference

Representation of an email address. More...

#include "config.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "mutt/lib.h"
#include "address.h"
#include "idna2.h"
+ Include dependency graph for address.c:

Go to the source code of this file.

Macros

#define is_special(ch, mask)    ((ch) >= 32 && (ch) < 96 && ((mask >> ((ch) -32)) & 1))
 Is this character special to an email address?
 
#define ADDRESS_SPECIAL_MASK   0x380000015c005304ULL
 AddressSpecials, for is_special()
 
#define USER_SPECIAL_MASK   0x280000015c001200ULL
 AddressSpecials except " ( .
 
#define DOMAIN_SPECIAL_MASK   0x000000015c001204ULL
 AddressSpecials except ( .
 
#define ROUTE_SPECIAL_MASK   0x000000015c000204ULL
 AddressSpecials except ( , .
 

Functions

static const char * parse_comment (const char *s, char *comment, size_t *commentlen, size_t commentmax)
 Extract a comment (parenthesised string)
 
static const char * parse_quote (const char *s, char *token, size_t *tokenlen, size_t tokenmax)
 Extract a quoted string.
 
static const char * next_token (const char *s, char *token, size_t *tokenlen, size_t tokenmax)
 Find the next word, skipping quoted and parenthesised text.
 
static const char * parse_mailboxdomain (const char *s, uint64_t special_mask, char *mailbox, size_t *mailboxlen, size_t mailboxmax, char *comment, size_t *commentlen, size_t commentmax)
 Extract part of an email address (and a comment)
 
static const char * parse_address (const char *s, char *token, size_t *tokenlen, size_t tokenmax, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
 Extract an email address.
 
static const char * parse_route_addr (const char *s, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
 Parse an email addresses.
 
static const char * parse_addr_spec (const char *s, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
 Parse an email address.
 
static bool add_addrspec (struct AddressList *al, const char *phrase, char *comment, size_t *commentlen, size_t commentmax)
 Parse an email address and add an Address to a list.
 
struct Addressmutt_addr_new (void)
 Create a new Address.
 
struct Addressmutt_addr_create (const char *personal, const char *mailbox)
 Create and populate a new Address.
 
int mutt_addrlist_remove (struct AddressList *al, const char *mailbox)
 Remove an Address from a list.
 
void mutt_addr_free (struct Address **ptr)
 Free a single Address.
 
int mutt_addrlist_parse (struct AddressList *al, const char *s)
 Parse a list of email addresses.
 
int mutt_addrlist_parse2 (struct AddressList *al, const char *s)
 Parse a list of email addresses.
 
void mutt_addrlist_qualify (struct AddressList *al, const char *host)
 Expand local names in an Address list using a hostname.
 
void mutt_addr_cat (char *buf, size_t buflen, const char *value, const char *specials)
 Copy a string and wrap it in quotes if it contains special characters.
 
struct Addressmutt_addr_copy (const struct Address *addr)
 Copy the real address.
 
void mutt_addrlist_copy (struct AddressList *dst, const struct AddressList *src, bool prune)
 Copy a list of addresses into another list.
 
bool mutt_addr_valid_msgid (const char *msgid)
 Is this a valid Message ID?
 
bool mutt_addrlist_equal (const struct AddressList *ala, const struct AddressList *alb)
 Compare two Address lists for equality.
 
int mutt_addrlist_count_recips (const struct AddressList *al)
 Count the number of Addresses with valid recipients.
 
bool mutt_addr_cmp (const struct Address *a, const struct Address *b)
 Compare two e-mail addresses.
 
bool mutt_addrlist_search (const struct AddressList *haystack, const struct Address *needle)
 Search for an e-mail address in a list.
 
static bool addr_is_intl (const struct Address *a)
 Does the Address have IDN components.
 
static bool addr_is_local (const struct Address *a)
 Does the Address have NO IDN components.
 
static int addr_mbox_to_udomain (const char *mbox, char **user, char **domain)
 Split a mailbox name into user and domain.
 
static void addr_set_intl (struct Address *a, char *intl_mailbox)
 Mark an Address as having IDN components.
 
static void addr_set_local (struct Address *a, char *local_mailbox)
 Mark an Address as having NO IDN components.
 
const char * mutt_addr_for_display (const struct Address *a)
 Convert an Address for display purposes.
 
size_t mutt_addr_write (struct Buffer *buf, struct Address *addr, bool display)
 Write a single Address to a buffer.
 
static size_t addrlist_write (const struct AddressList *al, struct Buffer *buf, bool display, const char *header, int cols)
 Write an AddressList to a buffer, optionally perform line wrapping and display conversion.
 
size_t mutt_addrlist_write_wrap (const struct AddressList *al, struct Buffer *buf, const char *header)
 Write an AddressList to a buffer, perform line wrapping.
 
size_t mutt_addrlist_write (const struct AddressList *al, struct Buffer *buf, bool display)
 Write an Address to a buffer.
 
size_t mutt_addrlist_write_list (const struct AddressList *al, struct ListHead *list)
 Write Addresses to a List.
 
void mutt_addrlist_write_file (const struct AddressList *al, FILE *fp, const char *header)
 Wrapper for mutt_write_address()
 
bool mutt_addr_to_intl (struct Address *a)
 Convert an Address to Punycode.
 
int mutt_addrlist_to_intl (struct AddressList *al, char **err)
 Convert an Address list to Punycode.
 
bool mutt_addr_to_local (struct Address *a)
 Convert an Address from Punycode.
 
int mutt_addrlist_to_local (struct AddressList *al)
 Convert an Address list from Punycode.
 
void mutt_addrlist_dedupe (struct AddressList *al)
 Remove duplicate addresses.
 
void mutt_addrlist_remove_xrefs (const struct AddressList *a, struct AddressList *b)
 Remove cross-references.
 
void mutt_addrlist_clear (struct AddressList *al)
 Unlink and free all Address in an AddressList.
 
void mutt_addrlist_append (struct AddressList *al, struct Address *a)
 Append an Address to an AddressList.
 
void mutt_addrlist_prepend (struct AddressList *al, struct Address *a)
 Prepend an Address to an AddressList.
 
bool mutt_addr_uses_unicode (const char *str)
 Does this address use Unicode character.
 
bool mutt_addrlist_uses_unicode (const struct AddressList *al)
 Do any of a list of addresses use Unicode characters.
 

Variables

const char AddressSpecials [] = "\"(),.:;<>@[\\]"
 Characters with special meaning for email addresses.
 

Detailed Description

Representation of an email address.

Authors
  • Michael R. Elkins
  • 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 address.c.

Macro Definition Documentation

◆ is_special

#define is_special (   ch,
  mask 
)     ((ch) >= 32 && (ch) < 96 && ((mask >> ((ch) -32)) & 1))

Is this character special to an email address?

Parameters
chCharacter
maskBitmask of characters 32-95 that are special (others are always zero)

Character bitmasks

The four bitmasks below are used for matching characters at speed, instead of using strchr(3).

To generate them, consider the value of each character, e.g. , == 44. Now set the 44th bit of a unsigned long long (presumed to be 64 bits), i.e., 1ULL << 44. Repeat for each character.

To test a character, say ( (40), we check if the 40th bit is set in the mask.

The characters we want to test, AddressSpecials, range in value between 34 and 93 (inclusive). This is too large for an integer type, so we subtract 32 to bring the values down to 2 to 61.

Definition at line 65 of file address.c.

◆ ADDRESS_SPECIAL_MASK

#define ADDRESS_SPECIAL_MASK   0x380000015c005304ULL

AddressSpecials, for is_special()

Definition at line 69 of file address.c.

◆ USER_SPECIAL_MASK

#define USER_SPECIAL_MASK   0x280000015c001200ULL

AddressSpecials except " ( .

\

Definition at line 72 of file address.c.

◆ DOMAIN_SPECIAL_MASK

#define DOMAIN_SPECIAL_MASK   0x000000015c001204ULL

AddressSpecials except ( .

[ \ ]

Definition at line 75 of file address.c.

◆ ROUTE_SPECIAL_MASK

#define ROUTE_SPECIAL_MASK   0x000000015c000204ULL

AddressSpecials except ( , .

[ \ ]

Definition at line 78 of file address.c.

Function Documentation

◆ parse_comment()

static const char * parse_comment ( const char *  s,
char *  comment,
size_t *  commentlen,
size_t  commentmax 
)
static

Extract a comment (parenthesised string)

Parameters
[in]sString, just after the opening parenthesis
[out]commentBuffer to store parenthesised string
[out]commentlenLength of parenthesised string
[in]commentmaxLength of buffer
Return values
ptrFirst character after parenthesised string
NULLError

Definition at line 89 of file address.c.

90{
91 int level = 1;
92
93 while (*s && level)
94 {
95 if (*s == '(')
96 {
97 level++;
98 }
99 else if (*s == ')')
100 {
101 if (--level == 0)
102 {
103 s++;
104 break;
105 }
106 }
107 else if (*s == '\\')
108 {
109 if (!*++s)
110 break;
111 }
112 if (*commentlen < commentmax)
113 comment[(*commentlen)++] = *s;
114 s++;
115 }
116 if (level != 0)
117 {
118 return NULL;
119 }
120 return s;
121}
+ Here is the caller graph for this function:

◆ parse_quote()

static const char * parse_quote ( const char *  s,
char *  token,
size_t *  tokenlen,
size_t  tokenmax 
)
static

Extract a quoted string.

Parameters
[in]sString, just after the opening quote mark
[out]tokenBuffer to store quoted string
[out]tokenlenLength of quoted string
[in]tokenmaxLength of buffer
Return values
ptrFirst character after quoted string
NULLError

Definition at line 132 of file address.c.

133{
134 while (*s)
135 {
136 if (*tokenlen < tokenmax)
137 token[*tokenlen] = *s;
138 if (*s == '\\')
139 {
140 if (!*++s)
141 break;
142
143 if (*tokenlen < tokenmax)
144 token[*tokenlen] = *s;
145 }
146 else if (*s == '"')
147 {
148 return s + 1;
149 }
150 (*tokenlen)++;
151 s++;
152 }
153 return NULL;
154}
+ Here is the caller graph for this function:

◆ next_token()

static const char * next_token ( const char *  s,
char *  token,
size_t *  tokenlen,
size_t  tokenmax 
)
static

Find the next word, skipping quoted and parenthesised text.

Parameters
[in]sString to search
[out]tokenBuffer for the token
[out]tokenlenLength of the next token
[in]tokenmaxLength of the buffer
Return values
ptrFirst character after the next token

Definition at line 164 of file address.c.

165{
166 if (*s == '(')
167 return parse_comment(s + 1, token, tokenlen, tokenmax);
168 if (*s == '"')
169 return parse_quote(s + 1, token, tokenlen, tokenmax);
170 if (*s && is_special(*s, ADDRESS_SPECIAL_MASK))
171 {
172 if (*tokenlen < tokenmax)
173 token[(*tokenlen)++] = *s;
174 return s + 1;
175 }
176 while (*s)
177 {
179 break;
180 if (*tokenlen < tokenmax)
181 token[(*tokenlen)++] = *s;
182 s++;
183 }
184 return s;
185}
#define ADDRESS_SPECIAL_MASK
AddressSpecials, for is_special()
Definition: address.c:69
static const char * parse_comment(const char *s, char *comment, size_t *commentlen, size_t commentmax)
Extract a comment (parenthesised string)
Definition: address.c:89
#define is_special(ch, mask)
Is this character special to an email address?
Definition: address.c:65
static const char * parse_quote(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
Extract a quoted string.
Definition: address.c:132
static bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition: string2.h:111
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_mailboxdomain()

static const char * parse_mailboxdomain ( const char *  s,
uint64_t  special_mask,
char *  mailbox,
size_t *  mailboxlen,
size_t  mailboxmax,
char *  comment,
size_t *  commentlen,
size_t  commentmax 
)
static

Extract part of an email address (and a comment)

Parameters
[in]sString to parse
[in]special_maskCharacters that are special (see is_special())
[out]mailboxBuffer for email address
[out]mailboxlenLength of saved email address
[in]mailboxmaxLength of mailbox buffer
[out]commentBuffer for comment
[out]commentlenLength of saved comment
[in]commentmaxLength of comment buffer
Return values
ptrFirst character after the email address part

This will be called twice to parse an email address, first for the mailbox name, then for the domain name. Each part can also have a comment in (). The comment can be at the start or end of the mailbox or domain.

Examples:

  • "john.doe@example.com"
  • "john.doe(comment)@example.com"
  • "john.doe@example.com(comment)"

The first call will return "john.doe" with optional comment, "comment". The second call will return "example.com" with optional comment, "comment".

Definition at line 211 of file address.c.

215{
216 const char *ps = NULL;
217
218 while (*s)
219 {
221 if ((*s == '\0'))
222 return s;
223
224 if (is_special(*s, special_mask))
225 return s;
226
227 if (*s == '(')
228 {
229 if (*commentlen && (*commentlen < commentmax))
230 comment[(*commentlen)++] = ' ';
231 ps = next_token(s, comment, commentlen, commentmax);
232 }
233 else
234 {
235 ps = next_token(s, mailbox, mailboxlen, mailboxmax);
236 }
237 if (!ps)
238 return NULL;
239 s = ps;
240 }
241
242 return s;
243}
static const char * next_token(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
Find the next word, skipping quoted and parenthesised text.
Definition: address.c:164
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:680
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_address()

static const char * parse_address ( const char *  s,
char *  token,
size_t *  tokenlen,
size_t  tokenmax,
char *  comment,
size_t *  commentlen,
size_t  commentmax,
struct Address addr 
)
static

Extract an email address.

Parameters
[in]sString, just after the opening <
[out]tokenBuffer for the email address
[out]tokenlenLength of the email address
[in]tokenmaxLength of the email address buffer
[out]commentBuffer for any comments
[out]commentlenLength of any comments
[in]commentmaxLength of the comment buffer
[in]addrAddress to store the results
Return values
ptrThe closing > of the email address
NULLError

Definition at line 258 of file address.c.

261{
262 s = parse_mailboxdomain(s, USER_SPECIAL_MASK, token, tokenlen, tokenmax,
263 comment, commentlen, commentmax);
264 if (!s)
265 return NULL;
266
267 if (*s == '@')
268 {
269 if (*tokenlen < tokenmax)
270 token[(*tokenlen)++] = '@';
271 s = parse_mailboxdomain(s + 1, DOMAIN_SPECIAL_MASK, token, tokenlen,
272 tokenmax, comment, commentlen, commentmax);
273 if (!s)
274 return NULL;
275 }
276
277 terminate_string(token, *tokenlen, tokenmax);
278 addr->mailbox = buf_new(token);
279
280 if (*commentlen && !addr->personal)
281 {
282 terminate_string(comment, *commentlen, commentmax);
283 addr->personal = buf_new(comment);
284 }
285
286 return s;
287}
static const char * parse_mailboxdomain(const char *s, uint64_t special_mask, char *mailbox, size_t *mailboxlen, size_t mailboxmax, char *comment, size_t *commentlen, size_t commentmax)
Extract part of an email address (and a comment)
Definition: address.c:211
#define USER_SPECIAL_MASK
AddressSpecials except " ( .
Definition: address.c:72
#define DOMAIN_SPECIAL_MASK
AddressSpecials except ( .
Definition: address.c:75
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:316
#define terminate_string(str, strlen, buflen)
Definition: string2.h:49
struct Buffer * personal
Real name of address.
Definition: address.h:37
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_route_addr()

static const char * parse_route_addr ( const char *  s,
char *  comment,
size_t *  commentlen,
size_t  commentmax,
struct Address addr 
)
static

Parse an email addresses.

Parameters
[in]sString, just after the opening <
[out]commentBuffer for any comments
[out]commentlenLength of any comments
[in]commentmaxLength of the comments buffer
[in]addrAddress to store the details
Return values
ptrFirst character after the email address

Definition at line 298 of file address.c.

300{
301 char token[1024] = { 0 };
302 size_t tokenlen = 0;
303
305
306 /* find the end of the route */
307 if (*s == '@')
308 {
309 while (s && (*s == '@'))
310 {
311 if (tokenlen < (sizeof(token) - 1))
312 token[tokenlen++] = '@';
313 s = parse_mailboxdomain(s + 1, ROUTE_SPECIAL_MASK, token, &tokenlen,
314 sizeof(token) - 1, comment, commentlen, commentmax);
315 }
316 if (!s || (*s != ':'))
317 {
318 return NULL; /* invalid route */
319 }
320
321 if (tokenlen < (sizeof(token) - 1))
322 token[tokenlen++] = ':';
323 s++;
324 }
325
326 s = parse_address(s, token, &tokenlen, sizeof(token) - 1, comment, commentlen,
327 commentmax, addr);
328 if (!s)
329 return NULL;
330
331 if (*s != '>')
332 {
333 return NULL;
334 }
335
336 if (!addr->mailbox)
337 {
338 addr->mailbox = buf_new("@");
339 }
340
341 s++;
342 return s;
343}
static const char * parse_address(const char *s, char *token, size_t *tokenlen, size_t tokenmax, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
Extract an email address.
Definition: address.c:258
#define ROUTE_SPECIAL_MASK
AddressSpecials except ( , .
Definition: address.c:78
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_addr_spec()

static const char * parse_addr_spec ( const char *  s,
char *  comment,
size_t *  commentlen,
size_t  commentmax,
struct Address addr 
)
static

Parse an email address.

Parameters
[in]sString to parse
[out]commentBuffer for any comments
[out]commentlenLength of any comments
[in]commentmaxLength of the comments buffer
[in]addrAddress to fill in
Return values
ptrFirst character after the email address

Definition at line 354 of file address.c.

356{
357 char token[1024] = { 0 };
358 size_t tokenlen = 0;
359
360 s = parse_address(s, token, &tokenlen, sizeof(token) - 1, comment, commentlen,
361 commentmax, addr);
362 if (s && *s && (*s != ',') && (*s != ';'))
363 {
364 return NULL;
365 }
366 return s;
367}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_addrspec()

static bool add_addrspec ( struct AddressList *  al,
const char *  phrase,
char *  comment,
size_t *  commentlen,
size_t  commentmax 
)
static

Parse an email address and add an Address to a list.

Parameters
[out]alAddress list
[in]phraseString to parse
[out]commentBuffer for any comments
[out]commentlenLength of any comments
[in]commentmaxLength of the comments buffer
Return values
trueAn address was successfully parsed and added

Definition at line 378 of file address.c.

380{
381 struct Address *cur = mutt_addr_new();
382
383 if (!parse_addr_spec(phrase, comment, commentlen, commentmax, cur))
384 {
385 mutt_addr_free(&cur);
386 return false;
387 }
388
389 mutt_addrlist_append(al, cur);
390 return true;
391}
static const char * parse_addr_spec(const char *s, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
Parse an email address.
Definition: address.c:354
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:460
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1481
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:399
An email address.
Definition: address.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_new()

struct Address * mutt_addr_new ( void  )

Create a new Address.

Return values
ptrNewly allocated Address

Free the result with mutt_addr_free()

Definition at line 399 of file address.c.

400{
401 return mutt_mem_calloc(1, sizeof(struct Address));
402}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_create()

struct Address * mutt_addr_create ( const char *  personal,
const char *  mailbox 
)

Create and populate a new Address.

Parameters
[in]personalThe personal name for the Address (can be NULL)
[in]mailboxThe mailbox for the Address (can be NULL)
Return values
ptrNewly allocated Address
Note
The personal and mailbox values, if not NULL, are going to be copied into the newly allocated Address.

Definition at line 412 of file address.c.

413{
414 struct Address *a = mutt_addr_new();
415 if (personal)
416 {
418 }
419 if (mailbox)
420 {
421 a->mailbox = buf_new(mailbox);
422 }
423 return a;
424}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_remove()

int mutt_addrlist_remove ( struct AddressList *  al,
const char *  mailbox 
)

Remove an Address from a list.

Parameters
[in,out]alAddressList
[in]mailboxEmail address to match
Return values
0Success
-1Error, or email not found

Definition at line 433 of file address.c.

434{
435 if (!al)
436 return -1;
437
438 if (!mailbox)
439 return 0;
440
441 int rc = -1;
442 struct Address *a = NULL, *tmp = NULL;
443 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
444 {
446 {
447 TAILQ_REMOVE(al, a, entries);
448 mutt_addr_free(&a);
449 rc = 0;
450 }
451 }
452
453 return rc;
454}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_free()

void mutt_addr_free ( struct Address **  ptr)

Free a single Address.

Parameters
[out]ptrAddress to free

Definition at line 460 of file address.c.

461{
462 if (!ptr || !*ptr)
463 return;
464
465 struct Address *a = *ptr;
466
467 buf_free(&a->personal);
468 buf_free(&a->mailbox);
469 FREE(ptr);
470}
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:331
#define FREE(x)
Definition: memory.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_parse()

int mutt_addrlist_parse ( struct AddressList *  al,
const char *  s 
)

Parse a list of email addresses.

Parameters
alAddressList to append addresses
sString to parse
Return values
numNumber of parsed addresses

Definition at line 478 of file address.c.

479{
480 if (!s)
481 return 0;
482
483 int parsed = 0;
484 char comment[1024], phrase[1024];
485 size_t phraselen = 0, commentlen = 0;
486
487 bool ws_pending = mutt_str_is_email_wsp(*s);
488
490 while (*s)
491 {
492 switch (*s)
493 {
494 case ';':
495 case ',':
496 if (phraselen != 0)
497 {
498 terminate_buffer(phrase, phraselen);
499 if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
500 {
501 parsed++;
502 }
503 }
504 else if (commentlen != 0)
505 {
506 struct Address *last = TAILQ_LAST(al, AddressList);
507 if (last && !last->personal && !buf_is_empty(last->mailbox))
508 {
509 terminate_buffer(comment, commentlen);
510 last->personal = buf_new(comment);
511 }
512 }
513
514 if (*s == ';')
515 {
516 /* add group terminator */
518 }
519
520 phraselen = 0;
521 commentlen = 0;
522 s++;
523 break;
524
525 case '(':
526 if ((commentlen != 0) && (commentlen < (sizeof(comment) - 1)))
527 comment[commentlen++] = ' ';
528 s = next_token(s, comment, &commentlen, sizeof(comment) - 1);
529 if (!s)
530 {
532 return 0;
533 }
534 break;
535
536 case '"':
537 if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)))
538 phrase[phraselen++] = ' ';
539 s = parse_quote(s + 1, phrase, &phraselen, sizeof(phrase) - 1);
540 if (!s)
541 {
543 return 0;
544 }
545 break;
546
547 case ':':
548 {
549 struct Address *a = mutt_addr_new();
550 terminate_buffer(phrase, phraselen);
551 if (phraselen != 0)
552 {
553 a->mailbox = buf_new(phrase);
554 }
555 a->group = true;
557 phraselen = 0;
558 commentlen = 0;
559 s++;
560 break;
561 }
562
563 case '<':
564 {
565 struct Address *a = mutt_addr_new();
566 terminate_buffer(phrase, phraselen);
567 if (phraselen != 0)
568 {
569 a->personal = buf_new(phrase);
570 }
571 s = parse_route_addr(s + 1, comment, &commentlen, sizeof(comment) - 1, a);
572 if (!s)
573 {
575 mutt_addr_free(&a);
576 return 0;
577 }
579 phraselen = 0;
580 commentlen = 0;
581 parsed++;
582 break;
583 }
584
585 default:
586 if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)) && ws_pending)
587 phrase[phraselen++] = ' ';
588 if (*s == '\\')
589 {
590 s++;
591 if (*s && (phraselen < (sizeof(phrase) - 1)))
592 {
593 phrase[phraselen++] = *s;
594 s++;
595 }
596 }
597 s = next_token(s, phrase, &phraselen, sizeof(phrase) - 1);
598 if (!s)
599 {
601 return 0;
602 }
603 break;
604 } // switch (*s)
605
606 ws_pending = mutt_str_is_email_wsp(*s);
608 } // while (*s)
609
610 if (phraselen != 0)
611 {
612 terminate_buffer(phrase, phraselen);
613 terminate_buffer(comment, commentlen);
614 if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
615 {
616 parsed++;
617 }
618 }
619 else if (commentlen != 0)
620 {
621 struct Address *last = TAILQ_LAST(al, AddressList);
622 if (last && buf_is_empty(last->personal) && !buf_is_empty(last->mailbox))
623 {
624 terminate_buffer(comment, commentlen);
625 buf_strcpy(last->personal, comment);
626 }
627 }
628
629 return parsed;
630}
static bool add_addrspec(struct AddressList *al, const char *phrase, char *comment, size_t *commentlen, size_t commentmax)
Parse an email address and add an Address to a list.
Definition: address.c:378
static const char * parse_route_addr(const char *s, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
Parse an email addresses.
Definition: address.c:298
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
#define TAILQ_LAST(head, headname)
Definition: queue.h:819
#define terminate_buffer(str, strlen)
Definition: string2.h:52
bool group
Group mailbox?
Definition: address.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_parse2()

int mutt_addrlist_parse2 ( struct AddressList *  al,
const char *  s 
)

Parse a list of email addresses.

Parameters
alAdd to this List of Addresses
sString to parse
Return values
numNumber of parsed addresses

Simple email addresses (without any personal name or grouping) can be separated by whitespace or commas.

Definition at line 641 of file address.c.

642{
643 if (!s || (*s == '\0'))
644 return 0;
645
646 int parsed = 0;
647
648 /* check for a simple whitespace separated list of addresses */
649 if (!strpbrk(s, "\"<>():;,\\"))
650 {
651 char *copy = mutt_str_dup(s);
652 char *r = copy;
653 while ((r = strtok(r, " \t")))
654 {
655 parsed += mutt_addrlist_parse(al, r);
656 r = NULL;
657 }
658 FREE(&copy);
659 }
660 else
661 {
662 parsed = mutt_addrlist_parse(al, s);
663 }
664
665 return parsed;
666}
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:478
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_qualify()

void mutt_addrlist_qualify ( struct AddressList *  al,
const char *  host 
)

Expand local names in an Address list using a hostname.

Parameters
alAddress list
hostHostname

Any addresses containing a bare name will be expanded using the hostname. e.g. "john", "example.com" -> 'john@.nosp@m.exam.nosp@m.ple.c.nosp@m.om'. This function has no effect if host is NULL or the empty string.

Definition at line 677 of file address.c.

678{
679 if (!al || !host || (*host == '\0'))
680 return;
681
682 struct Address *a = NULL;
683 TAILQ_FOREACH(a, al, entries)
684 {
685 if (!a->group && a->mailbox && !buf_find_char(a->mailbox, '@'))
686 {
687 buf_add_printf(a->mailbox, "@%s", host);
688 }
689 }
690}
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:216
const char * buf_find_char(const struct Buffer *buf, const char c)
Return a pointer to a char found in the buffer.
Definition: buffer.c:623
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_cat()

void mutt_addr_cat ( char *  buf,
size_t  buflen,
const char *  value,
const char *  specials 
)

Copy a string and wrap it in quotes if it contains special characters.

Parameters
bufBuffer for the result
buflenLength of the result buffer
valueString to copy
specialsCharacters to lookup

This function copies the string in the "value" parameter in the buffer pointed to by "buf" parameter. If the input string contains any of the characters specified in the "specials" parameters, the output string is wrapped in double quoted. Additionally, any backslashes or quotes inside the input string are backslash-escaped.

Definition at line 705 of file address.c.

706{
707 if (!buf || !value || !specials)
708 return;
709
710 if (strpbrk(value, specials))
711 {
712 char tmp[256] = { 0 };
713 char *pc = tmp;
714 size_t tmplen = sizeof(tmp) - 3;
715
716 *pc++ = '"';
717 for (; *value && (tmplen > 1); value++)
718 {
719 if ((*value == '\\') || (*value == '"'))
720 {
721 *pc++ = '\\';
722 tmplen--;
723 }
724 *pc++ = *value;
725 tmplen--;
726 }
727 *pc++ = '"';
728 *pc = '\0';
729 mutt_str_copy(buf, tmp, buflen);
730 }
731 else
732 {
733 mutt_str_copy(buf, value, buflen);
734 }
735}
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:653
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_copy()

struct Address * mutt_addr_copy ( const struct Address addr)

Copy the real address.

Parameters
addrAddress to copy
Return values
ptrNew Address

Definition at line 742 of file address.c.

743{
744 if (!addr)
745 return NULL;
746
747 struct Address *p = mutt_addr_new();
748 p->personal = buf_dup(addr->personal);
749 p->mailbox = buf_dup(addr->mailbox);
750 p->group = addr->group;
751 p->is_intl = addr->is_intl;
752 p->intl_checked = addr->intl_checked;
753 return p;
754}
struct Buffer * buf_dup(const struct Buffer *buf)
Copy a Buffer into a new allocated buffer.
Definition: buffer.c:557
bool intl_checked
Checked for IDN?
Definition: address.h:41
bool is_intl
International Domain Name.
Definition: address.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_copy()

void mutt_addrlist_copy ( struct AddressList *  dst,
const struct AddressList *  src,
bool  prune 
)

Copy a list of addresses into another list.

Parameters
dstDestination Address list
srcSource Address list
pruneSkip groups if there are more addresses

Definition at line 762 of file address.c.

763{
764 if (!dst || !src)
765 return;
766
767 struct Address *a = NULL;
768 TAILQ_FOREACH(a, src, entries)
769 {
770 struct Address *next = TAILQ_NEXT(a, entries);
771 if (prune && a->group && (!next || !next->mailbox))
772 {
773 /* ignore this element of the list */
774 }
775 else
776 {
778 }
779 }
780}
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:742
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_valid_msgid()

bool mutt_addr_valid_msgid ( const char *  msgid)

Is this a valid Message ID?

Parameters
msgidMessage ID
Return values
trueIt is a valid message ID

Incomplete. Only used to thwart the APOP MD5 attack

Definition at line 789 of file address.c.

790{
791 /* msg-id = "<" addr-spec ">"
792 * addr-spec = local-part "@" domain
793 * local-part = word *("." word)
794 * word = atom / quoted-string
795 * atom = 1*<any CHAR except specials, SPACE and CTLs>
796 * CHAR = ( 0.-127. )
797 * specials = "(" / ")" / "<" / ">" / "@"
798 * / "," / ";" / ":" / "\" / <">
799 * / "." / "[" / "]"
800 * SPACE = ( 32. )
801 * CTLS = ( 0.-31., 127.)
802 * quoted-string = <"> *(qtext/quoted-pair) <">
803 * qtext = <any CHAR except <">, "\" and CR>
804 * CR = ( 13. )
805 * quoted-pair = "\" CHAR
806 * domain = sub-domain *("." sub-domain)
807 * sub-domain = domain-ref / domain-literal
808 * domain-ref = atom
809 * domain-literal = "[" *(dtext / quoted-pair) "]"
810 */
811
812 if (!msgid || (*msgid == '\0'))
813 return false;
814
815 size_t l = mutt_str_len(msgid);
816 if (l < 5) /* <atom@atom> */
817 return false;
818 if ((msgid[0] != '<') || (msgid[l - 1] != '>'))
819 return false;
820 if (!(strrchr(msgid, '@')))
821 return false;
822
823 /* TODO: complete parser */
824 for (size_t i = 0; i < l; i++)
825 if ((unsigned char) msgid[i] > 127)
826 return false;
827
828 return true;
829}
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_addrlist_equal()

bool mutt_addrlist_equal ( const struct AddressList *  ala,
const struct AddressList *  alb 
)

Compare two Address lists for equality.

Parameters
alaFirst Address
albSecond Address
Return values
trueAddress lists are strictly identical

Definition at line 837 of file address.c.

838{
839 if (!ala || !alb)
840 {
841 return !(ala || alb);
842 }
843
844 struct Address *ana = TAILQ_FIRST(ala);
845 struct Address *anb = TAILQ_FIRST(alb);
846
847 while (ana && anb)
848 {
849 if (!buf_str_equal(ana->mailbox, anb->mailbox) ||
850 !buf_str_equal(ana->personal, anb->personal))
851 {
852 break;
853 }
854
855 ana = TAILQ_NEXT(ana, entries);
856 anb = TAILQ_NEXT(anb, entries);
857 }
858
859 return !(ana || anb);
860}
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition: buffer.c:653
#define TAILQ_FIRST(head)
Definition: queue.h:723
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_count_recips()

int mutt_addrlist_count_recips ( const struct AddressList *  al)

Count the number of Addresses with valid recipients.

Parameters
alAddress list
Return values
numNumber of valid Addresses

An Address has a recipient if the mailbox is set and is not a group

Definition at line 869 of file address.c.

870{
871 if (!al)
872 return 0;
873
874 int c = 0;
875 struct Address *a = NULL;
876 TAILQ_FOREACH(a, al, entries)
877 {
878 c += (a->mailbox && !a->group);
879 }
880 return c;
881}
+ Here is the caller graph for this function:

◆ mutt_addr_cmp()

bool mutt_addr_cmp ( const struct Address a,
const struct Address b 
)

Compare two e-mail addresses.

Parameters
aAddress 1
bAddress 2
Return values
trueThey are equivalent

Definition at line 889 of file address.c.

890{
891 if (!a || !b)
892 return false;
893 if (!a->mailbox || !b->mailbox)
894 return false;
895 if (!buf_istr_equal(a->mailbox, b->mailbox))
896 return false;
897 return true;
898}
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:665
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_search()

bool mutt_addrlist_search ( const struct AddressList *  haystack,
const struct Address needle 
)

Search for an e-mail address in a list.

Parameters
haystackAddress List
needleAddress containing the search email
Return values
trueThe Address is in the list

Definition at line 906 of file address.c.

907{
908 if (!needle || !haystack)
909 return false;
910
911 struct Address *a = NULL;
912 TAILQ_FOREACH(a, haystack, entries)
913 {
914 if (mutt_addr_cmp(needle, a))
915 return true;
916 }
917 return false;
918}
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:889
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addr_is_intl()

static bool addr_is_intl ( const struct Address a)
static

Does the Address have IDN components.

Parameters
aAddress to check
Return values
trueAddress contains IDN components

Definition at line 925 of file address.c.

926{
927 if (!a)
928 return false;
929 return a->intl_checked && a->is_intl;
930}
+ Here is the caller graph for this function:

◆ addr_is_local()

static bool addr_is_local ( const struct Address a)
static

Does the Address have NO IDN components.

Parameters
aAddress to check
Return values
trueAddress contains NO IDN components

Definition at line 937 of file address.c.

938{
939 if (!a)
940 return false;
941 return a->intl_checked && !a->is_intl;
942}
+ Here is the caller graph for this function:

◆ addr_mbox_to_udomain()

static int addr_mbox_to_udomain ( const char *  mbox,
char **  user,
char **  domain 
)
static

Split a mailbox name into user and domain.

Parameters
[in]mboxMailbox name to split
[out]userUser
[out]domainDomain
Return values
0Success
-1Error
Warning
The caller must free user and domain

Definition at line 954 of file address.c.

955{
956 if (!mbox || !user || !domain)
957 return -1;
958
959 char *ptr = strchr(mbox, '@');
960
961 /* Fail if '@' is missing, at the start, or at the end */
962 if (!ptr || (ptr == mbox) || (ptr[1] == '\0'))
963 return -1;
964
965 *user = mutt_strn_dup(mbox, ptr - mbox);
966 *domain = mutt_str_dup(ptr + 1);
967
968 return 0;
969}
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:452
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addr_set_intl()

static void addr_set_intl ( struct Address a,
char *  intl_mailbox 
)
static

Mark an Address as having IDN components.

Parameters
aAddress to modify
intl_mailboxEmail address with IDN components

Definition at line 976 of file address.c.

977{
978 if (!a)
979 return;
980
981 buf_strcpy(a->mailbox, intl_mailbox);
982 a->intl_checked = true;
983 a->is_intl = true;
984}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addr_set_local()

static void addr_set_local ( struct Address a,
char *  local_mailbox 
)
static

Mark an Address as having NO IDN components.

Parameters
aAddress
local_mailboxEmail address with NO IDN components

Definition at line 991 of file address.c.

992{
993 if (!a)
994 return;
995
996 buf_strcpy(a->mailbox, local_mailbox);
997 a->intl_checked = true;
998 a->is_intl = false;
999}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_for_display()

const char * mutt_addr_for_display ( const struct Address a)

Convert an Address for display purposes.

Parameters
aAddress to convert
Return values
ptrAddress to display
Warning
This function may return a static pointer. It must not be freed by the caller. Later calls may overwrite the returned pointer.

Definition at line 1009 of file address.c.

1010{
1011 if (!a)
1012 return NULL;
1013
1014 char *user = NULL, *domain = NULL;
1015 static char *buf = NULL;
1016
1017 if (!a->mailbox || addr_is_local(a))
1018 return buf_string(a->mailbox);
1019
1020 if (addr_mbox_to_udomain(buf_string(a->mailbox), &user, &domain) == -1)
1021 return buf_string(a->mailbox);
1022
1023 char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_MAY_BE_IRREVERSIBLE);
1024
1025 FREE(&user);
1026 FREE(&domain);
1027
1028 if (!local_mailbox)
1029 return buf_string(a->mailbox);
1030
1031 mutt_str_replace(&buf, local_mailbox);
1032 FREE(&local_mailbox);
1033
1034 return buf;
1035}
static int addr_mbox_to_udomain(const char *mbox, char **user, char **domain)
Split a mailbox name into user and domain.
Definition: address.c:954
static bool addr_is_local(const struct Address *a)
Does the Address have NO IDN components.
Definition: address.c:937
#define MI_MAY_BE_IRREVERSIBLE
Definition: idna2.h:30
char * mutt_idna_intl_to_local(const char *user, const char *domain, uint8_t flags)
Convert an email's domain from Punycode.
Definition: idna.c:116
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_write()

size_t mutt_addr_write ( struct Buffer buf,
struct Address addr,
bool  display 
)

Write a single Address to a buffer.

Parameters
bufBuffer for the Address
addrAddress to display
displayThis address will be displayed to the user
Return values
numLength of the string written to buf

If 'display' is set, then it doesn't matter if the transformation isn't reversible.

Definition at line 1047 of file address.c.

1048{
1049 if (!buf || !addr || (!addr->personal && !addr->mailbox))
1050 {
1051 return 0;
1052 }
1053
1054 const size_t initial_len = buf_len(buf);
1055
1056 if (addr->personal)
1057 {
1058 if (strpbrk(buf_string(addr->personal), AddressSpecials))
1059 {
1060 buf_addch(buf, '"');
1061 for (const char *pc = buf_string(addr->personal); *pc; pc++)
1062 {
1063 if ((*pc == '"') || (*pc == '\\'))
1064 {
1065 buf_addch(buf, '\\');
1066 }
1067 buf_addch(buf, *pc);
1068 }
1069 buf_addch(buf, '"');
1070 }
1071 else
1072 {
1073 buf_addstr(buf, buf_string(addr->personal));
1074 }
1075
1076 buf_addch(buf, ' ');
1077 }
1078
1079 if (addr->personal || (addr->mailbox && (buf_at(addr->mailbox, 0) == '@')))
1080 {
1081 buf_addch(buf, '<');
1082 }
1083
1084 if (addr->mailbox)
1085 {
1086 if (!mutt_str_equal(buf_string(addr->mailbox), "@"))
1087 {
1088 const char *a = display ? mutt_addr_for_display(addr) : buf_string(addr->mailbox);
1089 buf_addstr(buf, a);
1090 }
1091
1092 if (addr->personal || (addr->mailbox && (buf_at(addr->mailbox, 0) == '@')))
1093 {
1094 buf_addch(buf, '>');
1095 }
1096
1097 if (addr->group)
1098 {
1099 buf_addstr(buf, ": ");
1100 }
1101 }
1102 else
1103 {
1104 buf_addch(buf, ';');
1105 }
1106
1107 return buf_len(buf) - initial_len;
1108}
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:43
const char * mutt_addr_for_display(const struct Address *a)
Convert an Address for display purposes.
Definition: address.c:1009
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:638
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addrlist_write()

static size_t addrlist_write ( const struct AddressList *  al,
struct Buffer buf,
bool  display,
const char *  header,
int  cols 
)
static

Write an AddressList to a buffer, optionally perform line wrapping and display conversion.

Parameters
alAddressList to display
bufBuffer for the Address
displayTrue if these addresses will be displayed to the user
headerHeader name; if present, addresses we be written after ": "
colsMax columns at which to wrap, disabled if -1
Return values
numLength of the string written to buf

If 'display' is set, then it doesn't matter if the transformation isn't reversible.

Definition at line 1123 of file address.c.

1125{
1126 if (!buf || !al || TAILQ_EMPTY(al))
1127 return 0;
1128
1129 if (header)
1130 {
1131 buf_printf(buf, "%s: ", header);
1132 }
1133
1134 size_t cur_col = buf_len(buf);
1135 bool in_group = false;
1136 struct Address *a = NULL;
1137 TAILQ_FOREACH(a, al, entries)
1138 {
1139 struct Address *next = TAILQ_NEXT(a, entries);
1140
1141 if (a->group)
1142 {
1143 in_group = true;
1144 }
1145
1146 // wrap if needed
1147 const size_t cur_len = buf_len(buf);
1148 cur_col += mutt_addr_write(buf, a, display);
1149 if (cur_col > cols)
1150 {
1151 buf_insert(buf, cur_len, "\n\t");
1152 cur_col = 8;
1153 }
1154
1155 if (!a->group)
1156 {
1157 // group terminator
1158 if (in_group && !a->mailbox && !a->personal)
1159 {
1160 buf_addch(buf, ';');
1161 ++cur_col;
1162 in_group = false;
1163 }
1164 if (next && (next->mailbox || next->personal))
1165 {
1166 buf_addstr(buf, ", ");
1167 cur_col += 2;
1168 }
1169 if (!next)
1170 {
1171 break;
1172 }
1173 }
1174 }
1175
1176 return buf_len(buf);
1177}
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1047
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
size_t buf_insert(struct Buffer *buf, size_t offset, const char *s)
Add a string in the middle of a buffer.
Definition: buffer.c:268
#define TAILQ_EMPTY(head)
Definition: queue.h:721
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write_wrap()

size_t mutt_addrlist_write_wrap ( const struct AddressList *  al,
struct Buffer buf,
const char *  header 
)

Write an AddressList to a buffer, perform line wrapping.

Parameters
alAddressList to display
bufBuffer for the Address
headerHeader name; if present, addresses we be written after ": "
Return values
numLength of the string written to buf

If 'display' is set, then it doesn't matter if the transformation isn't reversible.

Definition at line 1190 of file address.c.

1192{
1193 return addrlist_write(al, buf, false, header, 74);
1194}
static size_t addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display, const char *header, int cols)
Write an AddressList to a buffer, optionally perform line wrapping and display conversion.
Definition: address.c:1123
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write()

size_t mutt_addrlist_write ( const struct AddressList *  al,
struct Buffer buf,
bool  display 
)

Write an Address to a buffer.

Parameters
alAddressList to display
bufBuffer for the Address
displayThis address will be displayed to the user
Return values
numLength of the string written to buf

If 'display' is set, then it doesn't matter if the transformation isn't reversible.

Definition at line 1207 of file address.c.

1208{
1209 return addrlist_write(al, buf, display, NULL, -1);
1210}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write_list()

size_t mutt_addrlist_write_list ( const struct AddressList *  al,
struct ListHead *  list 
)

Write Addresses to a List.

Parameters
alAddressList to write
listList for the Addresses
Return values
numNumber of addresses written

Definition at line 1218 of file address.c.

1219{
1220 if (!al || !list)
1221 return 0;
1222
1223 size_t count = 0;
1224 struct Address *a = NULL;
1225 TAILQ_FOREACH(a, al, entries)
1226 {
1227 struct Buffer buf = { 0 };
1228 mutt_addr_write(&buf, a, true);
1229 if (!buf_is_empty(&buf))
1230 {
1231 /* We're taking the ownership of the buffer string here */
1232 mutt_list_insert_tail(list, (char *) buf_string(&buf));
1233 count++;
1234 }
1235 }
1236
1237 return count;
1238}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
String manipulation buffer.
Definition: buffer.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write_file()

void mutt_addrlist_write_file ( const struct AddressList *  al,
FILE *  fp,
const char *  header 
)

Wrapper for mutt_write_address()

Parameters
alAddress list
fpFile to write to
headerHeader name; if present, addresses we be written after ": "

So we can handle very large recipient lists without needing a huge temporary buffer in memory

Definition at line 1249 of file address.c.

1250{
1251 struct Buffer *buf = buf_pool_get();
1252 mutt_addrlist_write_wrap(al, buf, header);
1253 fputs(buf_string(buf), fp);
1254 buf_pool_release(&buf);
1255 fputc('\n', fp);
1256}
size_t mutt_addrlist_write_wrap(const struct AddressList *al, struct Buffer *buf, const char *header)
Write an AddressList to a buffer, perform line wrapping.
Definition: address.c:1190
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_to_intl()

bool mutt_addr_to_intl ( struct Address a)

Convert an Address to Punycode.

Parameters
aAddress to convert
Return values
trueSuccess
falseOtherwise

Definition at line 1264 of file address.c.

1265{
1266 if (!a || !a->mailbox || addr_is_intl(a))
1267 return true;
1268
1269 char *user = NULL;
1270 char *domain = NULL;
1271 if (addr_mbox_to_udomain(buf_string(a->mailbox), &user, &domain) == -1)
1272 return true;
1273
1274 char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1275
1276 FREE(&user);
1277 FREE(&domain);
1278
1279 if (!intl_mailbox)
1280 return false;
1281
1282 addr_set_intl(a, intl_mailbox);
1283 FREE(&intl_mailbox);
1284 return true;
1285}
static bool addr_is_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:925
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:976
char * mutt_idna_local_to_intl(const char *user, const char *domain)
Convert an email's domain to Punycode.
Definition: idna.c:226
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_to_intl()

int mutt_addrlist_to_intl ( struct AddressList *  al,
char **  err 
)

Convert an Address list to Punycode.

Parameters
[in]alAddress list to modify
[out]errPointer for failed addresses
Return values
0Success, all addresses converted
-1Error, err will be set to the failed address

Definition at line 1294 of file address.c.

1295{
1296 if (!al)
1297 return 0;
1298
1299 int rc = 0;
1300
1301 if (err)
1302 *err = NULL;
1303
1304 struct Address *a = NULL;
1305 TAILQ_FOREACH(a, al, entries)
1306 {
1307 if (!a->mailbox || addr_is_intl(a))
1308 continue;
1309
1310 char *user = NULL;
1311 char *domain = NULL;
1312 if (addr_mbox_to_udomain(buf_string(a->mailbox), &user, &domain) == -1)
1313 continue;
1314
1315 char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1316
1317 FREE(&user);
1318 FREE(&domain);
1319
1320 if (!intl_mailbox)
1321 {
1322 rc = -1;
1323 if (err && !*err)
1324 *err = buf_strdup(a->mailbox);
1325 continue;
1326 }
1327
1328 addr_set_intl(a, intl_mailbox);
1329 FREE(&intl_mailbox);
1330 }
1331
1332 return rc;
1333}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:542
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_to_local()

bool mutt_addr_to_local ( struct Address a)

Convert an Address from Punycode.

Parameters
aAddress to convert
Return values
trueSuccess
falseOtherwise

Definition at line 1341 of file address.c.

1342{
1343 if (!a->mailbox)
1344 {
1345 return false;
1346 }
1347
1348 if (addr_is_local(a))
1349 {
1350 return true;
1351 }
1352
1353 char *user = NULL;
1354 char *domain = NULL;
1355 if (addr_mbox_to_udomain(buf_string(a->mailbox), &user, &domain) == -1)
1356 {
1357 return false;
1358 }
1359
1360 char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_NO_FLAGS);
1361 FREE(&user);
1362 FREE(&domain);
1363
1364 if (!local_mailbox)
1365 {
1366 return false;
1367 }
1368
1369 addr_set_local(a, local_mailbox);
1370 FREE(&local_mailbox);
1371 return true;
1372}
static void addr_set_local(struct Address *a, char *local_mailbox)
Mark an Address as having NO IDN components.
Definition: address.c:991
#define MI_NO_FLAGS
Definition: idna2.h:29
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_to_local()

int mutt_addrlist_to_local ( struct AddressList *  al)

Convert an Address list from Punycode.

Parameters
alAddress list to modify
Return values
0Always

Definition at line 1379 of file address.c.

1380{
1381 if (!al)
1382 return 0;
1383
1384 struct Address *a = NULL;
1385 TAILQ_FOREACH(a, al, entries)
1386 {
1388 }
1389 return 0;
1390}
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1341
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_dedupe()

void mutt_addrlist_dedupe ( struct AddressList *  al)

Remove duplicate addresses.

Parameters
alAddress list to de-dupe

Given a list of addresses, return a list of unique addresses

Definition at line 1398 of file address.c.

1399{
1400 if (!al)
1401 return;
1402
1403 struct Address *a = NULL;
1404 TAILQ_FOREACH(a, al, entries)
1405 {
1406 if (a->mailbox)
1407 {
1408 struct Address *a2 = TAILQ_NEXT(a, entries);
1409 struct Address *tmp = NULL;
1410
1411 if (a2)
1412 {
1413 TAILQ_FOREACH_FROM_SAFE(a2, al, entries, tmp)
1414 {
1415 if (a2->mailbox && buf_istr_equal(a->mailbox, a2->mailbox))
1416 {
1417 mutt_debug(LL_DEBUG2, "Removing %s\n", buf_string(a2->mailbox));
1418 TAILQ_REMOVE(al, a2, entries);
1419 mutt_addr_free(&a2);
1420 }
1421 }
1422 }
1423 }
1424 }
1425}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)
Definition: queue.h:740
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_remove_xrefs()

void mutt_addrlist_remove_xrefs ( const struct AddressList *  a,
struct AddressList *  b 
)

Remove cross-references.

Parameters
aReference AddressList
bAddressLis to trim

Remove addresses from "b" which are contained in "a"

Definition at line 1434 of file address.c.

1435{
1436 if (!a || !b)
1437 return;
1438
1439 struct Address *aa = NULL, *ab = NULL, *tmp = NULL;
1440
1441 TAILQ_FOREACH_SAFE(ab, b, entries, tmp)
1442 {
1443 TAILQ_FOREACH(aa, a, entries)
1444 {
1445 if (mutt_addr_cmp(aa, ab))
1446 {
1447 TAILQ_REMOVE(b, ab, entries);
1448 mutt_addr_free(&ab);
1449 break;
1450 }
1451 }
1452 }
1453}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_clear()

void mutt_addrlist_clear ( struct AddressList *  al)

Unlink and free all Address in an AddressList.

Parameters
alAddressList
Note
After this call, the AddressList is reinitialized and ready for reuse.

Definition at line 1461 of file address.c.

1462{
1463 if (!al)
1464 return;
1465
1466 struct Address *a = TAILQ_FIRST(al), *next = NULL;
1467 while (a)
1468 {
1469 next = TAILQ_NEXT(a, entries);
1470 mutt_addr_free(&a);
1471 a = next;
1472 }
1473 TAILQ_INIT(al);
1474}
#define TAILQ_INIT(head)
Definition: queue.h:765
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_append()

void mutt_addrlist_append ( struct AddressList *  al,
struct Address a 
)

Append an Address to an AddressList.

Parameters
alAddressList
aAddress

Definition at line 1481 of file address.c.

1482{
1483 if (al && a)
1484 TAILQ_INSERT_TAIL(al, a, entries);
1485}
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
+ Here is the caller graph for this function:

◆ mutt_addrlist_prepend()

void mutt_addrlist_prepend ( struct AddressList *  al,
struct Address a 
)

Prepend an Address to an AddressList.

Parameters
alAddressList
aAddress

Definition at line 1492 of file address.c.

1493{
1494 if (al && a)
1495 TAILQ_INSERT_HEAD(al, a, entries);
1496}
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:796
+ Here is the caller graph for this function:

◆ mutt_addr_uses_unicode()

bool mutt_addr_uses_unicode ( const char *  str)

Does this address use Unicode character.

Parameters
strAddress string to check
Return values
trueThe string uses 8-bit characters

Definition at line 1503 of file address.c.

1504{
1505 if (!str)
1506 return false;
1507
1508 while (*str)
1509 {
1510 if ((unsigned char) *str & (1 << 7))
1511 return true;
1512 str++;
1513 }
1514
1515 return false;
1516}
+ Here is the caller graph for this function:

◆ mutt_addrlist_uses_unicode()

bool mutt_addrlist_uses_unicode ( const struct AddressList *  al)

Do any of a list of addresses use Unicode characters.

Parameters
alAddress list to check
Return values
trueAny use 8-bit characters

Definition at line 1523 of file address.c.

1524{
1525 if (!al)
1526 {
1527 return false;
1528 }
1529
1530 struct Address *a = NULL;
1531 TAILQ_FOREACH(a, al, entries)
1532 {
1534 return true;
1535 }
1536 return false;
1537}
bool mutt_addr_uses_unicode(const char *str)
Does this address use Unicode character.
Definition: address.c:1503
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ AddressSpecials

const char AddressSpecials[] = "\"(),.:;<>@[\\]"

Characters with special meaning for email addresses.

Definition at line 43 of file address.c.