]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
mlmmj-send now forks multiple connections per subscriber.d/file
authormmj <none@none>
Tue, 11 May 2004 23:08:04 +0000 (09:08 +1000)
committermmj <none@none>
Tue, 11 May 2004 23:08:04 +0000 (09:08 +1000)
include/mlmmj-send.h
include/mlmmj.h
src/init_sockfd.c
src/mlmmj-send.c

index a023d67e8fe5a6ea666b9dae01bced80a27d580c..9dab4226988d98a8a87e7cbf0346843b49463382 100644 (file)
@@ -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 */
index a063f7a4ef29592b3c4cc6df4815b5fdc09d4e93..4816a426c194c1ad36c7b0ab160b38e66da55ba1 100644 (file)
@@ -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;
index 9d03d256c579863e742f10b6856c1fbe9297fddb..67edc1a7b8523a98cd39d4d5ea11c5bba06d5aa5 100644 (file)
@@ -34,4 +34,3 @@ void init_sockfd(int *sockfd, const char *relayhost)
                exit(EXIT_FAILURE);
        }
 }
-
index c7eedc4b966debe079b9cea9154de1f6c9c6e206..6b079ed04c826abe8bbc6e443e1a4979a98824cf 100644 (file)
 #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 @@ 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"
                                "<CR><LF>.<CR><LF> 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;
 }