Mercurial > hg > mlmmj
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; }