NeoMutt  2020-11-20
Teaching an old dog new tricks
DOXYGEN
address.c File Reference

Representation of an email address. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "mutt/lib.h"
#include "address.h"
#include "idna2.h"
+ Include dependency graph for address.c:

Go to the source code of this file.

Macros

#define is_special(ch)   strchr(AddressSpecials, ch)
 Is this character special to an email address? More...
 

Functions

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

Variables

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

Detailed Description

Representation of an email address.

Authors
  • Michael R. Elkins
  • Richard Russon
  • Pietro Cerutti

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file address.c.

Macro Definition Documentation

◆ is_special

#define is_special (   ch)    strchr(AddressSpecials, ch)

Is this character special to an email address?

Parameters
chCharacter

Definition at line 48 of file address.c.

Function Documentation

◆ parse_comment()

static const char* parse_comment ( const char *  s,
char *  comment,
size_t *  commentlen,
size_t  commentmax 
)
static

Extract a comment (parenthesised string)

Parameters
[in]sString, just after the opening parenthesis
[out]commentBuffer to store parenthesised string
[out]commentlenLength of parenthesised string
[in]commentmaxLength of buffer
Return values
ptrFirst character after parenthesised string
NULLError

Definition at line 78 of file address.c.

79 {
80  int level = 1;
81 
82  while (*s && level)
83  {
84  if (*s == '(')
85  level++;
86  else if (*s == ')')
87  {
88  if (--level == 0)
89  {
90  s++;
91  break;
92  }
93  }
94  else if (*s == '\\')
95  {
96  if (!*++s)
97  break;
98  }
99  if (*commentlen < commentmax)
100  comment[(*commentlen)++] = *s;
101  s++;
102  }
103  if (level != 0)
104  {
106  return NULL;
107  }
108  return s;
109 }
AddressError
possible values for AddressError
Definition: address.h: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:759
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_mailboxdomain()

static const char* parse_mailboxdomain ( const char *  s,
const char *  nonspecial,
char *  mailbox,
size_t *  mailboxlen,
size_t  mailboxmax,
char *  comment,
size_t *  commentlen,
size_t  commentmax 
)
static

Extract part of an email address (and a comment)

Parameters
[in]sString to parse
[in]nonspecialSpecific characters that are valid
[out]mailboxBuffer for email address
[out]mailboxlenLength of saved email address
[in]mailboxmaxLength of mailbox buffer
[out]commentBuffer for comment
[out]commentlenLength of saved comment
[in]commentmaxLength of comment buffer
Return values
ptrFirst character after the email address part

This will be called twice to parse an email address, first for the mailbox name, then for the domain name. Each part can also have a comment in (). The comment can be at the start or end of the mailbox or domain.

Examples:

  • "john.doe@example.com"
  • "john.doe(comment)@example.com"
  • "john.doe@example.com(comment)"

The first call will return "john.doe" with optional comment, "comment". The second call will return "example.com" with optional comment, "comment".

Definition at line 198 of file address.c.

202 {
203  const char *ps = NULL;
204 
205  while (*s)
206  {
208  if ((*s == '\0'))
209  return s;
210 
211  if (!strchr(nonspecial, *s) && is_special(*s))
212  return s;
213 
214  if (*s == '(')
215  {
216  if (*commentlen && (*commentlen < commentmax))
217  comment[(*commentlen)++] = ' ';
218  ps = next_token(s, comment, commentlen, commentmax);
219  }
220  else
221  ps = next_token(s, mailbox, mailboxlen, mailboxmax);
222  if (!ps)
223  return NULL;
224  s = ps;
225  }
226 
227  return s;
228 }
#define is_special(ch)
Is this character special to an email address?
Definition: address.c:48
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:743
static const char * next_token(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
Find the next word, skipping quoted and parenthesised text.
Definition: address.c:151
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_address()

static const char* parse_address ( const char *  s,
char *  token,
size_t *  tokenlen,
size_t  tokenmax,
char *  comment,
size_t *  commentlen,
size_t  commentmax,
struct Address addr 
)
static

Extract an email address.

Parameters
[in]sString, just after the opening <
[out]tokenBuffer for the email address
[out]tokenlenLength of the email address
[in]tokenmaxLength of the email address buffer
[out]commentBuffer for any comments
[out]commentlenLength of any comments
[in]commentmaxLength of the comment buffer
[in]addrAddress to store the results
Return values
ptrThe closing > of the email address
NULLError

Definition at line 243 of file address.c.

246 {
247  s = parse_mailboxdomain(s, ".\"(\\", token, tokenlen, tokenmax, comment,
248  commentlen, commentmax);
249  if (!s)
250  return NULL;
251 
252  if (*s == '@')
253  {
254  if (*tokenlen < tokenmax)
255  token[(*tokenlen)++] = '@';
256  s = parse_mailboxdomain(s + 1, ".([]\\", token, tokenlen, tokenmax, comment,
257  commentlen, commentmax);
258  if (!s)
259  return NULL;
260  }
261 
262  terminate_string(token, *tokenlen, tokenmax);
263  addr->mailbox = mutt_str_dup(token);
264 
265  if (*commentlen && !addr->personal)
266  {
267  terminate_string(comment, *commentlen, commentmax);
268  addr->personal = mutt_str_dup(comment);
269  }
270 
271  return s;
272 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
char * mailbox
Mailbox and host address.
Definition: address.h:37
static const char * parse_mailboxdomain(const char *s, const char *nonspecial, char *mailbox, size_t *mailboxlen, size_t mailboxmax, char *comment, size_t *commentlen, size_t commentmax)
Extract part of an email address (and a comment)
Definition: address.c:198
char * personal
Real name of address.
Definition: address.h:36
#define terminate_string(str, strlen, buflen)
Definition: string2.h:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_route_addr()

static const char* parse_route_addr ( const char *  s,
char *  comment,
size_t *  commentlen,
size_t  commentmax,
struct Address addr 
)
static

Parse an email addresses.

Parameters
[in]sString, just after the opening <
[out]commentBuffer for any comments
[out]commentlenLength of any comments
[in]commentmaxLength of the comments buffer
[in]addrAddress to store the details
Return values
ptrFirst character after the email address

Definition at line 283 of file address.c.

285 {
286  char token[1024];
287  size_t tokenlen = 0;
288 
290 
291  /* find the end of the route */
292  if (*s == '@')
293  {
294  while (s && (*s == '@'))
295  {
296  if (tokenlen < (sizeof(token) - 1))
297  token[tokenlen++] = '@';
298  s = parse_mailboxdomain(s + 1, ",.\\[](", token, &tokenlen,
299  sizeof(token) - 1, comment, commentlen, commentmax);
300  }
301  if (!s || (*s != ':'))
302  {
304  return NULL; /* invalid route */
305  }
306 
307  if (tokenlen < (sizeof(token) - 1))
308  token[tokenlen++] = ':';
309  s++;
310  }
311 
312  s = parse_address(s, token, &tokenlen, sizeof(token) - 1, comment, commentlen,
313  commentmax, addr);
314  if (!s)
315  return NULL;
316 
317  if (*s != '>')
318  {
320  return NULL;
321  }
322 
323  if (!addr->mailbox)
324  addr->mailbox = mutt_str_dup("@");
325 
326  s++;
327  return s;
328 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
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:743
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:1488
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_new()

struct Address* mutt_addr_new ( void  )

Create a new Address.

Return values
ptrNewly allocated Address

Free the result with mutt_addr_free()

Definition at line 385 of file address.c.

386 {
387  return mutt_mem_calloc(1, sizeof(struct Address));
388 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
An email address.
Definition: address.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_create()

struct Address* mutt_addr_create ( const char *  personal,
const char *  mailbox 
)

Create and populate a new Address.

Parameters
[in]personalThe personal name for the Address (can be NULL)
[in]mailboxThe mailbox for the Address (can be NULL)
Return values
ptrNewly allocated Address
Note
The personal and mailbox values, if not NULL, are going to be copied into the newly allocated Address.

Definition at line 398 of file address.c.

399 {
400  struct Address *a = mutt_addr_new();
403  return a;
404 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * personal
Real name of address.
Definition: address.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_remove()

int mutt_addrlist_remove ( struct AddressList *  al,
const char *  mailbox 
)

Remove an Address from a list.

Parameters
[in,out]alAddressList
[in]mailboxEmail address to match
Return values
0Success
-1Error, or email not found

Definition at line 413 of file address.c.

414 {
415  if (!al)
416  return -1;
417 
418  if (!mailbox)
419  return 0;
420 
421  int rc = -1;
422  struct Address *a = NULL, *tmp = NULL;
423  TAILQ_FOREACH_SAFE(a, al, entries, tmp)
424  {
426  {
427  TAILQ_REMOVE(al, a, entries);
428  mutt_addr_free(&a);
429  rc = 0;
430  }
431  }
432 
433  return rc;
434 }
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_free()

void mutt_addr_free ( struct Address **  ptr)

Free a single Address.

Parameters
[out]ptrAddress to free

Definition at line 440 of file address.c.

441 {
442  if (!ptr || !*ptr)
443  return;
444 
445  struct Address *a = *ptr;
446 
447  FREE(&a->personal);
448  FREE(&a->mailbox);
449  FREE(ptr);
450 }
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * personal
Real name of address.
Definition: address.h:36
#define FREE(x)
Definition: memory.h:40
+ Here is the caller graph for this function:

◆ mutt_addrlist_parse()

int mutt_addrlist_parse ( struct AddressList *  al,
const char *  s 
)

Parse a list of email addresses.

Parameters
alAddressList to append addresses
sString to parse
Return values
numNumber of parsed addresses

Definition at line 458 of file address.c.

459 {
460  if (!s)
461  return 0;
462 
463  int parsed = 0;
464  char comment[1024], phrase[1024];
465  size_t phraselen = 0, commentlen = 0;
466  AddressError = 0;
467 
468  bool ws_pending = mutt_str_is_email_wsp(*s);
469 
471  while (*s)
472  {
473  switch (*s)
474  {
475  case ';':
476  case ',':
477  if (phraselen != 0)
478  {
479  terminate_buffer(phrase, phraselen);
480  if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
481  {
482  parsed++;
483  }
484  }
485  else if (commentlen != 0)
486  {
487  struct Address *last = TAILQ_LAST(al, AddressList);
488  if (last && !last->personal && last->mailbox)
489  {
490  terminate_buffer(comment, commentlen);
491  last->personal = mutt_str_dup(comment);
492  }
493  }
494 
495  if (*s == ';')
496  {
497  /* add group terminator */
499  }
500 
501  phraselen = 0;
502  commentlen = 0;
503  s++;
504  break;
505 
506  case '(':
507  if ((commentlen != 0) && (commentlen < (sizeof(comment) - 1)))
508  comment[commentlen++] = ' ';
509  s = next_token(s, comment, &commentlen, sizeof(comment) - 1);
510  if (!s)
511  {
513  return 0;
514  }
515  break;
516 
517  case '"':
518  if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)))
519  phrase[phraselen++] = ' ';
520  s = parse_quote(s + 1, phrase, &phraselen, sizeof(phrase) - 1);
521  if (!s)
522  {
524  return 0;
525  }
526  break;
527 
528  case ':':
529  {
530  struct Address *a = mutt_addr_new();
531  terminate_buffer(phrase, phraselen);
532  a->mailbox = mutt_str_dup(phrase);
533  a->group = true;
534  mutt_addrlist_append(al, a);
535  phraselen = 0;
536  commentlen = 0;
537  s++;
538  break;
539  }
540 
541  case '<':
542  {
543  struct Address *a = mutt_addr_new();
544  terminate_buffer(phrase, phraselen);
545  a->personal = mutt_str_dup(phrase);
546  s = parse_route_addr(s + 1, comment, &commentlen, sizeof(comment) - 1, a);
547  if (!s)
548  {
550  mutt_addr_free(&a);
551  return 0;
552  }
553  mutt_addrlist_append(al, a);
554  phraselen = 0;
555  commentlen = 0;
556  parsed++;
557  break;
558  }
559 
560  default:
561  if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)) && ws_pending)
562  phrase[phraselen++] = ' ';
563  if (*s == '\\')
564  {
565  s++;
566  if (*s && (phraselen < (sizeof(phrase) - 1)))
567  {
568  phrase[phraselen++] = *s;
569  s++;
570  }
571  }
572  s = next_token(s, phrase, &phraselen, sizeof(phrase) - 1);
573  if (!s)
574  {
576  return 0;
577  }
578  break;
579  } // switch (*s)
580 
581  ws_pending = mutt_str_is_email_wsp(*s);
583  } // while (*s)
584 
585  if (phraselen != 0)
586  {
587  terminate_buffer(phrase, phraselen);
588  terminate_buffer(comment, commentlen);
589  if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
590  {
591  parsed++;
592  }
593  }
594  else if (commentlen != 0)
595  {
596  struct Address *last = TAILQ_LAST(al, AddressList);
597  if (last && !last->personal && last->mailbox)
598  {
599  terminate_buffer(comment, commentlen);
600  last->personal = mutt_str_dup(comment);
601  }
602  }
603 
604  return parsed;
605 }
#define TAILQ_LAST(head, headname)
Definition: queue.h:812
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1468
static const char * parse_route_addr(const char *s, char *comment, size_t *commentlen, size_t commentmax, struct Address *addr)
Parse an email addresses.
Definition: address.c:283
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
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:759
#define terminate_buffer(str, strlen)
Definition: string2.h:53
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:743
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
static const char * next_token(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
Find the next word, skipping quoted and parenthesised text.
Definition: address.c:151
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1488
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_parse2()

int mutt_addrlist_parse2 ( struct AddressList *  al,
const char *  s 
)

Parse a list of email addresses.

Parameters
alAdd to this List of Addresses
sString to parse
Return values
numNumber of parsed addresses

Simple email addresses (without any personal name or grouping) can be separated by whitespace or commas.

Definition at line 616 of file address.c.

617 {
618  if (!s || (*s == '\0'))
619  return 0;
620 
621  int parsed = 0;
622 
623  /* check for a simple whitespace separated list of addresses */
624  if (!strpbrk(s, "\"<>():;,\\"))
625  {
626  char *copy = mutt_str_dup(s);
627  char *r = copy;
628  while ((r = strtok(r, " \t")))
629  {
630  parsed += mutt_addrlist_parse(al, r);
631  r = NULL;
632  }
633  FREE(&copy);
634  }
635  else
636  parsed = mutt_addrlist_parse(al, s);
637 
638  return parsed;
639 }
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define FREE(x)
Definition: memory.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_qualify()

void mutt_addrlist_qualify ( struct AddressList *  al,
const char *  host 
)

Expand local names in an Address list using a hostname.

Parameters
alAddress list
hostHostname

Any addresses containing a bare name will be expanded using the hostname. e.g. "john", "example.com" -> 'john@.nosp@m.exam.nosp@m.ple.c.nosp@m.om'. This function has no effect if host is NULL or the empty string.

Definition at line 650 of file address.c.

651 {
652  if (!al || !host || (*host == '\0'))
653  return;
654 
655  struct Address *a = NULL;
656  TAILQ_FOREACH(a, al, entries)
657  {
658  if (!a->group && a->mailbox && !strchr(a->mailbox, '@'))
659  {
660  char *p = mutt_mem_malloc(mutt_str_len(a->mailbox) + mutt_str_len(host) + 2);
661  sprintf(p, "%s@%s", a->mailbox, host);
662  FREE(&a->mailbox);
663  a->mailbox = p;
664  }
665  }
666 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
bool group
Group mailbox?
Definition: address.h:38
#define FREE(x)
Definition: memory.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_cat()

void mutt_addr_cat ( char *  buf,
size_t  buflen,
const char *  value,
const char *  specials 
)

Copy a string and wrap it in quotes if it contains special characters.

Parameters
bufBuffer for the result
buflenLength of the result buffer
valueString to copy
specialsCharacters to lookup

This function copies the string in the "value" parameter in the buffer pointed to by "buf" parameter. If the input string contains any of the characters specified in the "specials" parameters, the output string is wrapped in double quoted. Additionally, any backslashes or quotes inside the input string are backslash-escaped.

Definition at line 681 of file address.c.

682 {
683  if (!buf || !value || !specials)
684  return;
685 
686  if (strpbrk(value, specials))
687  {
688  char tmp[256];
689  char *pc = tmp;
690  size_t tmplen = sizeof(tmp) - 3;
691 
692  *pc++ = '"';
693  for (; *value && (tmplen > 1); value++)
694  {
695  if ((*value == '\\') || (*value == '"'))
696  {
697  *pc++ = '\\';
698  tmplen--;
699  }
700  *pc++ = *value;
701  tmplen--;
702  }
703  *pc++ = '"';
704  *pc = '\0';
705  mutt_str_copy(buf, tmp, buflen);
706  }
707  else
708  mutt_str_copy(buf, value, buflen);
709 }
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_copy()

struct Address* mutt_addr_copy ( const struct Address addr)

Copy the real address.

Parameters
addrAddress to copy
Return values
ptrNew Address

Definition at line 716 of file address.c.

717 {
718  if (!addr)
719  return NULL;
720 
721  struct Address *p = mutt_addr_new();
722 
723  p->personal = mutt_str_dup(addr->personal);
724  p->mailbox = mutt_str_dup(addr->mailbox);
725  p->group = addr->group;
726  p->is_intl = addr->is_intl;
727  p->intl_checked = addr->intl_checked;
728  return p;
729 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_copy()

void mutt_addrlist_copy ( struct AddressList *  dst,
const struct AddressList *  src,
bool  prune 
)

Copy a list of addresses into another list.

Parameters
dstDestination Address list
srcSource Address list
pruneSkip groups if there are more addresses

Definition at line 737 of file address.c.

738 {
739  if (!dst || !src)
740  return;
741 
742  struct Address *a = NULL;
743  TAILQ_FOREACH(a, src, entries)
744  {
745  struct Address *next = TAILQ_NEXT(a, entries);
746  if (prune && a->group && (!next || !next->mailbox))
747  {
748  /* ignore this element of the list */
749  }
750  else
751  {
753  }
754  }
755 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
bool group
Group mailbox?
Definition: address.h:38
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1488
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_valid_msgid()

bool mutt_addr_valid_msgid ( const char *  msgid)

Is this a valid Message ID?

Parameters
msgidMessage ID
Return values
trueIt is a valid message ID

Incomplete. Only used to thwart the APOP MD5 attack

Definition at line 764 of file address.c.

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

◆ mutt_addrlist_equal()

bool mutt_addrlist_equal ( const struct AddressList *  ala,
const struct AddressList *  alb 
)

Compare two Address lists for equality.

Parameters
alaFirst Address
albSecond Address
Return values
trueAddress lists are strictly identical

Definition at line 812 of file address.c.

813 {
814  if (!ala || !alb)
815  {
816  return !(ala || alb);
817  }
818 
819  struct Address *ana = TAILQ_FIRST(ala);
820  struct Address *anb = TAILQ_FIRST(alb);
821 
822  while (ana && anb)
823  {
824  if (!mutt_str_equal(ana->mailbox, anb->mailbox) ||
825  !mutt_str_equal(ana->personal, anb->personal))
826  {
827  break;
828  }
829 
830  ana = TAILQ_NEXT(ana, entries);
831  anb = TAILQ_NEXT(anb, entries);
832  }
833 
834  return !(ana || anb);
835 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
#define TAILQ_FIRST(head)
Definition: queue.h:716
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
char * personal
Real name of address.
Definition: address.h:36
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_count_recips()

int mutt_addrlist_count_recips ( const struct AddressList *  al)

Count the number of Addresses with valid recipients.

Parameters
alAddress list
Return values
numNumber of valid Addresses

An Address has a recipient if the mailbox is set and is not a group

Definition at line 844 of file address.c.

845 {
846  if (!al)
847  return 0;
848 
849  int c = 0;
850  struct Address *a = NULL;
851  TAILQ_FOREACH(a, al, entries)
852  {
853  c += (a->mailbox && !a->group);
854  }
855  return c;
856 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:38
+ Here is the caller graph for this function:

◆ mutt_addr_cmp()

bool mutt_addr_cmp ( const struct Address a,
const struct Address b 
)

Compare two e-mail addresses.

Parameters
aAddress 1
bAddress 2
Return values
trueif they are equivalent

Definition at line 864 of file address.c.

865 {
866  if (!a || !b)
867  return false;
868  if (!a->mailbox || !b->mailbox)
869  return false;
870  if (!mutt_istr_equal(a->mailbox, b->mailbox))
871  return false;
872  return true;
873 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_search()

bool mutt_addrlist_search ( const struct AddressList *  haystack,
const struct Address needle 
)

Search for an e-mail address in a list.

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

Definition at line 881 of file address.c.

882 {
883  if (!needle || !haystack)
884  return false;
885 
886  struct Address *a = NULL;
887  TAILQ_FOREACH(a, haystack, entries)
888  {
889  if (mutt_addr_cmp(needle, a))
890  return true;
891  }
892  return false;
893 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:864
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addr_is_intl()

static bool addr_is_intl ( const struct Address a)
static

Does the Address have IDN components.

Parameters
aAddress to check
Return values
trueAddress contains IDN components

Definition at line 900 of file address.c.

901 {
902  if (!a)
903  return false;
904  return a->intl_checked && a->is_intl;
905 }
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
+ Here is the caller graph for this function:

◆ addr_is_local()

static bool addr_is_local ( const struct Address a)
static

Does the Address have NO IDN components.

Parameters
aAddress to check
Return values
trueAddress contains NO IDN components

Definition at line 912 of file address.c.

913 {
914  if (!a)
915  return false;
916  return a->intl_checked && !a->is_intl;
917 }
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
+ Here is the caller graph for this function:

◆ addr_mbox_to_udomain()

static int addr_mbox_to_udomain ( const char *  mbox,
char **  user,
char **  domain 
)
static

Split a mailbox name into user and domain.

Parameters
[in]mboxMailbox name to split
[out]userUser
[out]domainDomain
Return values
0Success
-1Error
Warning
The caller must free user and domain

Definition at line 929 of file address.c.

930 {
931  if (!mbox || !user || !domain)
932  return -1;
933 
934  char *ptr = strchr(mbox, '@');
935 
936  /* Fail if '@' is missing, at the start, or at the end */
937  if (!ptr || (ptr == mbox) || (ptr[1] == '\0'))
938  return -1;
939 
940  *user = mutt_strn_dup(mbox, ptr - mbox);
941  *domain = mutt_str_dup(ptr + 1);
942 
943  return 0;
944 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:548
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addr_set_intl()

static void addr_set_intl ( struct Address a,
char *  intl_mailbox 
)
static

Mark an Address as having IDN components.

Parameters
aAddress to modify
intl_mailboxEmail address with IDN components

Definition at line 951 of file address.c.

952 {
953  if (!a)
954  return;
955 
956  FREE(&a->mailbox);
957  a->mailbox = intl_mailbox;
958  a->intl_checked = true;
959  a->is_intl = true;
960 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
#define FREE(x)
Definition: memory.h:40
+ Here is the caller graph for this function:

◆ addr_set_local()

static void addr_set_local ( struct Address a,
char *  local_mailbox 
)
static

Mark an Address as having NO IDN components.

Parameters
aAddress
local_mailboxEmail address with NO IDN components

Definition at line 967 of file address.c.

968 {
969  if (!a)
970  return;
971 
972  FREE(&a->mailbox);
973  a->mailbox = local_mailbox;
974  a->intl_checked = true;
975  a->is_intl = false;
976 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_intl
International Domain Name.
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:40
#define FREE(x)
Definition: memory.h:40
+ Here is the caller graph for this function:

◆ mutt_addr_for_display()

const char* mutt_addr_for_display ( const struct Address a)

Convert an Address for display purposes.

Parameters
aAddress to convert
Return values
ptrAddress to display
Warning
This function may return a static pointer. It must not be freed by the caller. Later calls may overwrite the returned pointer.

Definition at line 986 of file address.c.

987 {
988  if (!a)
989  return NULL;
990 
991  char *user = NULL, *domain = NULL;
992  static char *buf = NULL;
993 
994  if (!a->mailbox || addr_is_local(a))
995  return a->mailbox;
996 
997  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
998  return a->mailbox;
999 
1000  char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_MAY_BE_IRREVERSIBLE);
1001 
1002  FREE(&user);
1003  FREE(&domain);
1004 
1005  if (!local_mailbox)
1006  return a->mailbox;
1007 
1008  mutt_str_replace(&buf, local_mailbox);
1009  FREE(&local_mailbox);
1010 
1011  return buf;
1012 }
char * mailbox
Mailbox and host address.
Definition: address.h:37
static int addr_mbox_to_udomain(const char *mbox, char **user, char **domain)
Split a mailbox name into user and domain.
Definition: address.c:929
static bool addr_is_local(const struct Address *a)
Does the Address have NO IDN components.
Definition: address.c:912
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
#define FREE(x)
Definition: memory.h:40
#define MI_MAY_BE_IRREVERSIBLE
Definition: idna2.h:32
char * mutt_idna_intl_to_local(const char *user, const char *domain, int flags)
Convert an email&#39;s domain from Punycode.
Definition: idna.c:147
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_write()

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

Write a single Address to a buffer.

Parameters
bufBuffer for the Address
buflenLength of the buffer
addrAddress to display
displayThis address will be displayed to the user
Return values
numLength of the string written to buf

If 'display' is set, then it doesn't matter if the transformation isn't reversible.

Definition at line 1025 of file address.c.

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

◆ mutt_addrlist_write()

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

Write an Address to a buffer.

Parameters
alAddressList to display
bufBuffer for the Address
buflenLength of the buffer
displayThis address will be displayed to the user
Return values
numLength of the string written to buf

If 'display' is set, then it doesn't matter if the transformation isn't reversible.

Note
It is assumed that buf is nul terminated!

Definition at line 1150 of file address.c.

1151 {
1152  if (!buf || (buflen == 0) || !al)
1153  return 0;
1154 
1155  size_t len = mutt_str_len(buf);
1156  if (len >= buflen)
1157  {
1158  return 0;
1159  }
1160 
1161  char *pbuf = buf + len;
1162  buflen -= len;
1163 
1164  struct Address *a = NULL;
1165  TAILQ_FOREACH(a, al, entries)
1166  {
1167  if (len > 0)
1168  {
1169  if (buflen > 1)
1170  {
1171  *pbuf++ = ',';
1172  buflen--;
1173  }
1174  if (buflen > 1)
1175  {
1176  *pbuf++ = ' ';
1177  buflen--;
1178  }
1179  }
1180 
1181  if (buflen == 1)
1182  {
1183  break;
1184  }
1185 
1186  len = mutt_addr_write(pbuf, buflen, a, display);
1187  pbuf += len;
1188  buflen -= len;
1189  }
1190 
1191  *pbuf = '\0';
1192  return pbuf - buf;
1193 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1025
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write_list()

size_t mutt_addrlist_write_list ( const struct AddressList *  al,
struct ListHead *  list 
)

Write Addresses to a List.

Parameters
alAddressList to write
listList for the Addresses
Return values
numNumber of addresses written

Definition at line 1201 of file address.c.

1202 {
1203  if (!al || !list)
1204  return 0;
1205 
1206  char addr[256];
1207  size_t count = 0;
1208  struct Address *a = NULL;
1209  TAILQ_FOREACH(a, al, entries)
1210  {
1211  if (mutt_addr_write(addr, sizeof(addr), a, true) != 0)
1212  {
1213  mutt_list_insert_tail(list, strdup(addr));
1214  count++;
1215  }
1216  }
1217 
1218  return count;
1219 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1025
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write_file()

void mutt_addrlist_write_file ( const struct AddressList *  al,
FILE *  fp,
int  start_col,
bool  display 
)

Wrapper for mutt_write_address()

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

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

Definition at line 1231 of file address.c.

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

1276 {
1277  if (!a || !a->mailbox || addr_is_intl(a))
1278  return true;
1279 
1280  char *user = NULL;
1281  char *domain = NULL;
1282  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1283  return true;
1284 
1285  char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1286 
1287  FREE(&user);
1288  FREE(&domain);
1289 
1290  if (!intl_mailbox)
1291  return false;
1292 
1293  addr_set_intl(a, intl_mailbox);
1294  return true;
1295 }
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:951
char * mailbox
Mailbox and host address.
Definition: address.h:37
static int addr_mbox_to_udomain(const char *mbox, char **user, char **domain)
Split a mailbox name into user and domain.
Definition: address.c:929
static bool addr_is_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:900
#define FREE(x)
Definition: memory.h:40
char * mutt_idna_local_to_intl(const char *user, const char *domain)
Convert an email&#39;s domain to Punycode.
Definition: idna.c:265
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_to_intl()

int mutt_addrlist_to_intl ( struct AddressList *  al,
char **  err 
)

Convert an Address list to Punycode.

Parameters
[in]alAddress list to modify
[out]errPointer for failed addresses
Return values
0Success, all addresses converted
-1Error, err will be set to the failed address

Definition at line 1304 of file address.c.

1305 {
1306  if (!al)
1307  return 0;
1308 
1309  int rc = 0;
1310 
1311  if (err)
1312  *err = NULL;
1313 
1314  struct Address *a = NULL;
1315  TAILQ_FOREACH(a, al, entries)
1316  {
1317  if (!a->mailbox || addr_is_intl(a))
1318  continue;
1319 
1320  char *user = NULL;
1321  char *domain = NULL;
1322  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1323  continue;
1324 
1325  char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1326 
1327  FREE(&user);
1328  FREE(&domain);
1329 
1330  if (!intl_mailbox)
1331  {
1332  rc = -1;
1333  if (err && !*err)
1334  *err = mutt_str_dup(a->mailbox);
1335  continue;
1336  }
1337 
1338  addr_set_intl(a, intl_mailbox);
1339  }
1340 
1341  return rc;
1342 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:951
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
static int addr_mbox_to_udomain(const char *mbox, char **user, char **domain)
Split a mailbox name into user and domain.
Definition: address.c:929
static bool addr_is_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:900
#define FREE(x)
Definition: memory.h:40
char * mutt_idna_local_to_intl(const char *user, const char *domain)
Convert an email&#39;s domain to Punycode.
Definition: idna.c:265
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_to_local()

bool mutt_addr_to_local ( struct Address a)

Convert an Address from Punycode.

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

Definition at line 1349 of file address.c.

1350 {
1351  if (!a->mailbox)
1352  {
1353  return false;
1354  }
1355 
1356  if (addr_is_local(a))
1357  {
1358  return true;
1359  }
1360 
1361  char *user = NULL;
1362  char *domain = NULL;
1363  if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1364  {
1365  return false;
1366  }
1367 
1368  char *local_mailbox = mutt_idna_intl_to_local(user, domain, 0);
1369  FREE(&user);
1370  FREE(&domain);
1371 
1372  if (!local_mailbox)
1373  {
1374  return false;
1375  }
1376 
1377  addr_set_local(a, local_mailbox);
1378  return true;
1379 }
static void addr_set_local(struct Address *a, char *local_mailbox)
Mark an Address as having NO IDN components.
Definition: address.c:967
char * mailbox
Mailbox and host address.
Definition: address.h:37
static int addr_mbox_to_udomain(const char *mbox, char **user, char **domain)
Split a mailbox name into user and domain.
Definition: address.c:929
static bool addr_is_local(const struct Address *a)
Does the Address have NO IDN components.
Definition: address.c:912
#define FREE(x)
Definition: memory.h:40
char * mutt_idna_intl_to_local(const char *user, const char *domain, int flags)
Convert an email&#39;s domain from Punycode.
Definition: idna.c:147
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_to_local()

int mutt_addrlist_to_local ( struct AddressList *  al)

Convert an Address list from Punycode.

Parameters
alAddress list to modify
Return values
0Always

Definition at line 1386 of file address.c.

1387 {
1388  if (!al)
1389  return 0;
1390 
1391  struct Address *a = NULL;
1392  TAILQ_FOREACH(a, al, entries)
1393  {
1394  mutt_addr_to_local(a);
1395  }
1396  return 0;
1397 }
#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:1349
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_dedupe()

void mutt_addrlist_dedupe ( struct AddressList *  al)

Remove duplicate addresses.

Parameters
alAddress list to de-dupe

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

Definition at line 1405 of file address.c.

1406 {
1407  if (!al)
1408  return;
1409 
1410  struct Address *a = NULL;
1411  TAILQ_FOREACH(a, al, entries)
1412  {
1413  if (a->mailbox)
1414  {
1415  struct Address *a2 = TAILQ_NEXT(a, entries);
1416  struct Address *tmp = NULL;
1417 
1418  if (a2)
1419  {
1420  TAILQ_FOREACH_FROM_SAFE(a2, al, entries, tmp)
1421  {
1422  if (a2->mailbox && mutt_istr_equal(a->mailbox, a2->mailbox))
1423  {
1424  mutt_debug(LL_DEBUG2, "Removing %s\n", a2->mailbox);
1425  TAILQ_REMOVE(al, a2, entries);
1426  mutt_addr_free(&a2);
1427  }
1428  }
1429  }
1430  }
1431  }
1432 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
Log at debug level 2.
Definition: logging.h:41
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)
Definition: queue.h:733
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_remove_xrefs()

void mutt_addrlist_remove_xrefs ( const struct AddressList *  a,
struct AddressList *  b 
)

Remove cross-references.

Parameters
aReference AddressList
bAddressLis to trim

Remove addresses from "b" which are contained in "a"

Definition at line 1441 of file address.c.

1442 {
1443  if (!a || !b)
1444  return;
1445 
1446  struct Address *aa = NULL, *ab = NULL, *tmp = NULL;
1447 
1448  TAILQ_FOREACH_SAFE(ab, b, entries, tmp)
1449  {
1450  TAILQ_FOREACH(aa, a, entries)
1451  {
1452  if (mutt_addr_cmp(aa, ab))
1453  {
1454  TAILQ_REMOVE(b, ab, entries);
1455  mutt_addr_free(&ab);
1456  break;
1457  }
1458  }
1459  }
1460 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
An email address.
Definition: address.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:864
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_clear()

void mutt_addrlist_clear ( struct AddressList *  al)

Unlink and free all Address in an AddressList.

Parameters
alAddressList
Note
After this call, the AddressList is reinitialized and ready for reuse.

Definition at line 1468 of file address.c.

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

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

1500 {
1501  if (al && a)
1502  TAILQ_INSERT_HEAD(al, a, entries);
1503 }
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:789
+ Here is the caller graph for this function:

◆ mutt_addr_uses_unicode()

bool mutt_addr_uses_unicode ( const char *  str)

Does this address use Unicode character.

Parameters
strAddress string to check
Return values
trueIf the string uses 8-bit characters

Definition at line 1510 of file address.c.

1511 {
1512  if (!str)
1513  return false;
1514 
1515  while (*str)
1516  {
1517  if ((unsigned char) *str & (1 << 7))
1518  return true;
1519  str++;
1520  }
1521 
1522  return false;
1523 }
+ Here is the caller graph for this function:

◆ mutt_addrlist_uses_unicode()

bool mutt_addrlist_uses_unicode ( const struct AddressList *  al)

Do any of a list of addresses use Unicode characters.

Parameters
alAddress list to check
Return values
trueIf any use 8-bit characters

Definition at line 1530 of file address.c.

1531 {
1532  if (!al)
1533  {
1534  return false;
1535  }
1536 
1537  struct Address *a = NULL;
1538  TAILQ_FOREACH(a, al, entries)
1539  {
1540  if (a->mailbox && !a->group && mutt_addr_uses_unicode(a->mailbox))
1541  return true;
1542  }
1543  return false;
1544 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
bool mutt_addr_uses_unicode(const char *str)
Does this address use Unicode character.
Definition: address.c:1510
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 call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ AddressSpecials

const char AddressSpecials[] = "@.,:;<>[]\\\"()"

Characters with special meaning for email addresses.

Definition at line 42 of file address.c.

◆ AddressError

int AddressError = 0

An out-of-band error code.

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

Definition at line 57 of file address.c.

◆ AddressErrors

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

Messages for the error codes in AddressError.

These must defined in the same order as enum AddressError.

Definition at line 64 of file address.c.