NeoMutt  2018-07-16 +2481-68dcde
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/mutt.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 Address *needle, const struct AddressList *haystack)
 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 (char *buf, size_t buflen, const struct AddressList *al, bool display)
 Write an Address to a buffer. 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?

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

78 {
79  int level = 1;
80 
81  while (*s && level)
82  {
83  if (*s == '(')
84  level++;
85  else if (*s == ')')
86  {
87  if (--level == 0)
88  {
89  s++;
90  break;
91  }
92  }
93  else if (*s == '\\')
94  {
95  if (!*++s)
96  break;
97  }
98  if (*commentlen < commentmax)
99  comment[(*commentlen)++] = *s;
100  s++;
101  }
102  if (level != 0)
103  {
105  return NULL;
106  }
107  return s;
108 }
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 119 of file address.c.

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

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

201 {
202  const char *ps = NULL;
203 
204  while (*s)
205  {
207  if (!*s)
208  return s;
209 
210  if (!strchr(nonspecial, *s) && is_special(*s))
211  return s;
212 
213  if (*s == '(')
214  {
215  if (*commentlen && (*commentlen < commentmax))
216  comment[(*commentlen)++] = ' ';
217  ps = next_token(s, comment, commentlen, commentmax);
218  }
219  else
220  ps = next_token(s, mailbox, mailboxlen, mailboxmax);
221  if (!ps)
222  return NULL;
223  s = ps;
224  }
225 
226  return s;
227 }
#define is_special(ch)
Is this character special to an email address?
Definition: address.c:47
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
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:150
+ 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 242 of file address.c.

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

284 {
285  char token[1024];
286  size_t tokenlen = 0;
287 
289 
290  /* find the end of the route */
291  if (*s == '@')
292  {
293  while (s && (*s == '@'))
294  {
295  if (tokenlen < (sizeof(token) - 1))
296  token[tokenlen++] = '@';
297  s = parse_mailboxdomain(s + 1, ",.\\[](", token, &tokenlen,
298  sizeof(token) - 1, comment, commentlen, commentmax);
299  }
300  if (!s || (*s != ':'))
301  {
303  return NULL; /* invalid route */
304  }
305 
306  if (tokenlen < (sizeof(token) - 1))
307  token[tokenlen++] = ':';
308  s++;
309  }
310 
311  s = parse_address(s, token, &tokenlen, sizeof(token) - 1, comment, commentlen,
312  commentmax, addr);
313  if (!s)
314  return NULL;
315 
316  if (*s != '>')
317  {
319  return NULL;
320  }
321 
322  if (!addr->mailbox)
323  addr->mailbox = mutt_str_strdup("@");
324 
325  s++;
326  return s;
327 }
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:197
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:242
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:776
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
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 338 of file address.c.

340 {
341  char token[1024];
342  size_t tokenlen = 0;
343 
344  s = parse_address(s, token, &tokenlen, sizeof(token) - 1, comment, commentlen,
345  commentmax, addr);
346  if (s && *s && (*s != ',') && (*s != ';'))
347  {
349  return NULL;
350  }
351  return s;
352 }
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:242
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 363 of file address.c.

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

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

398 {
399  struct Address *a = mutt_addr_new();
402  return a;
403 }
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:384
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
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
+ 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 412 of file address.c.

413 {
414  if (!al)
415  return -1;
416 
417  if (!mailbox)
418  return 0;
419 
420  int rc = -1;
421  struct Address *a = NULL, *tmp = NULL;
422  TAILQ_FOREACH_SAFE(a, al, entries, tmp)
423  {
424  if (mutt_str_strcasecmp(mailbox, a->mailbox) == 0)
425  {
426  TAILQ_REMOVE(al, a, entries);
427  mutt_addr_free(&a);
428  rc = 0;
429  }
430  }
431 
432  return rc;
433 }
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:729
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:439
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:821
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
+ 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 439 of file address.c.

440 {
441  if (!ptr || !*ptr)
442  return;
443 
444  struct Address *a = *ptr;
445 
446  FREE(&a->personal);
447  FREE(&a->mailbox);
448  FREE(ptr);
449 }
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 457 of file address.c.

458 {
459  if (!s)
460  return 0;
461 
462  int parsed = 0;
463  char comment[1024], phrase[1024];
464  size_t phraselen = 0, commentlen = 0;
465  AddressError = 0;
466 
467  bool ws_pending = mutt_str_is_email_wsp(*s);
468 
470  while (*s)
471  {
472  switch (*s)
473  {
474  case ';':
475  case ',':
476  if (phraselen != 0)
477  {
478  terminate_buffer(phrase, phraselen);
479  if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
480  {
481  parsed++;
482  }
483  }
484  else if (commentlen != 0)
485  {
486  struct Address *last = TAILQ_LAST(al, AddressList);
487  if (last && !last->personal)
488  {
489  terminate_buffer(comment, commentlen);
490  last->personal = mutt_str_strdup(comment);
491  }
492  }
493 
494  if (*s == ';')
495  {
496  /* add group terminator */
498  }
499 
500  phraselen = 0;
501  commentlen = 0;
502  s++;
503  break;
504 
505  case '(':
506  if ((commentlen != 0) && (commentlen < (sizeof(comment) - 1)))
507  comment[commentlen++] = ' ';
508  s = next_token(s, comment, &commentlen, sizeof(comment) - 1);
509  if (!s)
510  {
512  return 0;
513  }
514  break;
515 
516  case '"':
517  if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)))
518  phrase[phraselen++] = ' ';
519  s = parse_quote(s + 1, phrase, &phraselen, sizeof(phrase) - 1);
520  if (!s)
521  {
523  return 0;
524  }
525  break;
526 
527  case ':':
528  {
529  struct Address *a = mutt_addr_new();
530  terminate_buffer(phrase, phraselen);
531  a->mailbox = mutt_str_strdup(phrase);
532  a->group = true;
533  mutt_addrlist_append(al, a);
534  phraselen = 0;
535  commentlen = 0;
536  s++;
537  break;
538  }
539 
540  case '<':
541  {
542  struct Address *a = mutt_addr_new();
543  terminate_buffer(phrase, phraselen);
544  a->personal = mutt_str_strdup(phrase);
545  s = parse_route_addr(s + 1, comment, &commentlen, sizeof(comment) - 1, a);
546  if (!s)
547  {
549  mutt_addr_free(&a);
550  return 0;
551  }
552  mutt_addrlist_append(al, a);
553  phraselen = 0;
554  commentlen = 0;
555  parsed++;
556  break;
557  }
558 
559  default:
560  if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)) && ws_pending)
561  phrase[phraselen++] = ' ';
562  s = next_token(s, phrase, &phraselen, sizeof(phrase) - 1);
563  if (!s)
564  {
566  return 0;
567  }
568  break;
569  } // switch (*s)
570 
571  ws_pending = mutt_str_is_email_wsp(*s);
573  } // while (*s)
574 
575  if (phraselen != 0)
576  {
577  terminate_buffer(phrase, phraselen);
578  terminate_buffer(comment, commentlen);
579  if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
580  {
581  parsed++;
582  }
583  }
584  else if (commentlen != 0)
585  {
586  struct Address *last = TAILQ_LAST(al, AddressList);
587  if (last && !last->personal)
588  {
589  terminate_buffer(comment, commentlen);
590  last->personal = mutt_str_strdup(comment);
591  }
592  }
593 
594  return parsed;
595 }
#define TAILQ_LAST(head, headname)
Definition: queue.h:813
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1381
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:282
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:384
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:363
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:439
static const char * parse_quote(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
Extract a quoted string.
Definition: address.c:119
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:788
#define terminate_buffer(str, strlen)
Definition: string2.h:60
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
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:150
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1401
+ 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 606 of file address.c.

607 {
608  if (!s || !*s)
609  return 0;
610 
611  int parsed = 0;
612 
613  /* check for a simple whitespace separated list of addresses */
614  if (!strpbrk(s, "\"<>():;,\\"))
615  {
616  char *copy = mutt_str_strdup(s);
617  char *r = copy;
618  while ((r = strtok(r, " \t")))
619  {
620  parsed += mutt_addrlist_parse(al, r);
621  r = NULL;
622  }
623  FREE(&copy);
624  }
625  else
626  parsed = mutt_addrlist_parse(al, s);
627 
628  return parsed;
629 }
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:457
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#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 640 of file address.c.

641 {
642  if (!al || !host || !*host)
643  return;
644 
645  struct Address *a = NULL;
646  TAILQ_FOREACH(a, al, entries)
647  {
648  if (!a->group && a->mailbox && !strchr(a->mailbox, '@'))
649  {
650  char *p = mutt_mem_malloc(mutt_str_strlen(a->mailbox) + mutt_str_strlen(host) + 2);
651  sprintf(p, "%s@%s", a->mailbox, host);
652  FREE(&a->mailbox);
653  a->mailbox = p;
654  }
655  }
656 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
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 671 of file address.c.

672 {
673  if (!buf || !value || !specials)
674  return;
675 
676  if (strpbrk(value, specials))
677  {
678  char tmp[256];
679  char *pc = tmp;
680  size_t tmplen = sizeof(tmp) - 3;
681 
682  *pc++ = '"';
683  for (; *value && (tmplen > 1); value++)
684  {
685  if ((*value == '\\') || (*value == '"'))
686  {
687  *pc++ = '\\';
688  tmplen--;
689  }
690  *pc++ = *value;
691  tmplen--;
692  }
693  *pc++ = '"';
694  *pc = '\0';
695  mutt_str_strfcpy(buf, tmp, buflen);
696  }
697  else
698  mutt_str_strfcpy(buf, value, buflen);
699 }
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
+ 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 706 of file address.c.

707 {
708  if (!addr)
709  return NULL;
710 
711  struct Address *p = mutt_addr_new();
712 
713  p->personal = mutt_str_strdup(addr->personal);
714  p->mailbox = mutt_str_strdup(addr->mailbox);
715  p->group = addr->group;
716  p->is_intl = addr->is_intl;
717  p->intl_checked = addr->intl_checked;
718  return p;
719 }
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:384
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
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
+ 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 727 of file address.c.

728 {
729  if (!dst || !src)
730  return;
731 
732  struct Address *a = NULL;
733  TAILQ_FOREACH(a, src, entries)
734  {
735  struct Address *next = TAILQ_NEXT(a, entries);
736  if (prune && a->group && (!next || !next->mailbox))
737  {
738  /* ignore this element of the list */
739  }
740  else
741  {
743  }
744  }
745 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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:706
bool group
Group mailbox?
Definition: address.h:38
#define TAILQ_NEXT(elm, field)
Definition: queue.h:816
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1401
+ 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 (#2846).

Definition at line 754 of file address.c.

755 {
756  /* msg-id = "<" addr-spec ">"
757  * addr-spec = local-part "@" domain
758  * local-part = word *("." word)
759  * word = atom / quoted-string
760  * atom = 1*<any CHAR except specials, SPACE and CTLs>
761  * CHAR = ( 0.-127. )
762  * specials = "(" / ")" / "<" / ">" / "@"
763  * / "," / ";" / ":" / "\" / <">
764  * / "." / "[" / "]"
765  * SPACE = ( 32. )
766  * CTLS = ( 0.-31., 127.)
767  * quoted-string = <"> *(qtext/quoted-pair) <">
768  * qtext = <any CHAR except <">, "\" and CR>
769  * CR = ( 13. )
770  * quoted-pair = "\" CHAR
771  * domain = sub-domain *("." sub-domain)
772  * sub-domain = domain-ref / domain-literal
773  * domain-ref = atom
774  * domain-literal = "[" *(dtext / quoted-pair) "]"
775  */
776 
777  if (!msgid || !*msgid)
778  return false;
779 
780  size_t l = mutt_str_strlen(msgid);
781  if (l < 5) /* <atom@atom> */
782  return false;
783  if ((msgid[0] != '<') || (msgid[l - 1] != '>'))
784  return false;
785  if (!(strrchr(msgid, '@')))
786  return false;
787 
788  /* TODO: complete parser */
789  for (size_t i = 0; i < l; i++)
790  if ((unsigned char) msgid[i] > 127)
791  return false;
792 
793  return true;
794 }
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
+ 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 802 of file address.c.

803 {
804  if (!ala || !alb)
805  {
806  return !(ala || alb);
807  }
808 
809  struct Address *ana = TAILQ_FIRST(ala);
810  struct Address *anb = TAILQ_FIRST(alb);
811 
812  while (ana && anb)
813  {
814  if ((mutt_str_strcmp(ana->mailbox, anb->mailbox) != 0) ||
815  (mutt_str_strcmp(ana->personal, anb->personal) != 0))
816  {
817  break;
818  }
819 
820  ana = TAILQ_NEXT(ana, entries);
821  anb = TAILQ_NEXT(anb, entries);
822  }
823 
824  return !(ana || anb);
825 }
#define TAILQ_FIRST(head)
Definition: queue.h:717
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:816
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
+ 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 834 of file address.c.

835 {
836  if (!al)
837  return 0;
838 
839  int c = 0;
840  struct Address *a = NULL;
841  TAILQ_FOREACH(a, al, entries)
842  {
843  c += (a->mailbox && !a->group);
844  }
845  return c;
846 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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 854 of file address.c.

855 {
856  if (!a || !b)
857  return false;
858  if (!a->mailbox || !b->mailbox)
859  return false;
860  if (mutt_str_strcasecmp(a->mailbox, b->mailbox) != 0)
861  return false;
862  return true;
863 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
+ 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 Address needle,
const struct AddressList *  haystack 
)

Search for an e-mail address in a list.

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

Definition at line 871 of file address.c.

872 {
873  if (!needle || !haystack)
874  return false;
875 
876  struct Address *a = NULL;
877  TAILQ_FOREACH(a, haystack, entries)
878  {
879  if (mutt_addr_cmp(needle, a))
880  return true;
881  }
882  return false;
883 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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:854
+ 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 890 of file address.c.

891 {
892  if (!a)
893  return false;
894  return a->intl_checked && a->is_intl;
895 }
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 902 of file address.c.

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

920 {
921  if (!mbox || !user || !domain)
922  return -1;
923 
924  char *ptr = strchr(mbox, '@');
925 
926  /* Fail if '@' is missing, at the start, or at the end */
927  if (!ptr || (ptr == mbox) || (ptr[1] == '\0'))
928  return -1;
929 
930  *user = mutt_str_substr_dup(mbox, ptr);
931  *domain = mutt_str_strdup(ptr + 1);
932 
933  return 0;
934 }
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
char * mutt_str_substr_dup(const char *begin, const char *end)
Duplicate a sub-string.
Definition: string.c:579
+ 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 941 of file address.c.

942 {
943  if (!a)
944  return;
945 
946  FREE(&a->mailbox);
947  a->mailbox = intl_mailbox;
948  a->intl_checked = true;
949  a->is_intl = true;
950 }
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 957 of file address.c.

958 {
959  if (!a)
960  return;
961 
962  FREE(&a->mailbox);
963  a->mailbox = local_mailbox;
964  a->intl_checked = true;
965  a->is_intl = false;
966 }
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 976 of file address.c.

977 {
978  if (!a)
979  return NULL;
980 
981  char *user = NULL, *domain = NULL;
982  static char *buf = NULL;
983 
984  if (!a->mailbox || addr_is_local(a))
985  return a->mailbox;
986 
987  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
988  return a->mailbox;
989 
990  char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_MAY_BE_IRREVERSIBLE);
991 
992  FREE(&user);
993  FREE(&domain);
994 
995  if (!local_mailbox)
996  return a->mailbox;
997 
998  mutt_str_replace(&buf, local_mailbox);
999  FREE(&local_mailbox);
1000 
1001  return buf;
1002 }
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:919
static bool addr_is_local(const struct Address *a)
Does the Address have NO IDN components.
Definition: address.c:902
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
#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:145
+ 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 1015 of file address.c.

1016 {
1017  if (!buf || buflen == 0 || !addr)
1018  return 0;
1019 
1020  size_t len;
1021  char *pbuf = buf;
1022  char *pc = NULL;
1023 
1024  buflen--; /* save room for the terminal nul */
1025 
1026  if (addr->personal)
1027  {
1028  if (strpbrk(addr->personal, AddressSpecials))
1029  {
1030  if (buflen == 0)
1031  goto done;
1032  *pbuf++ = '"';
1033  buflen--;
1034  for (pc = addr->personal; *pc && (buflen > 0); pc++)
1035  {
1036  if ((*pc == '"') || (*pc == '\\'))
1037  {
1038  *pbuf++ = '\\';
1039  buflen--;
1040  }
1041  if (buflen == 0)
1042  goto done;
1043  *pbuf++ = *pc;
1044  buflen--;
1045  }
1046  if (buflen == 0)
1047  goto done;
1048  *pbuf++ = '"';
1049  buflen--;
1050  }
1051  else
1052  {
1053  if (buflen == 0)
1054  goto done;
1055  len = mutt_str_strfcpy(pbuf, addr->personal, buflen + 1 /* strfcpy terminates */);
1056  pbuf += len;
1057  buflen -= len;
1058  }
1059 
1060  if (buflen == 0)
1061  goto done;
1062  *pbuf++ = ' ';
1063  buflen--;
1064  }
1065 
1066  if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1067  {
1068  if (buflen == 0)
1069  goto done;
1070  *pbuf++ = '<';
1071  buflen--;
1072  }
1073 
1074  if (addr->mailbox)
1075  {
1076  if (buflen == 0)
1077  goto done;
1078  if (mutt_str_strcmp(addr->mailbox, "@") != 0)
1079  {
1080  const char *a = display ? mutt_addr_for_display(addr) : addr->mailbox;
1081  len = mutt_str_strfcpy(pbuf, a, buflen + 1 /* strfcpy terminates */);
1082  pbuf += len;
1083  buflen -= len;
1084  }
1085  else
1086  {
1087  *pbuf = '\0';
1088  }
1089 
1090  if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1091  {
1092  if (buflen == 0)
1093  goto done;
1094  *pbuf++ = '>';
1095  buflen--;
1096  }
1097 
1098  if (addr->group)
1099  {
1100  if (buflen == 0)
1101  goto done;
1102  *pbuf++ = ':';
1103  buflen--;
1104  if (buflen == 0)
1105  goto done;
1106  *pbuf++ = ' ';
1107  buflen--;
1108  }
1109  }
1110  else
1111  {
1112  if (buflen == 0)
1113  goto done;
1114  *pbuf++ = ';';
1115  }
1116 done:
1117  /* no need to check for length here since we already save space at the
1118  * beginning of this routine */
1119  *pbuf = '\0';
1120 
1121  return pbuf - buf;
1122 }
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:976
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:37
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write()

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

Write an Address to a buffer.

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

Note
It is assumed that buf is nul terminated!

Definition at line 1137 of file address.c.

1138 {
1139  if (!buf || buflen == 0 || !al)
1140  return 0;
1141 
1142  size_t len = mutt_str_strlen(buf);
1143  if (len >= buflen)
1144  {
1145  return 0;
1146  }
1147 
1148  char *pbuf = buf + len;
1149  buflen -= len;
1150 
1151  struct Address *a = NULL;
1152  TAILQ_FOREACH(a, al, entries)
1153  {
1154  if (len > 0)
1155  {
1156  if (buflen > 1)
1157  {
1158  *pbuf++ = ',';
1159  buflen--;
1160  }
1161  if (buflen > 1)
1162  {
1163  *pbuf++ = ' ';
1164  buflen--;
1165  }
1166  }
1167 
1168  if (buflen == 1)
1169  {
1170  break;
1171  }
1172 
1173  len = mutt_addr_write(pbuf, buflen, a, display);
1174  pbuf += len;
1175  buflen -= len;
1176  }
1177 
1178  *pbuf = '\0';
1179  return pbuf - buf;
1180 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
An email address.
Definition: address.h:34
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
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:1015
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:37
+ 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 1187 of file address.c.

1188 {
1189  if (!a || !a->mailbox || addr_is_intl(a))
1190  return true;
1191 
1192  char *user = NULL;
1193  char *domain = NULL;
1194  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1195  return true;
1196 
1197  char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1198 
1199  FREE(&user);
1200  FREE(&domain);
1201 
1202  if (!intl_mailbox)
1203  return false;
1204 
1205  addr_set_intl(a, intl_mailbox);
1206  return true;
1207 }
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:941
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:919
static bool addr_is_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:890
#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:263
+ 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 1216 of file address.c.

1217 {
1218  if (!al)
1219  return 0;
1220 
1221  int rc = 0;
1222 
1223  if (err)
1224  *err = NULL;
1225 
1226  struct Address *a = NULL;
1227  TAILQ_FOREACH(a, al, entries)
1228  {
1229  if (!a->mailbox || addr_is_intl(a))
1230  continue;
1231 
1232  char *user = NULL;
1233  char *domain = NULL;
1234  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1235  continue;
1236 
1237  char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1238 
1239  FREE(&user);
1240  FREE(&domain);
1241 
1242  if (!intl_mailbox)
1243  {
1244  rc = -1;
1245  if (err && !*err)
1246  *err = mutt_str_strdup(a->mailbox);
1247  continue;
1248  }
1249 
1250  addr_set_intl(a, intl_mailbox);
1251  }
1252 
1253  return rc;
1254 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:941
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:919
static bool addr_is_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:890
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#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:263
+ 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 1261 of file address.c.

1262 {
1263  if (!a->mailbox)
1264  {
1265  return false;
1266  }
1267 
1268  if (addr_is_local(a))
1269  {
1270  return true;
1271  }
1272 
1273  char *user = NULL;
1274  char *domain = NULL;
1275  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1276  {
1277  return false;
1278  }
1279 
1280  char *local_mailbox = mutt_idna_intl_to_local(user, domain, 0);
1281  FREE(&user);
1282  FREE(&domain);
1283 
1284  if (!local_mailbox)
1285  {
1286  return false;
1287  }
1288 
1289  addr_set_local(a, local_mailbox);
1290  return true;
1291 }
static void addr_set_local(struct Address *a, char *local_mailbox)
Mark an Address as having NO IDN components.
Definition: address.c:957
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:919
static bool addr_is_local(const struct Address *a)
Does the Address have NO IDN components.
Definition: address.c:902
#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:145
+ 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 1298 of file address.c.

1299 {
1300  if (!al)
1301  return 0;
1302 
1303  struct Address *a = NULL;
1304  TAILQ_FOREACH(a, al, entries)
1305  {
1306  mutt_addr_to_local(a);
1307  }
1308  return 0;
1309 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
An email address.
Definition: address.h:34
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1261
+ 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
Return values
ptrUpdated Address list

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

Definition at line 1318 of file address.c.

1319 {
1320  if (!al)
1321  return;
1322 
1323  struct Address *a = NULL;
1324  TAILQ_FOREACH(a, al, entries)
1325  {
1326  if (a->mailbox)
1327  {
1328  struct Address *a2 = TAILQ_NEXT(a, entries);
1329  struct Address *tmp = NULL;
1330 
1331  if (a2)
1332  {
1333  TAILQ_FOREACH_FROM_SAFE(a2, al, entries, tmp)
1334  {
1335  if (a2->mailbox && (mutt_str_strcasecmp(a->mailbox, a2->mailbox) == 0))
1336  {
1337  mutt_debug(LL_DEBUG2, "Removing %s\n", a2->mailbox);
1338  TAILQ_REMOVE(al, a2, entries);
1339  mutt_addr_free(&a2);
1340  }
1341  }
1342  }
1343  }
1344  }
1345 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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:439
Log at debug level 2.
Definition: logging.h:57
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:821
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)
Definition: queue.h:734
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#define TAILQ_NEXT(elm, field)
Definition: queue.h:816
#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 1354 of file address.c.

1355 {
1356  if (!a || !b)
1357  return;
1358 
1359  struct Address *aa = NULL, *ab = NULL, *tmp = NULL;
1360 
1361  TAILQ_FOREACH_SAFE(ab, b, entries, tmp)
1362  {
1363  TAILQ_FOREACH(aa, a, entries)
1364  {
1365  if (mutt_addr_cmp(aa, ab))
1366  {
1367  TAILQ_REMOVE(b, ab, entries);
1368  mutt_addr_free(&ab);
1369  break;
1370  }
1371  }
1372  }
1373 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:729
An email address.
Definition: address.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:439
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:821
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:854
+ 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 1381 of file address.c.

1382 {
1383  if (!al)
1384  return;
1385 
1386  struct Address *a = TAILQ_FIRST(al), *next = NULL;
1387  while (a)
1388  {
1389  next = TAILQ_NEXT(a, entries);
1390  mutt_addr_free(&a);
1391  a = next;
1392  }
1393  TAILQ_INIT(al);
1394 }
#define TAILQ_FIRST(head)
Definition: queue.h:717
An email address.
Definition: address.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:439
#define TAILQ_INIT(head)
Definition: queue.h:759
#define TAILQ_NEXT(elm, field)
Definition: queue.h:816
+ 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 1401 of file address.c.

1402 {
1403  if (al && a)
1404  TAILQ_INSERT_TAIL(al, a, entries);
1405 }
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:803
+ 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 1412 of file address.c.

1413 {
1414  if (al && a)
1415  TAILQ_INSERT_HEAD(al, a, entries);
1416 }
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:790
+ 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 56 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 63 of file address.c.