From: Baptiste Daroussin Date: Thu, 11 Jan 2024 16:44:42 +0000 (+0100) Subject: probes: fix a regression causing the probes not to sent the bounce numbers X-Git-Tag: RELEASE_1_4_4~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=958d31437ae64b1cae3963a453da32ae993d6636;p=thirdparty%2Fmlmmj.git probes: fix a regression causing the probes not to sent the bounce numbers move the code sending the probe into a reusable function for it to be testable, add a unit test which checks the probes properly contains what is expected. --- diff --git a/include/mlmmj.h b/include/mlmmj.h index 6d6ed8c5..a45b76ae 100644 --- a/include/mlmmj.h +++ b/include/mlmmj.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2002, 2003, 2004 Mads Martin Joergensen - * Copyright (C) 2022-2023 Baptiste Daroussin + * Copyright (C) 2022-2024 Baptiste Daroussin * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -134,6 +134,7 @@ int open_listdir(const char *listdir, bool usercheck); void ml_init(struct ml *ml); bool ml_open(struct ml *ml, bool checkuser); void ml_close(struct ml *ml); +bool send_probe(struct ml *ml, const char *addr); #define MY_ASSERT(expression) if (!(expression)) { \ errno = 0; \ diff --git a/include/prepstdreply.h b/include/prepstdreply.h index 4d15c8b0..456b0e88 100644 --- a/include/prepstdreply.h +++ b/include/prepstdreply.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2004 Mads Martin Joergensen * Copyright (C) 2011 Ben Schmidt - * Copyright (C) 2023 Baptiste Daroussin + * Copyright (C) 2023-2024 Baptiste Daroussin * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -47,6 +47,7 @@ const char *get_memory_line(void *state); void finish_memory_lines(memory_lines_state *s); file_lines_state *init_file_lines(const char *filename, char truncate); +file_lines_state *init_file_lines_fd(int fd, char truncate); void rewind_file_lines(void *state); const char *get_file_line(void *state); void finish_file_lines(file_lines_state *s); diff --git a/src/mlmmj-bounce.c b/src/mlmmj-bounce.c index aa5be753..49399f81 100644 --- a/src/mlmmj-bounce.c +++ b/src/mlmmj-bounce.c @@ -49,78 +49,12 @@ #include "utils.h" #include "send_mail.h" -static void -unlink_bounce(struct ml *ml, const char *to) +void +do_probe(struct ml *ml, const char *addr) { - char *tmpstr, *a, *probefile; - - /* error, so remove the probefile */ - tmpstr = xstrdup(to); - a = strchr(tmpstr, '@'); - MY_ASSERT(a); - *a = '='; - xasprintf(&probefile, "bounce/%s-probe", tmpstr); - unlinkat(ml->fd, probefile, 0); - free(probefile); - free(tmpstr); -} - -void do_probe(struct ml *ml, const char *addr) -{ - text *txt; - file_lines_state *fls; - char *myaddr, *from, *a, *queuefilename; - char *probefile; - int fd; - time_t t; - struct mail mail = { 0 }; - - myaddr = lowercase(addr); - - gen_addr_cookie(from, ml, "bounces-probe-", myaddr) - - a = strrchr(myaddr, '='); - if (!a) { - free(myaddr); - free(from); - log_error(LOG_ARGS, "do_probe(): malformed address"); - exit(EXIT_FAILURE); - - } - *a = '@'; - - txt = open_text(ml->fd, "probe", NULL, NULL, NULL, "bounce-probe"); - MY_ASSERT(txt); - register_default_unformatted(txt, ml); - register_unformatted(txt, "bouncenumbers", "%bouncenumbers%"); /* DEPRECATED */ - fls = init_file_lines(addr, ':'); - register_formatted(txt, "bouncenumbers", - rewind_file_lines, get_file_line, fls); - queuefilename = prepstdreply(txt, ml, "$listowner$", myaddr, NULL); - MY_ASSERT(queuefilename); - close_text(txt); - - finish_file_lines(fls); - - xasprintf(&probefile, "bounce/%s-probe", addr); - t = time(NULL); - fd = openat(ml->fd, probefile, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR); - if(fd < 0) - log_error(LOG_ARGS, "Could not open %s", probefile); - else - if (dprintf(fd, "%ld", (long int)t) < 0) - log_error(LOG_ARGS, "Could not write time in probe"); - free(probefile); - - mail.to = myaddr; - mail.from = from; - mail.fp = fopen(queuefilename, "r"); - if (!send_single_mail(&mail, ml, false)) { - unlink_bounce(ml, myaddr); - exit(EXIT_FAILURE); - } - fclose(mail.fp); - exit(EXIT_SUCCESS); + if (send_probe(ml, addr)) + exit(EXIT_SUCCESS); + exit(EXIT_FAILURE); } static void print_help(const char *prg) diff --git a/src/mlmmj.c b/src/mlmmj.c index 2d5b65b7..3711aaa2 100644 --- a/src/mlmmj.c +++ b/src/mlmmj.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 Baptiste Daroussin + * Copyright (C) 2021-2024 Baptiste Daroussin * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -35,6 +35,7 @@ #include #include "getlistdelim.h" +#include "send_mail.h" #include "mlmmj.h" #include "utils.h" #include "log_error.h" @@ -43,10 +44,77 @@ #include "gethdrline.h" #include "mygetline.h" #include "subscriberfuncs.h" +#include "prepstdreply.h" #include "find_email_adr.h" #include "strgen.h" #include "ctrlvalue.h" +bool +send_probe(struct ml *ml, const char *addr) +{ + text *txt; + file_lines_state *fls; + char *myaddr, *from, *a, *queuefilename; + char *probefile; + int fd, bfd; + time_t t; + struct mail mail = { 0 }; + + myaddr = lowercase(addr); + + gen_addr_cookie(from, ml, "bounces-probe-", myaddr) + + a = strrchr(myaddr, '='); + if (!a) { + free(myaddr); + free(from); + log_error(LOG_ARGS, "do_probe(): malformed address"); + return (false); + } + *a = '@'; + bfd = openat(ml->fd, "bounce", O_DIRECTORY); + if (bfd == -1) { + free(myaddr); + free(from); + log_error(LOG_ARGS, "impossible to open bounce directory"); + return (false); + } + + txt = open_text(ml->fd, "probe", NULL, NULL, NULL, "bounce-probe"); + MY_ASSERT(txt); + register_default_unformatted(txt, ml); + register_unformatted(txt, "bouncenumbers", "%bouncenumbers%"); /* DEPRECATED */ + fls = init_file_lines_fd(openat(bfd, addr, O_RDONLY), ':'); + register_formatted(txt, "bouncenumbers", + rewind_file_lines, get_file_line, fls); + queuefilename = prepstdreply(txt, ml, "$listowner$", myaddr, NULL); + MY_ASSERT(queuefilename); + close_text(txt); + finish_file_lines(fls); + + xasprintf(&probefile, "%s-probe", addr); + t = time(NULL); + fd = openat(bfd, probefile, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR); + if(fd < 0) + log_error(LOG_ARGS, "Could not open %s", probefile); + else + if (dprintf(fd, "%ld", (long int)t) < 0) + log_error(LOG_ARGS, "Could not write time in probe"); + + mail.to = myaddr; + mail.from = from; + mail.fp = fopen(queuefilename, "r"); + if (!send_single_mail(&mail, ml, false)) { + unlinkat(bfd, probefile, 0); + free(probefile); + return (false); + } + free(probefile); + fclose(mail.fp); + return (true); +} + + bool parse_lastdigest(char *line, long *lastindex, time_t *lasttime, long *lastissue, const char **errstr) diff --git a/src/prepstdreply.c b/src/prepstdreply.c index 04fc131e..8081e13d 100644 --- a/src/prepstdreply.c +++ b/src/prepstdreply.c @@ -189,7 +189,8 @@ finish_memory_lines(memory_lines_state *s) } -file_lines_state *init_file_lines(const char *filename, char truncate) +file_lines_state * +init_file_lines(const char *filename, char truncate) { file_lines_state *s = xcalloc(1, sizeof(file_lines_state)); s->filename = xstrdup(filename); @@ -197,6 +198,19 @@ file_lines_state *init_file_lines(const char *filename, char truncate) return s; } +file_lines_state +*init_file_lines_fd(int fd, char truncate) +{ + file_lines_state *s; + + if (fd == -1) + return (NULL); + s = xcalloc(1, sizeof(file_lines_state)); + s->fp = fdopen(fd, "r"); + s->truncate = truncate; + return (s); +} + void rewind_file_lines(void *state) { diff --git a/tests/mlmmj.c b/tests/mlmmj.c index b9532583..4e0b95e4 100644 --- a/tests/mlmmj.c +++ b/tests/mlmmj.c @@ -152,6 +152,7 @@ ATF_TC_WITHOUT_HEAD(requeuemail); ATF_TC_WITHOUT_HEAD(gethdrline); ATF_TC_WITHOUT_HEAD(readlf); ATF_TC_WITHOUT_HEAD(mod_get_addr_type); +ATF_TC_WITHOUT_HEAD(send_probe); ATF_TC_BODY(random_int, tc) { @@ -2797,6 +2798,64 @@ ATF_TC_BODY(mod_get_addr_type, tc) atf_utils_wait(p, 1, "", ""); } +ATF_TC_BODY(send_probe, tc) +{ + char *dir; + init_ml(true); + struct ml ml; + ml_init(&ml); + ml.dir = "list"; + ml_open(&ml, false); + rmdir("list/text"); + xasprintf(&dir, "%s/../listtexts/en", + atf_tc_get_config_var(tc, "srcdir")); + + symlink(dir, "list/text"); + atf_utils_create_file("list/control/smtpport", "25678"); + atf_utils_create_file("list/control/smtphelo", "heloname"); + int smtppipe[2]; + ATF_REQUIRE(socketpair(AF_UNIX, SOCK_STREAM, 0, smtppipe) >= 0); + pid_t p2 = single_mail_reception(smtppipe[1]); + atf_utils_readline(smtppipe[0]); + pid_t p = atf_utils_fork(); + if (p == 0) { + if (send_probe(&ml, "bapt=freebsd.org")) + exit(0); + exit(1); + } + atf_utils_wait(p2, 0, "save:mailout.txt", ""); + atf_utils_wait(p, 0, "", ""); + + if (!atf_utils_grep_file("Some messages to you could not be delivered", "mailout.txt")) { + atf_utils_cat_file("mailout.txt", ""); + atf_tc_fail("invalid file"); + } + + p = atf_utils_fork(); + if (p == 0) { + if (send_probe(&ml, "bapt@freebsd.org")) + exit(0); + exit(1); + } + atf_utils_wait(p, 1, "", ""); + + atf_utils_create_file("list/bounce/bapt=freebsd.org", "1234:blabla\n"); + p2 = single_mail_reception(smtppipe[1]); + atf_utils_readline(smtppipe[0]); + p = atf_utils_fork(); + if (p == 0) { + if (send_probe(&ml, "bapt=freebsd.org")) + exit(0); + exit(1); + } + atf_utils_wait(p2, 0, "save:mailout.txt", ""); + atf_utils_wait(p, 0, "", ""); + if (!atf_utils_grep_file("1234", "mailout.txt")) { + atf_utils_cat_file("mailout.txt", ">"); + atf_tc_fail("invalid mail sent"); + } +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, random_int); @@ -2883,6 +2942,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, gethdrline); ATF_TP_ADD_TC(tp, readlf); ATF_TP_ADD_TC(tp, mod_get_addr_type); + ATF_TP_ADD_TC(tp, send_probe); return (atf_no_error()); }