From: mmj Date: Tue, 11 May 2004 23:08:04 +0000 (+1000) Subject: mlmmj-send now forks multiple connections per subscriber.d/file X-Git-Tag: RELEASE_1_0_0~252 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=de97c042b3972579ec787326e4898375ec826f68;p=thirdparty%2Fmlmmj.git mlmmj-send now forks multiple connections per subscriber.d/file --- diff --git a/include/mlmmj-send.h b/include/mlmmj-send.h index a023d67e..9dab4226 100644 --- a/include/mlmmj-send.h +++ b/include/mlmmj-send.h @@ -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 */ diff --git a/include/mlmmj.h b/include/mlmmj.h index a063f7a4..4816a426 100644 --- a/include/mlmmj.h +++ b/include/mlmmj.h @@ -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; diff --git a/src/init_sockfd.c b/src/init_sockfd.c index 9d03d256..67edc1a7 100644 --- a/src/init_sockfd.c +++ b/src/init_sockfd.c @@ -34,4 +34,3 @@ void init_sockfd(int *sockfd, const char *relayhost) exit(EXIT_FAILURE); } } - diff --git a/src/mlmmj-send.c b/src/mlmmj-send.c index c7eedc4b..6b079ed0 100644 --- a/src/mlmmj-send.c +++ b/src/mlmmj-send.c @@ -14,6 +14,10 @@ #include #include #include +#include +#include +#include +#include #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 @@ static void print_help(const char *prg) 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 @@ int send_mail(int sockfd, const char *from, const char *to, const char *replyto, /* 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 @@ int send_mail(int sockfd, const char *from, const char *to, const char *replyto, 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" ". was written, to no" "avail\n"); write_rset(sockfd); @@ -159,17 +177,87 @@ int send_mail(int sockfd, const char *from, const char *to, const char *replyto, 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 @@ int main(int argc, char **argv) deletewhensent = 0; break; case 'F': - bounce_adr = optarg; + bounceaddr = optarg; break; case 'h': print_help(argv[0]); @@ -222,18 +310,18 @@ int main(int argc, char **argv) /* 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 @@ int main(int argc, char **argv) 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 @@ int main(int argc, char **argv) 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,57 +358,89 @@ int main(int argc, char **argv) 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); } - break; - } + 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; + } + fprintf(stderr, "found subfile '%s'\n", subfilename); + free(subfilename); - 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"); + 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++; + + 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') { /* The mail now goes to the archive */ rename(mailfilename, archivefilename); fclose(subfile); free(archivefilename); - free(subfilename); } else if(deletewhensent) unlink(mailfilename); - close(sockfd); fclose(mailfile); return EXIT_SUCCESS; }