Split sendmail into common and sendmail-specific portions.
authorMichael Poole <mdpoole@troilus.org>
Thu, 8 Mar 2007 00:52:57 +0000 (19:52 -0500)
committerMichael Poole <mdpoole@troilus.org>
Thu, 8 Mar 2007 00:52:57 +0000 (19:52 -0500)
This is in preparation for an SMTP alternative to the current code.

12 files changed:
configure.in
src/Makefile.am
src/mail-common.c [new file with mode: 0644]
src/mail-sendmail.c [new file with mode: 0644]
src/mail.h [new file with mode: 0644]
src/mail.help [new file with mode: 0644]
src/main-win32.c
src/main.c
src/nickserv.c
src/sendmail.c [deleted file]
src/sendmail.h [deleted file]
src/sendmail.help [deleted file]

index a821044a655a4fa87375427e9f59f8d80ac93dad..57deaaeb5b2eb80f3cec29a5fa8d1092ef3384ac 100644 (file)
@@ -239,7 +239,6 @@ if test "x$withval" = "xp10" ; then
   AC_MSG_RESULT(P10)
   AC_DEFINE(WITH_PROTOCOL_P10, 1, [Define if using the P10 dialect of IRC])
   MODULE_OBJS="$MODULE_OBJS proto-p10.\$(OBJEXT)"
-  PROTO_FILES=proto-p10.c
 elif test "x$withval" = "xbahamut" ; then
   AC_MSG_RESULT(Bahamut)
   AC_DEFINE(WITH_PROTOCOL_BAHAMUT, 1, [Define if using the Bahamut dialect of IRC])
@@ -248,6 +247,19 @@ else
   AC_MSG_ERROR([Unknown IRC dialect $withval])
 fi
 
+AC_MSG_CHECKING(how to send mail)
+AC_ARG_WITH(mail,
+[  --with-mail=name        How to send mail; one of:
+                          sendmail (the default)],
+[],
+[withval="sendmail"])
+if test "x$withval" = "xsendmail" ; then
+  AC_MSG_RESULT(sendmail)
+  MODULE_OBJS="$MODULE_OBJS mail-sendmail.\$(OBJEXT)"
+else
+  AC_MSG_ERROR([Unknown mail method $withval])
+fi
+
 AC_MSG_CHECKING([I/O multiplexing backends])
 IOMUXES=""
 
index 4ce9b7ffc385ba5fb7b03b921eaba6408e838945..34456de682cce521696a5793d826f36c2d5446ef 100644 (file)
@@ -10,7 +10,7 @@ noinst_DATA = \
        nickserv.help \
        opserv.help \
        saxdb.help \
-       sendmail.help \
+       mail.help \
        mod-helpserv.help \
        mod-memoserv.help \
        mod-sockcheck.help
@@ -48,6 +48,8 @@ EXTRA_srvx_SOURCES = \
        ioset-epoll.c \
        ioset-select.c \
        ioset-win32.c \
+       mail-common.c \
+       mail-sendmail.c \
        main-common.c \
        main-win32.c \
        proto-bahamut.c \
@@ -75,6 +77,7 @@ srvx_SOURCES = \
        helpfile.c helpfile.h \
        ioset.c ioset.h ioset-impl.h \
        log.c log.h \
+       mail.h \
        main.c common.h \
        md5.c md5.h \
        modcmd.c modcmd.h \
@@ -85,7 +88,6 @@ srvx_SOURCES = \
        proto.h \
        recdb.c recdb.h \
        saxdb.c saxdb.h \
-       sendmail.c sendmail.h \
        timeq.c timeq.h \
        tools.c
 
diff --git a/src/mail-common.c b/src/mail-common.c
new file mode 100644 (file)
index 0000000..84a9cf4
--- /dev/null
@@ -0,0 +1,163 @@
+/* mail-common.c - mail sending utilities
+ * Copyright 2002-2004, 2007 srvx Development Team
+ *
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with srvx; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+
+#include "conf.h"
+#include "modcmd.h"
+#include "nickserv.h"
+#include "saxdb.h"
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#define KEY_PROHIBITED   "prohibited"
+
+static const struct message_entry msgtab[] = {
+    { "MAILMSG_EMAIL_ALREADY_BANNED", "%s is already banned (%s)." },
+    { "MAILMSG_EMAIL_BANNED", "Email to %s has been forbidden." },
+    { "MAILMSG_EMAIL_NOT_BANNED", "Email to %s was not forbidden." },
+    { "MAILMSG_EMAIL_UNBANNED", "Email to %s is now allowed." },
+    { "MAILMSG_PROHIBITED_EMAIL", "%s: %s" },
+    { "MAILMSG_NO_PROHIBITED_EMAIL", "All email addresses are accepted." },
+    { NULL, NULL }
+};
+
+static dict_t prohibited_addrs, prohibited_masks;
+struct module *mail_module;
+
+const char *
+mail_prohibited_address(const char *addr)
+{
+    dict_iterator_t it;
+    const char *data;
+
+    if (prohibited_addrs && (data = dict_find(prohibited_addrs, addr, NULL)))
+        return data;
+    if (prohibited_masks)
+        for (it = dict_first(prohibited_masks); it; it = iter_next(it))
+            if (match_ircglob(addr, iter_key(it)))
+                return iter_data(it);
+    return NULL;
+}
+
+static int
+mail_ban_address(struct userNode *user, struct userNode *bot, const char *addr, const char *reason) {
+    dict_t target;
+    const char *str;
+
+    target = strpbrk(addr, "*?") ? prohibited_masks : prohibited_addrs;
+    if ((str = dict_find(target, addr, NULL))) {
+        if (user)
+            send_message(user, bot, "MAILMSG_EMAIL_ALREADY_BANNED", addr, str);
+        return 0;
+    }
+    dict_insert(target, strdup(addr), strdup(reason));
+    if (user) send_message(user, bot, "MAILMSG_EMAIL_BANNED", addr);
+    return 1;
+}
+
+static MODCMD_FUNC(cmd_banemail) {
+    char *reason = unsplit_string(argv+2, argc-2, NULL);
+    return mail_ban_address(user, cmd->parent->bot, argv[1], reason);
+}
+
+static MODCMD_FUNC(cmd_unbanemail) {
+    dict_t target;
+    const char *addr;
+
+    addr = argv[1];
+    target = strpbrk(addr, "*?") ? prohibited_masks : prohibited_addrs;
+    if (dict_remove(target, addr))
+        reply("MAILMSG_EMAIL_UNBANNED", addr);
+    else
+        reply("MAILMSG_EMAIL_NOT_BANNED", addr);
+    return 1;
+}
+
+static MODCMD_FUNC(cmd_stats_email) {
+    dict_iterator_t it;
+    int found = 0;
+
+    for (it=dict_first(prohibited_addrs); it; it=iter_next(it)) {
+        reply("MAILMSG_PROHIBITED_EMAIL", iter_key(it), (const char*)iter_data(it));
+        found = 1;
+    }
+    for (it=dict_first(prohibited_masks); it; it=iter_next(it)) {
+        reply("MAILMSG_PROHIBITED_EMAIL", iter_key(it), (const char*)iter_data(it));
+        found = 1;
+    }
+    if (!found)
+        reply("MAILMSG_NO_PROHIBITED_EMAIL");
+    return 0;
+}
+
+static int
+mail_saxdb_read(struct dict *db) {
+    struct dict *subdb;
+    struct record_data *rd;
+    dict_iterator_t it;
+
+    if ((subdb = database_get_data(db, KEY_PROHIBITED, RECDB_OBJECT))) {
+        for (it = dict_first(subdb); it; it = iter_next(it)) {
+            rd = iter_data(it);
+            if (rd->type == RECDB_QSTRING)
+                mail_ban_address(NULL, NULL, iter_key(it), rd->d.qstring);
+        }
+    }
+    return 0;
+}
+
+static int
+mail_saxdb_write(struct saxdb_context *ctx) {
+    dict_iterator_t it;
+
+    saxdb_start_record(ctx, KEY_PROHIBITED, 0);
+    for (it = dict_first(prohibited_masks); it; it = iter_next(it))
+        saxdb_write_string(ctx, iter_key(it), iter_data(it));
+    for (it = dict_first(prohibited_addrs); it; it = iter_next(it))
+        saxdb_write_string(ctx, iter_key(it), iter_data(it));
+    saxdb_end_record(ctx);
+    return 0;
+}
+
+static void
+mail_common_cleanup(void)
+{
+    dict_delete(prohibited_addrs);
+    dict_delete(prohibited_masks);
+}
+
+static void
+mail_common_init(void)
+{
+    prohibited_addrs = dict_new();
+    dict_set_free_keys(prohibited_addrs, free);
+    dict_set_free_data(prohibited_addrs, free);
+    prohibited_masks = dict_new();
+    dict_set_free_keys(prohibited_masks, free);
+    dict_set_free_data(prohibited_masks, free);
+    reg_exit_func(mail_common_cleanup);
+    saxdb_register("sendmail", mail_saxdb_read, mail_saxdb_write);
+    mail_module = module_register("sendmail", MAIN_LOG, "mail.help", NULL);
+    modcmd_register(mail_module, "banemail", cmd_banemail, 3, 0, "level", "601", NULL);
+    modcmd_register(mail_module, "stats email", cmd_stats_email, 0, 0, "flags", "+oper", NULL);
+    modcmd_register(mail_module, "unbanemail", cmd_unbanemail, 2, 0, "level", "601", NULL);
+    message_register_table(msgtab);
+}
diff --git a/src/mail-sendmail.c b/src/mail-sendmail.c
new file mode 100644 (file)
index 0000000..d6530b4
--- /dev/null
@@ -0,0 +1,208 @@
+/* mail-common.c - mail sending utilities
+ * Copyright 2002-2004, 2007 srvx Development Team
+ *
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with srvx; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include "mail-common.c"
+
+/* This function sends the given "paragraph" as flowed text, as
+ * defined in RFC 2646.  It lets us only worry about line wrapping
+ * here, and not in the code that generates mail.
+ */
+static void
+send_flowed_text(FILE *where, const char *para)
+{
+    const char *eol = strchr(para, '\n');
+    unsigned int shift;
+
+    while (*para) {
+        /* Do we need to space-stuff the line? */
+        if ((*para == ' ') || (*para == '>') || !strncmp(para, "From ", 5)) {
+            fputc(' ', where);
+            shift = 1;
+        } else {
+            shift = 0;
+        }
+        /* How much can we put on this line? */
+        if (!eol && (strlen(para) < (80 - shift))) {
+            /* End of paragraph; can put on one line. */
+            fputs(para, where);
+            fputs("\n", where);
+            break;
+        } else if (eol && (eol < para + (80 - shift))) {
+            /* Newline inside paragraph, no need to wrap. */
+            fprintf(where, "%.*s\n", (int)(eol - para), para);
+            para = eol + 1;
+        } else {
+            int pos;
+            /* Need to wrap.  Where's the last space in the line? */
+            for (pos=72-shift; pos && (para[pos] != ' '); pos--) ;
+            /* If we didn't find a space, look ahead instead. */
+            if (pos == 0) pos = strcspn(para, " \n");
+            fprintf(where, "%.*s\n", pos+1, para);
+            para += pos + 1;
+        }
+        if (eol && (eol < para)) eol = strchr(para, '\n');
+    }
+}
+
+void
+mail_send(struct userNode *from, struct handle_info *to, const char *subject, const char *body, int first_time)
+{
+    pid_t child;
+    int infds[2], outfds[2];
+    const char *fromaddr, *str;
+
+    /* Grab some config items first. */
+    str = conf_get_data("mail/enable", RECDB_QSTRING);
+    if (!str || !enabled_string(str))
+        return;
+    fromaddr = conf_get_data("mail/from_address", RECDB_QSTRING);
+
+    /* How this works: We fork, and the child tries to send the mail.
+     * It does this by setting up a pipe pair, and forking again (the
+     * grandchild exec()'s the mailer program).  The mid-level child
+     * sends the text to the grandchild's stdin, and then logs the
+     * success or failure.
+     */
+
+    child = fork();
+    if (child < 0) {
+        log_module(MAIN_LOG, LOG_ERROR, "sendmail() to %s couldn't fork(): %s (%d)", to->email_addr, strerror(errno), errno);
+        return;
+    } else if (child > 0) {
+        return;
+    }
+    /* We're in a child now; must _exit() to die properly. */
+    if (pipe(infds) < 0) {
+        log_module(MAIN_LOG, LOG_ERROR, "sendmail() child to %s couldn't pipe(infds): %s (%d)", to->email_addr, strerror(errno), errno);
+        _exit(1);
+    }
+    if (pipe(outfds) < 0) {
+        log_module(MAIN_LOG, LOG_ERROR, "sendmail() child to %s couldn't pipe(outfds): %s (%d)", to->email_addr, strerror(errno), errno);
+        _exit(1);
+    }
+    child = fork();
+    if (child < 0) {
+        log_module(MAIN_LOG, LOG_ERROR, "sendmail() child to %s couldn't fork(): %s (%d)", to->email_addr, strerror(errno), errno);
+        _exit(1);
+    } else if (child > 0) {
+        /* Mid-level child; get ready to send the mail. */
+        FILE *out = fdopen(infds[1], "w");
+        struct string_list *extras;
+        unsigned int nn;
+        int res, rv;
+
+        /* Close the end of pipes we do not use. */
+        close(infds[0]);
+        close(outfds[1]);
+
+        /* Do we have any "extra" headers to send? */
+        extras = conf_get_data("mail/extra_headers", RECDB_STRING_LIST);
+        if (extras) {
+            for (nn=0; nn<extras->used; nn++) {
+                fputs(extras->list[nn], out);
+                fputs("\n", out);
+            }
+        }
+
+        /* Content type?  (format=flowed is a standard for plain text
+         * that lets the receiver reconstruct paragraphs, defined in
+         * RFC 2646.  See comment above send_flowed_text() for more.)
+         */
+        if (!(str = conf_get_data("mail/charset", RECDB_QSTRING))) str = "us-ascii";
+        fprintf(out, "Content-Type: text/plain; charset=%s; format=flowed\n", str);
+
+        /* Send From, To and Subject headers */
+        if (!fromaddr) fromaddr = "admin@poorly.configured.network";
+        fprintf(out, "From: %s <%s>\n", from->nick, fromaddr);
+        fprintf(out, "To: \"%s\" <%s>\n", to->handle, to->email_addr);
+        fprintf(out, "Subject: %s\n", subject);
+
+        /* Send mail body */
+        fputs("\n", out); /* terminate headers */
+        extras = conf_get_data((first_time?"mail/body_prefix_first":"mail/body_prefix"), RECDB_STRING_LIST);
+        if (extras) {
+            for (nn=0; nn<extras->used; nn++) {
+                send_flowed_text(out, extras->list[nn]);
+            }
+            fputs("\n", out);
+        }
+        send_flowed_text(out, body);
+        extras = conf_get_data((first_time?"mail/body_suffix_first":"mail/body_suffix"), RECDB_STRING_LIST);
+        if (extras) {
+            fputs("\n", out);
+            for (nn=0; nn<extras->used; nn++)
+                send_flowed_text(out, extras->list[nn]);
+        }
+
+        /* Close file (sending mail) and check for return code */
+        fflush(out);
+        fclose(out);
+        do {
+            rv = wait4(child, &res, 0, NULL);
+        } while ((rv == -1) && (errno == EINTR));
+        if (rv == child) {
+            /* accept the wait() result */
+        } else {
+            log_module(MAIN_LOG, LOG_ERROR, "sendmail() child to %s: Bad wait() return code %d: %s (%d)", to->email_addr, rv, strerror(errno), errno);
+            _exit(1);
+        }
+        if (res) {
+            log_module(MAIN_LOG, LOG_ERROR, "sendmail() grandchild to %s: Exited with code %d", to->email_addr, res);
+            _exit(1);
+        } else {
+            log_module(MAIN_LOG, LOG_INFO, "sendmail() sent email to %s <%s>: %s", to->handle, to->email_addr, subject);
+        }
+        _exit(0);
+    } else {
+        /* Grandchild; dup2 the fds and exec the mailer. */
+        const char *argv[10], *mpath;
+        unsigned int argc = 0;
+
+        /* Close the end of pipes we do not use. */
+        close(infds[1]);
+        close(outfds[0]);
+
+        dup2(infds[0], STDIN_FILENO);
+        dup2(outfds[1], STDOUT_FILENO);
+        mpath = conf_get_data("mail/mailer", RECDB_QSTRING);
+        if (!mpath) mpath = "/usr/sbin/sendmail";
+        argv[argc++] = mpath;
+        if (fromaddr) {
+            argv[argc++] = "-f";
+            argv[argc++] = fromaddr;
+        }
+        argv[argc++] = to->email_addr;
+        argv[argc++] = NULL;
+        if (execv(mpath, (char**)argv) < 0) {
+            log_module(MAIN_LOG, LOG_ERROR, "sendmail() grandchild to %s couldn't execv(): %s (%d)", to->email_addr, strerror(errno), errno);
+        }
+        _exit(1);
+    }
+}
+
+void
+mail_init(void)
+{
+    mail_common_init();
+}
diff --git a/src/mail.h b/src/mail.h
new file mode 100644 (file)
index 0000000..208020c
--- /dev/null
@@ -0,0 +1,28 @@
+/* mail.h - mail sending utilities
+ * Copyright 2002 srvx Development Team
+ *
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with srvx; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+
+#if !defined(MAIL_H)
+#define MAIL_H
+
+void mail_init(void);
+void mail_send(struct userNode *from, struct handle_info *to, const char *subject, const char *body, int first_time);
+const char *mail_prohibited_address(const char *addr);
+
+#endif
diff --git a/src/mail.help b/src/mail.help
new file mode 100644 (file)
index 0000000..6951b5a
--- /dev/null
@@ -0,0 +1,7 @@
+"BANEMAIL" ("/msg $S BANEMAIL <address> <reason>",
+        "Keeps srvx from sending mail to the address.  The address may be a real address, or a glob that uses * and ? wildcards.",
+        "This also prevents anyone from using matching addresses as their account email address.",
+        "$uSee Also:$u unbanemail, stats email");
+"UNBANEMAIL" ("/msg $S UNBANEMAIL <address>",
+        "Removes an email address (or glob) from the banned email address list.",
+        "$uSee Also:$u banemail, stats email");
index ddf83801a94392e7bb6ea16278966b29aa4b9103..03b0036f92ce2c33d94249249a99cd1144be939c 100644 (file)
@@ -4,7 +4,7 @@
 #include "ioset.h"
 #include "modcmd.h"
 #include "saxdb.h"
-#include "sendmail.h"
+#include "mail.h"
 #include "timeq.h"
 
 #include "chanserv.h"
@@ -41,7 +41,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int
     modcmd_init();
     saxdb_init();
     gline_init();
-    sendmail_init();
+    mail_init();
     helpfile_init();
     conf_globals();
     conf_rlimits();
index 577f25b4bf55adbcf054fcabcb51506eb46d40c2..bffe2be80d31977222d1fa750b7a8a8e48aa09fa 100644 (file)
@@ -25,7 +25,7 @@
 #include "ioset.h"
 #include "modcmd.h"
 #include "saxdb.h"
-#include "sendmail.h"
+#include "mail.h"
 #include "timeq.h"
 
 #include "chanserv.h"
@@ -283,7 +283,7 @@ int main(int argc, char *argv[])
     modcmd_init();
     saxdb_init();
     gline_init();
-    sendmail_init();
+    mail_init();
     helpfile_init();
     conf_globals(); /* initializes the core services */
     conf_rlimits();
index 39428a031c7eaccb056730195454781025362bf2..bf22dd65f58553f3ff3c5e02fa805204be2c2244 100644 (file)
@@ -24,7 +24,7 @@
 #include "modcmd.h"
 #include "opserv.h" /* for gag_create(), opserv_bad_channel() */
 #include "saxdb.h"
-#include "sendmail.h"
+#include "mail.h"
 #include "timeq.h"
 
 #ifdef HAVE_REGEX_H
@@ -1044,7 +1044,7 @@ nickserv_make_cookie(struct userNode *user, struct handle_info *hi, enum cookie_
             snprintf(subject, sizeof(subject), fmt, netname);
             fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
             snprintf(body, sizeof(body), fmt, netname, cookie->cookie+COOKIELEN/2, nickserv->nick, self->name, hi->handle, COOKIELEN/2);
-            sendmail(nickserv, hi, subject, body, 1);
+            mail_send(nickserv, hi, subject, body, 1);
             fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
             snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle, COOKIELEN/2, hi->email_addr);
         } else {
@@ -1053,7 +1053,7 @@ nickserv_make_cookie(struct userNode *user, struct handle_info *hi, enum cookie_
             snprintf(subject, sizeof(subject), fmt, netname);
             fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_BODY");
             snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
-            sendmail(nickserv, hi, subject, body, 1);
+            mail_send(nickserv, hi, subject, body, 1);
             subject[0] = 0;
         }
         hi->email_addr = misc;
@@ -1070,7 +1070,7 @@ nickserv_make_cookie(struct userNode *user, struct handle_info *hi, enum cookie_
         break;
     }
     if (subject[0])
-        sendmail(nickserv, hi, subject, body, first_time);
+        mail_send(nickserv, hi, subject, body, first_time);
     nickserv_bake_cookie(cookie);
 }
 
@@ -1164,7 +1164,7 @@ static NICKSERV_FUNC(cmd_register)
         }
 
         /* .. and that we are allowed to send to it. */
-        if ((str = sendmail_prohibited_address(email_addr))) {
+        if ((str = mail_prohibited_address(email_addr))) {
             reply("NSMSG_EMAIL_PROHIBITED", email_addr, str);
             return 0;
         }
@@ -2328,7 +2328,7 @@ static OPTION_FUNC(opt_email)
             send_message(user, nickserv, "NSMSG_BAD_EMAIL_ADDR");
             return 0;
         }
-        if ((str = sendmail_prohibited_address(argv[1]))) {
+        if ((str = mail_prohibited_address(argv[1]))) {
             send_message(user, nickserv, "NSMSG_EMAIL_PROHIBITED", argv[1], str);
             return 0;
         }
diff --git a/src/sendmail.c b/src/sendmail.c
deleted file mode 100644 (file)
index 63bb548..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-/* sendmail.c - mail sending utilities
- * Copyright 2002-2004 srvx Development Team
- *
- * This file is part of srvx.
- *
- * srvx is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with srvx; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
- */
-
-#include "conf.h"
-#include "modcmd.h"
-#include "nickserv.h"
-#include "saxdb.h"
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#define KEY_PROHIBITED   "prohibited"
-
-static const struct message_entry msgtab[] = {
-    { "MAILMSG_EMAIL_ALREADY_BANNED", "%s is already banned (%s)." },
-    { "MAILMSG_EMAIL_BANNED", "Email to %s has been forbidden." },
-    { "MAILMSG_EMAIL_NOT_BANNED", "Email to %s was not forbidden." },
-    { "MAILMSG_EMAIL_UNBANNED", "Email to %s is now allowed." },
-    { "MAILMSG_PROHIBITED_EMAIL", "%s: %s" },
-    { "MAILMSG_NO_PROHIBITED_EMAIL", "All email addresses are accepted." },
-    { NULL, NULL }
-};
-
-static dict_t prohibited_addrs, prohibited_masks;
-struct module *sendmail_module;
-
-const char *
-sendmail_prohibited_address(const char *addr)
-{
-    dict_iterator_t it;
-    const char *data;
-
-    if (prohibited_addrs && (data = dict_find(prohibited_addrs, addr, NULL)))
-        return data;
-    if (prohibited_masks)
-        for (it = dict_first(prohibited_masks); it; it = iter_next(it))
-            if (match_ircglob(addr, iter_key(it)))
-                return iter_data(it);
-    return NULL;
-}
-
-/* This function sends the given "paragraph" as flowed text, as
- * defined in RFC 2646.  It lets us only worry about line wrapping
- * here, and not in the code that generates mail.
- */
-static void
-send_flowed_text(FILE *where, const char *para)
-{
-    const char *eol = strchr(para, '\n');
-    unsigned int shift;
-
-    while (*para) {
-        /* Do we need to space-stuff the line? */
-        if ((*para == ' ') || (*para == '>') || !strncmp(para, "From ", 5)) {
-            fputc(' ', where);
-            shift = 1;
-        } else {
-            shift = 0;
-        }
-        /* How much can we put on this line? */
-        if (!eol && (strlen(para) < (80 - shift))) {
-            /* End of paragraph; can put on one line. */
-            fputs(para, where);
-            fputs("\n", where);
-            break;
-        } else if (eol && (eol < para + (80 - shift))) {
-            /* Newline inside paragraph, no need to wrap. */
-            fprintf(where, "%.*s\n", (int)(eol - para), para);
-            para = eol + 1;
-        } else {
-            int pos;
-            /* Need to wrap.  Where's the last space in the line? */
-            for (pos=72-shift; pos && (para[pos] != ' '); pos--) ;
-            /* If we didn't find a space, look ahead instead. */
-            if (pos == 0) pos = strcspn(para, " \n");
-            fprintf(where, "%.*s\n", pos+1, para);
-            para += pos + 1;
-        }
-        if (eol && (eol < para)) eol = strchr(para, '\n');
-    }
-}
-
-void
-sendmail(struct userNode *from, struct handle_info *to, const char *subject, const char *body, int first_time)
-{
-    pid_t child;
-    int infds[2], outfds[2];
-    const char *fromaddr, *str;
-
-    /* Grab some config items first. */
-    str = conf_get_data("mail/enable", RECDB_QSTRING);
-    if (!str || !enabled_string(str))
-        return;
-    fromaddr = conf_get_data("mail/from_address", RECDB_QSTRING);
-
-    /* How this works: We fork, and the child tries to send the mail.
-     * It does this by setting up a pipe pair, and forking again (the
-     * grandchild exec()'s the mailer program).  The mid-level child
-     * sends the text to the grandchild's stdin, and then logs the
-     * success or failure.
-     */
-
-    child = fork();
-    if (child < 0) {
-        log_module(MAIN_LOG, LOG_ERROR, "sendmail() to %s couldn't fork(): %s (%d)", to->email_addr, strerror(errno), errno);
-        return;
-    } else if (child > 0) {
-        return;
-    }
-    /* We're in a child now; must _exit() to die properly. */
-    if (pipe(infds) < 0) {
-        log_module(MAIN_LOG, LOG_ERROR, "sendmail() child to %s couldn't pipe(infds): %s (%d)", to->email_addr, strerror(errno), errno);
-        _exit(1);
-    }
-    if (pipe(outfds) < 0) {
-        log_module(MAIN_LOG, LOG_ERROR, "sendmail() child to %s couldn't pipe(outfds): %s (%d)", to->email_addr, strerror(errno), errno);
-        _exit(1);
-    }
-    child = fork();
-    if (child < 0) {
-        log_module(MAIN_LOG, LOG_ERROR, "sendmail() child to %s couldn't fork(): %s (%d)", to->email_addr, strerror(errno), errno);
-        _exit(1);
-    } else if (child > 0) {
-        /* Mid-level child; get ready to send the mail. */
-        FILE *out = fdopen(infds[1], "w");
-        struct string_list *extras;
-        unsigned int nn;
-        int res, rv;
-
-        /* Close the end of pipes we do not use. */
-        close(infds[0]);
-        close(outfds[1]);
-
-        /* Do we have any "extra" headers to send? */
-        extras = conf_get_data("mail/extra_headers", RECDB_STRING_LIST);
-        if (extras) {
-            for (nn=0; nn<extras->used; nn++) {
-                fputs(extras->list[nn], out);
-                fputs("\n", out);
-            }
-        }
-
-        /* Content type?  (format=flowed is a standard for plain text
-         * that lets the receiver reconstruct paragraphs, defined in
-         * RFC 2646.  See comment above send_flowed_text() for more.)
-         */
-        if (!(str = conf_get_data("mail/charset", RECDB_QSTRING))) str = "us-ascii";
-        fprintf(out, "Content-Type: text/plain; charset=%s; format=flowed\n", str);
-
-        /* Send From, To and Subject headers */
-        if (!fromaddr) fromaddr = "admin@poorly.configured.network";
-        fprintf(out, "From: %s <%s>\n", from->nick, fromaddr);
-        fprintf(out, "To: \"%s\" <%s>\n", to->handle, to->email_addr);
-        fprintf(out, "Subject: %s\n", subject);
-
-        /* Send mail body */
-        fputs("\n", out); /* terminate headers */
-        extras = conf_get_data((first_time?"mail/body_prefix_first":"mail/body_prefix"), RECDB_STRING_LIST);
-        if (extras) {
-            for (nn=0; nn<extras->used; nn++) {
-                send_flowed_text(out, extras->list[nn]);
-            }
-            fputs("\n", out);
-        }
-        send_flowed_text(out, body);
-        extras = conf_get_data((first_time?"mail/body_suffix_first":"mail/body_suffix"), RECDB_STRING_LIST);
-        if (extras) {
-            fputs("\n", out);
-            for (nn=0; nn<extras->used; nn++)
-                send_flowed_text(out, extras->list[nn]);
-        }
-
-        /* Close file (sending mail) and check for return code */
-        fflush(out);
-        fclose(out);
-        do {
-            rv = wait4(child, &res, 0, NULL);
-        } while ((rv == -1) && (errno == EINTR));
-        if (rv == child) {
-            /* accept the wait() result */
-        } else {
-            log_module(MAIN_LOG, LOG_ERROR, "sendmail() child to %s: Bad wait() return code %d: %s (%d)", to->email_addr, rv, strerror(errno), errno);
-            _exit(1);
-        }
-        if (res) {
-            log_module(MAIN_LOG, LOG_ERROR, "sendmail() grandchild to %s: Exited with code %d", to->email_addr, res);
-            _exit(1);
-        } else {
-            log_module(MAIN_LOG, LOG_INFO, "sendmail() sent email to %s <%s>: %s", to->handle, to->email_addr, subject);
-        }
-        _exit(0);
-    } else {
-        /* Grandchild; dup2 the fds and exec the mailer. */
-        const char *argv[10], *mpath;
-        unsigned int argc = 0;
-
-        /* Close the end of pipes we do not use. */
-        close(infds[1]);
-        close(outfds[0]);
-
-        dup2(infds[0], STDIN_FILENO);
-        dup2(outfds[1], STDOUT_FILENO);
-        mpath = conf_get_data("mail/mailer", RECDB_QSTRING);
-        if (!mpath) mpath = "/usr/sbin/sendmail";
-        argv[argc++] = mpath;
-        if (fromaddr) {
-            argv[argc++] = "-f";
-            argv[argc++] = fromaddr;
-        }
-        argv[argc++] = to->email_addr;
-        argv[argc++] = NULL;
-        if (execv(mpath, (char**)argv) < 0) {
-            log_module(MAIN_LOG, LOG_ERROR, "sendmail() grandchild to %s couldn't execv(): %s (%d)", to->email_addr, strerror(errno), errno);
-        }
-        _exit(1);
-    }
-}
-
-static int
-sendmail_ban_address(struct userNode *user, struct userNode *bot, const char *addr, const char *reason) {
-    dict_t target;
-    const char *str;
-
-    target = strpbrk(addr, "*?") ? prohibited_masks : prohibited_addrs;
-    if ((str = dict_find(target, addr, NULL))) {
-        if (user)
-            send_message(user, bot, "MAILMSG_EMAIL_ALREADY_BANNED", addr, str);
-        return 0;
-    }
-    dict_insert(target, strdup(addr), strdup(reason));
-    if (user) send_message(user, bot, "MAILMSG_EMAIL_BANNED", addr);
-    return 1;
-}
-
-static MODCMD_FUNC(cmd_banemail) {
-    char *reason = unsplit_string(argv+2, argc-2, NULL);
-    return sendmail_ban_address(user, cmd->parent->bot, argv[1], reason);
-}
-
-static MODCMD_FUNC(cmd_unbanemail) {
-    dict_t target;
-    const char *addr;
-
-    addr = argv[1];
-    target = strpbrk(addr, "*?") ? prohibited_masks : prohibited_addrs;
-    if (dict_remove(target, addr))
-        reply("MAILMSG_EMAIL_UNBANNED", addr);
-    else
-        reply("MAILMSG_EMAIL_NOT_BANNED", addr);
-    return 1;
-}
-
-static MODCMD_FUNC(cmd_stats_email) {
-    dict_iterator_t it;
-    int found = 0;
-
-    for (it=dict_first(prohibited_addrs); it; it=iter_next(it)) {
-        reply("MAILMSG_PROHIBITED_EMAIL", iter_key(it), (const char*)iter_data(it));
-        found = 1;
-    }
-    for (it=dict_first(prohibited_masks); it; it=iter_next(it)) {
-        reply("MAILMSG_PROHIBITED_EMAIL", iter_key(it), (const char*)iter_data(it));
-        found = 1;
-    }
-    if (!found)
-        reply("MAILMSG_NO_PROHIBITED_EMAIL");
-    return 0;
-}
-
-static int
-sendmail_saxdb_read(struct dict *db) {
-    struct dict *subdb;
-    struct record_data *rd;
-    dict_iterator_t it;
-
-    if ((subdb = database_get_data(db, KEY_PROHIBITED, RECDB_OBJECT))) {
-        for (it = dict_first(subdb); it; it = iter_next(it)) {
-            rd = iter_data(it);
-            if (rd->type == RECDB_QSTRING)
-                sendmail_ban_address(NULL, NULL, iter_key(it), rd->d.qstring);
-        }
-    }
-    return 0;
-}
-
-static int
-sendmail_saxdb_write(struct saxdb_context *ctx) {
-    dict_iterator_t it;
-
-    saxdb_start_record(ctx, KEY_PROHIBITED, 0);
-    for (it = dict_first(prohibited_masks); it; it = iter_next(it))
-        saxdb_write_string(ctx, iter_key(it), iter_data(it));
-    for (it = dict_first(prohibited_addrs); it; it = iter_next(it))
-        saxdb_write_string(ctx, iter_key(it), iter_data(it));
-    saxdb_end_record(ctx);
-    return 0;
-}
-
-static void
-sendmail_cleanup(void)
-{
-    dict_delete(prohibited_addrs);
-    dict_delete(prohibited_masks);
-}
-
-void
-sendmail_init(void)
-{
-    prohibited_addrs = dict_new();
-    dict_set_free_keys(prohibited_addrs, free);
-    dict_set_free_data(prohibited_addrs, free);
-    prohibited_masks = dict_new();
-    dict_set_free_keys(prohibited_masks, free);
-    dict_set_free_data(prohibited_masks, free);
-    reg_exit_func(sendmail_cleanup);
-    saxdb_register("sendmail", sendmail_saxdb_read, sendmail_saxdb_write);
-    sendmail_module = module_register("sendmail", MAIN_LOG, "sendmail.help", NULL);
-    modcmd_register(sendmail_module, "banemail", cmd_banemail, 3, 0, "level", "601", NULL);
-    modcmd_register(sendmail_module, "stats email", cmd_stats_email, 0, 0, "flags", "+oper", NULL);
-    modcmd_register(sendmail_module, "unbanemail", cmd_unbanemail, 2, 0, "level", "601", NULL);
-    message_register_table(msgtab);
-}
diff --git a/src/sendmail.h b/src/sendmail.h
deleted file mode 100644 (file)
index 2a11fc1..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* sendmail.h - mail sending utilities
- * Copyright 2002 srvx Development Team
- *
- * This file is part of srvx.
- *
- * srvx is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with srvx; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
- */
-
-#if !defined(SENDMAIL_H)
-#define SENDMAIL_H
-
-void sendmail_init(void);
-void sendmail(struct userNode *from, struct handle_info *to, const char *subject, const char *body, int first_time);
-const char *sendmail_prohibited_address(const char *addr);
-
-#endif
diff --git a/src/sendmail.help b/src/sendmail.help
deleted file mode 100644 (file)
index 6951b5a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-"BANEMAIL" ("/msg $S BANEMAIL <address> <reason>",
-        "Keeps srvx from sending mail to the address.  The address may be a real address, or a glob that uses * and ? wildcards.",
-        "This also prevents anyone from using matching addresses as their account email address.",
-        "$uSee Also:$u unbanemail, stats email");
-"UNBANEMAIL" ("/msg $S UNBANEMAIL <address>",
-        "Removes an email address (or glob) from the banned email address list.",
-        "$uSee Also:$u banemail, stats email");