297void trim(std::string& value)
301 size_t i(value.length());
304 const char c(value[i - 1]);
305 if(c !=
' ' && c !=
'\r' && c !=
'\n' && c !=
'\t')
323bool is_quoted_char(
char c)
328 return c ==
'\t' || c >=
' ' && c != 0x7F;
341bool is_atom_char(
char c)
343 return (c >=
'A' && c <=
'Z')
344 || (c >=
'a' && c <=
'z')
345 || (c >=
'0' && c <=
'9')
346 || c ==
'!' || c ==
'#'
347 || c ==
'$' || c ==
'%'
348 || c ==
'&' || c ==
'\''
349 || c ==
'*' || c ==
'+'
350 || c ==
'-' || c ==
'/'
351 || c ==
'=' || c ==
'?'
352 || c ==
'^' || c ==
'_'
353 || c ==
'`' || c ==
'{'
354 || c ==
'|' || c ==
'}'
424 char const * start(
f_input.c_str());
426 char const * s(start);
427 for(; *s !=
'\0'; ++s)
447 for(; end > start; --end)
449 char const c(end[-1]);
450 if(c !=
' ' && c !=
'\n' && c !=
'\r' && c !=
'\t')
457 std::string
const e(start, end - start);
484 for(; end > start; --end)
486 char const c(end[-1]);
487 if(c !=
' ' && c !=
'\n' && c !=
'\r' && c !=
'\t')
498 std::string
const last_group(start, end - start);
521 for(; end > start; --end)
523 char const c(end[-1]);
524 if(c !=
' ' && c !=
'\n' && c !=
'\r' && c !=
'\t')
531 std::string
const e(start, end - start);
548 for(++s; *s !=
'\0' && *s !=
'"'; ++s)
552 if(!is_quoted_char(s[1]))
572 int comment_count(1);
573 for(++s; *s !=
'\0'; ++s)
577 if(!is_quoted_char(s[1]))
592 if(comment_count <= 0)
608 for(++s; *s !=
']'; ++s)
610 if(*s ==
'\0' || *s ==
'[' || *s ==
'\\')
634 for(; end > start; --end)
636 char const c(end[-1]);
637 if(c !=
' ' && c !=
'\n' && c !=
'\r' && c !=
'\t')
644 std::string
const e(start, end - start);
715 bool apply_quotes(
false);
718 char const * extra(
"");
719 char const * escape(
"");
749 char const * s(str.c_str());
750 for(; *s !=
'\0'; ++s)
752 if(!is_atom_char(*s) && strchr(extra, *s) ==
nullptr)
757 apply_quotes = *s !=
'\0';
763 for(
const char *s(str.c_str()); *s !=
'\0'; ++s)
765 if(strchr(escape, *s) !=
nullptr)
892 for(
const char *u(name.c_str()); *u !=
'\0' && *u !=
':'; ++u)
894 if(*u >=
'a' && *u <=
'z')
898 else if((*u >=
'A' && *u <=
'Z')
899 || (*u >=
'0' && *u <=
'9')
910 if(uname.empty() || uname[0] <
'A' || uname[0] >
'Z')
916 || uname ==
"RESENT-FROM")
921 || uname ==
"RESENT-SENDER")
927 || uname ==
"REPLY-TO"
928 || uname ==
"RESENT-TO"
929 || uname ==
"RESENT-CC")
934 || uname ==
"RESENT-BCC")
978 value.reserve(email.length());
979 std::string fullname;
980 std::string username;
983 bool has_angle(
false);
984 bool found_at(
false);
985 bool found_dot(
false);
987 char const * start(email.c_str());
988 char const * s(start);
989 for(; *s !=
'\0'; ++s)
998 for(++s; *s !=
'"'; ++s)
1002 throw std::logic_error(
"somehow we found a \\0 in a quoted string in tld_email_t which should not happen since it was already checked validity in tld_email_t::parse()");
1013 throw std::logic_error(
"somehow we found a \\0 in a quoted string after a backslash in tld_email_t which should not happen since it was already checked validity in tld_email_t::parse()");
1016 if((
static_cast<unsigned char>(*s) <
' ' && *s !=
'\t') || *s == 0x7F)
1032 if( *s !=
'<' && *s !=
'@' )
1044 for(++s;
count > 0; ++s)
1050 throw std::logic_error(
"somehow we found a \\0 in a comment in tld_email_t which should not happen since it was already checked in tld_email_t::parse()");
1068 if(!is_quoted_char(*s))
1070 throw std::logic_error(
"somehow we found a non-quotable character after a backslash (\\) in tld_email_t which should not happen since it was already checked in tld_email_t::parse()");
1076 if(
static_cast<unsigned char>(c) <
' ')
1087 if(!found_at || done || !value.empty() || !domain.empty())
1095 for(++s; *s !=
']'; ++s)
1098 if(c !=
' ' && c !=
'\n' && c !=
'\r' && c !=
'\t')
1103 for(; *s !=
'[' && *s !=
'\\' && *s !=
']' && *s !=
' ' && *s !=
'\n' && *s !=
'\r' && *s !=
'\t'; ++s)
1107 throw std::logic_error(
"somehow we found a \\0 in a literal domain in tld_email_t which should not happen since it was already checked in tld_email_t::parse()");
1111 if(
static_cast<unsigned char>(*s) <
' ' || *s == 0x7F)
1121 for(; *s !=
'[' && *s !=
'\\' && *s !=
']'; ++s)
1124 if(c !=
' ' && c !=
'\n' && c !=
'\r' && c !=
'\t')
1129 if(*s !=
']' || value.empty())
1137 || *value.rbegin() ==
'.'
1138 || value.find(
"..") != std::string::npos)
1150 if(has_angle || found_at || found_dot || done)
1172 if(!has_angle || !found_at || done)
1205 if(found_at || done)
1230 if( !value.empty() )
1239 for(++s; *s !=
'\0'; ++s)
1242 if(c !=
' ' && c !=
'\n' && c !=
'\r' && c !=
'\t')
1252 || (!value.empty() && *value.rbegin() ==
'.')
1253 || s[1] ==
'@' || s[1] ==
'>')
1264 if(!is_atom_char(*s))
1276 if(username.empty() || has_angle)
1322 std::unique_ptr<char, void(*)(
char *)> lowercase_domain(
tld_domain_to_lowercase(domain.c_str()),
reinterpret_cast<void(*)(
char *)
>(&::free));
1331 auto has_whitespace = [&](
char c )
1333 return (c ==
' ' || c ==
'\n' || c ==
'\r' || c ==
'\t');
1335 if( std::find_if( std::begin(username), std::end(username), has_whitespace ) != std::end(username) )
1340 if( std::find_if( std::begin(domain), std::end(domain), has_whitespace ) != std::end(domain) )
1354 if(fullname.empty())
1391 char const * s(group.c_str());
1395 for(; *s !=
'\0'; ++s)
1407 for(++s; *s ==
' ' || *s ==
'\n' || *s ==
'\r' || *s ==
'\t'; ++s);
1413#pragma GCC diagnostic push
1414#pragma GCC diagnostic ignored "-Wstrict-overflow"
1415 for(++s;
count > 0; ++s)
1416#pragma GCC diagnostic pop
1420 throw std::logic_error(
"somehow we found a \\0 in a quoted string in tld_email_t which should not happen since it was already checked in tld_email_t::parse()");
1433 if(!is_quoted_char(s[1]))
1435 throw std::logic_error(
"somehow we found a non-quotable character in tld_email_t which should not happen since it was already checked in tld_email_t::parse()");
1448 if(
static_cast<unsigned char>(*s) <
' ' || *s == 0x7F)
1527 return list->count();
1561 return list->next(e) ? 1 : 0;
std::string f_email_only
The complete email address without display name.
tld_result parse(const std::string &email)
Parse one email to a tld_email_t object.
std::string f_canonicalized_email
The email including the display name.
std::string f_domain
The domain part of the email address.
tld_result parse_group(const std::string &group)
Parse a group including comments.
std::string f_username
The user being named in this email address.
std::string f_fullname
The user full or display name.
std::string f_group
The group this emails was defined in.
std::string f_original_email
The email as read from the source.
The C++ side of the email list implementation.
tld_result f_result
The result of the parse() function.
int f_flags
The flags as passed to the parse() function.
void rewind() const
Rewind the reader to the start of the list.
tld_result parse(const std::string &emails, int flags)
Parse a new list of emails.
static tld_email_field_type email_field_type(const std::string &name)
Check whether a name represents a field with a list of emails.
int count() const
Return the number of emails recorded.
tld_email_list_t f_email_list
The list of emails.
std::string f_last_group
The last group read in the input.
std::string f_input
The input string of the last call to parse().
void parse_all_emails()
Parse all the emails in f_input.
tld_email_list()
Initialize the tld_email_list object.
int f_pos
The current position reading the emails.
bool next(tld_email_t &e) const
Retrieve a copy of the next email information.
static std::string quote_string(const std::string &name, char quote)
Transform a name if it requires quotation.
const char * f_group
The group this emails was defined in.
const char * f_canonicalized_email
The email including the display name.
const char * f_original_email
The email as read from the source.
const char * f_email_only
The complete email address without display name.
const char * f_username
The user being named in this email address.
const char * f_domain
The domain part of the email address.
const char * f_fullname
The user full or display name.
Set of information returned by the tld() function.
The public header of the libtld library.
LIBTLD_EXPORT char * tld_domain_to_lowercase(const char *domain)
Transform a domain with a TLD to lowercase before processing.
@ TLD_EMAIL_FIELD_TYPE_UNKNOWN
The input does not represent valid emails.
@ TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST
The input represents a mandatory list of mailboxes.
@ TLD_EMAIL_FIELD_TYPE_MAILBOX
The input represents a mailbox.
@ TLD_EMAIL_FIELD_TYPE_ADDRESS_LIST_OPT
The input represents an optional list of email addresses.
@ TLD_EMAIL_FIELD_TYPE_INVALID
The input of email_field_type() was not valid.
@ TLD_EMAIL_FIELD_TYPE_MAILBOX_LIST
The input represents a mailbox list.
LIBTLD_EXPORT void tld_email_free(struct tld_email_list *list)
Free the list of emails.
LIBTLD_EXPORT enum tld_result tld(const char *uri, struct tld_info *info)
Get information about the TLD for the specified URI.
LIBTLD_EXPORT void tld_email_rewind(struct tld_email_list *list)
Rewind the reading of the emails.
LIBTLD_EXPORT struct tld_email_list * tld_email_alloc()
Allocate a list of emails object.
LIBTLD_EXPORT int tld_email_count(struct tld_email_list *list)
Return the number of emails found after a parse.
LIBTLD_EXPORT enum tld_result tld_email_parse(struct tld_email_list *list, const char *emails, int flags)
Parse a list of emails in the email list object.
@ TLD_RESULT_SUCCESS
Success! The TLD of the specified URI is valid.
@ TLD_RESULT_INVALID
The TLD was found, but it is marked as invalid.
@ TLD_RESULT_NULL
The input URI is empty.
LIBTLD_EXPORT int tld_email_next(struct tld_email_list *list, struct tld_email *e)
Retrieve the next email.
void list()
List the default schemes accepted.