changeset 77:66d950e9a550

mlmmj-send now forks multiple connections per subscriber.d/file
author mmj
date Wed, 12 May 2004 09:08:04 +1000
parents 0c12d643f41d
children b6e5ee6e26e8
files include/mlmmj-send.h include/mlmmj.h src/init_sockfd.c src/mlmmj-send.c
diffstat 4 files changed, 203 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/include/mlmmj-send.h	Wed May 12 06:24:56 2004 +1000
+++ b/include/mlmmj-send.h	Wed May 12 09:08:04 2004 +1000
@@ -9,4 +9,12 @@
 #ifndef MMJML_SEND_H
 #define MMJML_SEND_H
 
+int send_mail(int sockfd, const char *from, const char *to,
+	      const char *replyto, FILE *mailfile);
+int send_mail_many(int sockfd, const char *from, const char *replyto,
+		   FILE *mailfile, FILE *subfile, const char *listaddr,
+		   const char *archivefilename);
+int initsmtp(int *sockfd, const char *relayhost);
+int endsmtp(int *sockfd);
+
 #endif /* MMJML_SEND_H */
--- a/include/mlmmj.h	Wed May 12 06:24:56 2004 +1000
+++ b/include/mlmmj.h	Wed May 12 09:08:04 2004 +1000
@@ -14,6 +14,7 @@
 #define RELAYHOST "127.0.0.1"
 #define READ_BUFSIZE 2048
 #define RECIPDELIM '+'
+#define MAX_CONNECTIONS 10 /* How many max connections to relayhost */
 
 struct mailhdr {
 	const char *token;
--- a/src/init_sockfd.c	Wed May 12 06:24:56 2004 +1000
+++ b/src/init_sockfd.c	Wed May 12 09:08:04 2004 +1000
@@ -34,4 +34,3 @@
 		exit(EXIT_FAILURE);
 	}
 }
-
--- a/src/mlmmj-send.c	Wed May 12 06:24:56 2004 +1000
+++ b/src/mlmmj-send.c	Wed May 12 09:08:04 2004 +1000
@@ -14,6 +14,10 @@
 #include <strings.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/wait.h>
+#include <signal.h>
 
 #include "mlmmj-send.h"
 #include "mlmmj.h"
@@ -26,7 +30,9 @@
 #include "init_sockfd.h"
 #include "strgen.h"
 #include "log_error.h"
+#include "mygetline.h"
 
+static int conncount = 0;  /* Connection count */
 
 static void print_help(const char *prg)
 {
@@ -34,58 +40,70 @@
 	exit(EXIT_SUCCESS);
 }
 
-static char *bounce_from_adr(char *recipient, char *listadr, char *mailfilename)
+char *bounce_from_adr(const char *recipient, const char *listadr,
+		      const char *mailfilename)
 {
-	char *bounce_adr;
-	char *indexstr, *listdomain, *a;
+	char *bounceaddr, *myrecipient, *mylistadr;
+	char *indexstr, *listdomain, *a, *mymailfilename;
 	size_t len;
 
-	indexstr = strrchr(mailfilename, '/');
+	mymailfilename = strdup(mailfilename);
+	if (!mymailfilename) {
+		return NULL;
+	}
+
+	indexstr = strrchr(mymailfilename, '/');
 	if (indexstr) {
 		indexstr++;  /* skip the slash */
 	} else {
-		indexstr = mailfilename;
+		indexstr = mymailfilename;
 	}
 
-	recipient = strdup(recipient);
-	if (!recipient) {
+	myrecipient = strdup(recipient);
+	if (!myrecipient) {
+		free(mymailfilename);
 		return NULL;
 	}
-	a = strchr(recipient, '@');
+	a = strchr(myrecipient, '@');
 	if (a) *a = '=';
 
-	listadr = strdup(listadr);
-	if (!listadr) {
-		free(recipient);
+	mylistadr = strdup(listadr);
+	if (!mylistadr) {
+		free(mymailfilename);
+		free(myrecipient);
 		return NULL;
 	}
 
-	listdomain = strchr(listadr, '@');
+	listdomain = strchr(mylistadr, '@');
 	if (!listdomain) {
-		free(recipient);
-		free(listadr);
+		free(mymailfilename);
+		free(myrecipient);
+		free(mylistadr);
+		return NULL;
 	}
 	*listdomain++ = '\0';
 
 	/* 12 = RECIPDELIM + "bounces-" + "-" + "@" + NUL */
-	len = strlen(listadr) + strlen(recipient) + strlen(indexstr)
+	len = strlen(mylistadr) + strlen(myrecipient) + strlen(indexstr)
 		 + strlen(listdomain) + 12;
-	bounce_adr = malloc(len);
-	if (!bounce_adr) {
-		free(recipient);
-		free(listadr);
+	bounceaddr = malloc(len);
+	if (!bounceaddr) {
+		free(myrecipient);
+		free(mylistadr);
 		return NULL;
 	}
-	snprintf(bounce_adr, len, "%s%cbounces-%s-%s@%s", listadr, RECIPDELIM,
-		 recipient, indexstr, listdomain);
+	snprintf(bounceaddr, len, "%s%cbounces-%s-%s@%s", mylistadr, RECIPDELIM,
+		 myrecipient, indexstr, listdomain);
 
-	free(recipient);
-	free(listadr);
-	return bounce_adr;
+	free(myrecipient);
+	free(mylistadr);
+	free(mymailfilename);
+
+	return bounceaddr;
 }
 
-int send_mail(int sockfd, const char *from, const char *to, const char *replyto,
-		FILE *mailfile)
+int send_mail(int sockfd, const char *from, const char *to,
+	      const char *replyto, FILE *mailfile)
 {
 	int retval;
 
@@ -120,7 +138,7 @@
 		/* FIXME: Queue etc.*/
 		return retval;
 	}
-	if((checkwait_smtpreply(sockfd, MLMMJ_DATA)) != 0) {
+	if((retval = checkwait_smtpreply(sockfd, MLMMJ_DATA)) != 0) {
 		log_error(LOG_ARGS, "Mailserver not ready for DATA\n");
 		write_rset(sockfd);
 		/* FIXME: Queue etc.*/
@@ -147,8 +165,8 @@
 		return retval;
 	}
 
-	if((checkwait_smtpreply(sockfd, MLMMJ_DOT)) != 0) {
-		log_error(LOG_ARGS, "Mailserver did not acknowledge end of mail\n"
+	if((retval = checkwait_smtpreply(sockfd, MLMMJ_DOT)) != 0) {
+		log_error(LOG_ARGS, "Mailserver did not ack end of mail.\n"
 				"<CR><LF>.<CR><LF> was written, to no"
 				"avail\n");
 		write_rset(sockfd);
@@ -159,17 +177,87 @@
 	return 0;
 }
 
+int initsmtp(int *sockfd, const char *relayhost)
+{
+	int retval = 0;
+	
+	init_sockfd(sockfd, relayhost);
+	
+	if((retval = checkwait_smtpreply(*sockfd, MLMMJ_CONNECT)) != 0) {
+		log_error(LOG_ARGS, "No proper greeting to our connect\n"
+			  "We continue and hope for the best\n");
+		/* FIXME: Queue etc. */
+	}	
+	write_helo(*sockfd, relayhost);
+	if((checkwait_smtpreply(*sockfd, MLMMJ_HELO)) != 0) {
+		log_error(LOG_ARGS, "Error with HELO\n"
+			  "We continue and hope for the best\n");
+		/* FIXME: quit and tell admin to configure correctly */
+	}
+
+	return retval;
+}
+
+int endsmtp(int *sockfd)
+{
+	int retval = 0;
+	
+	write_quit(*sockfd);
+
+	if((retval = checkwait_smtpreply(*sockfd, MLMMJ_QUIT)) != 0) {
+		log_error(LOG_ARGS, "Mailserver would not let us QUIT\n"
+			  "We close the socket anyway though\n");
+	}
+
+	close(*sockfd);
+
+	return retval;
+}
+
+int send_mail_many(int sockfd, const char *from, const char *replyto,
+		   FILE *mailfile, FILE *subfile, const char *listaddr,
+		   const char *archivefilename)
+{
+	char *bounceaddr, *addr;
+
+	while((addr = myfgetline(subfile))) {
+		chomp(addr);
+		if(from)
+			send_mail(sockfd, from, addr, replyto, mailfile);
+		else {
+			bounceaddr = bounce_from_adr(addr, listaddr,
+						     archivefilename);
+			send_mail(sockfd, bounceaddr, addr, replyto, mailfile);
+			free(bounceaddr);
+		}
+		free(addr);
+	}
+	return 0;
+}	
+
+void sig_child(int sig)
+{
+	pid_t pid;
+	int stat;
+
+	while((pid = waitpid(-1, &stat, WNOHANG) > 0))
+		conncount--;
+}
+
 int main(int argc, char **argv)
 {
 	size_t len = 0;
-	int sockfd = 0, opt, mindex, retval = 0;
+	int sockfd = 0, opt, mindex;
 	FILE *subfile = NULL, *mailfile = NULL;
-	char *listadr, buf[READ_BUFSIZE];
-	char *mailfilename = NULL, *subfilename = NULL, *listdir = NULL;
-	char *replyto = NULL, *bounce_adr = NULL, *to_addr = NULL;
-	char *bufres, *relayhost = NULL, *archivefilename = NULL;
-	char *listctrl = NULL;
-	int deletewhensent = 1;
+	char *listaddr, *mailfilename = NULL, *subfilename = NULL;
+	char *replyto = NULL, *bounceaddr = NULL, *to_addr = NULL;
+	char *relayhost = NULL, *archivefilename = NULL;
+	char *listctrl = NULL, *subddirname = NULL, *listdir = NULL;
+	int deletewhensent = 1, *newsockfd;
+	DIR *subddir;
+	struct dirent *dp;
+	pid_t childpid;
+	struct sigaction sigact;
 	
 	log_set_name(argv[0]);
 
@@ -179,7 +267,7 @@
 			deletewhensent = 0;
 			break;
 		case 'F':
-			bounce_adr = optarg;
+			bounceaddr = optarg;
 			break;
 		case 'h':
 			print_help(argv[0]);
@@ -222,18 +310,18 @@
 
 	
 	/* get the list address */
-	if(listctrl[0] == '1' && (bounce_adr == NULL || to_addr == NULL)) {
+	if(listctrl[0] == '1' && (bounceaddr == NULL || to_addr == NULL)) {
 		fprintf(stderr, "With -l 1 you need -F and -T\n");
 		exit(EXIT_FAILURE);
 	}
 
-	if((listctrl[0] == '2' && listdir == NULL)) {
-		fprintf(stderr, "With -l 2 you need -L\n");
+	if((listctrl[0] == '2' && (listdir == NULL || bounceaddr == NULL))) {
+		fprintf(stderr, "With -l 2 you need -L and -F\n");
 		exit(EXIT_FAILURE);
 	}
 
 	if(listctrl[0] != '1' && listctrl[0] != '2')
-		listadr = getlistaddr(listdir);
+		listaddr = getlistaddr(listdir);
 	
 	/* initialize file with mail to send */
 
@@ -242,11 +330,6 @@
 		exit(EXIT_FAILURE);
 	}
 
-	if(relayhost)
-		init_sockfd(&sockfd, relayhost);
-	else
-		init_sockfd(&sockfd, RELAYHOST);
-
 	switch(listctrl[0]) {
 	case '1': /* A single mail is to be sent, do nothing */
 		break;
@@ -262,14 +345,7 @@
 			exit(EXIT_SUCCESS);
 		}
 		break;
-	default: /* normal list mail */
-		subfilename = concatstr(2, listdir, "/subscribers");
-		if((subfile = fopen(subfilename, "r")) == NULL) {
-			log_error(LOG_ARGS, "Could not open '%s':",
-					    subfilename);
-			free(subfilename);
-			exit(EXIT_FAILURE);
-		}
+	default: /* normal list mail -- now handled when forking */
 		break;
 	}
 
@@ -282,44 +358,78 @@
 			 mindex);
 	}
 
-	if((retval = checkwait_smtpreply(sockfd, MLMMJ_CONNECT)) != 0) {
-		log_error(LOG_ARGS, "No proper greeting to our connect\n"
-			  "We continue and hope for the best\n");
-		/* FIXME: Queue etc. */
-	}	
-	write_helo(sockfd, "localhost");
-	if((checkwait_smtpreply(sockfd, MLMMJ_HELO)) != 0) {
-		log_error(LOG_ARGS, "Error with HELO\n"
-			  "We continue and hope for the best\n");
-		/* FIXME: quit and tell admin to configure correctly */
-	}
+	if(!relayhost)
+		relayhost = strdup(RELAYHOST);
 
-	/* FIXME: use myfgetline instead! */
 	switch(listctrl[0]) {
 	case '1': /* A single mail is to be sent */
-		send_mail(sockfd, bounce_adr, to_addr, replyto, mailfile);
+		initsmtp(&sockfd, relayhost);
+		send_mail(sockfd, bounceaddr, to_addr, replyto, mailfile);
+		endsmtp(&sockfd);
 		break;
 	case '2': /* Moderators */
-		while((bufres = fgets(buf, READ_BUFSIZE, subfile))) {
-			chomp(buf);
-			send_mail(sockfd, bounce_adr, buf, 0, mailfile);
-		}
+		initsmtp(&sockfd, relayhost);
+		send_mail_many(sockfd, bounceaddr, NULL, mailfile, subfile,
+			       NULL, NULL);
+		endsmtp(&sockfd);
 		break;
 	default: /* normal list mail */
-		while((bufres = fgets(buf, READ_BUFSIZE, subfile))) {
-			chomp(buf);
-			bounce_adr = bounce_from_adr(buf, listadr,
-					archivefilename);
-			send_mail(sockfd, bounce_adr, buf, 0, mailfile);
-			free(bounce_adr);
+		subddirname = concatstr(2, listdir, "/subscribers.d/");
+		if((subddir = opendir(subddirname)) == NULL) {
+			log_error(LOG_ARGS, "Could not opendir(%s)",
+					    subddirname);
+			free(subddirname);
+		}
+		free(subddirname);
+
+		sigact.sa_handler = sig_child;
+		sigemptyset(&sigact.sa_mask);
+		sigact.sa_flags = SA_NOCLDSTOP;
+		sigaction(SIGCHLD, &sigact, 0);
+
+		while((dp = readdir(subddir)) != NULL) {
+			if(!strcmp(dp->d_name, "."))
+				continue;
+			if(!strcmp(dp->d_name, ".."))
+				continue;
+			subfilename = concatstr(3, listdir, "/subscribers.d/",
+						dp->d_name);
+			if((subfile = fopen(subfilename, "r")) == NULL) {
+				log_error(LOG_ARGS, "Could not open '%s'",
+						    subfilename);
+				free(subfilename);
+				continue;
 		}
-		break;
-	}
+			fprintf(stderr, "found subfile '%s'\n", subfilename);
+			free(subfilename);
+
+			while((conncount > MAX_CONNECTIONS))
+				usleep(100);
+
+			childpid = fork();
+			if(childpid < 0)
+				log_error(LOG_ARGS, "Could not fork.");
+				/* TODO: we have to keep track of unsent
+				 * files */
+
+			conncount++;
 
-	write_quit(sockfd);
-	if((checkwait_smtpreply(sockfd, MLMMJ_QUIT)) != 0) {
-		log_error(LOG_ARGS, "Mailserver would not let us QUIT\n"
-			  "We close the socket anyway though\n");
+			if(childpid == 0) {
+				newsockfd = malloc(sizeof(int));
+				initsmtp(newsockfd, relayhost);
+				send_mail_many(*newsockfd, NULL, NULL,
+					       mailfile, subfile, listaddr,
+					       archivefilename);
+				endsmtp(newsockfd);
+				free(newsockfd);
+				exit(EXIT_SUCCESS);
+			} else {
+				log_error(LOG_ARGS, "%d/%d connections open",
+						conncount, MAX_CONNECTIONS);
+			}
+		}
+		closedir(subddir);
+		break;
 	}
 
 	if(listctrl[0] != '1' && listctrl[0] != '2') {
@@ -328,11 +438,9 @@
 
 		fclose(subfile);
 		free(archivefilename);
-		free(subfilename);
 	} else if(deletewhensent)
 		unlink(mailfilename);
 
-	close(sockfd);
 	fclose(mailfile);
 	return EXIT_SUCCESS;
 }