diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-smtp/smtp-address.h | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/src/lib-smtp/smtp-address.h b/src/lib-smtp/smtp-address.h new file mode 100644 index 0000000..326a673 --- /dev/null +++ b/src/lib-smtp/smtp-address.h @@ -0,0 +1,214 @@ +#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 |