bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch#include "lib.h"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch#include "str.h"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch#include "message-address.h"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch#include "smtp-parser.h"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch#include "smtp-address.h"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch/* From RFC 5321:
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Reverse-path = Path / "<>"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Forward-path = Path
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Path = "<" [ A-d-l ":" ] Mailbox ">"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch A-d-l = At-domain *( "," At-domain )
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch ; Note that this form, the so-called "source
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch ; route", MUST BE accepted, SHOULD NOT be
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch ; generated, and SHOULD be ignored.
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch At-domain = "@" Domain
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Domain = sub-domain *("." sub-domain)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch sub-domain = Let-dig [Ldh-str]
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Let-dig = ALPHA / DIGIT
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch address-literal = "[" ( IPv4-address-literal /
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch IPv6-address-literal /
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch General-address-literal ) "]"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch ; See Section 4.1.3
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Mailbox = Local-part "@" ( Domain / address-literal )
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Local-part = Dot-string / Quoted-string
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch ; MAY be case-sensitive
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Dot-string = Atom *("." Atom)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch Atom = 1*atext
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch/*
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch * SMTP address parsing
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address_parser {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_parser parser;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address address;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch bool parse:1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch bool path:1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch};
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstatic int
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_parser_parse_dot_string(struct smtp_parser *parser,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char **value_r)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const unsigned char *pbegin = parser->cur;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* Dot-string = Atom *("." Atom)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* NOTE: this deviates from Dot-String syntax to allow some Japanese
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch mail addresses with dots at non-standard places to be accepted. */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end ||
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch (!smtp_char_is_atext(*parser->cur) && *parser->cur != '.'))
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 0;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch while (parser->cur < parser->end &&
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch (smtp_char_is_atext(*parser->cur) || *parser->cur == '.'))
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (value_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *value_r = t_strndup(pbegin, parser->cur - pbegin);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstatic int
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_parse_localpart(struct smtp_parser *parser,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char **localpart_r)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch int ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parser_parse_quoted_string(parser, localpart_r)) != 0)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return smtp_parser_parse_dot_string(parser, localpart_r);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstatic int
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_parse_mailbox(struct smtp_address_parser *aparser,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch enum smtp_address_parse_flags flags)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_parser *parser = &aparser->parser;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char **value = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch int ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* Mailbox = Local-part "@" ( Domain / address-literal )
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch value = (aparser->parse ? &aparser->address.localpart : NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parse_localpart(parser, value)) <= 0)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((parser->cur >= parser->end || *parser->cur != '@') &&
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch (flags & SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART) == 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end ||
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch (aparser->path && *parser->cur == '>'))
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Missing domain";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch else
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Invalid character in localpart";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end || *parser->cur != '@')
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch value = (aparser->parse ? &aparser->address.domain : NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parser_parse_domain(parser, value)) == 0 &&
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch (ret=smtp_parser_parse_address_literal(parser,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch value, NULL)) == 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end ||
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch (aparser->path && *parser->cur == '>')) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Missing domain after '@'";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch } else {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Invalid domain";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstatic int
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_parse_source_route(struct smtp_parser *parser)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* Source-route = [ A-d-l ":" ]
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch A-d-l = At-domain *( "," At-domain )
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch At-domain = "@" Domain
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* "@" Domain */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end || *parser->cur != '@')
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 0;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch for (;;) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* Domain */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (smtp_parser_parse_domain(parser, NULL) <= 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error =
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch "Missing domain after '@' in source route";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* *( "," At-domain ) */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end || *parser->cur != ',')
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch break;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* "@" Domain */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end || *parser->cur != '@') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Missing '@' after ',' in source route";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* ":" */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end || *parser->cur != ':') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Missing ':' at end of source route";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstatic int
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_parse_path(struct smtp_address_parser *aparser,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch enum smtp_address_parse_flags flags)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_parser *parser = &aparser->parser;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch int ret, sret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* Path = "<" [ A-d-l ":" ] Mailbox ">"
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* "<" */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur < parser->end && *parser->cur == '<') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch aparser->path = TRUE;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch } else if ((flags & SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL) == 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 0;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* [ A-d-l ":" ] */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((sret=smtp_parse_source_route(parser)) < 0)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* Mailbox */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parse_mailbox(aparser, flags)) < 0)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (ret == 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur < parser->end && *parser->cur == '>') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (sret > 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error =
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch "Path only consists of source route";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((flags & SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch == 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Null path not allowed";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch } else {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Invalid character in localpart";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* ">" */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (aparser->path) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end || *parser->cur != '>') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Missing '>' at end of path";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch } else if (parser->cur < parser->end && *parser->cur == '>') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Unmatched '>' at end of path";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstatic int
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_parse_username(struct smtp_address_parser *aparser)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_parser *parser = &aparser->parser;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char **value = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const unsigned char *p, *dp;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch int ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* Best-effort extraction of SMTP address from a user name.
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch value = (aparser->parse ? &aparser->address.localpart : NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (*parser->cur == '\"') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* if the local part is a quoted string, parse it as any other
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch SMTP address */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parse_localpart(parser, value)) <= 0)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch } else {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* use the right-most '@' as separator */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch dp = parser->end - 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch while (dp > parser->cur && *dp != '@')
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch dp--;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (dp == parser->cur)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch dp = parser->end;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* check whether the resulting localpart could be encoded as
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch quoted string */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch for (p = parser->cur; p < dp; p++) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (!smtp_char_is_qtext(*p) || *p == ' ') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error =
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch "Invalid character in user name";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (aparser->parse) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch aparser->address.localpart =
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch p_strdup_until(parser->pool, parser->cur, dp);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur = dp;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur < parser->end && *parser->cur != '@') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Invalid character in user name";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end || *parser->cur != '@')
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->cur++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch value = (aparser->parse ? &aparser->address.domain : NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parser_parse_domain(parser, value)) == 0 &&
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch (ret=smtp_parser_parse_address_literal(parser,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch value, NULL)) == 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (parser->cur >= parser->end) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Missing domain after '@'";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch } else {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch parser->error = "Invalid domain";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschint smtp_address_parse_mailbox(pool_t pool,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char *mailbox, enum smtp_address_parse_flags flags,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address **address_r, const char **error_r)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address_parser aparser;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch int ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *address_r = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch if (error_r != NULL)
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *error_r = NULL;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((mailbox == NULL || *mailbox == '\0')) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((flags & SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY) == 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = "Mailbox is empty string";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *address_r = p_new(pool, struct smtp_address, 1);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch i_zero(&aparser);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_parser_init(&aparser.parser, pool_datastack_create(), mailbox);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch aparser.parse = (address_r != NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parse_mailbox(&aparser, flags)) <= 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = (ret < 0 ? aparser.parser.error :
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch "Invalid character in localpart");
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (aparser.parser.cur != aparser.parser.end) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = "Invalid character in mailbox";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *address_r = smtp_address_clone(pool, &aparser.address);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschint smtp_address_parse_path_full(pool_t pool, const char *path,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch enum smtp_address_parse_flags flags,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address **address_r, const char **error_r,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char **endp_r)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address_parser aparser;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch int ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *address_r = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (path == NULL || *path == '\0') {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((flags & SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY) == 0 ||
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch (flags & SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL) == 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = "Path is empty string";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *address_r = p_new(pool, struct smtp_address, 1);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch i_zero(&aparser);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_parser_init(&aparser.parser, pool_datastack_create(), path);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch aparser.parse = (address_r != NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parse_path(&aparser, flags)) <= 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = (ret < 0 ? aparser.parser.error :
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch "Missing '<' at beginning of path");
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (endp_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *endp_r = (const char *)aparser.parser.cur;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch else if (aparser.parser.cur != aparser.parser.end) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = "Invalid character in path";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *address_r = smtp_address_clone(pool, &aparser.address);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschint smtp_address_parse_path(pool_t pool, const char *path,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch enum smtp_address_parse_flags flags,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address **address_r, const char **error_r)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return smtp_address_parse_path_full(pool, path, flags,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch address_r, error_r, NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschint smtp_address_parse_username(pool_t pool, const char *username,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address **address_r, const char **error_r)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address_parser aparser;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch int ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *address_r = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((username == NULL || *username == '\0')) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = "Username is empty string";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch i_zero(&aparser);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_parser_init(&aparser.parser, pool_datastack_create(), username);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch aparser.parse = (address_r != NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if ((ret=smtp_parse_username(&aparser)) <= 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = (ret < 0 ? aparser.parser.error :
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch "Invalid character in user name");
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (aparser.parser.cur != aparser.parser.end) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (error_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *error_r = "Invalid character in user name";
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return -1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address_r != NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch *address_r = smtp_address_clone(pool, &aparser.address);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Boschvoid smtp_address_detail_parse(pool_t pool, const char *delimiters,
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch struct smtp_address *address, const char **username_r,
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch char *delim_r, const char **detail_r)
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch{
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch const char *localpart;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch const char *user, *p;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch size_t idx;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch i_assert(!smtp_address_isnull(address));
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch localpart = address->localpart;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch user = localpart;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *detail_r = "";
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *delim_r = '\0';
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch /* first character that matches the recipient_delimiter */
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch idx = strcspn(localpart, delimiters);
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch p = (localpart[idx] != '\0' ? &localpart[idx] : NULL);
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch if (p != NULL) {
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *delim_r = *p;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch /* user+detail */
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch user = p_strdup_until(pool, localpart, p);
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *detail_r = p+1;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch }
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch if (address->domain == NULL)
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *username_r = user;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch else if (strchr(user, '@') == NULL ) {
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch /* username is just glued to the domain... no SMTP escaping */
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *username_r = p_strconcat(pool,
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch user, "@", address->domain, NULL);
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch } else {
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch struct smtp_address uaddr;
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch /* username contains '@'; apply escaping */
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch smtp_address_init(&uaddr, user, address->domain);
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch if (pool->datastack_pool)
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *username_r = smtp_address_encode(&uaddr);
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch else
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch *username_r = p_strdup(pool, smtp_address_encode(&uaddr));
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch }
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch}
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Boschvoid smtp_address_detail_parse_temp(const char *delimiters,
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch struct smtp_address *address, const char **username_r,
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch char *delim_r, const char **detail_r)
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch{
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch smtp_address_detail_parse(pool_datastack_create(), delimiters,
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch address, username_r, delim_r, detail_r);
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch}
61ae3dd363d32db75d2c3effaab4ba093ce0f245Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch/*
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch * SMTP address construction
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschvoid smtp_address_write(string_t *out,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const struct smtp_address *address) ATTR_NULL(2)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch bool quoted = FALSE;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const unsigned char *p, *pend, *pblock;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch size_t begin;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch if (smtp_address_isnull(address))
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch begin = str_len(out);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* encode localpart */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address->localpart == NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch p = (const unsigned char *)address->localpart;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch pend = p + strlen(address->localpart);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch pblock = p;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch while (p < pend) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch while (p < pend && smtp_char_is_atext(*p))
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch p++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (!quoted && p < pend && (*p != '.' || p == pblock)) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch quoted = TRUE;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_insert(out, begin, "\"");
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append_n(out, pblock, p - pblock);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (p >= pend)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch break;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (!quoted) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append_c(out, '.');
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch } else {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch i_assert(smtp_char_is_qpair(*p));
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (!smtp_char_is_qtext(*p))
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append_c(out, '\\');
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append_c(out, *p);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch p++;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch pblock = p;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (p == pblock) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch quoted = TRUE;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_insert(out, begin, "\"");
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (quoted)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append_c(out, '\"');
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (address->domain == NULL)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append_c(out, '@');
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append(out, address->domain);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschvoid smtp_address_write_path(string_t *out,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const struct smtp_address *address)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append_c(out, '<');
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_address_write(out, address);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch str_append_c(out, '>');
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschconst char *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_encode(const struct smtp_address *address)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch string_t *str = t_str_new(256);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_address_write(str, address);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return str_c(str);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschconst char *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_encode_path(const struct smtp_address *address)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch string_t *str = t_str_new(256);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_address_write_path(str, address);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return str_c(str);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch/*
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch * SMTP address manipulation
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschvoid smtp_address_init(struct smtp_address *address,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char *localpart, const char *domain)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch i_zero(address);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch address->localpart = localpart;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch address->domain = (localpart == NULL ? NULL : domain);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschvoid smtp_address_init_from_msg(struct smtp_address *address,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const struct message_address *msg_addr)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch i_zero(address);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch address->localpart = msg_addr->mailbox;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch address->domain = (msg_addr->mailbox == NULL ? NULL : msg_addr->domain);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_clone(pool_t pool, const struct smtp_address *src)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address *new;
db926ebb4a359a44e1aba73712c6c8615db8bc83Stephan Bosch size_t size, lpsize, dsize = 0;
db926ebb4a359a44e1aba73712c6c8615db8bc83Stephan Bosch char *data, *localpart, *domain = NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch if (smtp_address_isnull(src))
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return NULL;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch /* @UNSAFE */
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch size = sizeof(struct smtp_address);
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch lpsize = strlen(src->localpart) + 1;
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch size = MALLOC_ADD(size, lpsize);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (src->domain != NULL) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch dsize = strlen(src->domain) + 1;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch size = MALLOC_ADD(size, dsize);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch data = p_malloc(pool, size);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new = (struct smtp_address *)data;
db926ebb4a359a44e1aba73712c6c8615db8bc83Stephan Bosch localpart = PTR_OFFSET(data, sizeof(*new));
db926ebb4a359a44e1aba73712c6c8615db8bc83Stephan Bosch memcpy(localpart, src->localpart, lpsize);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch if (dsize > 0) {
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch domain = PTR_OFFSET(data, sizeof(*new) + lpsize);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch memcpy(domain, src->domain, dsize);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch }
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new->localpart = localpart;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new->domain = domain;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return new;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_create(pool_t pool,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char *localpart, const char *domain)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address addr;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_address_init(&addr, localpart, domain);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return smtp_address_clone(pool, &addr);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_create_from_msg(pool_t pool,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const struct message_address *msg_addr)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address addr;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_address_init_from_msg(&addr, msg_addr);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return smtp_address_clone(pool, &addr);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_clone_temp(const struct smtp_address *src)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address *new;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch if (smtp_address_isnull(src))
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch return NULL;
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new = t_new(struct smtp_address, 1);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new->localpart = t_strdup(src->localpart);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new->domain = t_strdup(src->domain);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return new;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_create_temp(const char *localpart, const char *domain)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address addr;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_address_init(&addr, localpart, domain);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return smtp_address_clone_temp(&addr);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_create_from_msg_temp(const struct message_address *msg_addr)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address addr;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch smtp_address_init_from_msg(&addr, msg_addr);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return smtp_address_clone_temp(&addr);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_add_detail(pool_t pool, const struct smtp_address *address,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char *detail, char delim_c)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address *new_addr;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char delim[] = {delim_c, '\0'};
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch i_assert(!smtp_address_isnull(address));
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new_addr = p_new(pool, struct smtp_address, 1);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new_addr->localpart = p_strconcat(pool,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch address->localpart, delim, detail, NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new_addr->domain = p_strdup(pool, address->domain);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return new_addr;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschstruct smtp_address *
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschsmtp_address_add_detail_temp(const struct smtp_address *address,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char *detail, char delim_c)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch struct smtp_address *new_addr;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const char delim[] = {delim_c, '\0'};
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch i_assert(!smtp_address_isnull(address));
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new_addr = t_new(struct smtp_address, 1);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new_addr->localpart = t_strconcat(
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch address->localpart, delim, detail, NULL);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch new_addr->domain = t_strdup(address->domain);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return new_addr;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Boschint smtp_address_cmp(const struct smtp_address *address1,
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch const struct smtp_address *address2)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch{
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch bool null1, null2;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch int ret;
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch null1 = smtp_address_isnull(address1);
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch null2 = smtp_address_isnull(address2);
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch if (null1)
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch return (null2 ? 0 : -1);
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch else if (null2)
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch return 1;
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch if ((ret=null_strcasecmp(address1->domain, address2->domain)) != 0)
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch return ret;
aba05d93fe13aebb76d3ab8ca235a40f75b4afc4Stephan Bosch return null_strcmp(address1->localpart, address2->localpart);
03f08e4abef2afc782069bdfef305f84e98f0922Stephan Bosch}