NeoMutt  2023-03-22
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 (struct Buffer *buf, struct Address *addr, bool display)
 Write a single Address to a buffer. More...
 
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. More...
 
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. More...
 
size_t mutt_addrlist_write (const struct AddressList *al, struct Buffer *buf, 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, const char *header)
 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:1455
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:1435
#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 ( 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 1024 of file address.c.

1025{
1026 if (!buf || !addr || (!addr->personal && !addr->mailbox))
1027 {
1028 return 0;
1029 }
1030
1031 const size_t initial_len = mutt_buffer_len(buf);
1032
1033 if (addr->personal)
1034 {
1035 if (strpbrk(addr->personal, AddressSpecials))
1036 {
1037 mutt_buffer_addch(buf, '"');
1038 for (const char *pc = addr->personal; *pc; pc++)
1039 {
1040 if ((*pc == '"') || (*pc == '\\'))
1041 {
1042 mutt_buffer_addch(buf, '\\');
1043 }
1044 mutt_buffer_addch(buf, *pc);
1045 }
1046 mutt_buffer_addch(buf, '"');
1047 }
1048 else
1049 {
1050 mutt_buffer_addstr(buf, addr->personal);
1051 }
1052
1053 mutt_buffer_addch(buf, ' ');
1054 }
1055
1056 if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1057 {
1058 mutt_buffer_addch(buf, '<');
1059 }
1060
1061 if (addr->mailbox)
1062 {
1063 if (!mutt_str_equal(addr->mailbox, "@"))
1064 {
1065 const char *a = display ? mutt_addr_for_display(addr) : addr->mailbox;
1066 mutt_buffer_addstr(buf, a);
1067 }
1068
1069 if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1070 {
1071 mutt_buffer_addch(buf, '>');
1072 }
1073
1074 if (addr->group)
1075 {
1076 mutt_buffer_addstr(buf, ": ");
1077 }
1078 }
1079 else
1080 {
1081 mutt_buffer_addch(buf, ';');
1082 }
1083
1084 return mutt_buffer_len(buf) - initial_len;
1085}
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
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:409
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addrlist_write()

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.

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 1100 of file address.c.

1102{
1103 if (!buf || !al || TAILQ_EMPTY(al))
1104 return 0;
1105
1106 if (header)
1107 {
1108 mutt_buffer_printf(buf, "%s: ", header);
1109 }
1110
1111 size_t cur_col = mutt_buffer_len(buf);
1112 bool in_group = false;
1113 struct Address *a = NULL;
1114 TAILQ_FOREACH(a, al, entries)
1115 {
1116 struct Address *next = TAILQ_NEXT(a, entries);
1117
1118 if (a->group)
1119 {
1120 in_group = true;
1121 }
1122
1123 // wrap if needed
1124 const size_t cur_len = mutt_buffer_len(buf);
1125 cur_col += mutt_addr_write(buf, a, display);
1126 if (cur_col > cols)
1127 {
1128 mutt_buffer_insert(buf, cur_len, "\n\t");
1129 cur_col = 8;
1130 }
1131
1132 if (!a->group)
1133 {
1134 // group terminator
1135 if (in_group && !a->mailbox && !a->personal)
1136 {
1137 mutt_buffer_addch(buf, ';');
1138 ++cur_col;
1139 in_group = false;
1140 }
1141 if (next && (next->mailbox || next->personal))
1142 {
1143 mutt_buffer_addstr(buf, ", ");
1144 cur_col += 2;
1145 }
1146 if (!next)
1147 {
1148 break;
1149 }
1150 }
1151 }
1152
1153 return mutt_buffer_len(buf);
1154}
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1024
size_t mutt_buffer_insert(struct Buffer *buf, size_t offset, const char *s)
Add a string in the middle of a buffer.
Definition: buffer.c:263
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
#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 1167 of file address.c.

1169{
1170 return addrlist_write(al, buf, false, header, 74);
1171}
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:1100
+ 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 1184 of file address.c.

1185{
1186 return addrlist_write(al, buf, display, NULL, -1);
1187}
+ 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 1195 of file address.c.

1196{
1197 if (!al || !list)
1198 return 0;
1199
1200 size_t count = 0;
1201 struct Address *a = NULL;
1202 TAILQ_FOREACH(a, al, entries)
1203 {
1204 struct Buffer buf = { 0 };
1205 mutt_addr_write(&buf, a, true);
1206 if (!mutt_buffer_is_empty(&buf))
1207 {
1208 /* We're taking the ownership of the buffer string here */
1209 mutt_list_insert_tail(list, (char *) mutt_buffer_string(&buf));
1210 count++;
1211 }
1212 }
1213
1214 return count;
1215}
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:298
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
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 1226 of file address.c.

1227{
1228 struct Buffer *buf = mutt_buffer_pool_get();
1229 mutt_addrlist_write_wrap(al, buf, header);
1230 fputs(mutt_buffer_string(buf), fp);
1232 fputc('\n', fp);
1233}
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:1167
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
+ 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 1241 of file address.c.

1242{
1243 if (!a || !a->mailbox || addr_is_intl(a))
1244 return true;
1245
1246 char *user = NULL;
1247 char *domain = NULL;
1248 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1249 return true;
1250
1251 char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1252
1253 FREE(&user);
1254 FREE(&domain);
1255
1256 if (!intl_mailbox)
1257 return false;
1258
1259 addr_set_intl(a, intl_mailbox);
1260 return true;
1261}
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 1270 of file address.c.

1271{
1272 if (!al)
1273 return 0;
1274
1275 int rc = 0;
1276
1277 if (err)
1278 *err = NULL;
1279
1280 struct Address *a = NULL;
1281 TAILQ_FOREACH(a, al, entries)
1282 {
1283 if (!a->mailbox || addr_is_intl(a))
1284 continue;
1285
1286 char *user = NULL;
1287 char *domain = NULL;
1288 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1289 continue;
1290
1291 char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1292
1293 FREE(&user);
1294 FREE(&domain);
1295
1296 if (!intl_mailbox)
1297 {
1298 rc = -1;
1299 if (err && !*err)
1300 *err = mutt_str_dup(a->mailbox);
1301 continue;
1302 }
1303
1304 addr_set_intl(a, intl_mailbox);
1305 }
1306
1307 return rc;
1308}
+ 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 1316 of file address.c.

1317{
1318 if (!a->mailbox)
1319 {
1320 return false;
1321 }
1322
1323 if (addr_is_local(a))
1324 {
1325 return true;
1326 }
1327
1328 char *user = NULL;
1329 char *domain = NULL;
1330 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1331 {
1332 return false;
1333 }
1334
1335 char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_NO_FLAGS);
1336 FREE(&user);
1337 FREE(&domain);
1338
1339 if (!local_mailbox)
1340 {
1341 return false;
1342 }
1343
1344 addr_set_local(a, local_mailbox);
1345 return true;
1346}
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 1353 of file address.c.

1354{
1355 if (!al)
1356 return 0;
1357
1358 struct Address *a = NULL;
1359 TAILQ_FOREACH(a, al, entries)
1360 {
1362 }
1363 return 0;
1364}
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1316
+ 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 1372 of file address.c.

1373{
1374 if (!al)
1375 return;
1376
1377 struct Address *a = NULL;
1378 TAILQ_FOREACH(a, al, entries)
1379 {
1380 if (a->mailbox)
1381 {
1382 struct Address *a2 = TAILQ_NEXT(a, entries);
1383 struct Address *tmp = NULL;
1384
1385 if (a2)
1386 {
1387 TAILQ_FOREACH_FROM_SAFE(a2, al, entries, tmp)
1388 {
1389 if (a2->mailbox && mutt_istr_equal(a->mailbox, a2->mailbox))
1390 {
1391 mutt_debug(LL_DEBUG2, "Removing %s\n", a2->mailbox);
1392 TAILQ_REMOVE(al, a2, entries);
1393 mutt_addr_free(&a2);
1394 }
1395 }
1396 }
1397 }
1398 }
1399}
#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 1408 of file address.c.

1409{
1410 if (!a || !b)
1411 return;
1412
1413 struct Address *aa = NULL, *ab = NULL, *tmp = NULL;
1414
1415 TAILQ_FOREACH_SAFE(ab, b, entries, tmp)
1416 {
1417 TAILQ_FOREACH(aa, a, entries)
1418 {
1419 if (mutt_addr_cmp(aa, ab))
1420 {
1421 TAILQ_REMOVE(b, ab, entries);
1422 mutt_addr_free(&ab);
1423 break;
1424 }
1425 }
1426 }
1427}
+ 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 1435 of file address.c.

1436{
1437 if (!al)
1438 return;
1439
1440 struct Address *a = TAILQ_FIRST(al), *next = NULL;
1441 while (a)
1442 {
1443 next = TAILQ_NEXT(a, entries);
1444 mutt_addr_free(&a);
1445 a = next;
1446 }
1447 TAILQ_INIT(al);
1448}
#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 1455 of file address.c.

1456{
1457 if (al && a)
1458 TAILQ_INSERT_TAIL(al, a, entries);
1459}
#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 1466 of file address.c.

1467{
1468 if (al && a)
1469 TAILQ_INSERT_HEAD(al, a, entries);
1470}
#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 1477 of file address.c.

1478{
1479 if (!str)
1480 return false;
1481
1482 while (*str)
1483 {
1484 if ((unsigned char) *str & (1 << 7))
1485 return true;
1486 str++;
1487 }
1488
1489 return false;
1490}
+ 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 1497 of file address.c.

1498{
1499 if (!al)
1500 {
1501 return false;
1502 }
1503
1504 struct Address *a = NULL;
1505 TAILQ_FOREACH(a, al, entries)
1506 {
1507 if (a->mailbox && !a->group && mutt_addr_uses_unicode(a->mailbox))
1508 return true;
1509 }
1510 return false;
1511}
bool mutt_addr_uses_unicode(const char *str)
Does this address use Unicode character.
Definition: address.c:1477
+ 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.