From: Richard Russon Date: Sat, 30 Dec 2017 15:30:39 +0000 (+0000) Subject: reorg: idna -> address, envelope X-Git-Tag: neomutt-20180223~56^2~5 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=813440fe1618d7c066bfe6b2e9e91c9e3902f0df;p=neomutt reorg: idna -> address, envelope --- diff --git a/address.c b/address.c index 194b459e5..fbf250762 100644 --- a/address.c +++ b/address.c @@ -40,14 +40,20 @@ * | mutt_addr_cmp_strict() | Strictly compare two Address lists * | mutt_addr_copy() | Copy the real address * | mutt_addr_copy_list() | Copy a list of addresses + * | mutt_addr_for_display() | Convert an Address for display purposes * | mutt_addr_free() | Free a list of Addresses * | mutt_addr_has_recips() | Count the number of Addresses with valid recipients + * | mutt_addr_is_intl() | Does the Address have IDN components + * | mutt_addr_is_local() | Does the Address have NO IDN components + * | mutt_addr_mbox_to_udomain() | Split a mailbox name into user and domain * | mutt_addr_new() | Create a new Address * | mutt_addr_parse_list() | Parse a list of email addresses * | mutt_addr_parse_list2() | Parse a list of email addresses * | mutt_addr_qualify() | Expand local names in an Address list using a hostname * | mutt_addr_remove_from_list() | Remove an Address from a list * | mutt_addr_search() | Search for an e-mail address in a list + * | mutt_addr_set_intl() | Mark an Address as having IDN components + * | mutt_addr_set_local() | Mark an Address as having NO IDN components * | mutt_addr_valid_msgid() | Is this a valid Message ID? */ @@ -932,3 +938,106 @@ bool mutt_addr_search(struct Address *a, struct Address *lst) } return false; } + +/** + * mutt_addr_is_intl - Does the Address have IDN components + * @param a Address to check + * @retval true Address contains IDN components + */ +bool mutt_addr_is_intl(struct Address *a) +{ + return (a->intl_checked && a->is_intl); +} + +/** + * mutt_addr_is_local - Does the Address have NO IDN components + * @param a Address to check + * @retval true Address contains NO IDN components + */ +bool mutt_addr_is_local(struct Address *a) +{ + return (a->intl_checked && !a->is_intl); +} + +/** + * mutt_addr_mbox_to_udomain - Split a mailbox name into user and domain + * @param[in] mbox Mailbox name to split + * @param[out] user User + * @param[out] domain Domain + * @retval 0 Success + * @retval -1 Error + */ +int mutt_addr_mbox_to_udomain(const char *mbox, char **user, char **domain) +{ + static char *buf = NULL; + char *p = NULL; + + mutt_str_replace(&buf, mbox); + if (!buf) + return -1; + + p = strchr(buf, '@'); + if (!p || !p[1]) + return -1; + *p = '\0'; + *user = buf; + *domain = p + 1; + return 0; +} + +/** + * mutt_addr_set_intl - Mark an Address as having IDN components + * @param a Address to modify + * @param intl_mailbox Email address with IDN components + */ +void mutt_addr_set_intl(struct Address *a, char *intl_mailbox) +{ + FREE(&a->mailbox); + a->mailbox = intl_mailbox; + a->intl_checked = true; + a->is_intl = true; +} + +/** + * mutt_addr_set_local - Mark an Address as having NO IDN components + * @param a Address + * @param local_mailbox Email address with NO IDN components + */ +void mutt_addr_set_local(struct Address *a, char *local_mailbox) +{ + FREE(&a->mailbox); + a->mailbox = local_mailbox; + a->intl_checked = true; + a->is_intl = false; +} + +/** + * mutt_addr_for_display - Convert an Address for display purposes + * @param a Address to convert + * @retval ptr Address 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. + */ +const char *mutt_addr_for_display(struct Address *a) +{ + char *user = NULL, *domain = NULL; + static char *buf = NULL; + char *local_mailbox = NULL; + + FREE(&buf); + + if (!a->mailbox || mutt_addr_is_local(a)) + return a->mailbox; + + if (mutt_addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1) + return a->mailbox; + + local_mailbox = mutt_idna_intl_to_local(user, domain, MI_MAY_BE_IRREVERSIBLE); + if (!local_mailbox) + return a->mailbox; + + mutt_str_replace(&buf, local_mailbox); + FREE(&local_mailbox); + return buf; +} diff --git a/address.h b/address.h index 67f62e0da..03d6afe57 100644 --- a/address.h +++ b/address.h @@ -24,6 +24,7 @@ #define _MUTT_ADDRESS_H #include +#include /** * struct Address - An email address @@ -63,14 +64,20 @@ bool mutt_addr_cmp_strict(const struct Address *a, const struct Addre bool mutt_addr_cmp(struct Address *a, struct Address *b); struct Address *mutt_addr_copy_list(struct Address *addr, bool prune); struct Address *mutt_addr_copy(struct Address *addr); +const char * mutt_addr_for_display(struct Address *a); void mutt_addr_free(struct Address **p); int mutt_addr_has_recips(struct Address *a); +bool mutt_addr_is_intl(struct Address *a); +bool mutt_addr_is_local(struct Address *a); +int mutt_addr_mbox_to_udomain(const char *mbox, char **user, char **domain); struct Address *mutt_addr_new(void); struct Address *mutt_addr_parse_list2(struct Address *p, const char *s); struct Address *mutt_addr_parse_list(struct Address *top, const char *s); void mutt_addr_qualify(struct Address *addr, const char *host); int mutt_addr_remove_from_list(struct Address **a, const char *mailbox); bool mutt_addr_search(struct Address *a, struct Address *lst); +void mutt_addr_set_intl(struct Address *a, char *intl_mailbox); +void mutt_addr_set_local(struct Address *a, char *local_mailbox); bool mutt_addr_valid_msgid(const char *msgid); #endif /* _MUTT_ADDRESS_H */ diff --git a/envelope.c b/envelope.c index 112a661e8..e8b21d69f 100644 --- a/envelope.c +++ b/envelope.c @@ -31,6 +31,8 @@ * | mutt_env_free() | Free an Envelope * | mutt_env_merge() | Merge the headers of two Envelopes * | mutt_env_new() | Create a new Envelope + * | mutt_env_to_intl() | Convert an Envelope's Address fields to Punycode format + * | mutt_env_to_local() | Convert an Envelope's Address fields to local format */ #include "config.h" @@ -41,6 +43,7 @@ #include "mutt/string2.h" #include "envelope.h" #include "address.h" +#include "mutt_idna.h" /** * mutt_env_new - Create a new Envelope @@ -196,3 +199,59 @@ bool mutt_env_cmp_strict(const struct Envelope *e1, const struct Envelope *e2) return false; } } + +/** + * mutt_env_to_local - Convert an Envelope's Address fields to local format + * @param e Envelope to modify + * + * Run mutt_addrlist_to_local() on each of the Address fields in the Envelope. + */ +void mutt_env_to_local(struct Envelope *e) +{ + mutt_addrlist_to_local(e->return_path); + mutt_addrlist_to_local(e->from); + mutt_addrlist_to_local(e->to); + mutt_addrlist_to_local(e->cc); + mutt_addrlist_to_local(e->bcc); + mutt_addrlist_to_local(e->reply_to); + mutt_addrlist_to_local(e->mail_followup_to); +} + +/* Note that `a' in the `env->a' expression is macro argument, not + * "real" name of an `env' compound member. Real name will be substituted + * by preprocessor at the macro-expansion time. + * Note that #a escapes and double quotes the argument. + */ +#define H_TO_INTL(a) \ + if (mutt_addrlist_to_intl(env->a, err) && !e) \ + { \ + if (tag) \ + *tag = #a; \ + e = 1; \ + err = NULL; \ + } + +/** + * mutt_env_to_intl - Convert an Envelope's Address fields to Punycode format + * @param[in] env Envelope to modify + * @param[out] tag Name of the failed field + * @param[out] err Failed address + * @retval 0 Success, all addresses converted + * @retval 1 Error, tag and err will be set + * + * Run mutt_addrlist_to_intl() on each of the Address fields in the Envelope. + */ +int mutt_env_to_intl(struct Envelope *env, char **tag, char **err) +{ + int e = 0; + H_TO_INTL(return_path); + H_TO_INTL(from); + H_TO_INTL(to); + H_TO_INTL(cc); + H_TO_INTL(bcc); + H_TO_INTL(reply_to); + H_TO_INTL(mail_followup_to); + return e; +} + +#undef H_TO_INTL diff --git a/envelope.h b/envelope.h index ff11ceba2..4e4df32cb 100644 --- a/envelope.h +++ b/envelope.h @@ -68,5 +68,7 @@ bool mutt_env_cmp_strict(const struct Envelope *e1, const struct Env void mutt_env_free(struct Envelope **p); void mutt_env_merge(struct Envelope *base, struct Envelope **extra); struct Envelope *mutt_env_new(void); +int mutt_env_to_intl(struct Envelope *env, char **tag, char **err); +void mutt_env_to_local(struct Envelope *e); #endif /* _MUTT_ENVELOPE_H */ diff --git a/mutt_address.c b/mutt_address.c index 0be18f79e..948800b86 100644 --- a/mutt_address.c +++ b/mutt_address.c @@ -28,6 +28,71 @@ #include "address.h" #include "mutt_idna.h" +/** + * mutt_addrlist_to_intl - Convert an Address list to Punycode + * @param[in] a Address list to modify + * @param[out] err Pointer for failed addresses + * @retval 0 Success, all addresses converted + * @retval -1 Error, err will be set to the failed address + */ +int mutt_addrlist_to_intl(struct Address *a, char **err) +{ + char *user = NULL, *domain = NULL; + char *intl_mailbox = NULL; + int rc = 0; + + if (err) + *err = NULL; + + for (; a; a = a->next) + { + if (!a->mailbox || mutt_addr_is_intl(a)) + continue; + + if (mutt_addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1) + continue; + + intl_mailbox = mutt_idna_local_to_intl(user, domain); + if (!intl_mailbox) + { + rc = -1; + if (err && !*err) + *err = mutt_str_strdup(a->mailbox); + continue; + } + + mutt_addr_set_intl(a, intl_mailbox); + } + + return rc; +} + +/** + * mutt_addrlist_to_local - Convert an Address list from Punycode + * @param a Address list to modify + * @retval 0 Always + */ +int mutt_addrlist_to_local(struct Address *a) +{ + char *user = NULL, *domain = NULL; + char *local_mailbox = NULL; + + for (; a; a = a->next) + { + if (!a->mailbox || mutt_addr_is_local(a)) + continue; + + if (mutt_addr_mbox_to_udomain(a->mailbox, &user, &domain) == -1) + continue; + + local_mailbox = mutt_idna_intl_to_local(user, domain, 0); + if (local_mailbox) + mutt_addr_set_local(a, local_mailbox); + } + + return 0; +} + void rfc822_write_address_single(char *buf, size_t buflen, struct Address *addr, int display) { size_t len; diff --git a/mutt_idna.c b/mutt_idna.c index bc5007278..4a56bf6e5 100644 --- a/mutt_idna.c +++ b/mutt_idna.c @@ -85,50 +85,6 @@ static bool check_idn(char *domain) } #endif /* HAVE_LIBIDN */ -static int mbox_to_udomain(const char *mbx, char **user, char **domain) -{ - static char *buf = NULL; - char *p = NULL; - - mutt_str_replace(&buf, mbx); - if (!buf) - return -1; - - p = strchr(buf, '@'); - if (!p || !p[1]) - return -1; - *p = '\0'; - *user = buf; - *domain = p + 1; - return 0; -} - -static int addr_is_local(struct Address *a) -{ - return (a->intl_checked && !a->is_intl); -} - -static int addr_is_intl(struct Address *a) -{ - return (a->intl_checked && a->is_intl); -} - -static void set_local_mailbox(struct Address *a, char *local_mailbox) -{ - FREE(&a->mailbox); - a->mailbox = local_mailbox; - a->intl_checked = true; - a->is_intl = false; -} - -static void set_intl_mailbox(struct Address *a, char *intl_mailbox) -{ - FREE(&a->mailbox); - a->mailbox = intl_mailbox; - a->intl_checked = true; - a->is_intl = true; -} - char *mutt_idna_intl_to_local(char *orig_user, char *orig_domain, int flags) { char *local_user = NULL, *local_domain = NULL, *mailbox = NULL; @@ -265,127 +221,3 @@ cleanup: return mailbox; } - -/* higher level functions */ - -int mutt_addrlist_to_intl(struct Address *a, char **err) -{ - char *user = NULL, *domain = NULL; - char *intl_mailbox = NULL; - int rc = 0; - - if (err) - *err = NULL; - - for (; a; a = a->next) - { - if (!a->mailbox || addr_is_intl(a)) - continue; - - if (mbox_to_udomain(a->mailbox, &user, &domain) == -1) - continue; - - intl_mailbox = mutt_idna_local_to_intl(user, domain); - if (!intl_mailbox) - { - rc = -1; - if (err && !*err) - *err = mutt_str_strdup(a->mailbox); - continue; - } - - set_intl_mailbox(a, intl_mailbox); - } - - return rc; -} - -int mutt_addrlist_to_local(struct Address *a) -{ - char *user = NULL, *domain = NULL; - char *local_mailbox = NULL; - - for (; a; a = a->next) - { - if (!a->mailbox || addr_is_local(a)) - continue; - - if (mbox_to_udomain(a->mailbox, &user, &domain) == -1) - continue; - - local_mailbox = mutt_idna_intl_to_local(user, domain, 0); - if (local_mailbox) - set_local_mailbox(a, local_mailbox); - } - - return 0; -} - -/** - * mutt_addr_for_display - convert just for displaying purposes - */ -const char *mutt_addr_for_display(struct Address *a) -{ - char *user = NULL, *domain = NULL; - static char *buf = NULL; - char *local_mailbox = NULL; - - FREE(&buf); - - if (!a->mailbox || addr_is_local(a)) - return a->mailbox; - - if (mbox_to_udomain(a->mailbox, &user, &domain) == -1) - return a->mailbox; - - local_mailbox = mutt_idna_intl_to_local(user, domain, MI_MAY_BE_IRREVERSIBLE); - if (!local_mailbox) - return a->mailbox; - - mutt_str_replace(&buf, local_mailbox); - FREE(&local_mailbox); - return buf; -} - -/** - * mutt_env_to_local - Convert an Envelope structure - */ -void mutt_env_to_local(struct Envelope *e) -{ - mutt_addrlist_to_local(e->return_path); - mutt_addrlist_to_local(e->from); - mutt_addrlist_to_local(e->to); - mutt_addrlist_to_local(e->cc); - mutt_addrlist_to_local(e->bcc); - mutt_addrlist_to_local(e->reply_to); - mutt_addrlist_to_local(e->mail_followup_to); -} - -/* Note that `a' in the `env->a' expression is macro argument, not - * "real" name of an `env' compound member. Real name will be substituted - * by preprocessor at the macro-expansion time. - * Note that #a escapes and double quotes the argument. - */ -#define H_TO_INTL(a) \ - if (mutt_addrlist_to_intl(env->a, err) && !e) \ - { \ - if (tag) \ - *tag = #a; \ - e = 1; \ - err = NULL; \ - } - -int mutt_env_to_intl(struct Envelope *env, char **tag, char **err) -{ - int e = 0; - H_TO_INTL(return_path); - H_TO_INTL(from); - H_TO_INTL(to); - H_TO_INTL(cc); - H_TO_INTL(bcc); - H_TO_INTL(reply_to); - H_TO_INTL(mail_followup_to); - return e; -} - -#undef H_TO_INTL diff --git a/mutt_idna.h b/mutt_idna.h index 26c89d90c..b7d520a23 100644 --- a/mutt_idna.h +++ b/mutt_idna.h @@ -36,9 +36,6 @@ char *mutt_idna_local_to_intl(char *user, char *domain); int mutt_addrlist_to_intl(struct Address *a, char **err); int mutt_addrlist_to_local(struct Address *a); -void mutt_env_to_local(struct Envelope *e); -int mutt_env_to_intl(struct Envelope *env, char **tag, char **err); - const char *mutt_addr_for_display(struct Address *a); #endif /* _MUTT_IDNA_H */