NeoMutt  2020-06-26-30-g76c339
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...
 
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...
 

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:48
Mismatched parentheses.
Definition: address.h:51
+ 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 }
Mismatches quotes.
Definition: address.h:52
AddressError
possible values for AddressError
Definition: address.h:48
+ 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:767
+ 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 }
#define is_special(ch)
Is this character special to an email address?
Definition: address.c:48
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:751
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
+ 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 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
char * mailbox
Mailbox and host address.
Definition: address.h:37
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 * personal
Real name of address.
Definition: address.h:36
#define terminate_string(str, strlen, buflen)
Definition: string2.h:50
+ 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];
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 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
char * mailbox
Mailbox and host address.
Definition: address.h:37
Bad route address.
Definition: address.h:54
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
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
AddressError
possible values for AddressError
Definition: address.h:48
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:751
Bad route.
Definition: address.h:53
+ 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];
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 }
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
AddressError
possible values for AddressError
Definition: address.h:48
Bad address specifier.
Definition: address.h:55
+ 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
boolTrue if an 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 }
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
An email address.
Definition: address.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
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_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1434
+ 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
An email address.
Definition: address.h:34
+ 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 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * personal
Real name of address.
Definition: address.h:36
+ 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 }
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:891
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
+ 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 }
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * personal
Real name of address.
Definition: address.h:36
#define FREE(x)
Definition: memory.h:40
+ 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)
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;
534  mutt_addrlist_append(al, a);
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  }
553  mutt_addrlist_append(al, a);
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)
598  {
599  terminate_buffer(comment, commentlen);
600  last->personal = mutt_str_dup(comment);
601  }
602  }
603 
604  return parsed;
605 }
#define TAILQ_LAST(head, headname)
Definition: queue.h:812
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1414
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
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
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
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
static const char * parse_quote(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
Extract a quoted string.
Definition: address.c:120
AddressError
possible values for AddressError
Definition: address.h:48
bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition: string.c:767
#define terminate_buffer(str, strlen)
Definition: string2.h:53
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:751
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
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
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1434
+ 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
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#define FREE(x)
Definition: memory.h:40
+ 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 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
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:639
bool group
Group mailbox?
Definition: address.h:38
#define FREE(x)
Definition: memory.h:40
+ 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];
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:724
+ 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 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
+ 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 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
bool group
Group mailbox?
Definition: address.h:38
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1434
+ 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 }
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:639
+ 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:879
#define TAILQ_FIRST(head)
Definition: queue.h:716
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * personal
Real name of address.
Definition: address.h:36
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
+ 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 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:38
+ 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
trueif they 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 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:891
+ 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
trueIf the 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 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
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 }
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
+ 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 }
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
+ 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_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:551
+ 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 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
#define FREE(x)
Definition: memory.h:40
+ 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 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
#define FREE(x)
Definition: memory.h:40
+ 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 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
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
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:450
#define FREE(x)
Definition: memory.h:40
#define MI_MAY_BE_IRREVERSIBLE
Definition: idna2.h:32
char * mutt_idna_intl_to_local(const char *user, const char *domain, int flags)
Convert an email&#39;s domain from Punycode.
Definition: idna.c:147
+ 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  size_t len;
1031  char *pbuf = buf;
1032  char *pc = NULL;
1033 
1034  buflen--; /* save room for the terminal nul */
1035 
1036  if (addr->personal)
1037  {
1038  if (strpbrk(addr->personal, AddressSpecials))
1039  {
1040  if (buflen == 0)
1041  goto done;
1042  *pbuf++ = '"';
1043  buflen--;
1044  for (pc = addr->personal; *pc && (buflen > 0); pc++)
1045  {
1046  if ((*pc == '"') || (*pc == '\\'))
1047  {
1048  *pbuf++ = '\\';
1049  buflen--;
1050  }
1051  if (buflen == 0)
1052  goto done;
1053  *pbuf++ = *pc;
1054  buflen--;
1055  }
1056  if (buflen == 0)
1057  goto done;
1058  *pbuf++ = '"';
1059  buflen--;
1060  }
1061  else
1062  {
1063  if (buflen == 0)
1064  goto done;
1065  len = mutt_str_copy(pbuf, addr->personal, buflen + 1);
1066  pbuf += len;
1067  buflen -= len;
1068  }
1069 
1070  if (buflen == 0)
1071  goto done;
1072  *pbuf++ = ' ';
1073  buflen--;
1074  }
1075 
1076  if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1077  {
1078  if (buflen == 0)
1079  goto done;
1080  *pbuf++ = '<';
1081  buflen--;
1082  }
1083 
1084  if (addr->mailbox)
1085  {
1086  if (buflen == 0)
1087  goto done;
1088  if (mutt_str_equal(addr->mailbox, "@"))
1089  {
1090  *pbuf = '\0';
1091  }
1092  else
1093  {
1094  const char *a = display ? mutt_addr_for_display(addr) : addr->mailbox;
1095  len = mutt_str_copy(pbuf, a, buflen + 1);
1096  pbuf += len;
1097  buflen -= len;
1098  }
1099 
1100  if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1101  {
1102  if (buflen == 0)
1103  goto done;
1104  *pbuf++ = '>';
1105  buflen--;
1106  }
1107 
1108  if (addr->group)
1109  {
1110  if (buflen == 0)
1111  goto done;
1112  *pbuf++ = ':';
1113  buflen--;
1114  if (buflen == 0)
1115  goto done;
1116  *pbuf++ = ' ';
1117  buflen--;
1118  }
1119  }
1120  else
1121  {
1122  if (buflen == 0)
1123  goto done;
1124  *pbuf++ = ';';
1125  }
1126 done:
1127  /* no need to check for length here since we already save space at the
1128  * beginning of this routine */
1129  *pbuf = '\0';
1130 
1131  return pbuf - buf;
1132 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:879
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
char * mailbox
Mailbox and host address.
Definition: address.h:37
const char * mutt_addr_for_display(const struct Address *a)
Convert an Address for display purposes.
Definition: address.c:986
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
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:724
static unsigned char * pbuf
Cache 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 1147 of file address.c.

1148 {
1149  if (!buf || buflen == 0 || !al)
1150  return 0;
1151 
1152  size_t len = mutt_str_len(buf);
1153  if (len >= buflen)
1154  {
1155  return 0;
1156  }
1157 
1158  char *pbuf = buf + len;
1159  buflen -= len;
1160 
1161  struct Address *a = NULL;
1162  TAILQ_FOREACH(a, al, entries)
1163  {
1164  if (len > 0)
1165  {
1166  if (buflen > 1)
1167  {
1168  *pbuf++ = ',';
1169  buflen--;
1170  }
1171  if (buflen > 1)
1172  {
1173  *pbuf++ = ' ';
1174  buflen--;
1175  }
1176  }
1177 
1178  if (buflen == 1)
1179  {
1180  break;
1181  }
1182 
1183  len = mutt_addr_write(pbuf, buflen, a, display);
1184  pbuf += len;
1185  buflen -= len;
1186  }
1187 
1188  *pbuf = '\0';
1189  return pbuf - buf;
1190 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
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
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:639
static unsigned char * pbuf
Cache 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_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 1198 of file address.c.

1199 {
1200  if (!al || !list)
1201  return 0;
1202 
1203  char addr[256];
1204  size_t count = 0;
1205  struct Address *a = NULL;
1206  TAILQ_FOREACH(a, al, entries)
1207  {
1208  mutt_addr_write(addr, sizeof(addr), a, true);
1209  mutt_list_insert_tail(list, strdup(addr));
1210  count++;
1211  }
1212 
1213  return count;
1214 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
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
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_addr_to_intl()

bool mutt_addr_to_intl ( struct Address a)

Convert an Address to Punycode.

Parameters
aAddress to convert
Return values
boolTrue on success, false otherwise

Definition at line 1221 of file address.c.

1222 {
1223  if (!a || !a->mailbox || addr_is_intl(a))
1224  return true;
1225 
1226  char *user = NULL;
1227  char *domain = NULL;
1228  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1229  return true;
1230 
1231  char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1232 
1233  FREE(&user);
1234  FREE(&domain);
1235 
1236  if (!intl_mailbox)
1237  return false;
1238 
1239  addr_set_intl(a, intl_mailbox);
1240  return true;
1241 }
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:951
char * mailbox
Mailbox and host address.
Definition: address.h:37
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_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:900
#define FREE(x)
Definition: memory.h:40
char * mutt_idna_local_to_intl(const char *user, const char *domain)
Convert an email&#39;s domain to Punycode.
Definition: idna.c:265
+ 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 1250 of file address.c.

1251 {
1252  if (!al)
1253  return 0;
1254 
1255  int rc = 0;
1256 
1257  if (err)
1258  *err = NULL;
1259 
1260  struct Address *a = NULL;
1261  TAILQ_FOREACH(a, al, entries)
1262  {
1263  if (!a->mailbox || addr_is_intl(a))
1264  continue;
1265 
1266  char *user = NULL;
1267  char *domain = NULL;
1268  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1269  continue;
1270 
1271  char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1272 
1273  FREE(&user);
1274  FREE(&domain);
1275 
1276  if (!intl_mailbox)
1277  {
1278  rc = -1;
1279  if (err && !*err)
1280  *err = mutt_str_dup(a->mailbox);
1281  continue;
1282  }
1283 
1284  addr_set_intl(a, intl_mailbox);
1285  }
1286 
1287  return rc;
1288 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:951
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
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_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:900
#define FREE(x)
Definition: memory.h:40
char * mutt_idna_local_to_intl(const char *user, const char *domain)
Convert an email&#39;s domain to Punycode.
Definition: idna.c:265
+ 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
boolTrue on success, false otherwise

Definition at line 1295 of file address.c.

1296 {
1297  if (!a->mailbox)
1298  {
1299  return false;
1300  }
1301 
1302  if (addr_is_local(a))
1303  {
1304  return true;
1305  }
1306 
1307  char *user = NULL;
1308  char *domain = NULL;
1309  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1310  {
1311  return false;
1312  }
1313 
1314  char *local_mailbox = mutt_idna_intl_to_local(user, domain, 0);
1315  FREE(&user);
1316  FREE(&domain);
1317 
1318  if (!local_mailbox)
1319  {
1320  return false;
1321  }
1322 
1323  addr_set_local(a, local_mailbox);
1324  return true;
1325 }
static void addr_set_local(struct Address *a, char *local_mailbox)
Mark an Address as having NO IDN components.
Definition: address.c:967
char * mailbox
Mailbox and host address.
Definition: address.h:37
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 FREE(x)
Definition: memory.h:40
char * mutt_idna_intl_to_local(const char *user, const char *domain, int flags)
Convert an email&#39;s domain from Punycode.
Definition: idna.c:147
+ 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 1332 of file address.c.

1333 {
1334  if (!al)
1335  return 0;
1336 
1337  struct Address *a = NULL;
1338  TAILQ_FOREACH(a, al, entries)
1339  {
1340  mutt_addr_to_local(a);
1341  }
1342  return 0;
1343 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1295
+ 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 1351 of file address.c.

1352 {
1353  if (!al)
1354  return;
1355 
1356  struct Address *a = NULL;
1357  TAILQ_FOREACH(a, al, entries)
1358  {
1359  if (a->mailbox)
1360  {
1361  struct Address *a2 = TAILQ_NEXT(a, entries);
1362  struct Address *tmp = NULL;
1363 
1364  if (a2)
1365  {
1366  TAILQ_FOREACH_FROM_SAFE(a2, al, entries, tmp)
1367  {
1368  if (a2->mailbox && mutt_istr_equal(a->mailbox, a2->mailbox))
1369  {
1370  mutt_debug(LL_DEBUG2, "Removing %s\n", a2->mailbox);
1371  TAILQ_REMOVE(al, a2, entries);
1372  mutt_addr_free(&a2);
1373  }
1374  }
1375  }
1376  }
1377  }
1378 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
Log at debug level 2.
Definition: logging.h:41
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:891
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)
Definition: queue.h:733
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ 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 1387 of file address.c.

1388 {
1389  if (!a || !b)
1390  return;
1391 
1392  struct Address *aa = NULL, *ab = NULL, *tmp = NULL;
1393 
1394  TAILQ_FOREACH_SAFE(ab, b, entries, tmp)
1395  {
1396  TAILQ_FOREACH(aa, a, entries)
1397  {
1398  if (mutt_addr_cmp(aa, ab))
1399  {
1400  TAILQ_REMOVE(b, ab, entries);
1401  mutt_addr_free(&ab);
1402  break;
1403  }
1404  }
1405  }
1406 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
An email address.
Definition: address.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
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:

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

1415 {
1416  if (!al)
1417  return;
1418 
1419  struct Address *a = TAILQ_FIRST(al), *next = NULL;
1420  while (a)
1421  {
1422  next = TAILQ_NEXT(a, entries);
1423  mutt_addr_free(&a);
1424  a = next;
1425  }
1426  TAILQ_INIT(al);
1427 }
#define TAILQ_FIRST(head)
Definition: queue.h:716
An email address.
Definition: address.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
#define TAILQ_INIT(head)
Definition: queue.h:758
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
+ 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 1434 of file address.c.

1435 {
1436  if (al && a)
1437  TAILQ_INSERT_TAIL(al, a, entries);
1438 }
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
+ 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 1445 of file address.c.

1446 {
1447  if (al && a)
1448  TAILQ_INSERT_HEAD(al, a, entries);
1449 }
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:789
+ 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.