#ifndef SMTP_ADDRESS_H #define SMTP_ADDRESS_H #include "array-decl.h" struct message_address; enum smtp_address_parse_flags { /* Strictly enforce the RFC 5321 syntax */ SMTP_ADDRESS_PARSE_FLAG_STRICT = BIT(0), /* Allow an empty/NULL address */ SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY = BIT(1), /* Allow an address without a domain part */ SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART = BIT(2), /* Allow omission of the <...> brackets in a path. This flag is only relevant for smtp_address_parse_path(). */ SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL = BIT(3), /* Allow localpart to have all kinds of bad unquoted characters by parsing the last '@' in the string directly as the localpart/domain separator. Addresses starting with `<' or `"' are parsed as normal. The address is rejected when the resulting localpart and domain cannot be used to construct a valid RFC 5321 address. */ SMTP_ADDRESS_PARSE_FLAG_ALLOW_BAD_LOCALPART = BIT(4), /* Store an unparsed copy of the address in the `raw' field of struct smtp_address. When combined with SMTP_ADDRESS_PARSE_FLAG_SKIP_BROKEN, the broken address will be stored there. This flag is only relevant for smtp_address_parse_path(). */ SMTP_ADDRESS_PARSE_FLAG_PRESERVE_RAW = BIT(5), /* Try to skip over a broken address to allow working around syntax errors in e.g. the sender address for the MAIL command. This flag is only relevant for smtp_address_parse_path*(). The parser will return failure, but it will return a broken address which is be equivalent to <>. The raw broken address string is available in the address->raw field. When the broken address contains control characters or is badly delimited, parsing will still fail completely. */ SMTP_ADDRESS_PARSE_FLAG_IGNORE_BROKEN = BIT(6), }; struct smtp_address { /* Localpart */ const char *localpart; /* Domain */ const char *domain; /* Raw, unparsed address. If localpart == NULL, the value of this field is syntactically invalid and MUST NOT be used for any purposes that may be visible to external systems. It can be e.g. used for logging. This is always in mailbox format, meaning that there are no surrounding '<' and '>'. */ const char *raw; }; ARRAY_DEFINE_TYPE(smtp_address, struct smtp_address *); ARRAY_DEFINE_TYPE(smtp_address_const, const struct smtp_address *); /* * SMTP address parsing */ /* Parse the RFC 5321 address from the provided mailbox string. Returns 0 when the address was parsed successfully and -1 upon error. The address is returned in address_r. When address_r is NULL, the provided string will be verified for validity as a mailbox only. */ int smtp_address_parse_mailbox(pool_t pool, const char *mailbox, enum smtp_address_parse_flags flags, struct smtp_address **address_r, const char **error_r) ATTR_NULL(4, 5); /* Parse the RFC 5321 address from the provided path string. Returns 0 when the address was parsed successfully and -1 upon error. The address is returned in address_r. When address_r is NULL, the provided string will be verified for validity as a path only. The endp_r parameter is used to return a pointer to the end of the path string, so that the caller can continue parsing from there. When the SMTP_ADDRESS_PARSE_FLAG_IGNORE_BROKEN flag is set, a broken address will be returned, even when the return value is -1 (see above). If it is totally broken, *endp_r will be then be NULL. */ int smtp_address_parse_path_full(pool_t pool, const char *path, enum smtp_address_parse_flags flags, struct smtp_address **address_r, const char **error_r, const char **endp_r) ATTR_NULL(4, 5, 6); /* Parse the RFC 5321 address from the provided path string. Returns 0 when the address was parsed successfully and -1 upon error. The address is returned in address_r. When address_r is NULL, the provided string will be verified for validity as a path only. When the SMTP_ADDRESS_PARSE_FLAG_IGNORE_BROKEN flag is set, a broken address will be returned, even when the return value is -1 (see above). */ int smtp_address_parse_path(pool_t pool, const char *path, enum smtp_address_parse_flags flags, struct smtp_address **address_r, const char **error_r) ATTR_NULL(4, 5); /* Parse the RFC 5321 address from the provided username string. A username string is not strictly parsed as an RFC 5321 mailbox; it allows a more lenient syntax. If the address obtained from splitting the string at the last `@' can be encoded back into a valid RFC 5321 mailbox string, parsing the username will succeeded. Returns 0 when the address was parsed successfully and -1 upon error. The address is returned in address_r. When address_r is NULL, the provided string will be verified for validity as a username only. */ int smtp_address_parse_username(pool_t pool, const char *username, struct smtp_address **address_r, const char **error_r) ATTR_NULL(3, 4); /* Parse address+detail@domain into address@domain and detail using given delimiters. Returns used delimiter. */ void smtp_address_detail_parse(pool_t pool, const char *delimiters, struct smtp_address *address, const char **username_r, char *delim_r, const char **detail_r); void smtp_address_detail_parse_temp(const char *delimiters, struct smtp_address *address, const char **username_r, char *delim_r, const char **detail_r); /* Parse any (possibly broken) address on the input to the best of our ability until end of input or unquoted ` '. Things that are truly evil (unending quoted string, control characters and a path without a closing '>') will still fail and return -1. If the parse was successful, it will return 0. The parsed address string is returned in address_r. Any outer < and > are omitted in the parsed address. The endp_r parameter is used to return a pointer to the end of the path string, so that the caller can continue parsing from there.*/ int smtp_address_parse_any(const char *in, const char **address_r, const char **endp_r) ATTR_NULL(2, 3); /* * SMTP address construction */ void smtp_address_write(string_t *out, const struct smtp_address *address) ATTR_NULL(2); void smtp_address_write_path(string_t *out, const struct smtp_address *address) ATTR_NULL(2); const char *smtp_address_encode(const struct smtp_address *address) ATTR_NULL(1); const char *smtp_address_encode_path(const struct smtp_address *address) ATTR_NULL(1); const char * smtp_address_encode_raw(const struct smtp_address *address) ATTR_NULL(1); const char * smtp_address_encode_raw_path(const struct smtp_address *address) ATTR_NULL(1); /* * SMTP address manipulation */ void smtp_address_init(struct smtp_address *address, const char *localpart, const char *domain) ATTR_NULL(2,3); int smtp_address_init_from_msg(struct smtp_address *address, const struct message_address *msg_addr); struct smtp_address * smtp_address_clone(pool_t pool, const struct smtp_address *address) ATTR_NULL(2); struct smtp_address * smtp_address_create(pool_t pool, const char *localpart, const char *domain) ATTR_NULL(2, 3); int smtp_address_create_from_msg(pool_t pool, const struct message_address *msg_addr, struct smtp_address **address_r); struct smtp_address * smtp_address_clone_temp(const struct smtp_address *address) ATTR_NULL(1); struct smtp_address * smtp_address_create_temp(const char *localpart, const char *domain) ATTR_NULL(2, 3); int smtp_address_create_from_msg_temp(const struct message_address *msg_addr, struct smtp_address **address_r); struct smtp_address * smtp_address_add_detail(pool_t pool, const struct smtp_address *address, const char *detail, char delim_c); struct smtp_address * smtp_address_add_detail_temp(const struct smtp_address *address, const char *detail, char delim_c); int smtp_address_cmp(const struct smtp_address *address1, const struct smtp_address *address2) ATTR_NULL(1, 2); int smtp_address_cmp_icase(const struct smtp_address *address1, const struct smtp_address *address2) ATTR_NULL(1, 2); static inline bool ATTR_NULL(1, 2) smtp_address_equals(const struct smtp_address *address1, const struct smtp_address *address2) { return (smtp_address_cmp(address1, address2) == 0); } static inline bool ATTR_NULL(1, 2) smtp_address_equals_icase(const struct smtp_address *address1, const struct smtp_address *address2) { return (smtp_address_cmp_icase(address1, address2) == 0); } static inline bool ATTR_NULL(1) ATTR_PURE smtp_address_isnull(const struct smtp_address *address) { return (address == NULL || address->localpart == NULL); } static inline bool ATTR_NULL(1) ATTR_PURE smtp_address_is_broken(const struct smtp_address *address) { return (address != NULL && smtp_address_isnull(address) && (address->raw != NULL && *address->raw != '\0')); } #endif