NeoMutt  2023-03-22-27-g3cb248
Teaching an old dog new tricks
DOXYGEN
address.h File Reference

Representation of an email address. More...

#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include "mutt/lib.h"
+ Include dependency graph for address.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  Address
 An email address. More...
 

Macros

#define address_error(num)   AddressErrors[num]
 

Typedefs

typedef bool(* addr_predicate_t) (const struct Address *a)
 

Enumerations

enum  AddressError {
  ADDR_ERR_MEMORY = 1 , ADDR_ERR_MISMATCH_PAREN , ADDR_ERR_MISMATCH_QUOTE , ADDR_ERR_BAD_ROUTE ,
  ADDR_ERR_BAD_ROUTE_ADDR , ADDR_ERR_BAD_ADDR_SPEC
}
 Possible values for AddressError. More...
 

Functions

 TAILQ_HEAD (AddressList, Address)
 
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...
 
bool mutt_addr_valid_msgid (const char *msgid)
 Is this a valid Message ID? More...
 
bool mutt_addr_cmp (const struct Address *a, const struct Address *b)
 Compare two e-mail addresses. More...
 
struct Addressmutt_addr_copy (const struct Address *addr)
 Copy the real address. More...
 
struct Addressmutt_addr_create (const char *personal, const char *mailbox)
 Create and populate a new Address. More...
 
const char * mutt_addr_for_display (const struct Address *a)
 Convert an Address for display purposes. More...
 
void mutt_addr_free (struct Address **ptr)
 Free a single Address. More...
 
struct Addressmutt_addr_new (void)
 Create a new Address. More...
 
bool mutt_addr_to_intl (struct Address *a)
 Convert an Address to Punycode. More...
 
bool mutt_addr_to_local (struct Address *a)
 Convert an Address from Punycode. More...
 
bool mutt_addr_uses_unicode (const char *str)
 Does this address use Unicode character. More...
 
size_t mutt_addr_write (struct Buffer *buf, struct Address *addr, bool display)
 Write a single Address to a buffer. More...
 
void mutt_addrlist_append (struct AddressList *al, struct Address *a)
 Append an Address to an AddressList. More...
 
void mutt_addrlist_clear (struct AddressList *al)
 Unlink and free all Address in an AddressList. More...
 
void mutt_addrlist_copy (struct AddressList *dst, const struct AddressList *src, bool prune)
 Copy a list of addresses into another list. More...
 
int mutt_addrlist_count_recips (const struct AddressList *al)
 Count the number of Addresses with valid recipients. More...
 
void mutt_addrlist_dedupe (struct AddressList *al)
 Remove duplicate addresses. More...
 
bool mutt_addrlist_equal (const struct AddressList *ala, const struct AddressList *alb)
 Compare two Address lists for equality. 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_prepend (struct AddressList *al, struct Address *a)
 Prepend an Address to an AddressList. More...
 
void mutt_addrlist_qualify (struct AddressList *al, const char *host)
 Expand local names in an Address list using a hostname. More...
 
int mutt_addrlist_remove (struct AddressList *al, const char *mailbox)
 Remove an Address from a list. More...
 
void mutt_addrlist_remove_xrefs (const struct AddressList *a, struct AddressList *b)
 Remove cross-references. More...
 
bool mutt_addrlist_search (const struct AddressList *haystack, const struct Address *needle)
 Search for an e-mail address in a list. More...
 
int mutt_addrlist_to_intl (struct AddressList *al, char **err)
 Convert an Address list to Punycode. More...
 
int mutt_addrlist_to_local (struct AddressList *al)
 Convert an Address list from Punycode. More...
 
bool mutt_addrlist_uses_unicode (const struct AddressList *al)
 Do any of a list of addresses use Unicode characters. More...
 
size_t mutt_addrlist_write (const struct AddressList *al, struct Buffer *buf, bool display)
 Write an Address to a buffer. More...
 
size_t mutt_addrlist_write_wrap (const struct AddressList *al, struct Buffer *buf, const char *header)
 Write an AddressList to a buffer, perform line wrapping. More...
 
void mutt_addrlist_write_file (const struct AddressList *al, FILE *fp, const char *header)
 Wrapper for mutt_write_address() More...
 
size_t mutt_addrlist_write_list (const struct AddressList *al, struct ListHead *list)
 Write Addresses to a List. More...
 

Variables

int AddressError
 An out-of-band error code. More...
 
const char *const AddressErrors []
 Messages for the error codes in AddressError. More...
 
const char AddressSpecials []
 Characters with special meaning for email addresses. More...
 

Detailed Description

Representation of an email address.

Authors
  • 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.h.

Macro Definition Documentation

◆ address_error

#define address_error (   num)    AddressErrors[num]

Definition at line 63 of file address.h.

Typedef Documentation

◆ addr_predicate_t

typedef bool(* addr_predicate_t) (const struct Address *a)

Definition at line 73 of file address.h.

Enumeration Type Documentation

◆ AddressError

Possible values for AddressError.

Enumerator
ADDR_ERR_MEMORY 

Out of memory.

ADDR_ERR_MISMATCH_PAREN 

Mismatched parentheses.

ADDR_ERR_MISMATCH_QUOTE 

Mismatches quotes.

ADDR_ERR_BAD_ROUTE 

Bad route.

ADDR_ERR_BAD_ROUTE_ADDR 

Bad route address.

ADDR_ERR_BAD_ADDR_SPEC 

Bad address specifier.

Definition at line 49 of file address.h.

50{
51 ADDR_ERR_MEMORY = 1,
57};
@ ADDR_ERR_BAD_ROUTE
Bad route.
Definition: address.h:54
@ ADDR_ERR_BAD_ROUTE_ADDR
Bad route address.
Definition: address.h:55
@ ADDR_ERR_BAD_ADDR_SPEC
Bad address specifier.
Definition: address.h:56
@ ADDR_ERR_MEMORY
Out of memory.
Definition: address.h:51
@ ADDR_ERR_MISMATCH_PAREN
Mismatched parentheses.
Definition: address.h:52
@ ADDR_ERR_MISMATCH_QUOTE
Mismatches quotes.
Definition: address.h:53

Function Documentation

◆ TAILQ_HEAD()

TAILQ_HEAD ( AddressList  ,
Address   
)

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

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

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

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

◆ mutt_addr_cmp()

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

Compare two e-mail addresses.

Parameters
aAddress 1
bAddress 2
Return values
trueThey are equivalent

Definition at line 872 of file address.c.

873{
874 if (!a || !b)
875 return false;
876 if (!a->mailbox || !b->mailbox)
877 return false;
878 if (!mutt_istr_equal(a->mailbox, b->mailbox))
879 return false;
880 return true;
881}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
char * mailbox
Mailbox and host address.
Definition: address.h:38
+ 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 724 of file address.c.

725{
726 if (!addr)
727 return NULL;
728
729 struct Address *p = mutt_addr_new();
730
731 p->personal = mutt_str_dup(addr->personal);
732 p->mailbox = mutt_str_dup(addr->mailbox);
733 p->group = addr->group;
734 p->is_intl = addr->is_intl;
735 p->intl_checked = addr->intl_checked;
736 return p;
737}
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:389
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
bool intl_checked
Checked for IDN?
Definition: address.h:41
bool is_intl
International Domain Name.
Definition: address.h:40
char * personal
Real name of address.
Definition: address.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

403{
404 struct Address *a = mutt_addr_new();
407 return a;
408}
+ Here is the call graph for this function:
+ 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 994 of file address.c.

995{
996 if (!a)
997 return NULL;
998
999 char *user = NULL, *domain = NULL;
1000 static char *buf = NULL;
1001
1002 if (!a->mailbox || addr_is_local(a))
1003 return a->mailbox;
1004
1005 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1006 return a->mailbox;
1007
1008 char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_MAY_BE_IRREVERSIBLE);
1009
1010 FREE(&user);
1011 FREE(&domain);
1012
1013 if (!local_mailbox)
1014 return a->mailbox;
1015
1016 mutt_str_replace(&buf, local_mailbox);
1017 FREE(&local_mailbox);
1018
1019 return buf;
1020}
static int addr_mbox_to_udomain(const char *mbox, char **user, char **domain)
Split a mailbox name into user and domain.
Definition: address.c:937
static bool addr_is_local(const struct Address *a)
Does the Address have NO IDN components.
Definition: address.c:920
#define MI_MAY_BE_IRREVERSIBLE
Definition: idna2.h:30
char * mutt_idna_intl_to_local(const char *user, const char *domain, uint8_t flags)
Convert an email's domain from Punycode.
Definition: idna.c:144
#define FREE(x)
Definition: memory.h:43
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_free()

void mutt_addr_free ( struct Address **  ptr)

Free a single Address.

Parameters
[out]ptrAddress to free

Definition at line 444 of file address.c.

445{
446 if (!ptr || !*ptr)
447 return;
448
449 struct Address *a = *ptr;
450
451 FREE(&a->personal);
452 FREE(&a->mailbox);
453 FREE(ptr);
454}
+ 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 389 of file address.c.

390{
391 return mutt_mem_calloc(1, sizeof(struct Address));
392}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_to_intl()

bool mutt_addr_to_intl ( struct Address a)

Convert an Address to Punycode.

Parameters
aAddress to convert
Return values
trueSuccess
falseOtherwise

Definition at line 1249 of file address.c.

1250{
1251 if (!a || !a->mailbox || addr_is_intl(a))
1252 return true;
1253
1254 char *user = NULL;
1255 char *domain = NULL;
1256 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1257 return true;
1258
1259 char *intl_mailbox = mutt_idna_local_to_intl(user, domain);
1260
1261 FREE(&user);
1262 FREE(&domain);
1263
1264 if (!intl_mailbox)
1265 return false;
1266
1267 addr_set_intl(a, intl_mailbox);
1268 return true;
1269}
static bool addr_is_intl(const struct Address *a)
Does the Address have IDN components.
Definition: address.c:908
static void addr_set_intl(struct Address *a, char *intl_mailbox)
Mark an Address as having IDN components.
Definition: address.c:959
char * mutt_idna_local_to_intl(const char *user, const char *domain)
Convert an email's domain to Punycode.
Definition: idna.c:264
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_to_local()

bool mutt_addr_to_local ( struct Address a)

Convert an Address from Punycode.

Parameters
aAddress to convert
Return values
trueSuccess
falseOtherwise

Definition at line 1324 of file address.c.

1325{
1326 if (!a->mailbox)
1327 {
1328 return false;
1329 }
1330
1331 if (addr_is_local(a))
1332 {
1333 return true;
1334 }
1335
1336 char *user = NULL;
1337 char *domain = NULL;
1338 if (addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1)
1339 {
1340 return false;
1341 }
1342
1343 char *local_mailbox = mutt_idna_intl_to_local(user, domain, MI_NO_FLAGS);
1344 FREE(&user);
1345 FREE(&domain);
1346
1347 if (!local_mailbox)
1348 {
1349 return false;
1350 }
1351
1352 addr_set_local(a, local_mailbox);
1353 return true;
1354}
static void addr_set_local(struct Address *a, char *local_mailbox)
Mark an Address as having NO IDN components.
Definition: address.c:975
#define MI_NO_FLAGS
Definition: idna2.h:29
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_uses_unicode()

bool mutt_addr_uses_unicode ( const char *  str)

Does this address use Unicode character.

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

Definition at line 1485 of file address.c.

1486{
1487 if (!str)
1488 return false;
1489
1490 while (*str)
1491 {
1492 if ((unsigned char) *str & (1 << 7))
1493 return true;
1494 str++;
1495 }
1496
1497 return false;
1498}
+ Here is the caller graph for this function:

◆ mutt_addr_write()

size_t mutt_addr_write ( struct Buffer buf,
struct Address addr,
bool  display 
)

Write a single Address to a buffer.

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

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

Definition at line 1032 of file address.c.

1033{
1034 if (!buf || !addr || (!addr->personal && !addr->mailbox))
1035 {
1036 return 0;
1037 }
1038
1039 const size_t initial_len = mutt_buffer_len(buf);
1040
1041 if (addr->personal)
1042 {
1043 if (strpbrk(addr->personal, AddressSpecials))
1044 {
1045 mutt_buffer_addch(buf, '"');
1046 for (const char *pc = addr->personal; *pc; pc++)
1047 {
1048 if ((*pc == '"') || (*pc == '\\'))
1049 {
1050 mutt_buffer_addch(buf, '\\');
1051 }
1052 mutt_buffer_addch(buf, *pc);
1053 }
1054 mutt_buffer_addch(buf, '"');
1055 }
1056 else
1057 {
1058 mutt_buffer_addstr(buf, addr->personal);
1059 }
1060
1061 mutt_buffer_addch(buf, ' ');
1062 }
1063
1064 if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1065 {
1066 mutt_buffer_addch(buf, '<');
1067 }
1068
1069 if (addr->mailbox)
1070 {
1071 if (!mutt_str_equal(addr->mailbox, "@"))
1072 {
1073 const char *a = display ? mutt_addr_for_display(addr) : addr->mailbox;
1074 mutt_buffer_addstr(buf, a);
1075 }
1076
1077 if (addr->personal || (addr->mailbox && (*addr->mailbox == '@')))
1078 {
1079 mutt_buffer_addch(buf, '>');
1080 }
1081
1082 if (addr->group)
1083 {
1084 mutt_buffer_addstr(buf, ": ");
1085 }
1086 }
1087 else
1088 {
1089 mutt_buffer_addch(buf, ';');
1090 }
1091
1092 return mutt_buffer_len(buf) - initial_len;
1093}
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
const char * mutt_addr_for_display(const struct Address *a)
Convert an Address for display purposes.
Definition: address.c:994
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:409
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
+ 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 1463 of file address.c.

1464{
1465 if (al && a)
1466 TAILQ_INSERT_TAIL(al, a, entries);
1467}
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
+ 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 1443 of file address.c.

1444{
1445 if (!al)
1446 return;
1447
1448 struct Address *a = TAILQ_FIRST(al), *next = NULL;
1449 while (a)
1450 {
1451 next = TAILQ_NEXT(a, entries);
1452 mutt_addr_free(&a);
1453 a = next;
1454 }
1455 TAILQ_INIT(al);
1456}
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:444
#define TAILQ_INIT(head)
Definition: queue.h:765
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

746{
747 if (!dst || !src)
748 return;
749
750 struct Address *a = NULL;
751 TAILQ_FOREACH(a, src, entries)
752 {
753 struct Address *next = TAILQ_NEXT(a, entries);
754 if (prune && a->group && (!next || !next->mailbox))
755 {
756 /* ignore this element of the list */
757 }
758 else
759 {
761 }
762 }
763}
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1463
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:724
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

853{
854 if (!al)
855 return 0;
856
857 int c = 0;
858 struct Address *a = NULL;
859 TAILQ_FOREACH(a, al, entries)
860 {
861 c += (a->mailbox && !a->group);
862 }
863 return c;
864}
+ 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 1380 of file address.c.

1381{
1382 if (!al)
1383 return;
1384
1385 struct Address *a = NULL;
1386 TAILQ_FOREACH(a, al, entries)
1387 {
1388 if (a->mailbox)
1389 {
1390 struct Address *a2 = TAILQ_NEXT(a, entries);
1391 struct Address *tmp = NULL;
1392
1393 if (a2)
1394 {
1395 TAILQ_FOREACH_FROM_SAFE(a2, al, entries, tmp)
1396 {
1397 if (a2->mailbox && mutt_istr_equal(a->mailbox, a2->mailbox))
1398 {
1399 mutt_debug(LL_DEBUG2, "Removing %s\n", a2->mailbox);
1400 TAILQ_REMOVE(al, a2, entries);
1401 mutt_addr_free(&a2);
1402 }
1403 }
1404 }
1405 }
1406 }
1407}
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)
Definition: queue.h:740
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

821{
822 if (!ala || !alb)
823 {
824 return !(ala || alb);
825 }
826
827 struct Address *ana = TAILQ_FIRST(ala);
828 struct Address *anb = TAILQ_FIRST(alb);
829
830 while (ana && anb)
831 {
832 if (!mutt_str_equal(ana->mailbox, anb->mailbox) ||
833 !mutt_str_equal(ana->personal, anb->personal))
834 {
835 break;
836 }
837
838 ana = TAILQ_NEXT(ana, entries);
839 anb = TAILQ_NEXT(anb, entries);
840 }
841
842 return !(ana || anb);
843}
+ Here is the call graph for this function:
+ 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 462 of file address.c.

463{
464 if (!s)
465 return 0;
466
467 int parsed = 0;
468 char comment[1024], phrase[1024];
469 size_t phraselen = 0, commentlen = 0;
470 AddressError = 0;
471
472 bool ws_pending = mutt_str_is_email_wsp(*s);
473
475 while (*s)
476 {
477 switch (*s)
478 {
479 case ';':
480 case ',':
481 if (phraselen != 0)
482 {
483 terminate_buffer(phrase, phraselen);
484 if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
485 {
486 parsed++;
487 }
488 }
489 else if (commentlen != 0)
490 {
491 struct Address *last = TAILQ_LAST(al, AddressList);
492 if (last && !last->personal && last->mailbox)
493 {
494 terminate_buffer(comment, commentlen);
495 last->personal = mutt_str_dup(comment);
496 }
497 }
498
499 if (*s == ';')
500 {
501 /* add group terminator */
503 }
504
505 phraselen = 0;
506 commentlen = 0;
507 s++;
508 break;
509
510 case '(':
511 if ((commentlen != 0) && (commentlen < (sizeof(comment) - 1)))
512 comment[commentlen++] = ' ';
513 s = next_token(s, comment, &commentlen, sizeof(comment) - 1);
514 if (!s)
515 {
517 return 0;
518 }
519 break;
520
521 case '"':
522 if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)))
523 phrase[phraselen++] = ' ';
524 s = parse_quote(s + 1, phrase, &phraselen, sizeof(phrase) - 1);
525 if (!s)
526 {
528 return 0;
529 }
530 break;
531
532 case ':':
533 {
534 struct Address *a = mutt_addr_new();
535 terminate_buffer(phrase, phraselen);
536 a->mailbox = mutt_str_dup(phrase);
537 a->group = true;
539 phraselen = 0;
540 commentlen = 0;
541 s++;
542 break;
543 }
544
545 case '<':
546 {
547 struct Address *a = mutt_addr_new();
548 terminate_buffer(phrase, phraselen);
549 a->personal = mutt_str_dup(phrase);
550 s = parse_route_addr(s + 1, comment, &commentlen, sizeof(comment) - 1, a);
551 if (!s)
552 {
554 mutt_addr_free(&a);
555 return 0;
556 }
558 phraselen = 0;
559 commentlen = 0;
560 parsed++;
561 break;
562 }
563
564 default:
565 if ((phraselen != 0) && (phraselen < (sizeof(phrase) - 1)) && ws_pending)
566 phrase[phraselen++] = ' ';
567 if (*s == '\\')
568 {
569 s++;
570 if (*s && (phraselen < (sizeof(phrase) - 1)))
571 {
572 phrase[phraselen++] = *s;
573 s++;
574 }
575 }
576 s = next_token(s, phrase, &phraselen, sizeof(phrase) - 1);
577 if (!s)
578 {
580 return 0;
581 }
582 break;
583 } // switch (*s)
584
585 ws_pending = mutt_str_is_email_wsp(*s);
587 } // while (*s)
588
589 if (phraselen != 0)
590 {
591 terminate_buffer(phrase, phraselen);
592 terminate_buffer(comment, commentlen);
593 if (add_addrspec(al, phrase, comment, &commentlen, sizeof(comment) - 1))
594 {
595 parsed++;
596 }
597 }
598 else if (commentlen != 0)
599 {
600 struct Address *last = TAILQ_LAST(al, AddressList);
601 if (last && !last->personal && last->mailbox)
602 {
603 terminate_buffer(comment, commentlen);
604 last->personal = mutt_str_dup(comment);
605 }
606 }
607
608 return parsed;
609}
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:368
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:287
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1443
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:153
static const char * parse_quote(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
Extract a quoted string.
Definition: address.c:122
AddressError
Possible values for AddressError.
Definition: address.h:50
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:679
bool mutt_str_is_email_wsp(char c)
Is this a whitespace character (for an email header)
Definition: string.c:695
#define TAILQ_LAST(head, headname)
Definition: queue.h:819
#define terminate_buffer(str, strlen)
Definition: string2.h:53
+ 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 620 of file address.c.

621{
622 if (!s || (*s == '\0'))
623 return 0;
624
625 int parsed = 0;
626
627 /* check for a simple whitespace separated list of addresses */
628 if (!strpbrk(s, "\"<>():;,\\"))
629 {
630 char *copy = mutt_str_dup(s);
631 char *r = copy;
632 while ((r = strtok(r, " \t")))
633 {
634 parsed += mutt_addrlist_parse(al, r);
635 r = NULL;
636 }
637 FREE(&copy);
638 }
639 else
640 {
641 parsed = mutt_addrlist_parse(al, s);
642 }
643
644 return parsed;
645}
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:462
+ Here is the call graph for this function:
+ 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 1474 of file address.c.

1475{
1476 if (al && a)
1477 TAILQ_INSERT_HEAD(al, a, entries);
1478}
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:796
+ 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 656 of file address.c.

657{
658 if (!al || !host || (*host == '\0'))
659 return;
660
661 struct Address *a = NULL;
662 TAILQ_FOREACH(a, al, entries)
663 {
664 if (!a->group && a->mailbox && !strchr(a->mailbox, '@'))
665 {
666 char *p = mutt_mem_malloc(mutt_str_len(a->mailbox) + mutt_str_len(host) + 2);
667 sprintf(p, "%s@%s", a->mailbox, host);
668 FREE(&a->mailbox);
669 a->mailbox = p;
670 }
671 }
672}
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
+ 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 417 of file address.c.

418{
419 if (!al)
420 return -1;
421
422 if (!mailbox)
423 return 0;
424
425 int rc = -1;
426 struct Address *a = NULL, *tmp = NULL;
427 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
428 {
430 {
431 TAILQ_REMOVE(al, a, entries);
432 mutt_addr_free(&a);
433 rc = 0;
434 }
435 }
436
437 return rc;
438}
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
+ 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 1416 of file address.c.

1417{
1418 if (!a || !b)
1419 return;
1420
1421 struct Address *aa = NULL, *ab = NULL, *tmp = NULL;
1422
1423 TAILQ_FOREACH_SAFE(ab, b, entries, tmp)
1424 {
1425 TAILQ_FOREACH(aa, a, entries)
1426 {
1427 if (mutt_addr_cmp(aa, ab))
1428 {
1429 TAILQ_REMOVE(b, ab, entries);
1430 mutt_addr_free(&ab);
1431 break;
1432 }
1433 }
1434 }
1435}
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:872
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_search()

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

Search for an e-mail address in a list.

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

Definition at line 889 of file address.c.

890{
891 if (!needle || !haystack)
892 return false;
893
894 struct Address *a = NULL;
895 TAILQ_FOREACH(a, haystack, entries)
896 {
897 if (mutt_addr_cmp(needle, a))
898 return true;
899 }
900 return false;
901}
+ 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 1278 of file address.c.

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

1362{
1363 if (!al)
1364 return 0;
1365
1366 struct Address *a = NULL;
1367 TAILQ_FOREACH(a, al, entries)
1368 {
1370 }
1371 return 0;
1372}
bool mutt_addr_to_local(struct Address *a)
Convert an Address from Punycode.
Definition: address.c:1324
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_uses_unicode()

bool mutt_addrlist_uses_unicode ( const struct AddressList *  al)

Do any of a list of addresses use Unicode characters.

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

Definition at line 1505 of file address.c.

1506{
1507 if (!al)
1508 {
1509 return false;
1510 }
1511
1512 struct Address *a = NULL;
1513 TAILQ_FOREACH(a, al, entries)
1514 {
1515 if (a->mailbox && !a->group && mutt_addr_uses_unicode(a->mailbox))
1516 return true;
1517 }
1518 return false;
1519}
bool mutt_addr_uses_unicode(const char *str)
Does this address use Unicode character.
Definition: address.c:1485
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write()

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

Write an Address to a buffer.

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

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

Definition at line 1192 of file address.c.

1193{
1194 return addrlist_write(al, buf, display, NULL, -1);
1195}
static size_t addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display, const char *header, int cols)
Write an AddressList to a buffer, optionally perform line wrapping and display conversion.
Definition: address.c:1108
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write_wrap()

size_t mutt_addrlist_write_wrap ( const struct AddressList *  al,
struct Buffer buf,
const char *  header 
)

Write an AddressList to a buffer, perform line wrapping.

Parameters
alAddressList to display
bufBuffer for the Address
headerHeader name; if present, addresses we be written after ": "
Return values
numLength of the string written to buf

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

Definition at line 1175 of file address.c.

1177{
1178 return addrlist_write(al, buf, false, header, 74);
1179}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addrlist_write_file()

void mutt_addrlist_write_file ( const struct AddressList *  al,
FILE *  fp,
const char *  header 
)

Wrapper for mutt_write_address()

Parameters
alAddress list
fpFile to write to
headerHeader name; if present, addresses we be written after ": "

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

Definition at line 1234 of file address.c.

1235{
1236 struct Buffer *buf = mutt_buffer_pool_get();
1237 mutt_addrlist_write_wrap(al, buf, header);
1238 fputs(mutt_buffer_string(buf), fp);
1240 fputc('\n', fp);
1241}
size_t mutt_addrlist_write_wrap(const struct AddressList *al, struct Buffer *buf, const char *header)
Write an AddressList to a buffer, perform line wrapping.
Definition: address.c:1175
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
String manipulation buffer.
Definition: buffer.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

1204{
1205 if (!al || !list)
1206 return 0;
1207
1208 size_t count = 0;
1209 struct Address *a = NULL;
1210 TAILQ_FOREACH(a, al, entries)
1211 {
1212 struct Buffer buf = { 0 };
1213 mutt_addr_write(&buf, a, true);
1214 if (!mutt_buffer_is_empty(&buf))
1215 {
1216 /* We're taking the ownership of the buffer string here */
1217 mutt_list_insert_tail(list, (char *) mutt_buffer_string(&buf));
1218 count++;
1219 }
1220 }
1221
1222 return count;
1223}
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1032
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:298
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:

Variable Documentation

◆ AddressError

int AddressError
extern

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[]
extern

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.

◆ AddressSpecials

const char AddressSpecials[]
extern

Characters with special meaning for email addresses.

Definition at line 42 of file address.c.