]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: Add message_address_parse_full() and struct message_address_list
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 30 Jan 2024 20:17:38 +0000 (22:17 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Wed, 7 Aug 2024 13:15:57 +0000 (13:15 +0000)
src/lib-mail/message-address.c
src/lib-mail/message-address.h
src/lib-mail/test-message-address.c

index 9d192799468cfc07aa50f1bb03077b48abf9165e..ae37014079af666f6e87e5f5fd39f13c07546edc 100644 (file)
@@ -13,7 +13,8 @@ struct message_address_parser_context {
        pool_t pool;
        struct rfc822_parser_context parser;
 
-       struct message_address *first_addr, *last_addr, addr;
+       struct message_address addr;
+       struct message_address_list addr_list;
        string_t *str;
 
        bool fill_missing, non_strict_dots;
@@ -28,7 +29,7 @@ static void add_address(struct message_address_parser_context *ctx)
        memcpy(addr, &ctx->addr, sizeof(ctx->addr));
        i_zero(&ctx->addr);
 
-       DLLIST2_APPEND(&ctx->first_addr, &ctx->last_addr, addr);
+       DLLIST2_APPEND(&ctx->addr_list.head, &ctx->addr_list.tail, addr);
 }
 
 /* quote with "" and escape all '\', '"' and "'" characters if need */
@@ -439,10 +440,11 @@ static int parse_path(struct message_address_parser_context *ctx)
        return ret;
 }
 
-static struct message_address *
+static void
 message_address_parse_real(pool_t pool, const unsigned char *data, size_t size,
                           unsigned int max_addresses,
-                          enum message_address_parse_flags flags)
+                          enum message_address_parse_flags flags,
+                          struct message_address_list *list_r)
 {
        struct message_address_parser_context ctx;
 
@@ -461,7 +463,7 @@ message_address_parse_real(pool_t pool, const unsigned char *data, size_t size,
                (void)parse_address_list(&ctx, max_addresses);
        }
        rfc822_parser_deinit(&ctx.parser);
-       return ctx.first_addr;
+       *list_r = ctx.addr_list;
 }
 
 static int
@@ -481,7 +483,7 @@ message_address_parse_path_real(pool_t pool, const unsigned char *data,
        ret = parse_path(&ctx);
 
        rfc822_parser_deinit(&ctx.parser);
-       *addr_r = ctx.first_addr;
+       *addr_r = ctx.addr_list.head;
        return (ret < 0 ? -1 : 0);
 }
 
@@ -490,17 +492,24 @@ message_address_parse(pool_t pool, const unsigned char *data, size_t size,
                      unsigned int max_addresses,
                      enum message_address_parse_flags flags)
 {
-       struct message_address *addr;
+       struct message_address_list list;
+       message_address_parse_full(pool, data, size, max_addresses, flags,
+                                  &list);
+       return list.head;
+}
 
+void message_address_parse_full(pool_t pool, const unsigned char *data,
+                               size_t size, unsigned int max_addresses,
+                               enum message_address_parse_flags flags,
+                               struct message_address_list *list_r)
+{
        if (pool->datastack_pool) {
-               return message_address_parse_real(pool, data, size,
-                                                 max_addresses, flags);
-       }
-       T_BEGIN {
-               addr = message_address_parse_real(pool, data, size,
-                                                 max_addresses, flags);
+               message_address_parse_real(pool, data, size,
+                                          max_addresses, flags, list_r);
+       } else T_BEGIN {
+               message_address_parse_real(pool, data, size,
+                                          max_addresses, flags, list_r);
        } T_END;
-       return addr;
 }
 
 int message_address_parse_path(pool_t pool, const unsigned char *data,
index 85cff3dcc6f6ddcb3ee6f45b9882656ae710d1db..224f7a756050dd7c3792ca482aa093ff572250ab 100644 (file)
@@ -31,12 +31,22 @@ struct message_address {
        bool invalid_syntax;
 };
 
+struct message_address_list {
+       struct message_address *head, *tail;
+};
+
 /* Parse message addresses from given data. Note that giving an empty string
    will return NULL since there are no addresses. */
 struct message_address *
 message_address_parse(pool_t pool, const unsigned char *data, size_t size,
                      unsigned int max_addresses,
                      enum message_address_parse_flags flags);
+/* Same as message_address_parse(), but return message_address_list containing
+   both the first and the last address in the linked list. */
+void message_address_parse_full(pool_t pool, const unsigned char *data,
+                               size_t size, unsigned int max_addresses,
+                               enum message_address_parse_flags flags,
+                               struct message_address_list *list_r);
 
 /* Parse RFC 5322 "path" (Return-Path header) from given data. Returns -1 if
    the path is invalid and 0 otherwise.
index 261cbfba70afe5d637530237f1ab7f188eee4931..54aa9a83101ca794991a4d37d3c9b772d3cdfc1e 100644 (file)
@@ -19,8 +19,9 @@ static bool cmp_addr(const struct message_address *a1,
                a1->invalid_syntax == a2->invalid_syntax;
 }
 
-static const struct message_address *
-test_parse_address(const char *input, bool fill_missing)
+static void
+test_parse_address_full(const char *input, bool fill_missing,
+                       struct message_address_list *list_r)
 {
        const enum message_address_parse_flags flags =
                fill_missing ? MESSAGE_ADDRESS_PARSE_FLAG_FILL_MISSING : 0;
@@ -28,11 +29,18 @@ test_parse_address(const char *input, bool fill_missing)
           if there's any out-of-bounds access */
        size_t input_len = strlen(input);
        unsigned char *input_dup = i_memdup(input, input_len);
-       const struct message_address *addr =
-               message_address_parse(pool_datastack_create(),
-                                     input_dup, input_len, UINT_MAX, flags);
+       message_address_parse_full(pool_datastack_create(),
+                                  input_dup, input_len, UINT_MAX, flags,
+                                  list_r);
        i_free(input_dup);
-       return addr;
+}
+
+static const struct message_address *
+test_parse_address(const char *input, bool fill_missing)
+{
+       struct message_address_list list;
+       test_parse_address_full(input, fill_missing, &list);
+       return list.head;
 }
 
 static void test_message_address(void)
@@ -322,6 +330,33 @@ static void test_message_address(void)
        test_end();
 }
 
+static void test_message_address_list(void)
+{
+       test_begin("message address list");
+
+       const char *test_input =
+               "user1@example1.com, user2@example2.com, user3@example3.com";
+       const struct message_address wanted_addrs[] = {
+               { NULL, NULL, NULL, NULL, "user1", "example1.com", FALSE },
+               { NULL, NULL, NULL, NULL, "user2", "example2.com", FALSE },
+               { NULL, NULL, NULL, NULL, "user3", "example3.com", FALSE },
+       };
+
+       struct message_address_list list;
+       struct message_address *addr, *scanned_last_addr;
+       test_parse_address_full(test_input, FALSE, &list);
+       addr = list.head;
+       for (unsigned int i = 0; i < N_ELEMENTS(wanted_addrs); i++) {
+               test_assert_idx(cmp_addr(addr, &wanted_addrs[i]), i);
+               scanned_last_addr = addr;
+               addr = addr->next;
+       }
+       test_assert(list.tail == scanned_last_addr);
+       test_assert(addr == NULL);
+
+       test_end();
+}
+
 static void test_message_address_nuls(void)
 {
        const unsigned char input[] =
@@ -521,6 +556,7 @@ int main(void)
 {
        static void (*const test_functions[])(void) = {
                test_message_address,
+               test_message_address_list,
                test_message_address_nuls,
                test_message_address_nuls_display_name,
                test_message_address_non_strict_dots,