]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
lastdigest: add a function to parse the line and its unit test
authorBaptiste Daroussin <bapt@FreeBSD.org>
Thu, 27 Oct 2022 12:50:40 +0000 (14:50 +0200)
committerBaptiste Daroussin <bapt@FreeBSD.org>
Fri, 28 Oct 2022 09:07:03 +0000 (11:07 +0200)
include/mlmmj.h
src/Makefile.am
src/mlmmj-maintd.c
src/mlmmj.c [new file with mode: 0644]
tests/mlmmj.c

index 48362b56c8a755cefe4ee6916d5b72c88412f998..0c199cc6417df04c5135bdfb559a55aa13027953 100644 (file)
@@ -25,6 +25,8 @@
 #define MLMMJ_GENERIC_INCLUDES
 
 #include "config.h"
+#include <stdbool.h>
+#include <time.h>
 
 #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; \
index 569d01945041d53639916f5975234121e3e4c9fb..b9281814c948ee8a74ef122acb929f6c6f5db1db 100644 (file)
@@ -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
index 5d176d5e97e203f87e5e3c13067e597682b3f0b0..baf1dc43eee6a8a5e1d0b93c6d8f52bc57a9df9a 100644 (file)
@@ -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 (file)
index 0000000..d80c6fa
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021-2022 Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * 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 <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#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);
+}
index 923ff6215bf2fd372b22ba71dbee40ecb700ff3e..9cbfd799e328064e411c2237b9e8155b149e70ab 100644 (file)
@@ -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());
 }