NeoMutt  2019-12-07-60-g0cfa53
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 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...
 
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: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 198 of file address.c.

202 {
203  const char *ps = NULL;
204 
205  while (*s)
206  {
208  if (!*s)
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: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: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_strdup(token);
264 
265  if (*commentlen && !addr->personal)
266  {
267  terminate_string(comment, *commentlen, commentmax);
268  addr->personal = mutt_str_strdup(comment);
269  }
270 
271  return s;
272 }
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
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 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_strdup("@");
325 
326  s++;
327  return s;
328 }
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: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 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:1402
+ 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 }
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
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 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  {
425  if (mutt_str_strcasecmp(mailbox, a->mailbox) == 0)
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
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
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 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_strdup(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_strdup(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_strdup(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  s = next_token(s, phrase, &phraselen, sizeof(phrase) - 1);
564  if (!s)
565  {
567  return 0;
568  }
569  break;
570  } // switch (*s)
571 
572  ws_pending = mutt_str_is_email_wsp(*s);
574  } // while (*s)
575 
576  if (phraselen != 0)
577  {
578  terminate_buffer(phrase, phraselen);
579  terminate_buffer(comment, commentlen);
580  if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
581  {
582  parsed++;
583  }
584  }
585  else if (commentlen != 0)
586  {
587  struct Address *last = TAILQ_LAST(al, AddressList);
588  if (last && !last->personal)
589  {
590  terminate_buffer(comment, commentlen);
591  last->personal = mutt_str_strdup(comment);
592  }
593  }
594 
595  return parsed;
596 }
#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:1382
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
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: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:151
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1402
+ 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 607 of file address.c.

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

642 {
643  if (!al || !host || !*host)
644  return;
645 
646  struct Address *a = NULL;
647  TAILQ_FOREACH(a, al, entries)
648  {
649  if (!a->group && a->mailbox && !strchr(a->mailbox, '@'))
650  {
651  char *p = mutt_mem_malloc(mutt_str_strlen(a->mailbox) + mutt_str_strlen(host) + 2);
652  sprintf(p, "%s@%s", a->mailbox, host);
653  FREE(&a->mailbox);
654  a->mailbox = p;
655  }
656  }
657 }
#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
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 672 of file address.c.

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

708 {
709  if (!addr)
710  return NULL;
711 
712  struct Address *p = mutt_addr_new();
713 
714  p->personal = mutt_str_strdup(addr->personal);
715  p->mailbox = mutt_str_strdup(addr->mailbox);
716  p->group = addr->group;
717  p->is_intl = addr->is_intl;
718  p->intl_checked = addr->intl_checked;
719  return p;
720 }
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
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 728 of file address.c.

729 {
730  if (!dst || !src)
731  return;
732 
733  struct Address *a = NULL;
734  TAILQ_FOREACH(a, src, entries)
735  {
736  struct Address *next = TAILQ_NEXT(a, entries);
737  if (prune && a->group && (!next || !next->mailbox))
738  {
739  /* ignore this element of the list */
740  }
741  else
742  {
744  }
745  }
746 }
#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:707
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:1402
+ 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 755 of file address.c.

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

804 {
805  if (!ala || !alb)
806  {
807  return !(ala || alb);
808  }
809 
810  struct Address *ana = TAILQ_FIRST(ala);
811  struct Address *anb = TAILQ_FIRST(alb);
812 
813  while (ana && anb)
814  {
815  if ((mutt_str_strcmp(ana->mailbox, anb->mailbox) != 0) ||
816  (mutt_str_strcmp(ana->personal, anb->personal) != 0))
817  {
818  break;
819  }
820 
821  ana = TAILQ_NEXT(ana, entries);
822  anb = TAILQ_NEXT(anb, entries);
823  }
824 
825  return !(ana || anb);
826 }
#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
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 835 of file address.c.

836 {
837  if (!al)
838  return 0;
839 
840  int c = 0;
841  struct Address *a = NULL;
842  TAILQ_FOREACH(a, al, entries)
843  {
844  c += (a->mailbox && !a->group);
845  }
846  return c;
847 }
#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 855 of file address.c.

856 {
857  if (!a || !b)
858  return false;
859  if (!a->mailbox || !b->mailbox)
860  return false;
861  if (mutt_str_strcasecmp(a->mailbox, b->mailbox) != 0)
862  return false;
863  return true;
864 }
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 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 872 of file address.c.

873 {
874  if (!needle || !haystack)
875  return false;
876 
877  struct Address *a = NULL;
878  TAILQ_FOREACH(a, haystack, entries)
879  {
880  if (mutt_addr_cmp(needle, a))
881  return true;
882  }
883  return false;
884 }
#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:855
+ 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 891 of file address.c.

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

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

921 {
922  if (!mbox || !user || !domain)
923  return -1;
924 
925  char *ptr = strchr(mbox, '@');
926 
927  /* Fail if '@' is missing, at the start, or at the end */
928  if (!ptr || (ptr == mbox) || (ptr[1] == '\0'))
929  return -1;
930 
931  *user = mutt_str_substr_dup(mbox, ptr);
932  *domain = mutt_str_strdup(ptr + 1);
933 
934  return 0;
935 }
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 942 of file address.c.

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

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

978 {
979  if (!a)
980  return NULL;
981 
982  char *user = NULL, *domain = NULL;
983  static char *buf = NULL;
984 
985  if (!a->mailbox || addr_is_local(a))
986  return a->mailbox;
987 
988  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
989  return a->mailbox;
990 
991  char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_MAY_BE_IRREVERSIBLE);
992 
993  FREE(&user);
994  FREE(&domain);
995 
996  if (!local_mailbox)
997  return a->mailbox;
998 
999  mutt_str_replace(&buf, local_mailbox);
1000  FREE(&local_mailbox);
1001 
1002  return buf;
1003 }
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:920
static bool addr_is_local(const struct Address *a)
Does the Address have NO IDN components.
Definition: address.c:903
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: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 1016 of file address.c.

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

1139 {
1140  if (!buf || buflen == 0 || !al)
1141  return 0;
1142 
1143  size_t len = mutt_str_strlen(buf);
1144  if (len >= buflen)
1145  {
1146  return 0;
1147  }
1148 
1149  char *pbuf = buf + len;
1150  buflen -= len;
1151 
1152  struct Address *a = NULL;
1153  TAILQ_FOREACH(a, al, entries)
1154  {
1155  if (len > 0)
1156  {
1157  if (buflen > 1)
1158  {
1159  *pbuf++ = ',';
1160  buflen--;
1161  }
1162  if (buflen > 1)
1163  {
1164  *pbuf++ = ' ';
1165  buflen--;
1166  }
1167  }
1168 
1169  if (buflen == 1)
1170  {
1171  break;
1172  }
1173 
1174  len = mutt_addr_write(pbuf, buflen, a, display);
1175  pbuf += len;
1176  buflen -= len;
1177  }
1178 
1179  *pbuf = '\0';
1180  return pbuf - buf;
1181 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
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:1016
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_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 1188 of file address.c.

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

1218 {
1219  if (!al)
1220  return 0;
1221 
1222  int rc = 0;
1223 
1224  if (err)
1225  *err = NULL;
1226 
1227  struct Address *a = NULL;
1228  TAILQ_FOREACH(a, al, entries)
1229  {
1230  if (!a->mailbox || addr_is_intl(a))
1231  continue;
1232 
1233  char *user = NULL;
1234  char *domain = NULL;
1235  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1236  continue;
1237 
1238  char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1239 
1240  FREE(&user);
1241  FREE(&domain);
1242 
1243  if (!intl_mailbox)
1244  {
1245  rc = -1;
1246  if (err && !*err)
1247  *err = mutt_str_strdup(a->mailbox);
1248  continue;
1249  }
1250 
1251  addr_set_intl(a, intl_mailbox);
1252  }
1253 
1254  return rc;
1255 }
#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:942
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:920
static bool addr_is_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:891
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: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 1262 of file address.c.

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

1300 {
1301  if (!al)
1302  return 0;
1303 
1304  struct Address *a = NULL;
1305  TAILQ_FOREACH(a, al, entries)
1306  {
1307  mutt_addr_to_local(a);
1308  }
1309  return 0;
1310 }
#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:1262
+ 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 1319 of file address.c.

1320 {
1321  if (!al)
1322  return;
1323 
1324  struct Address *a = NULL;
1325  TAILQ_FOREACH(a, al, entries)
1326  {
1327  if (a->mailbox)
1328  {
1329  struct Address *a2 = TAILQ_NEXT(a, entries);
1330  struct Address *tmp = NULL;
1331 
1332  if (a2)
1333  {
1334  TAILQ_FOREACH_FROM_SAFE(a2, al, entries, tmp)
1335  {
1336  if (a2->mailbox && (mutt_str_strcasecmp(a->mailbox, a2->mailbox) == 0))
1337  {
1338  mutt_debug(LL_DEBUG2, "Removing %s\n", a2->mailbox);
1339  TAILQ_REMOVE(al, a2, entries);
1340  mutt_addr_free(&a2);
1341  }
1342  }
1343  }
1344  }
1345  }
1346 }
#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
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)
Definition: queue.h:733
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: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 1355 of file address.c.

1356 {
1357  if (!a || !b)
1358  return;
1359 
1360  struct Address *aa = NULL, *ab = NULL, *tmp = NULL;
1361 
1362  TAILQ_FOREACH_SAFE(ab, b, entries, tmp)
1363  {
1364  TAILQ_FOREACH(aa, a, entries)
1365  {
1366  if (mutt_addr_cmp(aa, ab))
1367  {
1368  TAILQ_REMOVE(b, ab, entries);
1369  mutt_addr_free(&ab);
1370  break;
1371  }
1372  }
1373  }
1374 }
#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:855
+ 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 1382 of file address.c.

1383 {
1384  if (!al)
1385  return;
1386 
1387  struct Address *a = TAILQ_FIRST(al), *next = NULL;
1388  while (a)
1389  {
1390  next = TAILQ_NEXT(a, entries);
1391  mutt_addr_free(&a);
1392  a = next;
1393  }
1394  TAILQ_INIT(al);
1395 }
#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 1402 of file address.c.

1403 {
1404  if (al && a)
1405  TAILQ_INSERT_TAIL(al, a, entries);
1406 }
#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 1413 of file address.c.

1414 {
1415  if (al && a)
1416  TAILQ_INSERT_HEAD(al, a, entries);
1417 }
#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.