]> code.citadel.org Git - citadel.git/blobdiff - citadel/serv_spam.c
* Use syslog-compatible logging levels in lprintf(); the loglevel chosen
[citadel.git] / citadel / serv_spam.c
index 17074b46c5668d612197a755d1d6f7be614cc973..fd14ad0ac8678c8039e480d7b2d080b27c6f2da6 100644 (file)
@@ -1,11 +1,13 @@
 /*
  * $Id$
  *
- * Reject incoming SMTP messages containing strings that tell us that the
- * message is probably spam.
- *
+ * This module allows Citadel to use SpamAssassin to filter incoming messages
+ * arriving via SMTP.  For more information on SpamAssassin, visit
+ * http://www.spamassassin.org (the SpamAssassin project is not in any way
+ * affiliated with the Citadel project).
  */
 
+#define SPAMASSASSIN_PORT       "783"
 
 #include "sysdep.h"
 #include <stdlib.h>
@@ -39,7 +41,7 @@
 #include "support.h"
 #include "config.h"
 #include "control.h"
-#include "dynloader.h"
+#include "serv_extensions.h"
 #include "room_ops.h"
 #include "user_ops.h"
 #include "policy.h"
 #include "msgbase.h"
 #include "tools.h"
 #include "internet_addressing.h"
+#include "domain.h"
 #include "clientsocket.h"
 
 
 
+/* 
+ * This is a scanner I had started writing before deciding to just farm the
+ * job out to SpamAssassin.  It *does* work but it's not in use.  We've
+ * commented it out so it doesn't even compile.
+ */
 #ifdef ___NOT_CURRENTLY_IN_USE___
 /* Scan a message for spam */
 int spam_filter(struct CtdlMessage *msg) {
@@ -92,21 +100,29 @@ int spam_filter(struct CtdlMessage *msg) {
  */
 int spam_assassin(struct CtdlMessage *msg) {
        int sock = (-1);
+       char sahosts[SIZ];
+       int num_sahosts;
        char buf[SIZ];
-       FILE *msg_fp;
-       long content_length;
-       long block_length;
        int is_spam = 0;
+       int sa;
 
-#define SPAMASSASSIN_HOST      "127.0.0.1"
-#define SPAMASSASSIN_PORT      "783"
-
-       msg_fp = tmpfile();
-       if (msg_fp == NULL) return(0);
+       /* For users who have authenticated to this server we never want to
+        * apply spam filtering, because presumably they're trustworthy.
+        */
+       if (CC->logged_in) return(0);
+
+       /* See if we have any SpamAssassin hosts configured */
+       num_sahosts = get_hosts(sahosts, "spamassassin");
+       if (num_sahosts < 1) return(0);
+
+       /* Try them one by one until we get a working one */
+        for (sa=0; sa<num_sahosts; ++sa) {
+                extract(buf, sahosts, sa);
+                lprintf(CTDL_INFO, "Connecting to SpamAssassin at <%s>\n", buf);
+                sock = sock_connect(buf, SPAMASSASSIN_PORT, "tcp");
+                if (sock >= 0) lprintf(CTDL_DEBUG, "Connected!\n");
+        }
 
-       /* Connect to the SpamAssassin server */
-       lprintf(9, "Connecting to SpamAssassin\n");
-       sock = sock_connect(SPAMASSASSIN_HOST, SPAMASSASSIN_PORT, "tcp");
        if (sock < 0) {
                /* If the service isn't running, just pass the mail
                 * through.  Potentially throwing away mails isn't good.
@@ -114,59 +130,34 @@ int spam_assassin(struct CtdlMessage *msg) {
                return(0);
        }
 
-       /* Measure the message (I don't like doing this with a tempfile
-          but right now it's the only way)
-        */
-       lprintf(9, "Measuring message\n");
-       CtdlRedirectOutput(msg_fp, -1);
-       CtdlOutputPreLoadedMsg(msg, 0L, MT_RFC822, 0, 0, 1);
-       CtdlRedirectOutput(NULL, -1);
-       fseek(msg_fp, 0L, SEEK_END);
-       content_length = ftell(msg_fp);
-       rewind(msg_fp);
-       lprintf(9, "Content-length is %ld\n", content_length);
-
        /* Command */
-       lprintf(9, "Transmitting command\n");
-       sprintf(buf, "CHECK SPAMC/1.2\r\nContent-length: %ld\r\n\r\n",
-               content_length);
-       lprintf(9, buf);
-       lprintf(9, "sock_write() returned %d\n",
-               sock_write(sock, buf, strlen(buf))
-       );
-       while (content_length > 0) {
-               block_length = sizeof(buf);
-               if (block_length > content_length) {
-                       block_length = content_length;
-               }
-               fread(buf, block_length, 1, msg_fp);
-               sock_write(sock, buf, block_length);
-               content_length -= block_length;
-               lprintf(9, "Wrote %ld bytes (%ld remaining)\n",
-                       block_length, content_length);
-       }
-       fclose(msg_fp); /* this also deletes the file */
+       lprintf(CTDL_DEBUG, "Transmitting command\n");
+       sprintf(buf, "CHECK SPAMC/1.2\r\n\r\n");
+       sock_write(sock, buf, strlen(buf));
+
+       /* Message */
+       CtdlRedirectOutput(NULL, sock);
+       CtdlOutputPreLoadedMsg(msg, 0L, MT_RFC822, HEADERS_ALL, 0, 1);
+       CtdlRedirectOutput(NULL, -1);
 
        /* Close one end of the socket connection; this tells SpamAssassin
         * that we're done.
         */
-       lprintf(9, "sock_shutdown() returned %d\n", 
-               sock_shutdown(sock, SHUT_WR)
-       );
+       sock_shutdown(sock, SHUT_WR);
        
        /* Response */
-       lprintf(9, "Awaiting response\n");
+       lprintf(CTDL_DEBUG, "Awaiting response\n");
         if (sock_gets(sock, buf) < 0) {
                 goto bail;
         }
-        lprintf(9, "<%s\n", buf);
+        lprintf(CTDL_DEBUG, "<%s\n", buf);
        if (strncasecmp(buf, "SPAMD", 5)) {
                goto bail;
        }
         if (sock_gets(sock, buf) < 0) {
                 goto bail;
         }
-        lprintf(9, "<%s\n", buf);
+        lprintf(CTDL_DEBUG, "<%s\n", buf);
        if (!strncasecmp(buf, "Spam: True", 10)) {
                is_spam = 1;
        }
@@ -176,7 +167,7 @@ int spam_assassin(struct CtdlMessage *msg) {
                        phree(msg->cm_fields['0']);
                }
                msg->cm_fields['0'] = strdoop(
-                       "Message rejected by SpamAssassin");
+                       "5.7.1 Message rejected by SpamAssassin");
        }
 
 bail:  close(sock);
@@ -185,17 +176,14 @@ bail:     close(sock);
 
 
 
-char *Dynamic_Module_Init(void)
+char *serv_spam_init(void)
 {
 
-/* ** This one isn't in use.  It's a spam filter I wrote, but we're going to
-      try the SpamAssassin stuff instead.
+/* (disabled built-in scanner, see above)
        CtdlRegisterMessageHook(spam_filter, EVT_SMTPSCAN);
  */
 
-
        CtdlRegisterMessageHook(spam_assassin, EVT_SMTPSCAN);
 
-
         return "$Id$";
 }