changeset 268:1dbadf407849

mlmmj-send now prepares headers and mail, and To: header feature added
author mmj
date Thu, 24 Jun 2004 21:56:06 +1000
parents 55738fb09e46
children facf047c93c5
files ChangeLog TUNABLES include/mail-functions.h include/mlmmj-send.h include/mlmmj.h src/Makefile.am src/mail-functions.c src/mlmmj-send.c
diffstat 8 files changed, 229 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Jun 22 19:08:47 2004 +1000
+++ b/ChangeLog	Thu Jun 24 21:56:06 2004 +1000
@@ -1,3 +1,10 @@
+0.8.1
+ o Add the option to add a To: header including the recipient emailaddress.
+   NOTE that this does not remove any existing To: headers, they should be
+   removed in control/delheaders
+ o Optimize mlmmj-send by preparing the mail in memory to reduce the amount of
+   write syscalls. control/memmailsize (size in bytes) controls how big it can
+   be. Default is 16k before it's send line by line.
  o Make sure we check if the Subject: prefix might be present in the
    de-quoted printable version of the Subject. If so, don't add it.
  o Fix bug with queuefilename not being correctly initialized when generating
--- a/TUNABLES	Tue Jun 22 19:08:47 2004 +1000
+++ b/TUNABLES	Thu Jun 24 21:56:06 2004 +1000
@@ -63,3 +63,16 @@
    If this file exists, all headers of a post to the list is matched against
    the rules. The first rule to match wins. See README.access for syntax and
    examples.
+
+ · memorymailsize		(normal)
+
+   Here is specified in bytes how big a mail can be and still be prepared for
+   sending in memory. It's greatly reducing the amount of write system calls to
+   prepare it in memory before sending it, but can also lead to denial of
+   service attacks. Default is 16k (16384 bytes).
+
+ · addtohdr			(boolean)
+
+   When this file is present, a To: header including the recipients
+   emailaddress will be added to outgoing mail. Recommended usage is to remove
+   existing To: headers with delheaders (see above) first.
--- a/include/mail-functions.h	Tue Jun 22 19:08:47 2004 +1000
+++ b/include/mail-functions.h	Thu Jun 24 21:56:06 2004 +1000
@@ -32,7 +32,11 @@
 int write_mail_from(int sockfd, const char *from_addr);
 int write_rcpt_to(int sockfd, const char *rcpt_addr);
 int write_custom_line(int sockfd, const char *line);
-int write_mailbody_from_map(int sockfd, char *mailmap, size_t mailsize);
+int write_mailbody_from_map(int sockfd, char *mailmap, size_t mailsize,
+			    const char *tohdr);
+char *get_preppedhdrs_from_map(char *mapstart, size_t *hdrslen);
+char *get_prepped_mailbody_from_map(char *mapstart, size_t size,
+				    size_t *bodylen);
 int write_replyto(int sockfd, const char *replyaddr);
 int write_dot(int sockfd);
 int write_quit(int sockfd);
--- a/include/mlmmj-send.h	Tue Jun 22 19:08:47 2004 +1000
+++ b/include/mlmmj-send.h	Thu Jun 24 21:56:06 2004 +1000
@@ -26,11 +26,15 @@
 
 int send_mail(int sockfd, const char *from, const char *to,
 	      const char *replyto, char *mailmap, size_t mailsize,
-	      const char *listdir, const char *mlmmjbounce);
+	      const char *listdir, const char *mlmmjbounce,
+	      const char *hdrs, size_t hdrslen, const char *body,
+	      size_t bodylen);
 int send_mail_many(int sockfd, const char *from, const char *replyto,
 		   char *mailmap, size_t mailsize, int subfd,
 		   const char *listaddr, const char *archivefilename,
-		   const char *listdir, const char *mlmmjbounce);
+		   const char *listdir, const char *mlmmjbounce,
+		   const char *hdrs, size_t hdrslen, const char *body,
+		   size_t bodylen);
 int initsmtp(int *sockfd, const char *relayhost);
 int endsmtp(int *sockfd);
 
--- a/include/mlmmj.h	Tue Jun 22 19:08:47 2004 +1000
+++ b/include/mlmmj.h	Thu Jun 24 21:56:06 2004 +1000
@@ -42,6 +42,9 @@
 			     mlmmj-maintd runs daemonized? 7200s is 2 hours */
 #define MAINTD_LOGFILE "mlmmj-maintd.lastrun.log"
 
+#define MEMORYMAILSIZE 16384  /* How big can a mail be before we don't want to
+			         it in memory? control/memorymailsize */
+
 struct strlist {
 	int count;
 	char **strs;
--- a/src/Makefile.am	Tue Jun 22 19:08:47 2004 +1000
+++ b/src/Makefile.am	Thu Jun 24 21:56:06 2004 +1000
@@ -15,7 +15,8 @@
 mlmmj_send_SOURCES = mlmmj-send.c writen.c mail-functions.c itoa.c chomp.c \
                      incindexfile.c checkwait_smtpreply.c getlistaddr.c \
 		     mylocking.c init_sockfd.c strgen.c random-int.c \
-		     print-version.c log_error.c mygetline.c memory.c
+		     print-version.c log_error.c mygetline.c memory.c \
+		     statctrl.c ctrlvalue.c
 
 mlmmj_recieve_SOURCES = mlmmj-recieve.c writen.c random-int.c strgen.c \
 			print-version.c log_error.c dumpfd2fd.c memory.c
--- a/src/mail-functions.c	Tue Jun 22 19:08:47 2004 +1000
+++ b/src/mail-functions.c	Thu Jun 24 21:56:06 2004 +1000
@@ -116,11 +116,13 @@
 }
 
 
-int write_mailbody_from_map(int sockfd, char *mapstart, size_t size)
+int write_mailbody_from_map(int sockfd, char *mapstart, size_t size,
+			    const char *tohdr)
 {
 	char *cur, *next;
 	char newlinebuf[3];
 	size_t len;
+	int i = 1;
 
 	for(next = cur = mapstart; next < mapstart + size; next++) {
 		if(*next == '\n') {
@@ -139,6 +141,14 @@
 				log_error(LOG_ARGS, "Could not write mail");
 				return -1;
 			}
+			if(i && tohdr && *(next+1) == '\n') { /* add To: header */
+				if(writen(sockfd, tohdr, strlen(tohdr)) < 0) {
+					log_error(LOG_ARGS, "Could not write"
+							    " To: header");
+					return -1;
+				}
+				i = 0; /* Make sure we don't write it again */
+			}
 			cur = next + 1;
 		}
 	}
@@ -146,6 +156,85 @@
 	return 0;
 }
 
+char *get_preppedhdrs_from_map(char *mapstart, size_t *hlen)
+{
+	char *cur, *next, *endhdrs, *retstr, *r;
+	const char newlinebuf[] = "\r\n";
+	size_t hdrlen, n = 0;
+
+	endhdrs = strstr(mapstart, "\n\n");
+	if(endhdrs == NULL)
+		return NULL; /* The map doesn't map a file with a mail */
+
+	hdrlen = endhdrs - mapstart + 1;
+
+	for(next = cur = mapstart; next < mapstart + hdrlen; next++)
+		if(*next == '\n')
+			n++;
+
+	retstr = mymalloc(hdrlen + n);
+	*hlen = hdrlen + n;	
+	r = retstr;	
+
+	for(next = cur = mapstart; next < mapstart + hdrlen; next++) {
+		if(*next == '\n') {
+			strncpy(r, cur, next - cur);
+			r += next - cur;
+			strncpy(r, newlinebuf, 2);
+			r += 2;
+			cur = next + 1;
+		}
+	}
+
+	return retstr;
+}
+
+char *get_prepped_mailbody_from_map(char *mapstart, size_t size, size_t *blen)
+{
+	char *cur, *next, *endhdrs, *retstr, *r;
+	char newlinebuf[3];
+	size_t bodylen, len, n = 0;
+
+	endhdrs = strstr(mapstart, "\n\n");
+	if(endhdrs == NULL)
+		return NULL; /* The map doesn't map a file with a mail */
+
+	endhdrs++; /* Skip the first newline, it's in hdrs */
+
+	bodylen = size - (endhdrs - mapstart);
+	
+	for(next = cur = endhdrs; next < mapstart + size; next++) {
+		if(*next == '\n') {
+			n++;
+			if(*(next+1) == '.')
+				n++;
+		}
+	}
+
+	retstr = mymalloc(bodylen + n);
+	*blen = bodylen + n;
+	r = retstr;	
+	
+	for(next = cur = endhdrs; next < mapstart + size; next++) {
+		if(*next == '\n') {
+			strncpy(r, cur, next - cur);
+			r += next - cur;
+			newlinebuf[0] = '\r';
+			newlinebuf[1] = '\n';
+			len = 2;
+			if(*(next+1) == '.') {
+				newlinebuf[2] = '.';
+				len = 3;
+			}
+			strncpy(r, newlinebuf, len);
+			r += len;
+			cur = next + 1;
+		}
+	}
+
+	return retstr;
+}
+
 /* "\r\n" has length 2 */
 #define EXTRA_CUSTOM_LEN 3
 
--- a/src/mlmmj-send.c	Tue Jun 22 19:08:47 2004 +1000
+++ b/src/mlmmj-send.c	Thu Jun 24 21:56:06 2004 +1000
@@ -36,6 +36,7 @@
 #include <syslog.h>
 #include <stdarg.h>
 #include <sys/mman.h>
+#include <limits.h>
 
 #include "mlmmj-send.h"
 #include "mlmmj.h"
@@ -51,6 +52,11 @@
 #include "mygetline.h"
 #include "wrappers.h"
 #include "memory.h"
+#include "statctrl.h"
+#include "ctrlvalue.h"
+
+static int addtohdr = 0;
+static int prepmailinmem = 0;
 
 char *bounce_from_adr(const char *recipient, const char *listadr,
 		      const char *mailfilename)
@@ -158,10 +164,12 @@
 
 int send_mail(int sockfd, const char *from, const char *to,
 	      const char *replyto, char *mailmap, size_t mailsize,
-	      const char *listdir, const char *mlmmjbounce)
+	      const char *listdir, const char *mlmmjbounce,
+	      const char *hdrs, size_t hdrslen, const char *body,
+	      size_t bodylen)
 {
 	int retval = 0;
-	char *reply;
+	char *reply, *tohdr;
 	
 	retval = write_mail_from(sockfd, from);
 	if(retval) {
@@ -222,11 +230,38 @@
 		}
 	}
 
-	retval = write_mailbody_from_map(sockfd, mailmap, mailsize);
+	if(addtohdr)
+		tohdr = concatstr(3, "To: ", to, "\r\n");
+	else
+		tohdr = NULL;
+
+	if(prepmailinmem) {
+		retval = writen(sockfd, hdrs, hdrslen);
+		if(retval < 0) {
+			log_error(LOG_ARGS, "Could not write mailheaders.\n");
+			return retval;
+		}
+		if(tohdr) {
+			retval = writen(sockfd, tohdr, strlen(tohdr));
+			if(retval < 0) {
+				log_error(LOG_ARGS, "Could not write To:.\n");
+				return retval;
+			}
+			myfree(tohdr);
+		}
+		retval = writen(sockfd, body, bodylen);
+		if(retval < 0) {
+			log_error(LOG_ARGS, "Could not write mailbody.\n");
+			return retval;
+		}
+	} else {
+		retval = write_mailbody_from_map(sockfd, mailmap, mailsize,
+						 tohdr);
 	if(retval) {
-		log_error(LOG_ARGS, "Could not write mailbody\n");
+			log_error(LOG_ARGS, "Could not write mail\n");
 		return retval;
 	}
+	}
 
 	retval = write_dot(sockfd);
 	if(retval) {
@@ -297,7 +332,9 @@
 int send_mail_many(int sockfd, const char *from, const char *replyto,
 		   char *mailmap, size_t mailsize, int subfd,
 		   const char *listaddr, const char *archivefilename,
-		   const char *listdir, const char *mlmmjbounce)
+		   const char *listdir, const char *mlmmjbounce,
+		   const char *hdrs, size_t hdrslen, const char *body,
+		   size_t bodylen)
 {
 	int sendres = 0, addrfd;
 	char *bounceaddr, *addr, *index, *dirname, *addrfilename;
@@ -330,12 +367,14 @@
 
 		if(from)
 			sendres = send_mail(sockfd, from, addr, replyto,
-					    mailmap, mailsize, listdir, NULL);
+					    mailmap, mailsize, listdir, NULL,
+					    hdrs, hdrslen, body, bodylen);
 		else {
 			bounceaddr = bounce_from_adr(addr, listaddr,
 						     archivefilename);
 			sendres = send_mail(sockfd, bounceaddr, addr, replyto,
-				  mailmap, mailsize, listdir, mlmmjbounce);
+				  mailmap, mailsize, listdir, mlmmjbounce,
+				  hdrs, hdrslen, body, bodylen);
 			myfree(bounceaddr);
 		}
 		if(sendres && listaddr && archivefilename) {
@@ -411,7 +450,7 @@
 
 int main(int argc, char **argv)
 {
-	size_t len = 0;
+	size_t len = 0, hdrslen, bodylen;
 	int sockfd = 0, mailfd = 0, opt, mindex, subfd, tmpfd;
 	int deletewhensent = 1, sendres, archive = 1;
 	char *listaddr, *mailfilename = NULL, *subfilename = NULL;
@@ -419,6 +458,8 @@
 	char *relayhost = NULL, *archivefilename = NULL, *tmpstr;
 	char *listctrl = NULL, *subddirname = NULL, *listdir = NULL;
 	char *mlmmjbounce = NULL, *bindir, *mailmap, *probefile, *a;
+	char *body = NULL, *hdrs = NULL, *memmailsizestr = NULL;
+	size_t memmailsize = 0;
 	DIR *subddir;
 	struct dirent *dp;
 	struct stat st;
@@ -519,12 +560,45 @@
 		exit(EXIT_FAILURE);
 	}
 
+	addtohdr = statctrl(listdir, "addtohdr");
+	memmailsizestr = ctrlvalue(listdir, "memorymailsize");
+	if(memmailsizestr) {
+		memmailsize = strtol(memmailsizestr, NULL, 10);
+		myfree(memmailsizestr);
+	}
+
+	if(memmailsize == 0)
+		memmailsize = MEMORYMAILSIZE;
+
+	if(st.st_size > memmailsize) {
+		prepmailinmem = 0;
+		errno = 0;
+		log_error(LOG_ARGS, "Not preparing in memory. "
+				    "Mail is %ld bytes", (long)st.st_size);
+	} else
+		prepmailinmem = 1;
+
 	mailmap = mmap(0, st.st_size, PROT_READ, MAP_SHARED, mailfd, 0);
 	if(mailmap == MAP_FAILED) {
 		log_error(LOG_ARGS, "Could not mmap mailfd");
 		exit(EXIT_FAILURE);
 	}
 
+	if(prepmailinmem) {
+		hdrs = get_preppedhdrs_from_map(mailmap, &hdrslen);
+		if(hdrs == NULL) {
+			log_error(LOG_ARGS, "Could not prepare headers");
+			exit(EXIT_FAILURE);
+		}
+		body = get_prepped_mailbody_from_map(mailmap, st.st_size,
+						     &bodylen);
+		if(body == NULL) {
+			log_error(LOG_ARGS, "Could not prepare mailbody");
+			myfree(hdrs);
+			exit(EXIT_FAILURE);
+		}
+	}
+
 	switch(listctrl[0]) {
 	case '1': /* A single mail is to be sent, do nothing */
 	case '5':
@@ -534,6 +608,8 @@
 		if((subfd = open(subfilename, O_RDONLY)) < 0) {
 			log_error(LOG_ARGS, "Could not open '%s':",
 					    subfilename);
+			myfree(hdrs);
+			myfree(body);
 			myfree(subfilename);
 			/* No moderators is no error. Could be the sysadmin
 			 * likes to do it manually.
@@ -546,6 +622,8 @@
 		if((subfd = open(subfilename, O_RDONLY)) < 0) {
 			log_error(LOG_ARGS, "Could not open '%s':",
 					    subfilename);
+			myfree(hdrs);
+			myfree(body);
 			exit(EXIT_FAILURE);
 		}
 
@@ -569,7 +647,8 @@
 	case '1': /* A single mail is to be sent */
 		initsmtp(&sockfd, relayhost);
 		sendres = send_mail(sockfd, bounceaddr, to_addr, replyto,
-				mailmap, st.st_size, listdir, NULL);
+				mailmap, st.st_size, listdir, NULL,
+				hdrs, hdrslen, body, bodylen);
 		endsmtp(&sockfd);
 		if(sendres) {
 			/* error, so keep it in the queue */
@@ -610,8 +689,9 @@
 		break;
 	case '2': /* Moderators */
 		initsmtp(&sockfd, relayhost);
-		if(send_mail_many(sockfd, bounceaddr, NULL, mailmap, st.st_size,
-				subfd, NULL, NULL, listdir, NULL))
+		if(send_mail_many(sockfd, bounceaddr, NULL, mailmap,
+				  st.st_size, subfd, NULL, NULL, listdir,
+				  NULL, hdrs, hdrslen, body, bodylen))
 			close(sockfd);
 		else
 			endsmtp(&sockfd);
@@ -620,7 +700,7 @@
 		initsmtp(&sockfd, relayhost);
 		if(send_mail_many(sockfd, NULL, NULL, mailmap, st.st_size,
 				subfd, listaddr, mailfilename, listdir,
-				mlmmjbounce))
+				mlmmjbounce, hdrs, hdrslen, body, bodylen))
 			close(sockfd);
 		else
 			endsmtp(&sockfd);
@@ -630,7 +710,7 @@
 		initsmtp(&sockfd, relayhost);
 		if(send_mail_many(sockfd, bounceaddr, NULL, mailmap, st.st_size,
 				subfd, listaddr, mailfilename, listdir,
-				mlmmjbounce))
+				mlmmjbounce, hdrs, hdrslen, body, bodylen))
 			close(sockfd);
 		else
 			endsmtp(&sockfd);
@@ -638,7 +718,8 @@
 	case '5': /* bounceprobe - handle relayhost local users bouncing*/
 		initsmtp(&sockfd, relayhost);
 		sendres = send_mail(sockfd, bounceaddr, to_addr, replyto,
-				mailmap, st.st_size, listdir, NULL);
+				mailmap, st.st_size, listdir, NULL,
+				hdrs, hdrslen, body, bodylen);
 		endsmtp(&sockfd);
 		if(sendres) {
 			/* error, so remove the probefile */
@@ -658,6 +739,8 @@
 			log_error(LOG_ARGS, "Could not opendir(%s)",
 					    subddirname);
 			myfree(subddirname);
+			myfree(hdrs);
+			myfree(body);
 			exit(EXIT_FAILURE);
 		}
 		myfree(subddirname);
@@ -680,7 +763,8 @@
 			initsmtp(&sockfd, relayhost);
 			sendres = send_mail_many(sockfd, NULL, NULL, mailmap,
 					st.st_size, subfd, listaddr,
-					archivefilename, listdir, mlmmjbounce);
+					archivefilename, listdir, mlmmjbounce,
+					hdrs, hdrslen, body, bodylen);
 			if (sendres) {
 				/* If send_mail_many() failed we close the
 				 * connection to the mail server in a brutal
@@ -696,6 +780,8 @@
 		break;
 	}
 	
+	myfree(hdrs);
+	myfree(body);
 	munmap(mailmap, st.st_size);
 	close(mailfd);