NeoMutt  2022-04-29-247-gc6aae8
Teaching an old dog new tricks
DOXYGEN
address.c File Reference

Representation of an email address. More...

#include "config.h"
#include <stdbool.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)   strchr(AddressSpecials, ch)
 Is this character special to an email address? More...
 

Functions

static const char * parse_comment (const char *s, char *comment, size_t *commentlen, size_t commentmax)
 Extract a comment (parenthesised string) More...
 
static const char * parse_quote (const char *s, char *token, size_t *tokenlen, size_t tokenmax)
 Extract a quoted string. More...
 
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. More...
 
static const char * parse_mailboxdomain (const char *s, const char *nonspecial, 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) More...
 
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. More...
 
static const char * parse_route_addr (const char *s, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
 Parse an email addresses. More...
 
static const char * parse_addr_spec (const char *s, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
 Parse an email address. More...
 
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. More...
 
struct Addressmutt_addr_new (void)
 Create a new Address. More...
 
struct Addressmutt_addr_create (const char *personal, const char *mailbox)
 Create and populate a new Address. More...
 
int mutt_addrlist_remove (struct AddressList *al, const char *mailbox)
 Remove an Address from a list. More...
 
void mutt_addr_free (struct Address **ptr)
 Free a single Address. More...
 
int mutt_addrlist_parse (struct AddressList *al, const char *s)
 Parse a list of email addresses. More...
 
int mutt_addrlist_parse2 (struct AddressList *al, const char *s)
 Parse a list of email addresses. More...
 
void mutt_addrlist_qualify (struct AddressList *al, const char *host)
 Expand local names in an Address list using a hostname. More...
 
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. More...
 
struct Addressmutt_addr_copy (const struct Address *addr)
 Copy the real address. More...
 
void mutt_addrlist_copy (struct AddressList *dst, const struct AddressList *src, bool prune)
 Copy a list of addresses into another list. More...
 
bool mutt_addr_valid_msgid (const char *msgid)
 Is this a valid Message ID? More...
 
bool mutt_addrlist_equal (const struct AddressList *ala, const struct AddressList *alb)
 Compare two Address lists for equality. More...
 
int mutt_addrlist_count_recips (const struct AddressList *al)
 Count the number of Addresses with valid recipients. More...
 
bool mutt_addr_cmp (const struct Address *a, const struct Address *b)
 Compare two e-mail addresses. More...
 
bool mutt_addrlist_search (const struct AddressList *haystack, const struct Address *needle)
 Search for an e-mail address in a list. More...
 
static bool addr_is_intl (const struct Address *a)
 Does the Address have IDN components. More...
 
static bool addr_is_local (const struct Address *a)
 Does the Address have NO IDN components. More...
 
static int addr_mbox_to_udomain (const char *mbox, char **user, char **domain)
 Split a mailbox name into user and domain. More...
 
static void addr_set_intl (struct Address *a, char *intl_mailbox)
 Mark an Address as having IDN components. More...
 
static void addr_set_local (struct Address *a, char *local_mailbox)
 Mark an Address as having NO IDN components. More...
 
const char * mutt_addr_for_display (const struct Address *a)
 Convert an Address for display purposes. More...
 
size_t mutt_addr_write (char *buf, size_t buflen, struct Address *addr, bool display)
 Write a single Address to a buffer. More...
 
size_t mutt_addrlist_write (const struct AddressList *al, char *buf, size_t buflen, bool display)
 Write an Address to a buffer. More...
 
size_t mutt_addrlist_write_list (const struct AddressList *al, struct ListHead *list)
 Write Addresses to a List. More...
 
void mutt_addrlist_write_file (const struct AddressList *al, FILE *fp, int start_col, bool display)
 Wrapper for mutt_write_address() More...
 
bool mutt_addr_to_intl (struct Address *a)
 Convert an Address to Punycode. More...
 
int mutt_addrlist_to_intl (struct AddressList *al, char **err)
 Convert an Address list to Punycode. More...
 
bool mutt_addr_to_local (struct Address *a)
 Convert an Address from Punycode. More...
 
int mutt_addrlist_to_local (struct AddressList *al)
 Convert an Address list from Punycode. More...
 
void mutt_addrlist_dedupe (struct AddressList *al)
 Remove duplicate addresses. More...
 
void mutt_addrlist_remove_xrefs (const struct AddressList *a, struct AddressList *b)
 Remove cross-references. More...
 
void mutt_addrlist_clear (struct AddressList *al)
 Unlink and free all Address in an AddressList. More...
 
void mutt_addrlist_append (struct AddressList *al, struct Address *a)
 Append an Address to an AddressList. More...
 
void mutt_addrlist_prepend (struct AddressList *al, struct Address *a)
 Prepend an Address to an AddressList. More...
 
bool mutt_addr_uses_unicode (const char *str)
 Does this address use Unicode character. More...
 
bool mutt_addrlist_uses_unicode (const struct AddressList *al)
 Do any of a list of addresses use Unicode characters. More...
 

Variables

const char AddressSpecials [] = "@.,:;<>[]\\\"()"
 Characters with special meaning for email addresses. More...
 
int AddressError = 0
 An out-of-band error code. More...
 
const char *const AddressErrors []
 Messages for the error codes in AddressError. More...
 

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)    strchr(AddressSpecials, ch)

Is this character special to an email address?

Parameters
chCharacter

Definition at line 48 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 78 of file address.c.

79{
80 int level = 1;
81
82 while (*s && level)
83 {
84 if (*s == '(')
85 level++;
86 else if (*s == ')')
87 {
88 if (--level == 0)
89 {
90 s++;
91 break;
92 }
93 }
94 else if (*s == '\\')
95 {
96 if (!*++s)
97 break;
98 }
99 if (*commentlen < commentmax)
100 comment[(*commentlen)++] = *s;
101 s++;
102 }
103 if (level != 0)
104 {
106 return NULL;
107 }
108 return s;
109}
AddressError
Possible values for AddressError.
Definition: address.h:50
@ ADDR_ERR_MISMATCH_PAREN
Mismatched parentheses.
Definition: address.h:52
+ 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 120 of file address.c.

121{
122 while (*s)
123 {
124 if (*tokenlen < tokenmax)
125 token[*tokenlen] = *s;
126 if (*s == '\\')
127 {
128 if (!*++s)
129 break;
130
131 if (*tokenlen < tokenmax)
132 token[*tokenlen] = *s;
133 }
134 else if (*s == '"')
135 return s + 1;
136 (*tokenlen)++;
137 s++;
138 }
140 return NULL;
141}
@ ADDR_ERR_MISMATCH_QUOTE
Mismatches quotes.
Definition: address.h:53
+ 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 151 of file address.c.

152{
153 if (*s == '(')
154 return parse_comment(s + 1, token, tokenlen, tokenmax);
155 if (*s == '"')
156 return parse_quote(s + 1, token, tokenlen, tokenmax);
157 if (*s && is_special(*s))
158 {
159 if (*tokenlen < tokenmax)
160 token[(*tokenlen)++] = *s;
161 return s + 1;
162 }
163 while (*s)
164 {
165 if (mutt_str_is_email_wsp(*s) || is_special(*s))
166 break;
167 if (*tokenlen < tokenmax)
168 token[(*tokenlen)++] = *s;
169 s++;
170 }
171 return s;
172}
static const char * parse_comment(const char *s, char *comment, size_t *commentlen, size_t commentmax)
Extract a comment (parenthesised string)
Definition: address.c:78
#define is_special(ch)
Is this character special to an email address?
Definition: address.c:48
static const char * parse_quote(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
Extract a quoted string.
Definition: address.c:120
bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition: string.c:695
+ 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,
const char *  nonspecial,
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]nonspecialSpecific characters that are valid
[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 198 of file address.c.

202{
203 const char *ps = NULL;
204
205 while (*s)
206 {
208 if ((*s == '\0'))
209 return s;
210
211 if (!strchr(nonspecial, *s) && is_special(*s))
212 return s;
213
214 if (*s == '(')
215 {
216 if (*commentlen && (*commentlen < commentmax))
217 comment[(*commentlen)++] = ' ';
218 ps = next_token(s, comment, commentlen, commentmax);
219 }
220 else
221 ps = next_token(s, mailbox, mailboxlen, mailboxmax);
222 if (!ps)
223 return NULL;
224 s = ps;
225 }
226
227 return s;
228}
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:151
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:679
+ 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 243 of file address.c.

246{
247 s = parse_mailboxdomain(s, ".\"(\\", token, tokenlen, tokenmax, comment,
248 commentlen, commentmax);
249 if (!s)
250 return NULL;
251
252 if (*s == '@')
253 {
254 if (*tokenlen < tokenmax)
255 token[(*tokenlen)++] = '@';
256 s = parse_mailboxdomain(s + 1, ".([]\\", token, tokenlen, tokenmax, comment,
257 commentlen, commentmax);
258 if (!s)
259 return NULL;
260 }
261
262 terminate_string(token, *tokenlen, tokenmax);
263 addr->mailbox = mutt_str_dup(token);
264
265 if (*commentlen && !addr->personal)
266 {
267 terminate_string(comment, *commentlen, commentmax);
268 addr->personal = mutt_str_dup(comment);
269 }
270
271 return s;
272}
static const char * parse_mailboxdomain(const char *s, const char *nonspecial, 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:198
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
#define terminate_string(str, strlen, buflen)
Definition: string2.h:50
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
+ 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 283 of file address.c.

285{
286 char token[1024] = { 0 };
287 size_t tokenlen = 0;
288
290
291 /* find the end of the route */
292 if (*s == '@')
293 {
294 while (s && (*s == '@'))
295 {
296 if (tokenlen < (sizeof(token) - 1))
297 token[tokenlen++] = '@';
298 s = parse_mailboxdomain(s + 1, ",.\\[](", token, &tokenlen,
299 sizeof(token) - 1, comment, commentlen, commentmax);
300 }
301 if (!s || (*s != ':'))
302 {
304 return NULL; /* invalid route */
305 }
306
307 if (tokenlen < (sizeof(token) - 1))
308 token[tokenlen++] = ':';
309 s++;
310 }
311
312 s = parse_address(s, token, &tokenlen, sizeof(token) - 1, comment, commentlen,
313 commentmax, addr);
314 if (!s)
315 return NULL;
316
317 if (*s != '>')
318 {
320 return NULL;
321 }
322
323 if (!addr->mailbox)
324 addr->mailbox = mutt_str_dup("@");
325
326 s++;
327 return s;
328}
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:243
@ ADDR_ERR_BAD_ROUTE
Bad route.
Definition: address.h:54
@ ADDR_ERR_BAD_ROUTE_ADDR
Bad route address.
Definition: address.h:55
+ 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 339 of file address.c.

341{
342 char token[1024] = { 0 };
343 size_t tokenlen = 0;
344
345 s = parse_address(s, token, &tokenlen, sizeof(token) - 1, comment, commentlen,
346 commentmax, addr);
347 if (s && *s && (*s != ',') && (*s != ';'))
348 {
350 return NULL;
351 }
352 return s;
353}
@ ADDR_ERR_BAD_ADDR_SPEC
Bad address specifier.
Definition: address.h:56
+ 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 364 of file address.c.

366{
367 struct Address *cur = mutt_addr_new();
368
369 if (!parse_addr_spec(phrase, comment, commentlen, commentmax, cur))
370 {
371 mutt_addr_free(&cur);
372 return false;
373 }
374
375 mutt_addrlist_append(al, cur);
376 return true;
377}
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:339
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
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 385 of file address.c.

386{
387 return mutt_mem_calloc(1, sizeof(struct Address));
388}
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 398 of file address.c.

399{
400 struct Address *a = mutt_addr_new();
403 return a;
404}
+ 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 413 of file address.c.

414{
415 if (!al)
416 return -1;
417
418 if (!mailbox)
419 return 0;
420
421 int rc = -1;
422 struct Address *a = NULL, *tmp = NULL;
423 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
424 {
426 {
427 TAILQ_REMOVE(al, a, entries);
428 mutt_addr_free(&a);
429 rc = 0;
430 }
431 }
432
433 return rc;
434}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
#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 440 of file address.c.

441{
442 if (!ptr || !*ptr)
443 return;
444
445 struct Address *a = *ptr;
446
447 FREE(&a->personal);
448 FREE(&a->mailbox);
449 FREE(ptr);
450}
#define FREE(x)
Definition: memory.h:43
+ 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 458 of file address.c.

459{
460 if (!s)
461 return 0;
462
463 int parsed = 0;
464 char comment[1024], phrase[1024];
465 size_t phraselen = 0, commentlen = 0;
466 AddressError = 0;
467
468 bool ws_pending = mutt_str_is_email_wsp(*s);
469
471 while (*s)
472 {
473 switch (*s)
474 {
475 case ';':
476 case ',':
477 if (phraselen != 0)
478 {
479 terminate_buffer(phrase, phraselen);
480 if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
481 {
482 parsed++;
483 }
484 }
485 else if (commentlen != 0)
486 {
487 struct Address *last = TAILQ_LAST(al, AddressList);
488 if (last && !last->personal && last->mailbox)
489 {
490 terminate_buffer(comment, commentlen);
491 last->personal = mutt_str_dup(comment);
492 }
493 }
494
495 if (*s == ';')
496 {
497 /* add group terminator */
499 }
500
501 phraselen = 0;
502 commentlen = 0;
503 s++;
504 break;
505
506 case '(':
507 if ((commentlen != 0) && (commentlen < (sizeof(comment) - 1)))
508 comment[commentlen++] = ' ';
509 s = next_token(s, comment, &commentlen, sizeof(comment) - 1);
510 if (!s)
511 {
513 return 0;
514 }
515 break;
516
517 case '"':
518 if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)))
519 phrase[phraselen++] = ' ';
520 s = parse_quote(s + 1, phrase, &phraselen, sizeof(phrase) - 1);
521 if (!s)
522 {
524 return 0;
525 }
526 break;
527
528 case ':':
529 {
530 struct Address *a = mutt_addr_new();
531 terminate_buffer(phrase, phraselen);
532 a->mailbox = mutt_str_dup(phrase);
533 a->group = true;
535 phraselen = 0;
536 commentlen = 0;
537 s++;
538 break;
539 }
540
541 case '<':
542 {
543 struct Address *a = mutt_addr_new();
544 terminate_buffer(phrase, phraselen);
545 a->personal = mutt_str_dup(phrase);
546 s = parse_route_addr(s + 1, comment, &commentlen, sizeof(comment) - 1, a);
547 if (!s)
548 {
550 mutt_addr_free(&a);
551 return 0;
552 }
554 phraselen = 0;
555 commentlen = 0;
556 parsed++;
557 break;
558 }
559
560 default:
561 if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)) && ws_pending)
562 phrase[phraselen++] = ' ';
563 if (*s == '\\')
564 {
565 s++;
566 if (*s && (phraselen < (sizeof(phrase) - 1)))
567 {
568 phrase[phraselen++] = *s;
569 s++;
570 }
571 }
572 s = next_token(s, phrase, &phraselen, sizeof(phrase) - 1);
573 if (!s)
574 {
576 return 0;
577 }
578 break;
579 } // switch (*s)
580
581 ws_pending = mutt_str_is_email_wsp(*s);
583 } // while (*s)
584
585 if (phraselen != 0)
586 {
587 terminate_buffer(phrase, phraselen);
588 terminate_buffer(comment, commentlen);
589 if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
590 {
591 parsed++;
592 }
593 }
594 else if (commentlen != 0)
595 {
596 struct Address *last = TAILQ_LAST(al, AddressList);
597 if (last && !last->personal && last->mailbox)
598 {
599 terminate_buffer(comment, commentlen);
600 last->personal = mutt_str_dup(comment);
601 }
602 }
603
604 return parsed;
605}
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:364
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:283
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
#define TAILQ_LAST(head, headname)
Definition: queue.h:819
#define terminate_buffer(str, strlen)
Definition: string2.h:53
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 616 of file address.c.

617{
618 if (!s || (*s == '\0'))
619 return 0;
620
621 int parsed = 0;
622
623 /* check for a simple whitespace separated list of addresses */
624 if (!strpbrk(s, "\"<>():;,\\"))
625 {
626 char *copy = mutt_str_dup(s);
627 char *r = copy;
628 while ((r = strtok(r, " \t")))
629 {
630 parsed += mutt_addrlist_parse(al, r);
631 r = NULL;
632 }
633 FREE(&copy);
634 }
635 else
636 parsed = mutt_addrlist_parse(al, s);
637
638 return parsed;
639}
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
+ 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 650 of file address.c.

651{
652 if (!al || !host || (*host == '\0'))
653 return;
654
655 struct Address *a = NULL;
656 TAILQ_FOREACH(a, al, entries)
657 {
658 if (!a->group && a->mailbox && !strchr(a->mailbox, '@'))
659 {
660 char *p = mutt_mem_malloc(mutt_str_len(a->mailbox) + mutt_str_len(host) + 2);
661 sprintf(p, "%s@%s", a->mailbox, host);
662 FREE(&a->mailbox);
663 a->mailbox = p;
664 }
665 }
666}
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
#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 681 of file address.c.

682{
683 if (!buf || !value || !specials)
684 return;
685
686 if (strpbrk(value, specials))
687 {
688 char tmp[256] = { 0 };
689 char *pc = tmp;
690 size_t tmplen = sizeof(tmp) - 3;
691
692 *pc++ = '"';
693 for (; *value && (tmplen > 1); value++)
694 {
695 if ((*value == '\\') || (*value == '"'))
696 {
697 *pc++ = '\\';
698 tmplen--;
699 }
700 *pc++ = *value;
701 tmplen--;
702 }
703 *pc++ = '"';
704 *pc = '\0';
705 mutt_str_copy(buf, tmp, buflen);
706 }
707 else
708 mutt_str_copy(buf, value, buflen);
709}
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:652
+ 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 716 of file address.c.

717{
718 if (!addr)
719 return NULL;
720
721 struct Address *p = mutt_addr_new();
722
723 p->personal = mutt_str_dup(addr->personal);
724 p->mailbox = mutt_str_dup(addr->mailbox);
725 p->group = addr->group;
726 p->is_intl = addr->is_intl;
727 p->intl_checked = addr->intl_checked;
728 return p;
729}
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 737 of file address.c.

738{
739 if (!dst || !src)
740 return;
741
742 struct Address *a = NULL;
743 TAILQ_FOREACH(a, src, entries)
744 {
745 struct Address *next = TAILQ_NEXT(a, entries);
746 if (prune && a->group && (!next || !next->mailbox))
747 {
748 /* ignore this element of the list */
749 }
750 else
751 {
753 }
754 }
755}
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
#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 764 of file address.c.

765{
766 /* msg-id = "<" addr-spec ">"
767 * addr-spec = local-part "@" domain
768 * local-part = word *("." word)
769 * word = atom / quoted-string
770 * atom = 1*<any CHAR except specials, SPACE and CTLs>
771 * CHAR = ( 0.-127. )
772 * specials = "(" / ")" / "<" / ">" / "@"
773 * / "," / ";" / ":" / "\" / <">
774 * / "." / "[" / "]"
775 * SPACE = ( 32. )
776 * CTLS = ( 0.-31., 127.)
777 * quoted-string = <"> *(qtext/quoted-pair) <">
778 * qtext = <any CHAR except <">, "\" and CR>
779 * CR = ( 13. )
780 * quoted-pair = "\" CHAR
781 * domain = sub-domain *("." sub-domain)
782 * sub-domain = domain-ref / domain-literal
783 * domain-ref = atom
784 * domain-literal = "[" *(dtext / quoted-pair) "]"
785 */
786
787 if (!msgid || (*msgid == '\0'))
788 return false;
789
790 size_t l = mutt_str_len(msgid);
791 if (l < 5) /* <atom@atom> */
792 return false;
793 if ((msgid[0] != '<') || (msgid[l - 1] != '>'))
794 return false;
795 if (!(strrchr(msgid, '@')))
796 return false;
797
798 /* TODO: complete parser */
799 for (size_t i = 0; i < l; i++)
800 if ((unsigned char) msgid[i] > 127)
801 return false;
802
803 return true;
804}
+ 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 812 of file address.c.

813{
814 if (!ala || !alb)
815 {
816 return !(ala || alb);
817 }
818
819 struct Address *ana = TAILQ_FIRST(ala);
820 struct Address *anb = TAILQ_FIRST(alb);
821
822 while (ana && anb)
823 {
824 if (!mutt_str_equal(ana->mailbox, anb->mailbox) ||
825 !mutt_str_equal(ana->personal, anb->personal))
826 {
827 break;
828 }
829
830 ana = TAILQ_NEXT(ana, entries);
831 anb = TAILQ_NEXT(anb, entries);
832 }
833
834 return !(ana || anb);
835}
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
#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 844 of file address.c.

845{
846 if (!al)
847 return 0;
848
849 int c = 0;
850 struct Address *a = NULL;
851 TAILQ_FOREACH(a, al, entries)
852 {
853 c += (a->mailbox && !a->group);
854 }
855 return c;
856}
+ 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 864 of file address.c.

865{
866 if (!a || !b)
867 return false;
868 if (!a->mailbox || !b->mailbox)
869 return false;
870 if (!mutt_istr_equal(a->mailbox, b->mailbox))
871 return false;
872 return true;
873}
+ 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 881 of file address.c.

882{
883 if (!needle || !haystack)
884 return false;
885
886 struct Address *a = NULL;
887 TAILQ_FOREACH(a, haystack, entries)
888 {
889 if (mutt_addr_cmp(needle, a))
890 return true;
891 }
892 return false;
893}
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:864
+ 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 900 of file address.c.

901{
902 if (!a)
903 return false;
904 return a->intl_checked && a->is_intl;
905}
+ 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 912 of file address.c.

913{
914 if (!a)
915 return false;
916 return a->intl_checked && !a->is_intl;
917}
+ 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 929 of file address.c.

930{
931 if (!mbox || !user || !domain)
932 return -1;
933
934 char *ptr = strchr(mbox, '@');
935
936 /* Fail if '@' is missing, at the start, or at the end */
937 if (!ptr || (ptr == mbox) || (ptr[1] == '\0'))
938 return -1;
939
940 *user = mutt_strn_dup(mbox, ptr - mbox);
941 *domain = mutt_str_dup(ptr + 1);
942
943 return 0;
944}
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:451
+ 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 951 of file address.c.

952{
953 if (!a)
954 return;
955
956 FREE(&a->mailbox);
957 a->mailbox = intl_mailbox;
958 a->intl_checked = true;
959 a->is_intl = true;
960}
+ 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 967 of file address.c.

968{
969 if (!a)
970 return;
971
972 FREE(&a->mailbox);
973 a->mailbox = local_mailbox;
974 a->intl_checked = true;
975 a->is_intl = false;
976}
+ 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 986 of file address.c.

987{
988 if (!a)
989 return NULL;
990
991 char *user = NULL, *domain = NULL;
992 static char *buf = NULL;
993
994 if (!a->mailbox || addr_is_local(a))
995 return a->mailbox;
996
997 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
998 return a->mailbox;
999
1000 char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_MAY_BE_IRREVERSIBLE);
1001
1002 FREE(&user);
1003 FREE(&domain);
1004
1005 if (!local_mailbox)
1006 return a->mailbox;
1007
1008 mutt_str_replace(&buf, local_mailbox);
1009 FREE(&local_mailbox);
1010
1011 return buf;
1012}
static int addr_mbox_to_udomain(const char *mbox, char **user, char **domain)
Split a mailbox name into user and domain.
Definition: address.c:929
static bool addr_is_local(const struct Address *a)
Does the Address have NO IDN components.
Definition: address.c:912
#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:144
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_write()

size_t mutt_addr_write ( char *  buf,
size_t  buflen,
struct Address addr,
bool  display 
)

Write a single Address to a buffer.

Parameters
bufBuffer for the Address
buflenLength of the buffer
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 1025 of file address.c.

1026{
1027 if (!buf || (buflen == 0) || !addr)
1028 return 0;
1029
1030 if (!addr->personal && !addr->mailbox)
1031 return 0;
1032
1033 size_t len;
1034 char *pbuf = buf;
1035 char *pc = NULL;
1036
1037 buflen--; /* save room for the terminal nul */
1038
1039 if (addr->personal)
1040 {
1041 if (strpbrk(addr->personal, AddressSpecials))
1042 {
1043 if (buflen == 0)
1044 goto done;
1045 *pbuf++ = '"';
1046 buflen--;
1047 for (pc = addr->personal; *pc && (buflen > 0); pc++)
1048 {
1049 if ((*pc == '"') || (*pc == '\\'))
1050 {
1051 *pbuf++ = '\\';
1052 buflen--;
1053 }
1054 if (buflen == 0)
1055 goto done;
1056 *pbuf++ = *pc;
1057 buflen--;
1058 }
1059 if (buflen == 0)
1060 goto done;
1061 *pbuf++ = '"';
1062 buflen--;
1063 }
1064 else
1065 {
1066 if (buflen == 0)
1067 goto done;
1068 len = mutt_str_copy(pbuf, addr->personal, buflen + 1);
1069 pbuf += len;
1070 buflen -= len;
1071 }
1072
1073 if (buflen == 0)
1074 goto done;
1075 *pbuf++ = ' ';
1076 buflen--;
1077 }
1078
1079 if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1080 {
1081 if (buflen == 0)
1082 goto done;
1083 *pbuf++ = '<';
1084 buflen--;
1085 }
1086
1087 if (addr->mailbox)
1088 {
1089 if (buflen == 0)
1090 goto done;
1091 if (mutt_str_equal(addr->mailbox, "@"))
1092 {
1093 *pbuf = '\0';
1094 }
1095 else
1096 {
1097 const char *a = display ? mutt_addr_for_display(addr) : addr->mailbox;
1098 len = mutt_str_copy(pbuf, a, buflen + 1);
1099 pbuf += len;
1100 buflen -= len;
1101 }
1102
1103 if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1104 {
1105 if (buflen == 0)
1106 goto done;
1107 *pbuf++ = '>';
1108 buflen--;
1109 }
1110
1111 if (addr->group)
1112 {
1113 if (buflen == 0)
1114 goto done;
1115 *pbuf++ = ':';
1116 buflen--;
1117 if (buflen == 0)
1118 goto done;
1119 *pbuf++ = ' ';
1120 buflen--;
1121 }
1122 }
1123 else
1124 {
1125 if (buflen == 0)
1126 goto done;
1127 *pbuf++ = ';';
1128 }
1129done:
1130 /* no need to check for length here since we already save space at the
1131 * beginning of this routine */
1132 *pbuf = '\0';
1133
1134 return pbuf - buf;
1135}
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
const char * mutt_addr_for_display(const struct Address *a)
Convert an Address for display purposes.
Definition: address.c:986
static unsigned char * pbuf
Cached PGP data packet.
Definition: pgppacket.c:38
+ 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,
char *  buf,
size_t  buflen,
bool  display 
)

Write an Address to a buffer.

Parameters
alAddressList to display
bufBuffer for the Address
buflenLength of the buffer
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.

Note
It is assumed that buf is nul terminated!

Definition at line 1150 of file address.c.

1151{
1152 if (!buf || (buflen == 0) || !al)
1153 return 0;
1154
1155 size_t len = mutt_str_len(buf);
1156 if (len >= buflen)
1157 {
1158 return 0;
1159 }
1160
1161 char *pbuf = buf + len;
1162 buflen -= len;
1163
1164 struct Address *a = NULL;
1165 TAILQ_FOREACH(a, al, entries)
1166 {
1167 if (len > 0)
1168 {
1169 if (buflen > 1)
1170 {
1171 *pbuf++ = ',';
1172 buflen--;
1173 }
1174 if (buflen > 1)
1175 {
1176 *pbuf++ = ' ';
1177 buflen--;
1178 }
1179 }
1180
1181 if (buflen == 1)
1182 {
1183 break;
1184 }
1185
1186 len = mutt_addr_write(pbuf, buflen, a, display);
1187 pbuf += len;
1188 buflen -= len;
1189 }
1190
1191 *pbuf = '\0';
1192 return pbuf - buf;
1193}
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1025
+ 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 1201 of file address.c.

1202{
1203 if (!al || !list)
1204 return 0;
1205
1206 char addr[256] = { 0 };
1207 size_t count = 0;
1208 struct Address *a = NULL;
1209 TAILQ_FOREACH(a, al, entries)
1210 {
1211 if (mutt_addr_write(addr, sizeof(addr), a, true) != 0)
1212 {
1213 mutt_list_insert_tail(list, strdup(addr));
1214 count++;
1215 }
1216 }
1217
1218 return count;
1219}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
+ 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,
int  start_col,
bool  display 
)

Wrapper for mutt_write_address()

Parameters
alAddress list
fpFile to write to
start_colStarting column in the output line
displayTrue if these addresses will be displayed to the user

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

Definition at line 1231 of file address.c.

1232{
1233 char buf[1024] = { 0 };
1234 int count = 0;
1235 int linelen = start_col;
1236
1237 struct Address *a = NULL;
1238 TAILQ_FOREACH(a, al, entries)
1239 {
1240 buf[0] = '\0';
1241 size_t len = mutt_addr_write(buf, sizeof(buf), a, display);
1242 if (len == 0)
1243 continue;
1244 if (count && (linelen + len > 74))
1245 {
1246 fputs("\n\t", fp);
1247 linelen = len + 8; /* tab is usually about 8 spaces... */
1248 }
1249 else
1250 {
1251 if (count && a->mailbox)
1252 {
1253 fputc(' ', fp);
1254 linelen++;
1255 }
1256 linelen += len;
1257 }
1258 fputs(buf, fp);
1259 struct Address *next = TAILQ_NEXT(a, entries);
1260 if (!a->group && next && next->mailbox)
1261 {
1262 linelen++;
1263 fputc(',', fp);
1264 }
1265 count++;
1266 }
1267 fputc('\n', fp);
1268}
+ 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 1276 of file address.c.

1277{
1278 if (!a || !a->mailbox || addr_is_intl(a))
1279 return true;
1280
1281 char *user = NULL;
1282 char *domain = NULL;
1283 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1284 return true;
1285
1286 char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1287
1288 FREE(&user);
1289 FREE(&domain);
1290
1291 if (!intl_mailbox)
1292 return false;
1293
1294 addr_set_intl(a, intl_mailbox);
1295 return true;
1296}
static bool addr_is_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:900
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:951
char * mutt_idna_local_to_intl(const char *user, const char *domain)
Convert an email's domain to Punycode.
Definition: idna.c:264
+ 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 1305 of file address.c.

1306{
1307 if (!al)
1308 return 0;
1309
1310 int rc = 0;
1311
1312 if (err)
1313 *err = NULL;
1314
1315 struct Address *a = NULL;
1316 TAILQ_FOREACH(a, al, entries)
1317 {
1318 if (!a->mailbox || addr_is_intl(a))
1319 continue;
1320
1321 char *user = NULL;
1322 char *domain = NULL;
1323 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1324 continue;
1325
1326 char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1327
1328 FREE(&user);
1329 FREE(&domain);
1330
1331 if (!intl_mailbox)
1332 {
1333 rc = -1;
1334 if (err && !*err)
1335 *err = mutt_str_dup(a->mailbox);
1336 continue;
1337 }
1338
1339 addr_set_intl(a, intl_mailbox);
1340 }
1341
1342 return rc;
1343}
+ 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 1351 of file address.c.

1352{
1353 if (!a->mailbox)
1354 {
1355 return false;
1356 }
1357
1358 if (addr_is_local(a))
1359 {
1360 return true;
1361 }
1362
1363 char *user = NULL;
1364 char *domain = NULL;
1365 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1366 {
1367 return false;
1368 }
1369
1370 char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_NO_FLAGS);
1371 FREE(&user);
1372 FREE(&domain);
1373
1374 if (!local_mailbox)
1375 {
1376 return false;
1377 }
1378
1379 addr_set_local(a, local_mailbox);
1380 return true;
1381}
static void addr_set_local(struct Address *a, char *local_mailbox)
Mark an Address as having NO IDN components.
Definition: address.c:967
#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 1388 of file address.c.

1389{
1390 if (!al)
1391 return 0;
1392
1393 struct Address *a = NULL;
1394 TAILQ_FOREACH(a, al, entries)
1395 {
1397 }
1398 return 0;
1399}
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1351
+ 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 1407 of file address.c.

1408{
1409 if (!al)
1410 return;
1411
1412 struct Address *a = NULL;
1413 TAILQ_FOREACH(a, al, entries)
1414 {
1415 if (a->mailbox)
1416 {
1417 struct Address *a2 = TAILQ_NEXT(a, entries);
1418 struct Address *tmp = NULL;
1419
1420 if (a2)
1421 {
1422 TAILQ_FOREACH_FROM_SAFE(a2, al, entries, tmp)
1423 {
1424 if (a2->mailbox && mutt_istr_equal(a->mailbox, a2->mailbox))
1425 {
1426 mutt_debug(LL_DEBUG2, "Removing %s\n", a2->mailbox);
1427 TAILQ_REMOVE(al, a2, entries);
1428 mutt_addr_free(&a2);
1429 }
1430 }
1431 }
1432 }
1433 }
1434}
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
#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 1443 of file address.c.

1444{
1445 if (!a || !b)
1446 return;
1447
1448 struct Address *aa = NULL, *ab = NULL, *tmp = NULL;
1449
1450 TAILQ_FOREACH_SAFE(ab, b, entries, tmp)
1451 {
1452 TAILQ_FOREACH(aa, a, entries)
1453 {
1454 if (mutt_addr_cmp(aa, ab))
1455 {
1456 TAILQ_REMOVE(b, ab, entries);
1457 mutt_addr_free(&ab);
1458 break;
1459 }
1460 }
1461 }
1462}
+ 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 1470 of file address.c.

1471{
1472 if (!al)
1473 return;
1474
1475 struct Address *a = TAILQ_FIRST(al), *next = NULL;
1476 while (a)
1477 {
1478 next = TAILQ_NEXT(a, entries);
1479 mutt_addr_free(&a);
1480 a = next;
1481 }
1482 TAILQ_INIT(al);
1483}
#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 1490 of file address.c.

1491{
1492 if (al && a)
1493 TAILQ_INSERT_TAIL(al, a, entries);
1494}
#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 1501 of file address.c.

1502{
1503 if (al && a)
1504 TAILQ_INSERT_HEAD(al, a, entries);
1505}
#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 1512 of file address.c.

1513{
1514 if (!str)
1515 return false;
1516
1517 while (*str)
1518 {
1519 if ((unsigned char) *str & (1 << 7))
1520 return true;
1521 str++;
1522 }
1523
1524 return false;
1525}
+ 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 1532 of file address.c.

1533{
1534 if (!al)
1535 {
1536 return false;
1537 }
1538
1539 struct Address *a = NULL;
1540 TAILQ_FOREACH(a, al, entries)
1541 {
1542 if (a->mailbox && !a->group && mutt_addr_uses_unicode(a->mailbox))
1543 return true;
1544 }
1545 return false;
1546}
bool mutt_addr_uses_unicode(const char *str)
Does this address use Unicode character.
Definition: address.c:1512
+ 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 42 of file address.c.

◆ AddressError

int AddressError = 0

An out-of-band error code.

Many of the Address functions set this variable on error. Its values are defined in AddressError. Text for the errors can be looked up using AddressErrors.

Definition at line 57 of file address.c.

◆ AddressErrors

const char* const AddressErrors[]
Initial value:
= {
"out of memory", "mismatched parentheses", "mismatched quotes",
"bad route in <>", "bad address in <>", "bad address spec",
}

Messages for the error codes in AddressError.

These must defined in the same order as enum AddressError.

Definition at line 64 of file address.c.