From 25dab09cffdeb4f76ee1c6d7f6e9a811c3fbe4a8 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Thu, 16 Jul 2026 16:14:57 +0200 Subject: [PATCH] Test external mail response parsing --- src/agents/collector/CMakeLists.txt | 12 ++++++ src/agents/collector/external_transport.c | 39 +++++++++++------ src/agents/collector/external_transport.h | 4 ++ .../collector/tests/external-transport-test.c | 42 +++++++++++++++++++ 4 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 src/agents/collector/tests/external-transport-test.c diff --git a/src/agents/collector/CMakeLists.txt b/src/agents/collector/CMakeLists.txt index fc89d20..eec4e95 100644 --- a/src/agents/collector/CMakeLists.txt +++ b/src/agents/collector/CMakeLists.txt @@ -32,3 +32,15 @@ target_link_libraries(bongocollector ) install(TARGETS bongocollector DESTINATION ${SBIN_INSTALL_DIR}) + +if(BUILD_TESTING) + add_executable(collector-transport-test + tests/external-transport-test.c + external_transport.c + ) + target_include_directories(collector-transport-test PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + target_link_libraries(collector-transport-test ${CURL_LIBRARIES}) + add_test(NAME collector-external-transport COMMAND collector-transport-test) +endif() diff --git a/src/agents/collector/external_transport.c b/src/agents/collector/external_transport.c index 13d7b13..e7fcc19 100644 --- a/src/agents/collector/external_transport.c +++ b/src/agents/collector/external_transport.c @@ -97,12 +97,17 @@ AddId(CollectorRemoteIds *ids, const char *uid, size_t uid_length, return 0; } -static int -ParsePop3Ids(char *response, CollectorRemoteIds *ids) +int +CollectorRemoteParsePop3(const char *response, CollectorRemoteIds *ids) { + char *copy; char *line; char *save = NULL; - for (line = strtok_r(response, "\r\n", &save); line != NULL; + int result = 0; + if (response == NULL || ids == NULL) return -1; + copy = strdup(response); + if (copy == NULL) return -1; + for (line = strtok_r(copy, "\r\n", &save); line != NULL; line = strtok_r(NULL, "\r\n", &save)) { char *number_end; char *uid; @@ -115,19 +120,26 @@ ParsePop3Ids(char *response, CollectorRemoteIds *ids) uid = number_end; while (isspace((unsigned char) *uid)) uid++; if (*uid != '\0' && AddId(ids, uid, strcspn(uid, " \t"), - line, number_length) != 0) return -1; + line, number_length) != 0) { + result = -1; + break; + } } - return 0; + free(copy); + return result; } -static int -ParseImapIds(char *response, CollectorRemoteIds *ids) +int +CollectorRemoteParseImap(const char *response, CollectorRemoteIds *ids) { - char *search = strstr(response, "SEARCH"); - char *validity = strstr(response, "UIDVALIDITY"); - char *token; + const char *search; + const char *validity; + const char *token; + if (response == NULL || ids == NULL) return -1; + search = strstr(response, "SEARCH"); + validity = strstr(response, "UIDVALIDITY"); if (validity != NULL) { - char *end; + const char *end; validity += strlen("UIDVALIDITY"); while (*validity != '\0' && !isdigit((unsigned char) *validity)) validity++; end = validity; @@ -140,7 +152,7 @@ ParseImapIds(char *response, CollectorRemoteIds *ids) if (search == NULL) return 0; token = search + strlen("SEARCH"); while (*token != '\0' && *token != '\r' && *token != '\n') { - char *end; + const char *end; while (isspace((unsigned char) *token)) token++; if (!isdigit((unsigned char) *token)) break; end = token; @@ -425,7 +437,8 @@ CollectorRemoteList(const CollectorExternalAccount *account, if (response.data == NULL) goto done; } result = strcmp(account->inbound_protocol, "imap") == 0 ? - ParseImapIds(response.data, ids) : ParsePop3Ids(response.data, ids); + CollectorRemoteParseImap(response.data, ids) : + CollectorRemoteParsePop3(response.data, ids); if (result != 0) { CollectorRemoteIdsFree(ids); SetError(error, error_size, "too many remote messages or insufficient memory"); diff --git a/src/agents/collector/external_transport.h b/src/agents/collector/external_transport.h index d398bcf..f69e04e 100644 --- a/src/agents/collector/external_transport.h +++ b/src/agents/collector/external_transport.h @@ -29,4 +29,8 @@ int CollectorRemoteDelete(const CollectorExternalAccount *account, char *error, size_t error_size); void CollectorRemoteIdsFree(CollectorRemoteIds *ids); +/* Exposed for protocol parser tests and offline response validation. */ +int CollectorRemoteParsePop3(const char *response, CollectorRemoteIds *ids); +int CollectorRemoteParseImap(const char *response, CollectorRemoteIds *ids); + #endif diff --git a/src/agents/collector/tests/external-transport-test.c b/src/agents/collector/tests/external-transport-test.c new file mode 100644 index 0000000..61995e0 --- /dev/null +++ b/src/agents/collector/tests/external-transport-test.c @@ -0,0 +1,42 @@ +#include +#include + +#include "external_transport.h" + +static int +CheckPop3(void) +{ + CollectorRemoteIds ids = {0}; + const char response[] = "+OK 2 messages\r\n1 alpha-uid\r\n2 beta-uid\r\n.\r\n"; + int failed = CollectorRemoteParsePop3(response, &ids) != 0 || + ids.count != 2 || strcmp(ids.items[0].locator, "1") != 0 || + strcmp(ids.items[0].uid, "alpha-uid") != 0 || + strcmp(ids.items[1].locator, "2") != 0 || + strcmp(ids.items[1].uid, "beta-uid") != 0; + CollectorRemoteIdsFree(&ids); + return failed; +} + +static int +CheckImap(void) +{ + CollectorRemoteIds ids = {0}; + const char response[] = "* OK [UIDVALIDITY 4242] valid\r\n* SEARCH 7 99 101\r\n"; + int failed = CollectorRemoteParseImap(response, &ids) != 0 || + strcmp(ids.uidvalidity, "4242") != 0 || ids.count != 3 || + strcmp(ids.items[0].uid, "7") != 0 || + strcmp(ids.items[1].uid, "99") != 0 || + strcmp(ids.items[2].locator, "101") != 0; + CollectorRemoteIdsFree(&ids); + return failed; +} + +int +main(void) +{ + if (CheckPop3() || CheckImap()) { + fprintf(stderr, "external transport parser test failed\n"); + return 1; + } + return 0; +}