]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
mail-functions: factorize the code.
authorBaptiste Daroussin <bapt@FreeBSD.org>
Mon, 24 Oct 2022 15:16:12 +0000 (17:16 +0200)
committerBaptiste Daroussin <bapt@FreeBSD.org>
Mon, 24 Oct 2022 15:16:12 +0000 (17:16 +0200)
Stop returning errcode based en errno which might bring portability
issues

Add a full testsuite

src/mail-functions.c
tests/mlmmj.c

index bd9c625266b2420c15612649cacc57b8e0f003bd..4331a9e71a620a7e5eb464c6f51701285a2fac1e 100644 (file)
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002, 2003 Mads Martin Joergensen <mmj at mmj.dk>
- *
- * $Id$
+/*
+ * Copyright (C) 2002, 2003 Mads Martin Joergensen <mmj at mmj.dk>
+ * Copyright (C) 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
 #include "wrappers.h"
 #include "log_error.h"
 
-/* "EHLO \r\n" has length 7 */
-#define EXTRA_EHLO_LEN 7
-int write_ehlo(int sockfd, const char *hostname)
-{
-       size_t bytes_written;
-       
-       bytes_written = dprintf(sockfd, "EHLO %s\r\n", hostname);
+static int
+write_sock(int sockfd, const char *errstr, const char *fmt, ...) {
+       int bytes_written;
+       va_list ap;
+
+       va_start(ap, fmt);
+       bytes_written = vdprintf(sockfd, fmt, ap);
+       va_end(ap);
        if(bytes_written < 0) {
-               log_error(LOG_ARGS, "Could not write EHLO");
-               return errno;
+               log_error(LOG_ARGS, "Could not write %s", errstr);
+               return -1;
        }
        return 0;
 }
-/* "HELO \r\n" has length 7 */
-#define EXTRA_HELO_LEN 7
+
+int write_ehlo(int sockfd, const char *hostname)
+{
+       return (write_sock(sockfd, "EHLO", "EHLO %s\r\n", hostname));
+}
+
 int write_helo(int sockfd, const char *hostname)
 {
-       size_t bytes_written;
-       
-       bytes_written = dprintf(sockfd, "HELO %s\r\n", hostname);
-       if(bytes_written < 0) {
-               log_error(LOG_ARGS, "Could not write HELO");
-               return errno;
-       }
-       return 0;
+       return (write_sock(sockfd, "HELO", "HELO %s\r\n", hostname));
 }
-/* "MAIL FROM:<> \r\n" has length 15 */
-#define EXTRA_FROM_LEN 15
+
 int write_mail_from(int sockfd, const char *from_addr, const char *extra)
 {
-       size_t bytes_written;
-
        if(extra && extra[0] != '\0') {
                if(extra[0] == ' ') extra++;
-               bytes_written = dprintf(sockfd, "MAIL FROM:<%s> %s\r\n", from_addr,
-                               extra);
+               return (write_sock(sockfd, "FROM", "MAIL FROM:<%s> %s\r\n",
+                   from_addr, extra));
        } else
-               bytes_written = dprintf(sockfd, "MAIL FROM:<%s>\r\n", from_addr);
-       if(bytes_written < 0) {
-               log_error(LOG_ARGS, "Could not write FROM");
-               return errno;
-       }
-       return 0;
+               return (write_sock(sockfd, "FROM", "MAIL FROM:<%s>\r\n", from_addr));
 }
 
-/* "RCPT TO:<>\r\n" has length 12 */
-#define EXTRA_RCPT_LEN 12
 int write_rcpt_to(int sockfd, const char *rcpt_addr)
 {
-       size_t bytes_written;
-       
-       bytes_written = dprintf(sockfd, "RCPT TO:<%s>\r\n", rcpt_addr);
-       if(bytes_written < 0) {
-               log_error(LOG_ARGS, "Could not write TO");
-               return errno;
-       }
-       return 0;
+       return (write_sock(sockfd, "TO", "RCPT TO:<%s>\r\n", rcpt_addr));
 }
 
 
@@ -102,20 +83,23 @@ int write_mailbody_from_map(int sockfd, char *mapstart, size_t size,
 {
        char *cur, *next;
        char newlinebuf[3];
+       size_t len;
        int i = 1;
 
        for(next = cur = mapstart; next < mapstart + size; next++) {
                if(*next == '\n') {
-                       if(writen(sockfd, cur, next - cur) < 0) {
+                       if(dprintf(sockfd, "%.*s", (int)(next - cur), cur) < 0) {
                                log_error(LOG_ARGS, "Could not write mail");
                                return -1;
                        }
                        newlinebuf[0] = '\r';
                        newlinebuf[1] = '\n';
+                       len = 2;
                        if(next < (mapstart + size - 1) && *(next+1) == '.') {
                                newlinebuf[2] = '.';
+                               len++;
                        }
-                       if(dprintf(sockfd, "%s", newlinebuf) < 0) {
+                       if(dprintf(sockfd, "%.*s", (int)len, newlinebuf) < 0) {
                                log_error(LOG_ARGS, "Could not write mail");
                                return -1;
                        }
@@ -215,69 +199,25 @@ char *get_prepped_mailbody_from_map(char *mapstart, size_t size, size_t *blen)
 
 int write_dot(int sockfd)
 {
-       size_t bytes_written;
-
-       bytes_written = dprintf(sockfd, "\r\n.\r\n");   
-       if(bytes_written < 0)
-               return errno;
-
-       return 0;
-}
-
-/* "\r\n" has length 2 */
-#define EXTRA_CUSTOM_LEN 2
-int write_custom_line(int sockfd, const char *line)
-{
-       size_t bytes_written;
-       
-       bytes_written = dprintf(sockfd, "%s\r\n", line);
-       if(bytes_written < 0) {
-               log_error(LOG_ARGS, "Could not write customline");
-               return errno;
-       }
-       return 0;
+       return write_sock(sockfd, "", "\r\n.\r\n");
 }
 
-/* "Reply-To: \r\n" has length 12 */
-#define EXTRA_REPLYTO_LEN 12
 int write_replyto(int sockfd, const char *replyaddr)
 {
-       size_t bytes_written;
-       
-       bytes_written = dprintf(sockfd, "Reply-To: %s\r\n", replyaddr);
-       if(bytes_written < 0) {
-               log_error(LOG_ARGS, "Could not write Reply-To header");
-               return errno;
-       }
-       return 0;
+       return write_sock(sockfd, "Reply-To header", "Reply-To: %s\r\n", replyaddr);
 }
 
 int write_data(int sockfd)
 {
-       if(write_custom_line(sockfd, "DATA")) {
-               log_error(LOG_ARGS, "Could not write DATA");
-               return errno;
-       }
-
-       return 0;
+       return write_sock(sockfd, "DATA", "DATA\r\n");
 }
 
 int write_quit(int sockfd)
 {
-       if(write_custom_line(sockfd, "QUIT")) {
-               log_error(LOG_ARGS, "Could not write QUIT");
-               return errno;
-       }
-
-       return 0;
+       return write_sock(sockfd, "QUIT", "QUIT\r\n");
 }
 
 int write_rset(int sockfd)
 {
-       if(write_custom_line(sockfd, "RSET")) {
-               log_error(LOG_ARGS, "Could not write RSET");
-               return errno;
-       }
-
-       return 0;
+       return write_sock(sockfd, "RSET", "RSET\r\n");
 }
index 1cdcf8b72243cb4e660e4f5c40190dd7c543acea..0bbb67bdaad2a0f71855659c6c8925993ad14f2d 100644 (file)
@@ -23,6 +23,7 @@
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
+#include <sys/mman.h>
 
 #include <atf-c.h>
 #include <inttypes.h>
@@ -58,6 +59,16 @@ ATF_TC_WITHOUT_HEAD(exec_or_die);
 ATF_TC_WITHOUT_HEAD(exec_and_wait);
 ATF_TC_WITHOUT_HEAD(find_email_adr);
 ATF_TC_WITHOUT_HEAD(strtoim);
+ATF_TC_WITHOUT_HEAD(write_ehlo);
+ATF_TC_WITHOUT_HEAD(write_helo);
+ATF_TC_WITHOUT_HEAD(write_dot);
+ATF_TC_WITHOUT_HEAD(write_data);
+ATF_TC_WITHOUT_HEAD(write_quit);
+ATF_TC_WITHOUT_HEAD(write_rset);
+ATF_TC_WITHOUT_HEAD(write_replyto);
+ATF_TC_WITHOUT_HEAD(write_rcpt_to);
+ATF_TC_WITHOUT_HEAD(write_mail_from);
+ATF_TC_WITHOUT_HEAD(write_mailbody_from_map);
 
 #ifndef NELEM
 #define NELEM(array)    (sizeof(array) / sizeof((array)[0]))
@@ -427,6 +438,242 @@ ATF_TC_BODY(strtoim, tc)
        ATF_REQUIRE_STREQ(errp, "invalid");
 }
 
+ATF_TC_BODY(write_ehlo, tc)
+{
+       ATF_REQUIRE_EQ(write_ehlo(-1, "myname"), -1);
+       int fd = open("ehlo.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_ehlo(fd, "myname"), 0);
+       close(fd);
+       if (!atf_utils_compare_file("ehlo.txt", "EHLO myname\r\n"))
+               atf_tc_fail("Unexpected output");
+}
+
+ATF_TC_BODY(write_helo, tc)
+{
+       ATF_REQUIRE_EQ(write_helo(-1, "myname"), -1);
+       int fd = open("helo.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_helo(fd, "myname"), 0);
+       close(fd);
+       if (!atf_utils_compare_file("helo.txt", "HELO myname\r\n"))
+               atf_tc_fail("Unexpected output");
+}
+
+ATF_TC_BODY(write_dot, tc)
+{
+       ATF_REQUIRE_EQ(write_dot(-1), -1);
+       int fd = open("dot.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_dot(fd), 0);
+       close(fd);
+       if (!atf_utils_compare_file("dot.txt", "\r\n.\r\n"))
+               atf_tc_fail("Unexpected output");
+}
+
+ATF_TC_BODY(write_data, tc)
+{
+       ATF_REQUIRE_EQ(write_data(-1), -1);
+       int fd = open("data.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_data(fd), 0);
+       close(fd);
+       if (!atf_utils_compare_file("data.txt", "DATA\r\n"))
+               atf_tc_fail("Unexpected output");
+}
+
+ATF_TC_BODY(write_quit, tc)
+{
+       ATF_REQUIRE_EQ(write_quit(-1), -1);
+       int fd = open("quit.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_quit(fd), 0);
+       close(fd);
+       if (!atf_utils_compare_file("quit.txt", "QUIT\r\n"))
+               atf_tc_fail("Unexpected output");
+}
+
+ATF_TC_BODY(write_rset, tc)
+{
+       ATF_REQUIRE_EQ(write_rset(-1), -1);
+       int fd = open("rset.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_rset(fd), 0);
+       close(fd);
+       if (!atf_utils_compare_file("rset.txt", "RSET\r\n"))
+               atf_tc_fail("Unexpected output");
+}
+
+ATF_TC_BODY(write_replyto, tc)
+{
+       ATF_REQUIRE_EQ(write_replyto(-1, "toto"), -1);
+       int fd = open("replyto.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_replyto(fd, "toto"), 0);
+       close(fd);
+       if (!atf_utils_compare_file("replyto.txt", "Reply-To: toto\r\n"))
+               atf_tc_fail("Unexpected output");
+}
+
+ATF_TC_BODY(write_rcpt_to, tc)
+{
+       ATF_REQUIRE_EQ(write_rcpt_to(-1, "toto"), -1);
+       int fd = open("rcpt_to.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_rcpt_to(fd, "toto"), 0);
+       close(fd);
+       if (!atf_utils_compare_file("rcpt_to.txt", "RCPT TO:<toto>\r\n")) {
+               atf_utils_cat_file("rcpt_to.txt", "");
+               atf_tc_fail("Unexpected output");
+       }
+}
+
+ATF_TC_BODY(write_mail_from, tc)
+{
+       ATF_REQUIRE_EQ(write_mail_from(-1, "toto", NULL), -1);
+       int fd = open("mail_from.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_mail_from(fd, "toto", NULL), 0);
+       close(fd);
+       if (!atf_utils_compare_file("mail_from.txt", "MAIL FROM:<toto>\r\n")) {
+               atf_utils_cat_file("mail_from.txt", "");
+               atf_tc_fail("Unexpected output");
+       }
+       fd = open("mail_from.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_mail_from(fd, "toto", "meh"), 0);
+       close(fd);
+       if (!atf_utils_compare_file("mail_from.txt", "MAIL FROM:<toto> meh\r\n")) {
+               atf_utils_cat_file("mail_from.txt", "");
+               atf_tc_fail("Unexpected output");
+       }
+       fd = open("mail_from.txt", O_CREAT|O_WRONLY|O_TRUNC, 0644);
+       ATF_REQUIRE_EQ(write_mail_from(fd, "toto", ""), 0);
+       close(fd);
+       if (!atf_utils_compare_file("mail_from.txt", "MAIL FROM:<toto>\r\n")) {
+               atf_utils_cat_file("mail_from.txt", "");
+               atf_tc_fail("Unexpected output");
+       }
+       fd = open("mail_from.txt", O_CREAT|O_WRONLY|O_TRUNC, 0644);
+       ATF_REQUIRE_EQ(write_mail_from(fd, "toto", " "), 0);
+       close(fd);
+       if (!atf_utils_compare_file("mail_from.txt", "MAIL FROM:<toto> \r\n")) {
+               atf_utils_cat_file("mail_from.txt", "");
+               atf_tc_fail("Unexpected output");
+       }
+}
+
+ATF_TC_BODY(write_mailbody_from_map, tc)
+{
+       /* no new lines: ignore */
+       struct stat st;
+       char *start;
+       FILE *f = fopen("myemailbody.txt", "w");
+       fprintf(f, "line");
+       fclose(f);
+       int fd1 = open("myemailbody.txt", O_RDONLY);
+       fstat(fd1, &st);
+       ATF_REQUIRE((start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd1, 0)) != NULL);
+       int fd = open("out.txt", O_CREAT|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_mailbody_from_map(fd, start, st.st_size, "test@plop.meh"), 0);
+       close(fd);
+       munmap(start, st.st_size);
+       close(fd1);
+       if (!atf_utils_compare_file("out.txt", "")) {
+               atf_utils_cat_file("out.txt", ">");
+               atf_tc_fail("Unexpected output");
+       }
+
+       /* With a single new line */
+       f = fopen("myemailbody.txt", "w");
+       fprintf(f, "line\n");
+       fclose(f);
+       fd1 = open("myemailbody.txt", O_RDONLY);
+       fstat(fd1, &st);
+       ATF_REQUIRE((start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd1, 0)) != NULL);
+       fd = open("out.txt", O_CREAT|O_TRUNC|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_mailbody_from_map(fd, start, st.st_size, "test@plop.meh"), 0);
+       close(fd);
+       munmap(start, st.st_size);
+       close(fd1);
+       if (!atf_utils_compare_file("out.txt", "line\r\n")) {
+               atf_utils_cat_file("out.txt", ">");
+               atf_tc_fail("Unexpected output");
+       }
+
+       /* With a single new line with a . */
+       f = fopen("myemailbody.txt", "w");
+       fprintf(f, "line\n.");
+       fclose(f);
+       fd1 = open("myemailbody.txt", O_RDONLY);
+       fstat(fd1, &st);
+       ATF_REQUIRE((start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd1, 0)) != NULL);
+       fd = open("out.txt", O_CREAT|O_TRUNC|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_mailbody_from_map(fd, start, st.st_size, "test@plop.meh"), 0);
+       close(fd);
+       munmap(start, st.st_size);
+       close(fd1);
+       if (!atf_utils_compare_file("out.txt", "line\r\n.")) {
+               atf_utils_cat_file("out.txt", ">");
+               atf_tc_fail("Unexpected output");
+       }
+
+       /* With a single new line, 2 new lines */
+       f = fopen("myemailbody.txt", "w");
+       fprintf(f, "line\n\n");
+       fclose(f);
+       fd1 = open("myemailbody.txt", O_RDONLY);
+       fstat(fd1, &st);
+       ATF_REQUIRE((start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd1, 0)) != NULL);
+       fd = open("out.txt", O_CREAT|O_TRUNC|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_mailbody_from_map(fd, start, st.st_size, "test@plop.meh"), 0);
+       close(fd);
+       munmap(start, st.st_size);
+       close(fd1);
+       if (!atf_utils_compare_file("out.txt", "line\r\ntest@plop.meh\r\n")) {
+               atf_utils_cat_file("out.txt", ">");
+               atf_tc_fail("Unexpected output");
+       }
+
+
+       /* With a single 2 lines separated by 2 new lines*/
+       f = fopen("myemailbody.txt", "w");
+       fprintf(f, "line\n\nline2\n\n");
+       fclose(f);
+       fd1 = open("myemailbody.txt", O_RDONLY);
+       fstat(fd1, &st);
+       ATF_REQUIRE((start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd1, 0)) != NULL);
+       fd = open("out.txt", O_CREAT|O_TRUNC|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_mailbody_from_map(fd, start, st.st_size, "test@plop.meh"), 0);
+       close(fd);
+       munmap(start, st.st_size);
+       close(fd1);
+       if (!atf_utils_compare_file("out.txt", "line\r\ntest@plop.meh\r\nline2\r\n\r\n")) {
+               atf_utils_cat_file("out.txt", ">");
+               atf_tc_fail("Unexpected output");
+       }
+
+
+       /* No to header */
+       f = fopen("myemailbody.txt", "w");
+       fprintf(f, "line\n\nline2\n\n");
+       fclose(f);
+       fd1 = open("myemailbody.txt", O_RDONLY);
+       fstat(fd1, &st);
+       ATF_REQUIRE((start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd1, 0)) != NULL);
+       fd = open("out.txt", O_CREAT|O_TRUNC|O_WRONLY, 0644);
+       ATF_REQUIRE_EQ(write_mailbody_from_map(fd, start, st.st_size, NULL), 0);
+       close(fd);
+       munmap(start, st.st_size);
+       close(fd1);
+       if (!atf_utils_compare_file("out.txt", "line\r\n\r\nline2\r\n\r\n")) {
+               atf_utils_cat_file("out.txt", ">");
+               atf_tc_fail("Unexpected output");
+       }
+
+       /* With invalid socket */
+       f = fopen("myemailbody.txt", "w");
+       fprintf(f, "line\n");
+       fclose(f);
+       fd1 = open("myemailbody.txt", O_RDONLY);
+       fstat(fd1, &st);
+       ATF_REQUIRE((start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd1, 0)) != NULL);
+       ATF_REQUIRE_EQ(write_mailbody_from_map(-1, start, st.st_size, "test@plop.meh"), -1);
+       munmap(start, st.st_size);
+       close(fd1);
+}
+
+
 ATF_TP_ADD_TCS(tp)
 {
        ATF_TP_ADD_TC(tp, random_int);
@@ -441,6 +688,16 @@ ATF_TP_ADD_TCS(tp)
        ATF_TP_ADD_TC(tp, exec_and_wait);
        ATF_TP_ADD_TC(tp, find_email_adr);
        ATF_TP_ADD_TC(tp, strtoim);
+       ATF_TP_ADD_TC(tp, write_ehlo);
+       ATF_TP_ADD_TC(tp, write_helo);
+       ATF_TP_ADD_TC(tp, write_dot);
+       ATF_TP_ADD_TC(tp, write_data);
+       ATF_TP_ADD_TC(tp, write_quit);
+       ATF_TP_ADD_TC(tp, write_rset);
+       ATF_TP_ADD_TC(tp, write_replyto);
+       ATF_TP_ADD_TC(tp, write_rcpt_to);
+       ATF_TP_ADD_TC(tp, write_mail_from);
+       ATF_TP_ADD_TC(tp, write_mailbody_from_map);
 
        return (atf_no_error());
 }