]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
VERP support
authormmj <none@none>
Sun, 16 Jan 2005 18:43:48 +0000 (05:43 +1100)
committermmj <none@none>
Sun, 16 Jan 2005 18:43:48 +0000 (05:43 +1100)
ChangeLog
TUNABLES
VERSION
include/getaddrsfromfd.h [new file with mode: 0644]
include/mail-functions.h
include/mlmmj-send.h
src/Makefile.am
src/checkwait_smtpreply.c
src/getaddrsfromfd.c [new file with mode: 0644]
src/mail-functions.c
src/mlmmj-send.c

index d4b47a3212cd05050e9136bae6270cacd9fee993..828410fa9f4eb2912567b018a9f01b70f13954a6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,5 @@
+1.2.0-RC1
+ o Add VERP support. http://www.postfix.org/VERP_README.html for Postfix howto
 1.1.1-RC2
  o It's ok to log to a symbolic link to somewhere else
  o Add Message-Id: and Date: headers to mail from mlmmj
index 2a9614817adb53401fd2c3acf5565c34c753cb53..4f070fc4e1f623b1ae9806b791c01cb7d9898c82 100644 (file)
--- a/TUNABLES
+++ b/TUNABLES
@@ -109,3 +109,13 @@ to specify several entries (one pr. line), it's marked "list".
    If this file exists, no mail confirmation is needed to subscribe to the
    list. This should in principle never ever be used, but there is times
    on local lists etc. where this is useful. HANDLE WITH CARE!
+
+ · verp                                (normal)
+
+   Enable VERP support. Anything added in this variable will be appended the
+   MAIL FROM: line. If "postfix" is put in the file, it'll make postfix use
+   VERP by adding XVERP=-= to the MAIL FROM: line.
+
+ · maxverprecips               (normal)
+
+   How many recipients pr. mail delivered to the smtp server. Defaults to 100.
diff --git a/VERSION b/VERSION
index 08f525b97e0b61d15ded80249048f91104e33b84..5ff7bb87efbdf626a159815a82ae2c95486ba1b2 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.1-RC2
+1.2.0-RC1
diff --git a/include/getaddrsfromfd.h b/include/getaddrsfromfd.h
new file mode 100644 (file)
index 0000000..dedcb93
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2005 Mads Martin Joergensen <mmj at mmj.dk>
+ *
+ * $Id$
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef GETADDRSFROMFD_H
+#define GETADDRSFROMFD_H
+
+#include <sys/types.h>
+#include "mlmmj.h"
+
+off_t getaddrsfromfd(struct strlist *slist, int fd, int max);
+
+#endif /* GETADDRSFROMFD_H */
index 4c9a7150280a6d46db2e083d6410cf000b5ae441..488a80c77d64d1665a2f9d5bdaa00afb5621f21b 100644 (file)
@@ -29,7 +29,7 @@
 #include <stdio.h>
 
 int write_helo(int sockfd, const char *hostname);
-int write_mail_from(int sockfd, const char *from_addr);
+int write_mail_from(int sockfd, const char *from_addr, const char *extra);
 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,
index ecddb1f3d1f3341afd0ac7d42330a988b347b279..06d53188126f176f5ba7169409a11168a047f4ae 100644 (file)
@@ -29,12 +29,22 @@ int send_mail(int sockfd, const char *from, const char *to,
              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,
+int send_mail_many_fd(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 *hdrs, size_t hdrslen, const char *body,
                   size_t bodylen);
+int send_mail_many_list(int sockfd, const char *from, const char *replyto,
+                  char *mailmap, size_t mailsize, struct strlist *addrs,
+                  const char *listaddr, const char *archivefilename,
+                  const char *listdir, const char *mlmmjbounce,
+                  const char *hdrs, size_t hdrslen, const char *body,
+                  size_t bodylen);
+int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
+                  size_t mailsize, const char *from, const char *listdir,
+                  const char *hdrs, size_t hdrslen, const char *body,
+                  size_t bodylen, const char *extra);
 int initsmtp(int *sockfd, const char *relayhost);
 int endsmtp(int *sockfd);
 
index 08e13ff95c8a0977024ec4df129ce078ccccc1cd..92b49a0abb8c1f5535a55bb49837e35a3e85b978 100644 (file)
@@ -16,7 +16,7 @@ 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 \
-                    statctrl.c ctrlvalue.c
+                    statctrl.c ctrlvalue.c getaddrsfromfd.c
 
 mlmmj_recieve_SOURCES = mlmmj-recieve.c writen.c random-int.c strgen.c \
                        print-version.c log_error.c dumpfd2fd.c memory.c \
index 2a5222bebae2387ab3df370cbfab3efde19f9985..74e776ce22773364fc6a8e5782a51b69f79b43d5 100644 (file)
@@ -92,11 +92,11 @@ char *checkwait_smtpreply(int sockfd, int replytype)
                break;
        case MLMMJ_QUIT:
                if(smtpreply[0] != '2' || smtpreply[1] != '2')
-                       return (char *)0xDEADBEEF;
+                       return mystrdup(smtpreply);
                break;
        case MLMMJ_RSET:
                if(smtpreply[0] != '2' || smtpreply[1] != '5')
-                       return (char *)0xDEADBEEF;
+                       return mystrdup(smtpreply);
                break;
        default:
                break;
diff --git a/src/getaddrsfromfd.c b/src/getaddrsfromfd.c
new file mode 100644 (file)
index 0000000..4af4961
--- /dev/null
@@ -0,0 +1,54 @@
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "mlmmj.h"
+#include "log_error.h"
+#include "memory.h"
+#include "strgen.h"
+#include "getaddrsfromfd.h"
+
+off_t getaddrsfromfd(struct strlist *slist, int fd, int max)
+{
+       off_t offset = lseek(fd, 0, SEEK_CUR);
+       char *start, *cur, *next;
+       struct stat st;
+       size_t len;
+
+       if(fstat(fd, &st) < 0) {
+               log_error(LOG_ARGS, "Could not fstat fd");
+               return -1;
+       }
+
+       start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+       if(start == MAP_FAILED) {
+               log_error(LOG_ARGS, "Could not mmap fd");
+               return -1;
+       }
+       
+       for(next = cur = (start + offset); next < start + st.st_size; next++) {
+               if(*next == '\n' || next == start + st.st_size - 1) {
+                       len = next - cur;
+                       if(next == start + st.st_size - 1 && *next != '\n')
+                               len++;
+                       slist->strs[slist->count] = mymalloc(len + 1);
+                       strncpy(slist->strs[slist->count], cur, len);
+                       slist->strs[slist->count][len] = '\0';
+                       slist->count++;
+                       cur = next + 1;
+               } else {
+                       continue;
+               }
+               if(slist->count >= max) {
+                       offset = (off_t)(cur - start);
+                       goto donegetting;
+               }
+       }
+       offset = st.st_size;
+donegetting:                   
+       munmap(start, st.st_size);
+       lseek(fd, offset, SEEK_SET);
+       return st.st_size - offset;
+}
index d181f223fc7384727b070bbb0a846ad41e398611..23009e56455c01f26851f1250789a29bf2dae44f 100644 (file)
@@ -63,19 +63,26 @@ int write_helo(int sockfd, const char *hostname)
 }
 /* "MAIL FROM: <>\r\n" has length 15 */
 #define EXTRA_FROM_LEN 16
-int write_mail_from(int sockfd, const char *from_addr)
+int write_mail_from(int sockfd, const char *from_addr, const char *extra)
 {
-       size_t len = (size_t)(strlen(from_addr) + EXTRA_FROM_LEN);
+       size_t len = (size_t)(strlen(from_addr) + EXTRA_FROM_LEN +
+                       strlen(extra) + 2);
        char *mail_from;
        size_t bytes_written;
 
-       if((mail_from = mymalloc(len)) == NULL)
-               return errno;
-       snprintf(mail_from, len, "MAIL FROM: <%s>\r\n", from_addr);
+       mail_from = mymalloc(len);
+
+       if(extra && extra[0] == ' ')
+               snprintf(mail_from, len, "MAIL FROM: <%s>%s\r\n", from_addr,
+                               extra);
+       else
+               snprintf(mail_from, len, "MAIL FROM: <%s> %s\r\n", from_addr,
+                               extra);
+
        len = strlen(mail_from);
 
 #if 0
-       fprintf(stderr, "\nwrite_mail_from, mail_from = [%s]\n", mail_from);
+       fprintf(stderr, "%s", mail_from);
 #endif
        bytes_written = writen(sockfd, mail_from, len);
        if(bytes_written < 0) {
@@ -101,9 +108,8 @@ int write_rcpt_to(int sockfd, const char *rcpt_addr)
 
        snprintf(rcpt_to, len, "RCPT TO: <%s>\r\n", rcpt_addr);
        len = strlen(rcpt_to);
-
 #if 0
-       fprintf(stderr, "\nwrite_rcpt_to, rcpt_to = [%s]\n", rcpt_to);
+       log_error(LOG_ARGS, "%s", rcpt_to);
 #endif
        bytes_written = writen(sockfd, rcpt_to, len);
        if(bytes_written < 0) {
@@ -289,7 +295,7 @@ int write_replyto(int sockfd, const char *replyaddr)
        snprintf(replyto, len, "Reply-To: %s\r\n", replyaddr);
        len = strlen(replyto);
 
-#ifdef MLMMJ_DEBUG
+#if 0
        fprintf(stderr, "\nwrite_replyto, replyto = [%s]\n", replyto);
 #endif
        bytes_written = writen(sockfd, replyto, len);
index acfe3932c8adf15eb8f0df103f48a25281a4b804..b3deb0b9691a464ea681d91d0cd2f7ddf4979a28 100644 (file)
@@ -42,8 +42,8 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#include "mlmmj-send.h"
 #include "mlmmj.h"
+#include "mlmmj-send.h"
 #include "mail-functions.h"
 #include "itoa.h"
 #include "incindexfile.h"
 #include "statctrl.h"
 #include "ctrlvalue.h"
 #include "mylocking.h"
+#include "getaddrsfromfd.h"
 
 static int addtohdr = 0;
 static int prepmailinmem = 0;
+static int maxverprecips = MAXVERPRECIPS;
 
 char *bounce_from_adr(const char *recipient, const char *listadr,
                      const char *mailfilename)
@@ -159,8 +161,8 @@ int bouncemail(const char *listdir, const char *mlmmjbounce, const char *from)
        
        execlp(mlmmjbounce, mlmmjbounce,
                        "-L", listdir,
-                       "-a", addr,
-                       "-n", num, NULL);
+                       "-a", num,
+                       "-n", addr, NULL);
 
        log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjbounce);
 
@@ -176,7 +178,7 @@ int send_mail(int sockfd, const char *from, const char *to,
        int retval = 0;
        char *reply, *tohdr;
        
-       retval = write_mail_from(sockfd, from);
+       retval = write_mail_from(sockfd, from, "");
        if(retval) {
                log_error(LOG_ARGS, "Could not write MAIL FROM\n");
                return retval;
@@ -318,13 +320,15 @@ int initsmtp(int *sockfd, const char *relayhost)
 int endsmtp(int *sockfd)
 {
        int retval = 0;
-       char *reply;
+       char *reply = NULL;
        
        write_quit(*sockfd);
-
-       if((reply = checkwait_smtpreply(*sockfd, MLMMJ_QUIT)) != 0) {
+       reply = checkwait_smtpreply(*sockfd, MLMMJ_QUIT);
+       if(reply) {
+               printf("reply from quit: %s\n", reply);
                log_error(LOG_ARGS, "Mailserver would not let us QUIT. "
-                         "We close the socket anyway though.");
+                         "We close the socket anyway though. "
+                         "Mailserver reply = [%s]", reply);
                myfree(reply);
                retval = MLMMJ_QUIT;
        }
@@ -334,109 +338,218 @@ int endsmtp(int *sockfd)
        return retval;
 }
 
-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,
+int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
+                  size_t mailsize, const char *from, const char *listdir,
                   const char *hdrs, size_t hdrslen, const char *body,
-                  size_t bodylen)
+                  size_t bodylen, const char *verpextra)
 {
-       int sendres = 0, addrfd;
-       char *bounceaddr, *addr, *index, *dirname, *addrfilename;
-       char *start, *cur, *next;
-       struct stat st;
-       size_t len;
+       int retval, i;
+       char *reply;
 
-       if(fstat(subfd, &st) < 0) {
-               log_error(LOG_ARGS, "Could not stat subfd");
-               return -1;
+       retval = write_mail_from(sockfd, from, verpextra);
+       if(retval) {
+               log_error(LOG_ARGS, "Could not write MAIL FROM\n");
+               return retval;
+       }
+       reply = checkwait_smtpreply(sockfd, MLMMJ_FROM);
+       if(reply) {
+               log_error(LOG_ARGS, "Error in MAIL FROM. Reply = [%s]",
+                               reply);
+               myfree(reply);
+               write_rset(sockfd);
+               checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               return MLMMJ_FROM;
+       }
+       for(i = 0; i < addrs->count; i++) {
+               retval = write_rcpt_to(sockfd, addrs->strs[i]);
+               if(retval) {
+                       log_error(LOG_ARGS, "Could not write RCPT TO:\n");
+                       return retval;
+               }
+
+               reply = checkwait_smtpreply(sockfd, MLMMJ_RCPTTO);
+               if(reply) {
+                       log_error(LOG_ARGS, "Error in RCPT TO. Reply = [%s]",
+                                       reply);
+                       myfree(reply);
+                       return MLMMJ_RCPTTO;
+               }
        }
 
-       start = mmap(0, st.st_size, PROT_READ, MAP_SHARED, subfd, 0);
-       if(start == MAP_FAILED) {
-               log_error(LOG_ARGS, "Could not mmap subfd");
+       retval = write_data(sockfd);
+       if(retval) {
+               log_error(LOG_ARGS, "Could not write DATA\b");
+               return retval;
+       }
+
+       reply = checkwait_smtpreply(sockfd, MLMMJ_DATA);
+       if(reply) {
+               log_error(LOG_ARGS, "Error with DATA. Reply = [%s]", reply);
+               myfree(reply);
+               write_rset(sockfd);
+               checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               return MLMMJ_DATA;
+       }
+
+       if(prepmailinmem) {
+               retval = writen(sockfd, hdrs, hdrslen);
+               if(retval < 0) {
+                       log_error(LOG_ARGS, "Could not write mailheaders.\n");
+                       return retval;
+               }
+               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,
+                                                NULL);
+               if(retval) {
+                       log_error(LOG_ARGS, "Could not write mail\n");
+                       return retval;
+               }
+       }
+
+       retval = write_dot(sockfd);
+       if(retval) {
+               log_error(LOG_ARGS, "Could not write <CR><LF>.<CR><LF>\n");
+               return retval;
+       }
+
+       reply = checkwait_smtpreply(sockfd, MLMMJ_DOT);
+       if(reply) {
+               log_error(LOG_ARGS, "Mailserver did not ack end of mail.\n"
+                               "<CR><LF>.<CR><LF> was written, to no"
+                               "avail. Reply = [%s]", reply);
+               myfree(reply);
+               write_rset(sockfd);
+               checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               return MLMMJ_DOT;
+       }
+
+       return 0;
+}
+
+int send_mail_many_fd(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 *hdrs, size_t hdrslen, const char *body,
+                     size_t bodylen)
+{
+       int res, ret, i;
+       struct strlist stl;
+
+       do {
+               res = getaddrsfromfd(&stl, subfd, maxverprecips);
+               if(stl.count == maxverprecips) {
+                       ret = send_mail_many_list(sockfd, from, replyto,
+                                       mailmap, mailsize, &stl, listaddr,
+                                       archivefilename, listdir, mlmmjbounce,
+                                       hdrs, hdrslen, body, bodylen);
+                       for(i = 0; i < stl.count; i++)
+                               myfree(stl.strs[i]);
+                       if(ret < 0)
+                               return ret;
+                       stl.count = 0;
+               }
+       } while(res > 0);
+
+       if(stl.count) {
+               ret = send_mail_many_list(sockfd, from, replyto, mailmap,
+                               mailsize, &stl, listaddr, archivefilename,
+                               listdir, mlmmjbounce, hdrs, hdrslen, body,
+                               bodylen);
+               for(i = 0; i < stl.count; i++)
+                       myfree(stl.strs[i]);
+               stl.count = 0;
+               return ret;
+       }
+
+       return 0;
+}
+
+int requeuemail(const char *listdir, const char *index, struct strlist *addrs,
+               int addrcount)
+{
+       int addrfd, i;
+       char *dirname, *addrfilename, *addr;
+       
+       dirname = concatstr(3, listdir, "/requeue/", index);
+       if(mkdir(dirname, 0750) < 0 && errno != EEXIST) {
+               log_error(LOG_ARGS, "Could not mkdir(%s) for "
+                               "requeueing. Mail cannot "
+                               "be requeued.", dirname);
+               myfree(dirname);
                return -1;
        }
+       addrfilename = concatstr(2, dirname, "/subscribers");
+       myfree(dirname);
+       addrfd = open(addrfilename, O_WRONLY|O_CREAT|O_APPEND,
+                       S_IRUSR|S_IWUSR);
+       if(addrfd < 0) {
+               log_error(LOG_ARGS, "Could not open %s",
+                               addrfilename);
+               myfree(addrfilename);
+               return -1;
+       } else {
+               /* Dump the remaining addresses. We dump the remaining before
+                * we write the failing address to ensure the potential good
+                * ones will be tried first when mlmmj-maintd sends out mails
+                * that have been requeued. addrcount was so far we were */
+               for(i = addrcount + 1; i < addrs->count; i++) {
+                       addr = concatstr(2, addrs->strs[i], "\n");
+                       if(writen(addrfd, addr, strlen(addr)) < 0) {
+                               log_error(LOG_ARGS, "Could not add [%s] "
+                                                   "to requeue file", addr);
+                               return -1;
+                       }
+                       myfree(addr);
+               }
+               addr = concatstr(2, addrs->strs[addrcount], "\n");
+               if(writen(addrfd, addr, strlen(addr)) < 0) {
+                       log_error(LOG_ARGS, "Could not add [%s] to requeue "
+                                       "file", addr);
+                       return -1;
+               }
+               myfree(addr);
+       }
+       myfree(addrfilename);
+       close(addrfd);
 
-       for(next = cur = start; next < start + st.st_size; next++) {
-               if(*next == '\n' || next == start + st.st_size - 1) {
-                       len = next - cur;
-                       if(next == start + st.st_size - 1 && *next != '\n')
-                               len++;
-                       addr = mymalloc(len + 1);
-                       strncpy(addr, cur, len);
-                       addr[len] = '\0';
-                       cur = next + 1;
-               } else
-                       continue;
+       return 0;
+}
+
+int send_mail_many_list(int sockfd, const char *from, const char *replyto,
+                  char *mailmap, size_t mailsize, struct strlist *addrs,
+                  const char *listaddr, const char *archivefilename,
+                  const char *listdir, const char *mlmmjbounce,
+                  const char *hdrs, size_t hdrslen, const char *body,
+                  size_t bodylen)
+{
+       int res = 0, i;
+       char *bounceaddr, *addr, *index;
 
+       for(i = 0; i < addrs->count; i++) {
+               addr = addrs->strs[i];
                if(from) {
-                       sendres = send_mail(sockfd, from, addr, replyto,
+                       res = send_mail(sockfd, from, addr, replyto,
                                            mailmap, mailsize, listdir, NULL,
                                            hdrs, hdrslen, body, bodylen);
                } else {
                        bounceaddr = bounce_from_adr(addr, listaddr,
                                                     archivefilename);
-                       sendres = send_mail(sockfd, bounceaddr, addr, replyto,
+                       res = send_mail(sockfd, bounceaddr, addr, replyto,
                                  mailmap, mailsize, listdir, mlmmjbounce,
                                  hdrs, hdrslen, body, bodylen);
                        myfree(bounceaddr);
                }
-               if(sendres && listaddr && archivefilename) {
+               if(res && listaddr && archivefilename) {
                        /* we failed, so save the addresses and bail */
-                       index = mybasename(archivefilename);    
-                       dirname = concatstr(3, listdir, "/requeue/", index);
-                       myfree(index);
-                       if(mkdir(dirname, 0750) < 0 && errno != EEXIST) {
-                               log_error(LOG_ARGS, "Could not mkdir(%s) for "
-                                                   "requeueing. Mail cannot "
-                                                   "be requeued.", dirname);
-                               myfree(dirname);
-                               myfree(addr);
-                               return -1;
-                       }
-                       addrfilename = concatstr(2, dirname, "/subscribers");
-                       myfree(dirname);
-                       addrfd = open(addrfilename, O_WRONLY|O_CREAT|O_APPEND,
-                                                       S_IRUSR|S_IWUSR);
-                       if(addrfd < 0) {
-                               log_error(LOG_ARGS, "Could not open %s",
-                                                   addrfilename);
-                               myfree(addrfilename);
-                               myfree(addr);
-                               return -1;
-                       } else {
-                               /* Dump the remaining addresses. We dump the
-                                * remaining before we write the failing
-                                * address to ensure the potential good ones
-                                * will be tried first when mlmmj-maintd
-                                * sends out mails that have been requeued. */
-                               if(writen(addrfd, cur, start+st.st_size-cur)
-                                               < 0) {
-                                       log_error(LOG_ARGS, "Could not dump "
-                                                       "remaining addresses "
-                                                       "of subfile to "
-                                                       "requeue address "
-                                                       "file");
-                               }
-                               /* Dirty hack to add newline. */
-                               addr[len] = '\n';
-                               if(writen(addrfd, addr, len+1) < 0) {
-                                       addr[len] = '\0';
-                                       log_error(LOG_ARGS, "Could not add "
-                                                       "[%s] to requeue "
-                                                       "address file", addr);
-                               }
-                               
-                       }
-                       
-                       myfree(addr);
-                       myfree(addrfilename);
-                       close(addrfd);
-
-                       return -1;
+                       index = mybasename(archivefilename);
+                       return requeuemail(listdir, index, addrs, i);
                }
-               myfree(addr);
        }
        return 0;
 }      
@@ -471,22 +584,24 @@ static void print_help(const char *prg)
 int main(int argc, char **argv)
 {
        size_t len = 0, hdrslen, bodylen;
-       int sockfd = 0, mailfd = 0, opt, mindex, subfd = 0, tmpfd;
-       int deletewhensent = 1, sendres, archive = 1, digest = 0;
-       int ctrlarchive;
+       int sockfd = 0, mailfd = 0, opt, mindex = 0, subfd = 0, tmpfd, i;
+       int deletewhensent = 1, sendres = 0, archive = 1, digest = 0;
+       int ctrlarchive, res;
        char *listaddr = NULL, *mailfilename = NULL, *subfilename = NULL;
        char *replyto = NULL, *bounceaddr = NULL, *to_addr = NULL;
        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;
-       char relay[16];
+       char *body = NULL, *hdrs = NULL, *memmailsizestr = NULL, *verp = NULL;
+       char relay[16], *listname, *listfqdn, *verpfrom, *maxverprecipsstr;
+       char strindex[32], *reply;
        ssize_t memmailsize = 0;
        DIR *subddir;
        struct dirent *dp;
        struct stat st;
        struct hostent *relayent;
        uid_t uid;
+       struct strlist stl;
 
        CHECKFULLPATH(argv[0]);
        
@@ -582,6 +697,18 @@ int main(int argc, char **argv)
                exit(EXIT_FAILURE);
        }
 
+       maxverprecipsstr = ctrlvalue(listdir, "maxverprecips");
+       if(maxverprecipsstr) {
+               maxverprecips = atol(maxverprecipsstr);
+               log_error(LOG_ARGS, "maxverprecipsstr = [%s] maxverprecips = [%d]",
+                               maxverprecipsstr, maxverprecips);
+               myfree(maxverprecipsstr);
+       }
+       if(maxverprecips <= 0)
+               maxverprecips = MAXVERPRECIPS;
+
+       verp = ctrlvalue(listdir, "verp");
+       chomp(verp);
 
        switch(listctrl[0]) {
                case '1':
@@ -705,6 +832,8 @@ int main(int argc, char **argv)
                         mindex);
        }
 
+       itoa(mindex, strindex);
+
        if(!relayhost) {
                relayhost = ctrlvalue(listdir, "relayhost");
                chomp(relayhost);
@@ -770,16 +899,16 @@ int main(int argc, char **argv)
                break;
        case '2': /* Moderators */
                initsmtp(&sockfd, relay);
-               if(send_mail_many(sockfd, bounceaddr, NULL, mailmap,
-                                 st.st_size, subfd, NULL, NULL, listdir,
-                                 NULL, hdrs, hdrslen, body, bodylen))
+               if(send_mail_many_fd(sockfd, bounceaddr, NULL, mailmap,
+                                    st.st_size, subfd, NULL, NULL, listdir,
+                                    NULL, hdrs, hdrslen, body, bodylen))
                        close(sockfd);
                else
                        endsmtp(&sockfd);
                break;
        case '3': /* resending earlier failed mails */
                initsmtp(&sockfd, relay);
-               if(send_mail_many(sockfd, NULL, NULL, mailmap, st.st_size,
+               if(send_mail_many_fd(sockfd, NULL, NULL, mailmap, st.st_size,
                                subfd, listaddr, mailfilename, listdir,
                                mlmmjbounce, hdrs, hdrslen, body, bodylen))
                        close(sockfd);
@@ -789,9 +918,10 @@ int main(int argc, char **argv)
                break;
        case '4': /* send mails to owner */
                initsmtp(&sockfd, relay);
-               if(send_mail_many(sockfd, bounceaddr, NULL, mailmap, st.st_size,
-                               subfd, listaddr, mailfilename, listdir,
-                               mlmmjbounce, hdrs, hdrslen, body, bodylen))
+               if(send_mail_many_fd(sockfd, bounceaddr, NULL, mailmap,
+                               st.st_size, subfd, listaddr, mailfilename,
+                               listdir, mlmmjbounce, hdrs, hdrslen, body,
+                               bodylen))
                        close(sockfd);
                else
                        endsmtp(&sockfd);
@@ -834,6 +964,46 @@ int main(int argc, char **argv)
                        exit(EXIT_FAILURE);
                }
 
+               stl.strs = (char **)mymalloc(1 + maxverprecips * sizeof(char *));
+               stl.count = 0;
+               listname = genlistname(listaddr);       
+               listfqdn = genlistfqdn(listaddr);       
+               verpfrom = concatstr(5, listname, "+bounces-", strindex, "@",
+                               listfqdn);
+               myfree(listname);
+               myfree(listfqdn);
+
+               if(verp && (strcmp(verp, "postfix") == 0)) {
+                       myfree(verp);
+                       verp = mystrdup("XVERP=-=");
+               }
+
+               if(addtohdr && verp) {
+                       log_error(LOG_ARGS, "Cannot use VERP and add To: "
+                                       "header. Not sending with VERP.");
+                       verp = NULL;
+               }
+
+               if(verp) {
+                       initsmtp(&sockfd, relay);
+                       if(write_mail_from(sockfd, verpfrom, verp)) {
+                               log_error(LOG_ARGS,
+                                               "Could not write MAIL FROM\n");
+                               verp = NULL;
+                       } else {
+                               reply = checkwait_smtpreply(sockfd, MLMMJ_FROM);
+                               if(reply) {
+                                       log_error(LOG_ARGS,
+                                               "Mailserver did not "
+                                               "accept verp mail from. "
+                                               "Not sending with VERP.");
+                                       myfree(reply);
+                                       verp = NULL;
+                               }
+                       }
+                       endsmtp(&sockfd);
+               }
+
                while((dp = readdir(subddir)) != NULL) {
                        if(!strcmp(dp->d_name, "."))
                                continue;
@@ -846,13 +1016,76 @@ int main(int argc, char **argv)
                                myfree(subfilename);
                                continue;
                        }
+                       do {
+                               res = getaddrsfromfd(&stl, subfd,
+                                               maxverprecips);
+                               if(stl.count == maxverprecips) {
+                                       initsmtp(&sockfd, relay);
+                                       if(verp) {
+                                               sendres = send_mail_verp(
+                                                               sockfd, &stl,
+                                                               mailmap,
+                                                               st.st_size,
+                                                               verpfrom,
+                                                               listdir, hdrs,
+                                                               hdrslen, body,
+                                                               bodylen, verp);
+                                               if(sendres)
+                                                       requeuemail(listdir,
+                                                               strindex,
+                                                               &stl, 0);
+                                       } else {
+                                               sendres = send_mail_many_list(
+                                                               sockfd, NULL,
+                                                               NULL, mailmap,
+                                                               st.st_size,
+                                                               &stl,
+                                                               listaddr,
+                                                               archivefilename,
+                                                               listdir,
+                                                               mlmmjbounce,
+                                                               hdrs, hdrslen,
+                                                               body, bodylen);
+                                       }
+                                       endsmtp(&sockfd);
+                                       for(i = 0; i < stl.count; i++)
+                                               myfree(stl.strs[i]);
+                                       stl.count = 0;
+                               }
+                       } while(res > 0);
+                       if(stl.count) {
+                               initsmtp(&sockfd, relay);
+                               if(verp) {
+                                       sendres = send_mail_verp(sockfd,
+                                                       &stl, mailmap,
+                                                       st.st_size,
+                                                       verpfrom,
+                                                       listdir, hdrs, hdrslen,
+                                                       body, bodylen, verp);
+                                       if(sendres)
+                                               requeuemail(listdir, strindex,
+                                                               &stl, 0);
+                               } else {
+                                       sendres = send_mail_many_list(sockfd,
+                                                       NULL, NULL, mailmap,
+                                                       st.st_size, &stl,
+                                                       listaddr,
+                                                       archivefilename,
+                                                       listdir, mlmmjbounce,
+                                                       hdrs, hdrslen, body,
+                                                       bodylen);
+                               }
+                               endsmtp(&sockfd);
+                               for(i = 0; i < stl.count; i++)
+                                       myfree(stl.strs[i]);
+                               stl.count = 0;
+                       }
+
+                       myfree(verpfrom);
                        myfree(subfilename);
+                       myfree(stl.strs);
+                       close(subfd);
 
-                       initsmtp(&sockfd, relay);
-                       sendres = send_mail_many(sockfd, NULL, NULL, mailmap,
-                                       st.st_size, subfd, listaddr,
-                                       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
@@ -862,7 +1095,6 @@ int main(int argc, char **argv)
                        } else {
                                endsmtp(&sockfd);
                        }
-                       close(subfd);
                }
                closedir(subddir);
                myfree(subddirname);
@@ -875,6 +1107,7 @@ int main(int argc, char **argv)
        close(sockfd);
        munmap(mailmap, st.st_size);
        close(mailfd);
+       myfree(verp);
 
        if(archive) {
                if(!ctrlarchive) {