From: Baptiste Daroussin Date: Mon, 24 Oct 2022 15:16:12 +0000 (+0200) Subject: mail-functions: factorize the code. X-Git-Tag: RELEASE_1_4_0a1~56 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d9647ac011fea25010da3fc6b30baebcc1e860d4;p=thirdparty%2Fmlmmj.git mail-functions: factorize the code. Stop returning errcode based en errno which might bring portability issues Add a full testsuite --- diff --git a/src/mail-functions.c b/src/mail-functions.c index bd9c6252..4331a9e7 100644 --- a/src/mail-functions.c +++ b/src/mail-functions.c @@ -1,6 +1,6 @@ -/* Copyright (C) 2002, 2003 Mads Martin Joergensen - * - * $Id$ +/* + * Copyright (C) 2002, 2003 Mads Martin Joergensen + * Copyright (C) 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 @@ -37,63 +37,44 @@ #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"); } diff --git a/tests/mlmmj.c b/tests/mlmmj.c index 1cdcf8b7..0bbb67bd 100644 --- a/tests/mlmmj.c +++ b/tests/mlmmj.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -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:\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:\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: 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:\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: \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()); }