]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
send_mails: extract code from mlmmj-send
authorBaptiste Daroussin <bapt@FreeBSD.org>
Fri, 5 Nov 2021 09:17:45 +0000 (10:17 +0100)
committerBaptiste Daroussin <bapt@FreeBSD.org>
Fri, 5 Nov 2021 09:46:40 +0000 (10:46 +0100)
Prepare the land for a refactoring of the send emails function, to avoid
having to call the mlmmj-send binary.

include/mlmmj-send.h
include/send_mails.h [new file with mode: 0644]
src/Makefile.am
src/mlmmj-send.c
src/send_mails.c [new file with mode: 0644]

index 47db0bdc2e8cdc6cd9ea2cbad9feb094866f436a..90e33681a1a77dda861f7ca4c348ec0ac79d5c8e 100644 (file)
 
 #include "mlmmj.h"
 
-int send_mail(int sockfd, const char *from, const char *to,
-             const char *replyto, char *mailmap, size_t mailsize,
-             struct mlmmj_list *, const char *mlmmjbounce,
-             const char *hdrs, size_t hdrslen, const char *body,
-             size_t bodylen);
 int send_mail_many_fd(int sockfd, const char *from, const char *replyto,
                   char *mailmap, size_t mailsize, int subfd,
                   const char *archivefilename, struct mlmmj_list *list,
@@ -45,7 +40,5 @@ int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
                   size_t mailsize, const char *from, struct mlmmj_list *list,
                   const char *hdrs, size_t hdrslen, const char *body,
                   size_t bodylen, const char *extra);
-int initsmtp(int *sockfd, const char *relayhost, unsigned short port, const char *heloname);
-int endsmtp(int *sockfd);
 
 #endif /* MMJML_SEND_H */
diff --git a/include/send_mails.h b/include/send_mails.h
new file mode 100644 (file)
index 0000000..c190fd3
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004, 2003, 2004 Mads Martin Joergensen <mmj at mmj.dk>
+ * Copyright (C) 2021 Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * 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 SEND_MAILS_H
+#define SEND_MAILS_H
+
+int initsmtp(int *sockfd, const char *relayhost, unsigned short port, const char *heloname);
+int endsmtp(int *sockfd);
+int send_mail(int sockfd, const char *from, const char *to, const char *replyto, char *mailmap, size_t mailsize, struct mlmmj_list *list, const char *mlmmjbounce, const char *hdrs, size_t hdrslen, const char *body, size_t bodylen, bool addtohdr, bool prepmailinmem);
+int bouncemail(struct mlmmj_list *list, const char *mlmmjbounce, const char *from);
+#endif
index 0a67dcdcf8374106b5b073bfb78c1fd5e7f98934..a8a59e41d84baae4e7e872618066b8d8f8779a09 100644 (file)
@@ -15,7 +15,7 @@ mlmmj_send_SOURCES = mlmmj.c mlmmj-send.c  mail-functions.c itoa.c chomp.c \
                      incindexfile.c checkwait_smtpreply.c  utils.c \
                     mylocking.c init_sockfd.c strgen.c random-int.c \
                     print-version.c log_error.c mygetline.c memory.c \
-                    controls.c getaddrsfromfd.c readn.c
+                    controls.c getaddrsfromfd.c readn.c send_mails.c
 
 mlmmj_receive_SOURCES = mlmmj-receive.c  random-int.c strgen.c \
                        print-version.c log_error.c dumpfd2fd.c memory.c \
index d2d7cd06b486fa9bb43d5c819134a2f7a5d1b3e7..fd781310d0dadad730648ed453580e8505ddf99b 100644 (file)
@@ -50,7 +50,6 @@
 #include "incindexfile.h"
 #include "chomp.h"
 #include "checkwait_smtpreply.h"
-#include "init_sockfd.h"
 #include "strgen.h"
 #include "log_error.h"
 #include "mygetline.h"
@@ -60,6 +59,7 @@
 #include "mylocking.h"
 #include "getaddrsfromfd.h"
 #include "utils.h"
+#include "send_mails.h"
 
 static int addtohdr = 0;
 static int prepmailinmem = 0;
@@ -190,328 +190,6 @@ char *bounce_from_adr(const char *recipient, const char *mailfilename,
        return bounceaddr;
 }
 
-int bouncemail(struct mlmmj_list *list, const char *mlmmjbounce, const char *from)
-{
-       char *myfrom = mystrdup(from);
-       char *addr, *num, *c;
-       size_t len;
-       pid_t pid = 0;
-
-       if((c = strchr(myfrom, '@')) == NULL) {
-               myfree(myfrom);
-               return 0; /* Success when malformed 'from' */
-       }
-       *c = '\0';
-       num = strrchr(myfrom, '-');
-       num++;
-       c = strstr(myfrom, list->delim);
-       myfrom = strchr(c, '-');
-       myfrom++;
-       len = num - myfrom - 1;
-       addr = mymalloc(len + 1);
-       addr[len] = '\0';
-       strncpy(addr, myfrom, len);
-
-       pid = fork();
-       
-       if(pid < 0) {
-               log_error(LOG_ARGS, "fork() failed!");
-               return 1;
-       }
-       
-       if(pid > 0)
-               return 0;
-       
-       execlp(mlmmjbounce, mlmmjbounce,
-                       "-L", list->dir,
-                       "-a", num,
-                       "-n", addr, (char *)NULL);
-
-       log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjbounce);
-
-       return 1;
-}
-
-int send_mail(int sockfd, const char *from, const char *to,
-             const char *replyto, char *mailmap, size_t mailsize,
-             struct mlmmj_list *list, const char *mlmmjbounce,
-             const char *hdrs, size_t hdrslen, const char *body,
-             size_t bodylen)
-{
-       int retval = 0;
-       char *reply, *reply2, *tohdr;
-
-       if(sockfd == -1)
-               return EBADF;
-
-       if(strchr(to, '@') == NULL) {
-               errno = 0;
-               log_error(LOG_ARGS, "No @ in address, ignoring %s",
-                               to);
-               return 0;
-       }
-       
-       retval = write_mail_from(sockfd, from, "");
-       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);
-               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
-               if (reply2 != NULL) myfree(reply2);
-               return MLMMJ_FROM;
-       }
-       retval = write_rcpt_to(sockfd, to);
-       if(retval) {
-               log_error(LOG_ARGS, "Could not write RCPT TO:\n");
-               return retval;
-       }
-
-       reply = checkwait_smtpreply(sockfd, MLMMJ_RCPTTO);
-       if(reply) {
-               write_rset(sockfd);
-               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
-               if (reply2 != NULL) myfree(reply2);
-               if(mlmmjbounce && ((reply[0] == '4') || (reply[0] == '5'))
-                               && (reply[1] == '5')) {
-                       myfree(reply);
-                       return bouncemail(list, mlmmjbounce, from);
-               } else {
-                       log_error(LOG_ARGS, "Error in RCPT TO. Reply = [%s]",
-                                       reply);
-                       myfree(reply);
-                       return MLMMJ_RCPTTO;
-               }
-       }
-
-       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);
-               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
-               if (reply2 != NULL) myfree(reply2);
-               return MLMMJ_DATA;
-       }
-
-       if(replyto) {
-               retval = write_replyto(sockfd, replyto);
-               if(retval) {
-                       log_error(LOG_ARGS, "Could not write reply-to addr.\n");
-                       return retval;
-               }
-       }
-
-       if(addtohdr)
-               tohdr = concatstr(3, "To: ", to, "\r\n");
-       else
-               tohdr = NULL;
-
-       if(prepmailinmem) {
-               retval = dprintf(sockfd, "%.*s", (int) hdrslen, hdrs);
-               if(retval < 0) {
-                       log_error(LOG_ARGS, "Could not write mailheaders.\n");
-                       return retval;
-               }
-               if(tohdr) {
-                       retval = dprintf(sockfd, "%s", tohdr);
-                       if(retval < 0) {
-                               log_error(LOG_ARGS, "Could not write To:.\n");
-                               return retval;
-                       }
-                       myfree(tohdr);
-               }
-               retval = dprintf(sockfd, "%.*s", (int)bodylen, body);
-               if(retval < 0) {
-                       log_error(LOG_ARGS, "Could not write mailbody.\n");
-                       return retval;
-               }
-       } else {
-               retval = write_mailbody_from_map(sockfd, mailmap, mailsize,
-                                                tohdr);
-               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);
-               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
-               if (reply2 != NULL) myfree(reply2);
-               return MLMMJ_DOT;
-       }
-
-       return 0;
-}
-
-int initsmtp(int *sockfd, const char *relayhost, unsigned short port, const char *heloname)
-{
-       int retval = 0;
-       int try_ehlo = 1;
-       char *reply = NULL;
-
-       do {
-               init_sockfd(sockfd, relayhost, port);
-
-               if(*sockfd == -1) {
-                       retval = EBADF;
-                       break;
-               }
-
-               if((reply = checkwait_smtpreply(*sockfd, MLMMJ_CONNECT)) != NULL) {
-                       log_error(LOG_ARGS, "No proper greeting to our connect"
-                                       "Reply: [%s]", reply);
-                       myfree(reply);
-                       retval = MLMMJ_CONNECT;
-                       /* FIXME: Queue etc. */
-                       break;
-               }
-
-               if (try_ehlo) {
-                       write_ehlo(*sockfd, heloname);
-                       if((reply = checkwait_smtpreply(*sockfd, MLMMJ_EHLO))
-                                       == NULL) {
-                               /* EHLO successful don't try more */
-                               break;
-                       }
-
-                       /* RFC 1869 - 4.5. - In the case of any error response,
-                        * the client SMTP should issue either the HELO or QUIT
-                        * command.
-                        * RFC 1869 - 4.5. - If the server SMTP recognizes the
-                        * EHLO command, but the command argument is
-                        * unacceptable, it will return code 501.
-                        */
-                       if (strncmp(reply, "501", 3) == 0) {
-                               myfree(reply);
-                               /* Commmand unacceptable; we choose to QUIT but
-                                * ignore any QUIT errors; return that EHLO was
-                                * the error.
-                                */
-                               endsmtp(sockfd);
-                               retval = MLMMJ_EHLO;
-                               break;
-                       }
-
-                       /* RFC 1869 - 4.6. - A server SMTP that conforms to RFC
-                        * 821 but does not support the extensions specified
-                        * here will not recognize the EHLO command and will
-                        * consequently return code 500, as specified in RFC
-                        * 821.  The server SMTP should stay in the same state
-                        * after returning this code (see section 4.1.1 of RFC
-                        * 821).  The client SMTP may then issue either a HELO
-                        * or a QUIT command.
-                        */
-
-                       if (reply[0] != '5') {
-                               myfree(reply);
-                               /* Server doesn't understand EHLO, but gives a
-                                * broken response. Try with new connection.
-                                */
-                               endsmtp(sockfd);
-                               try_ehlo = 0;
-                               continue;
-                       }
-
-                       myfree(reply);
-
-                       /* RFC 1869 - 4.7. - Other improperly-implemented
-                        * servers will not accept a HELO command after EHLO has
-                        * been sent and rejected.  In some cases, this problem
-                        * can be worked around by sending a RSET after the
-                        * failure response to EHLO, then sending the HELO.
-                        */
-                       write_rset(*sockfd);
-                       reply = checkwait_smtpreply(*sockfd, MLMMJ_RSET);
-
-                       /* RFC 1869 - 4.7. - Clients that do this should be
-                        * aware that many implementations will return a failure
-                        * code (e.g., 503 Bad sequence of commands) in response
-                        * to the RSET. This code can be safely ignored.
-                        */
-                       myfree(reply);
-
-                       /* Try HELO on the same connection
-                        */
-               }
-
-               write_helo(*sockfd, heloname);
-               if((reply = checkwait_smtpreply(*sockfd, MLMMJ_HELO))
-                               == NULL) {
-                       /* EHLO successful don't try more */
-                       break;
-               }
-               if (try_ehlo) {
-                       myfree(reply);
-                       /* We reused a connection we tried EHLO on. Maybe
-                        * that's why it failed. Try with new connection.
-                        */
-                       endsmtp(sockfd);
-                       try_ehlo = 0;
-                       continue;
-               }
-
-               log_error(LOG_ARGS, "Error with HELO. Reply: "
-                               "[%s]", reply);
-               myfree(reply);
-               /* FIXME: quit and tell admin to configure
-                * correctly */
-               retval = MLMMJ_HELO;
-               break;
-
-       } while (1);
-
-       return retval;
-}
-
-int endsmtp(int *sockfd)
-{
-       int retval = 0;
-       char *reply = NULL;
-
-       if(*sockfd == -1)
-               return retval;
-       
-       write_quit(*sockfd);
-       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. "
-                         "Mailserver reply = [%s]", reply);
-               myfree(reply);
-               retval = MLMMJ_QUIT;
-       }
-
-       close(*sockfd);
-       *sockfd = -1;
-
-       return retval;
-}
-
 int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
                   size_t mailsize, const char *from, struct mlmmj_list *list,
                   const char *hdrs, size_t hdrslen, const char *body,
@@ -742,12 +420,12 @@ int send_mail_many_list(int sockfd, const char *from, const char *replyto,
                if(from) {
                        res = send_mail(sockfd, from, addr, replyto,
                                            mailmap, mailsize, list, NULL,
-                                           hdrs, hdrslen, body, bodylen);
+                                           hdrs, hdrslen, body, bodylen, addtohdr, prepmailinmem);
                } else {
                        bounceaddr = bounce_from_adr(addr, archivefilename, list);
                        res = send_mail(sockfd, bounceaddr, addr, replyto,
                                  mailmap, mailsize, list, mlmmjbounce,
-                                 hdrs, hdrslen, body, bodylen);
+                                 hdrs, hdrslen, body, bodylen, addtohdr, prepmailinmem);
                        myfree(bounceaddr);
                }
                if(res && list->addr && archivefilename) {
@@ -1077,7 +755,7 @@ int main(int argc, char **argv)
                initsmtp(&sockfd, relay, smtpport, smtphelo);
                if(send_mail(sockfd, bounceaddr, to_addr, replyto,
                                mailmap, st.st_size, &list, NULL,
-                               hdrs, hdrslen, body, bodylen)) {
+                               hdrs, hdrslen, body, bodylen, addtohdr, prepmailinmem)) {
                        close(sockfd);
                        sockfd = -1;
                        /* error, so keep it in the queue */
@@ -1169,7 +847,7 @@ int main(int argc, char **argv)
                initsmtp(&sockfd, relay, smtpport, smtphelo);
                if(send_mail(sockfd, bounceaddr, to_addr, replyto,
                                mailmap, st.st_size, &list, NULL,
-                               hdrs, hdrslen, body, bodylen)) {
+                               hdrs, hdrslen, body, bodylen, addtohdr, prepmailinmem)) {
                        close(sockfd);
                        sockfd = -1;
                        /* error, so remove the probefile */
diff --git a/src/send_mails.c b/src/send_mails.c
new file mode 100644 (file)
index 0000000..306166b
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2004, 2003, 2004 Mads Martin Joergensen <mmj at mmj.dk>
+ * Copyright (C) 2021 Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "mlmmj.h"
+#include "send_mails.h"
+#include "log_error.h"
+#include "init_sockfd.h"
+#include "checkwait_smtpreply.h"
+#include "memory.h"
+#include "mail-functions.h"
+
+int
+initsmtp(int *sockfd, const char *relayhost, unsigned short port, const char *heloname)
+{
+       int retval = 0;
+       int try_ehlo = 1;
+       char *reply = NULL;
+
+       do {
+               init_sockfd(sockfd, relayhost, port);
+
+               if(*sockfd == -1) {
+                       retval = EBADF;
+                       break;
+               }
+
+               if((reply = checkwait_smtpreply(*sockfd, MLMMJ_CONNECT)) != NULL) {
+                       log_error(LOG_ARGS, "No proper greeting to our connect"
+                                       "Reply: [%s]", reply);
+                       myfree(reply);
+                       retval = MLMMJ_CONNECT;
+                       /* FIXME: Queue etc. */
+                       break;
+               }
+
+               if (try_ehlo) {
+                       write_ehlo(*sockfd, heloname);
+                       if((reply = checkwait_smtpreply(*sockfd, MLMMJ_EHLO))
+                                       == NULL) {
+                               /* EHLO successful don't try more */
+                               break;
+                       }
+
+                       /* RFC 1869 - 4.5. - In the case of any error response,
+                        * the client SMTP should issue either the HELO or QUIT
+                        * command.
+                        * RFC 1869 - 4.5. - If the server SMTP recognizes the
+                        * EHLO command, but the command argument is
+                        * unacceptable, it will return code 501.
+                        */
+                       if (strncmp(reply, "501", 3) == 0) {
+                               myfree(reply);
+                               /* Commmand unacceptable; we choose to QUIT but
+                                * ignore any QUIT errors; return that EHLO was
+                                * the error.
+                                */
+                               endsmtp(sockfd);
+                               retval = MLMMJ_EHLO;
+                               break;
+                       }
+
+                       /* RFC 1869 - 4.6. - A server SMTP that conforms to RFC
+                        * 821 but does not support the extensions specified
+                        * here will not recognize the EHLO command and will
+                        * consequently return code 500, as specified in RFC
+                        * 821.  The server SMTP should stay in the same state
+                        * after returning this code (see section 4.1.1 of RFC
+                        * 821).  The client SMTP may then issue either a HELO
+                        * or a QUIT command.
+                        */
+
+                       if (reply[0] != '5') {
+                               myfree(reply);
+                               /* Server doesn't understand EHLO, but gives a
+                                * broken response. Try with new connection.
+                                */
+                               endsmtp(sockfd);
+                               try_ehlo = 0;
+                               continue;
+                       }
+
+                       myfree(reply);
+
+                       /* RFC 1869 - 4.7. - Other improperly-implemented
+                        * servers will not accept a HELO command after EHLO has
+                        * been sent and rejected.  In some cases, this problem
+                        * can be worked around by sending a RSET after the
+                        * failure response to EHLO, then sending the HELO.
+                        */
+                       write_rset(*sockfd);
+                       reply = checkwait_smtpreply(*sockfd, MLMMJ_RSET);
+
+                       /* RFC 1869 - 4.7. - Clients that do this should be
+                        * aware that many implementations will return a failure
+                        * code (e.g., 503 Bad sequence of commands) in response
+                        * to the RSET. This code can be safely ignored.
+                        */
+                       myfree(reply);
+
+                       /* Try HELO on the same connection
+                        */
+               }
+
+               write_helo(*sockfd, heloname);
+               if((reply = checkwait_smtpreply(*sockfd, MLMMJ_HELO))
+                               == NULL) {
+                       /* EHLO successful don't try more */
+                       break;
+               }
+               if (try_ehlo) {
+                       myfree(reply);
+                       /* We reused a connection we tried EHLO on. Maybe
+                        * that's why it failed. Try with new connection.
+                        */
+                       endsmtp(sockfd);
+                       try_ehlo = 0;
+                       continue;
+               }
+
+               log_error(LOG_ARGS, "Error with HELO. Reply: "
+                               "[%s]", reply);
+               myfree(reply);
+               /* FIXME: quit and tell admin to configure
+                * correctly */
+               retval = MLMMJ_HELO;
+               break;
+
+       } while (1);
+
+       return retval;
+}
+
+int
+endsmtp(int *sockfd)
+{
+       int retval = 0;
+       char *reply = NULL;
+
+       if(*sockfd == -1)
+               return retval;
+       
+       write_quit(*sockfd);
+       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. "
+                         "Mailserver reply = [%s]", reply);
+               myfree(reply);
+               retval = MLMMJ_QUIT;
+       }
+
+       close(*sockfd);
+       *sockfd = -1;
+
+       return retval;
+}
+
+int
+send_mail(int sockfd, const char *from, const char *to,
+             const char *replyto, char *mailmap, size_t mailsize,
+             struct mlmmj_list *list, const char *mlmmjbounce,
+             const char *hdrs, size_t hdrslen, const char *body,
+             size_t bodylen, bool addtohdr, bool prepmailinmem)
+{
+       int retval = 0;
+       char *reply, *reply2, *tohdr;
+
+       if(sockfd == -1)
+               return EBADF;
+
+       if(strchr(to, '@') == NULL) {
+               errno = 0;
+               log_error(LOG_ARGS, "No @ in address, ignoring %s",
+                               to);
+               return 0;
+       }
+       
+       retval = write_mail_from(sockfd, from, "");
+       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);
+               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               if (reply2 != NULL) myfree(reply2);
+               return MLMMJ_FROM;
+       }
+       retval = write_rcpt_to(sockfd, to);
+       if(retval) {
+               log_error(LOG_ARGS, "Could not write RCPT TO:\n");
+               return retval;
+       }
+
+       reply = checkwait_smtpreply(sockfd, MLMMJ_RCPTTO);
+       if(reply) {
+               write_rset(sockfd);
+               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               if (reply2 != NULL) myfree(reply2);
+               if(mlmmjbounce && ((reply[0] == '4') || (reply[0] == '5'))
+                               && (reply[1] == '5')) {
+                       myfree(reply);
+                       return bouncemail(list, mlmmjbounce, from);
+               } else {
+                       log_error(LOG_ARGS, "Error in RCPT TO. Reply = [%s]",
+                                       reply);
+                       myfree(reply);
+                       return MLMMJ_RCPTTO;
+               }
+       }
+
+       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);
+               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               if (reply2 != NULL) myfree(reply2);
+               return MLMMJ_DATA;
+       }
+
+       if(replyto) {
+               retval = write_replyto(sockfd, replyto);
+               if(retval) {
+                       log_error(LOG_ARGS, "Could not write reply-to addr.\n");
+                       return retval;
+               }
+       }
+
+       if(addtohdr)
+               myasprintf(&tohdr, "To: %s\r\n", to);
+       else
+               tohdr = NULL;
+
+       if(prepmailinmem) {
+               retval = dprintf(sockfd, "%.*s", (int) hdrslen, hdrs);
+               if(retval < 0) {
+                       log_error(LOG_ARGS, "Could not write mailheaders.\n");
+                       return retval;
+               }
+               if(tohdr) {
+                       retval = dprintf(sockfd, "%s", tohdr);
+                       if(retval < 0) {
+                               log_error(LOG_ARGS, "Could not write To:.\n");
+                               return retval;
+                       }
+                       myfree(tohdr);
+               }
+               retval = dprintf(sockfd, "%.*s", (int)bodylen, body);
+               if(retval < 0) {
+                       log_error(LOG_ARGS, "Could not write mailbody.\n");
+                       return retval;
+               }
+       } else {
+               retval = write_mailbody_from_map(sockfd, mailmap, mailsize,
+                                                tohdr);
+               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);
+               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               if (reply2 != NULL) myfree(reply2);
+               return MLMMJ_DOT;
+       }
+
+       return 0;
+}
+
+int
+bouncemail(struct mlmmj_list *list, const char *mlmmjbounce, const char *from)
+{
+       char *myfrom = mystrdup(from);
+       char *addr, *num, *c;
+       size_t len;
+       pid_t pid = 0;
+
+       if((c = strchr(myfrom, '@')) == NULL) {
+               myfree(myfrom);
+               return 0; /* Success when malformed 'from' */
+       }
+       *c = '\0';
+       num = strrchr(myfrom, '-');
+       num++;
+       c = strstr(myfrom, list->delim);
+       myfrom = strchr(c, '-');
+       myfrom++;
+       len = num - myfrom - 1;
+       addr = mymalloc(len + 1);
+       addr[len] = '\0';
+       strncpy(addr, myfrom, len);
+
+       pid = fork();
+       
+       if(pid < 0) {
+               log_error(LOG_ARGS, "fork() failed!");
+               return 1;
+       }
+       
+       if(pid > 0)
+               return 0;
+       
+       execlp(mlmmjbounce, mlmmjbounce,
+                       "-L", list->dir,
+                       "-a", num,
+                       "-n", addr, (char *)NULL);
+
+       log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjbounce);
+
+       return 1;
+}