From: Baptiste Daroussin Date: Thu, 27 Oct 2022 12:50:40 +0000 (+0200) Subject: lastdigest: add a function to parse the line and its unit test X-Git-Tag: RELEASE_1_4_0a1~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a4e67254def0d4e9842e5182b8b8f5350169091;p=thirdparty%2Fmlmmj.git lastdigest: add a function to parse the line and its unit test --- diff --git a/include/mlmmj.h b/include/mlmmj.h index 48362b56..0c199cc6 100644 --- a/include/mlmmj.h +++ b/include/mlmmj.h @@ -25,6 +25,8 @@ #define MLMMJ_GENERIC_INCLUDES #include "config.h" +#include +#include #define RELAYHOST "127.0.0.1" #define READ_BUFSIZE 2048 @@ -95,6 +97,8 @@ enum subreason { extern char * subreason_strs[6]; /* count matches enum above; defined in subscriberfuncs.c */ void print_version(const char *prg); +bool parse_lastdigest(char *line, long *lastindex, time_t *lasttime, + long *lastissue, const char **errstr); #define MY_ASSERT(expression) if (!(expression)) { \ errno = 0; \ diff --git a/src/Makefile.am b/src/Makefile.am index 569d0194..b9281814 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,7 +27,8 @@ libmlmmj_a_SOURCES= mail-functions.c chomp.c incindexfile.c \ do_all_the_voodoo_here.c log_oper.c send_list.c \ unistr.c gethdrline.c send_digest.c \ writen.c getlistaddr.c strgen.c statctrl.c \ - ctrlvalue.c readn.c getlistdelim.c ctrlvalues.c utils.c + ctrlvalue.c readn.c getlistdelim.c ctrlvalues.c \ + utils.c mlmmj.c mlmmj_send_SOURCES = mlmmj-send.c mlmmj_send_LDADD= libmlmmj.a diff --git a/src/mlmmj-maintd.c b/src/mlmmj-maintd.c index 5d176d5e..baf1dc43 100644 --- a/src/mlmmj-maintd.c +++ b/src/mlmmj-maintd.c @@ -609,7 +609,6 @@ unsub_bouncers(int dfd, const char *mlmmjunsub, const char *listdir, int logfd) static bool run_digests(int dfd, const char *mlmmjsend, const char *listdir, int logfd) { - char *lasttimestr, *lastindexstr, *lastissuestr; char *s1, *s2; time_t digestinterval, t, lasttime; long digestmaxmails, lastindex, index, lastissue; @@ -639,47 +638,9 @@ run_digests(int dfd, const char *mlmmjsend, const char *listdir, int logfd) s1 = mygetline(fd); /* Syntax is lastindex:lasttime or lastindex:lasttime:lastissue */ - if (s1 && (lasttimestr = strchr(s1, ':'))) { - *(lasttimestr++) = '\0'; - if ((lastissuestr = strchr(lasttimestr, ':'))) { - *(lastissuestr++) = '\0'; - lastissue = strtoim(lastissuestr, LONG_MIN, LONG_MAX, - &errstr); - if (errstr != NULL) { - log(" - 'lastdigests' contains malformed " - "data: Impossible to parse lastissue: '%s':" - " %s", lastissuestr, errstr); - close(fd); - return (false); - } - } else { - lastissue = 0; - } - lasttime = strtotimet(lasttimestr, &errstr); - if (errstr) { - log(" - 'lastdigest' invalid last time string: " - "'%s': %s", lasttimestr, errstr); - close(fd); - return (false); - } - lastindexstr = s1; - lastindex = strtoim(lastindexstr, LONG_MIN, LONG_MAX, &errstr); - if (errstr != NULL) { - log("'lastdigests' invalid last index: '%s': %s\n", - lastindexstr, errstr); - return (false); - } - } else { - if (s1 && (strlen(s1) > 0)) { - log_error(LOG_ARGS, "'lastdigest' invalid first line"); - free(s1); - close(fd); - return (false); - } - /* If lastdigest is empty, we start from scratch */ - lasttime = 0; - lastindex = 0; - lastissue = 0; + if (!parse_lastdigest(s1, &lastindex, &lasttime, &lastissue, &errstr)) { + log(" - malformerd lastdigest '%s': %s", s1, errstr); + return (false); } indexfd = openat(dfd, "index", O_RDONLY); diff --git a/src/mlmmj.c b/src/mlmmj.c new file mode 100644 index 00000000..d80c6fa1 --- /dev/null +++ b/src/mlmmj.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2021-2022 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 + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mlmmj.h" +#include "utils.h" +#include "log_error.h" +#include "xmalloc.h" +#include "chomp.h" + +bool +parse_lastdigest(char *line, long *lastindex, time_t *lasttime, + long *lastissue, const char **errstr) +{ + size_t nfield = 0; + char *walk; + + *errstr = NULL; + + if (line == NULL) { + *lastindex = 0; + *lasttime = 0; + *lastissue = 0; + return (true); + } + walk = line; + while (strsep(&walk, ":") != NULL) + nfield++; + if (nfield < 2 || nfield > 3) { + *errstr = "Invalid format, expecting 2 or 3 fields"; + return (false); + } + *lastindex = strtoim(line, 0, LONG_MAX, errstr); + if (*errstr != NULL) { + *errstr = "Invalid value for lastindex"; + return (false); + } + walk = line + strlen(line) + 1; + *lasttime = strtotimet(walk, errstr); + if (*errstr != NULL) { + *errstr = "Invalid value for lasttime"; + return (false); + } + if (nfield == 2) { + *lastissue = 0; + return true; + } + walk = walk + strlen(walk) + 1; + *lastissue = strtoim(walk, LONG_MIN, LONG_MAX, errstr); + if (*errstr != NULL) { + *errstr = "Invalid value for lastissue"; + return (false); + } + return (true); +} diff --git a/tests/mlmmj.c b/tests/mlmmj.c index 923ff621..9cbfd799 100644 --- a/tests/mlmmj.c +++ b/tests/mlmmj.c @@ -71,6 +71,7 @@ ATF_TC_WITHOUT_HEAD(write_mail_from); ATF_TC_WITHOUT_HEAD(write_mailbody_from_map); ATF_TC_WITHOUT_HEAD(strtotimet); ATF_TC_WITHOUT_HEAD(decode_qp); +ATF_TC_WITHOUT_HEAD(parse_lastdigest); #ifndef NELEM #define NELEM(array) (sizeof(array) / sizeof((array)[0])) @@ -702,6 +703,88 @@ ATF_TC_BODY(decode_qp, tc) ATF_REQUIRE_STREQ(decode_qp("This_ is a subject"), "This_ is a subject"); } +ATF_TC_BODY(parse_lastdigest, tc) +{ + time_t lasttime; + long lastissue; + long lastindex; + const char *errstr; + char *line; + + line = xstrdup("1:2:3"); + ATF_REQUIRE(parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE(errstr == NULL); + ATF_REQUIRE(lastindex == 1); + ATF_REQUIRE(lasttime == 2); + ATF_REQUIRE(lastissue == 3); + free(line); + + line = xstrdup("1"); + ATF_REQUIRE(!parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE_STREQ(errstr, "Invalid format, expecting 2 or 3 fields"); + free(line); + + line = xstrdup("1:2:3:4"); + ATF_REQUIRE(!parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE_STREQ(errstr, "Invalid format, expecting 2 or 3 fields"); + free(line); + + ATF_REQUIRE(parse_lastdigest(NULL, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE(errstr == NULL); + ATF_REQUIRE(lastindex == 0); + ATF_REQUIRE(lasttime == 0); + ATF_REQUIRE(lastissue == 0); + + line = xstrdup("1:2"); + ATF_REQUIRE(parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE(errstr == NULL); + ATF_REQUIRE(lastindex == 1); + ATF_REQUIRE(lasttime == 2); + ATF_REQUIRE(lastissue == 0); + free(line); + + line = xstrdup("a:2"); + ATF_REQUIRE(!parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE_STREQ(errstr, "Invalid value for lastindex"); + free(line); + + line = xstrdup("-1:2"); + ATF_REQUIRE(!parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE_STREQ(errstr, "Invalid value for lastindex"); + free(line); + + line = xstrdup("1:"); + ATF_REQUIRE(!parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE_STREQ(errstr, "Invalid value for lasttime"); + free(line); + + line = xstrdup("1:a"); + ATF_REQUIRE(!parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE_STREQ(errstr, "Invalid value for lasttime"); + free(line); + + line = xstrdup("1:1:"); + ATF_REQUIRE(!parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE_STREQ(errstr, "Invalid value for lastissue"); + free(line); + + line = xstrdup("1:1:a"); + ATF_REQUIRE(!parse_lastdigest(line, &lastindex, &lasttime, &lastissue, + &errstr)); + ATF_REQUIRE_STREQ(errstr, "Invalid value for lastissue"); + free(line); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, random_int); @@ -728,6 +811,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, write_mailbody_from_map); ATF_TP_ADD_TC(tp, strtotimet); ATF_TP_ADD_TC(tp, decode_qp); + ATF_TP_ADD_TC(tp, parse_lastdigest); return (atf_no_error()); }