* SpamAssassin connector is now configurable in <.A>ide <S>ysconfig <I>nternet.
authorArt Cancro <ajc@citadel.org>
Sat, 15 Jun 2002 04:52:26 +0000 (04:52 +0000)
committerArt Cancro <ajc@citadel.org>
Sat, 15 Jun 2002 04:52:26 +0000 (04:52 +0000)
* Allow more than one SA server (it'll try 'em all)
* Don't run SA for logged in users

citadel/ChangeLog
citadel/Makefile.in
citadel/domain.c
citadel/domain.h
citadel/routines2.c
citadel/serv_spam.c

index 66a6a018d9228c2e392c1ab610ca212c2e92158e..f94f86845e4361e531dffc1e647317c3ee4dca9f 100644 (file)
@@ -1,4 +1,9 @@
  $Log$
+ Revision 591.42  2002/06/15 04:52:26  ajc
+ * SpamAssassin connector is now configurable in <.A>ide <S>ysconfig <I>nternet.
+ * Allow more than one SA server (it'll try 'em all)
+ * Don't run SA for logged in users
+
  Revision 591.41  2002/06/14 20:42:56  ajc
  * Discovered that spamd works even without the Content-length: command, so I
    was able to redo the spam checker to work without a temp file.
@@ -3720,3 +3725,4 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
        * Initial CVS import
+
index 765e989bc87537ea2335f70f51479231cc152e93..59652a93cc96ea3fa9e94cf3b9fc8d7a2317b979 100644 (file)
@@ -128,10 +128,14 @@ SERV_OBJS = server_main.o
 
 parsedate.o: parsedate.c
 
-LIBSERV_OBJS = user_ops.lo citserver.lo sysdep.lo dynloader.lo tools.lo $(DATABASE:.c=.lo) \
-       control.lo policy.lo config.lo support.lo room_ops.lo file_ops.lo msgbase.lo \
-       locate_host.lo housekeeping.lo logging.lo mime_parser.lo html.lo internet_addressing.lo \
-       serv_crypto.lo parsedate.lo genstamp.lo clientsocket.lo $(AUTH) $(LIBOBJS:.o=.lo)
+LIBSERV_OBJS = user_ops.lo citserver.lo sysdep.lo dynloader.lo \
+       tools.lo $(DATABASE:.c=.lo) $(DOMAIN:.c=.lo) \
+       control.lo policy.lo config.lo support.lo room_ops.lo \
+       file_ops.lo msgbase.lo \
+       locate_host.lo housekeeping.lo logging.lo mime_parser.lo html.lo \
+       internet_addressing.lo \
+       serv_crypto.lo parsedate.lo genstamp.lo \
+       clientsocket.lo $(AUTH) $(LIBOBJS:.o=.lo)
 
 libcitserver.la: $(LIBSERV_OBJS)
        $(LIBTOOL) $(CC) $(LDFLAGS) -rpath $(prefix) -no-undefined \
@@ -158,10 +162,10 @@ modules/libpop3.la: serv_pop3.lo md5.lo $(LIBTOOL) libcitserver.la
        $(LTSHARE) -o libpop3.la ../serv_pop3.lo ../md5.lo ../libcitserver.la
 
 modules/libmrtg.la: serv_mrtg.lo md5.lo $(LIBTOOL) libcitserver.la
-       $(LTSHARE) -o libmrtg.la ../serv_mrtg.lo ../md5.lo ../libcitserver.la
+       $(LTSHARE) -o libmrtg.la ../serv_mrtg.lo ../libcitserver.la
 
 modules/libspam.la: serv_spam.lo md5.lo $(LIBTOOL) libcitserver.la
-       $(LTSHARE) -o libspam.la ../serv_spam.lo ../md5.lo ../libcitserver.la
+       $(LTSHARE) -o libspam.la ../serv_spam.lo ../libcitserver.la
 
 modules/libinetcfg.la: serv_inetcfg.lo $(LIBTOOL) libcitserver.la
        $(LTSHARE) -o libinetcfg.la ../serv_inetcfg.lo ../libcitserver.la
index cbbe27834301034791a57b4f3d9e4c731e2128d1..0d276626c1f8116cbab5e15b841705a2d54f236d 100644 (file)
 
 
 /*
- * get_smarthosts() checks the Internet configuration for "smarthost"
+ * get_hosts() checks the Internet configuration for various types of
  * entries and returns them in the same format as getmx() does -- fill the
  * buffer with a delimited list of hosts and return the number of hosts.
+ * 
+ * This is used to fetch MX smarthosts, SpamAssassin hosts, etc.
  */
-int get_smarthosts(char *mxbuf) {
+int get_hosts(char *mxbuf, char *rectype) {
        int config_lines;
        int i;
        char buf[SIZ];
@@ -41,7 +43,7 @@ int get_smarthosts(char *mxbuf) {
                extract_token(host, buf, 0, '|');
                extract_token(type, buf, 1, '|');
 
-               if (!strcasecmp(type, "smarthost")) {
+               if (!strcasecmp(type, rectype)) {
                        strcat(mxbuf, host);
                        strcat(mxbuf, "|");
                        ++total_smarthosts;
@@ -125,7 +127,7 @@ int getmx(char *mxbuf, char *dest) {
        /* If we're configured to send all mail to a smart-host, then our
         * job here is really easy.
         */
-       n = get_smarthosts(mxbuf);
+       n = get_hosts(mxbuf, "smarthost");
        if (n > 0) return(n);
 
        /*
index de70f81749d4e3aa65469d6dec76f35d45ca6a94..5900cf7d13506627016448f655645bdb6c6f3efe 100644 (file)
@@ -8,8 +8,8 @@ struct mx {
        char host[1024];
 };
 
-int get_smarthosts(char *mxbuf);
 int getmx(char *mxbuf, char *dest);
+int get_hosts(char *mxbuf, char *rectype);
 
 
 /* HP/UX has old include files...these are from arpa/nameser.h */
index 77d36c5758df3bb23a7a3d6d7913bd0c7946c4d8..50d7cfbb206e4d85f7ec6f66803c84b3392ea99a 100644 (file)
@@ -846,7 +846,8 @@ void get_inet_rec_type(char *buf) {
        keyopt(" <2> gateway domain (Domain for all Citadel systems)\n");
        keyopt(" <3> smart-host     (Forward all outbound mail to this host)\n");
        keyopt(" <4> directory      (Consult the Global Address Book)\n");
-       sel = intprompt("Which one", 1, 1, 4);
+       keyopt(" <5> SpamAssassin   (Address of SpamAssassin server)\n");
+       sel = intprompt("Which one", 1, 1, 5);
        switch(sel) {
                case 1: strcpy(buf, "localhost");
                        return;
@@ -856,6 +857,8 @@ void get_inet_rec_type(char *buf) {
                        return;
                case 4: strcpy(buf, "directory");
                        return;
+               case 5: strcpy(buf, "spamassassin");
+                       return;
        }
 }
 
index 3ecc360bd7337ad120fc9adf2949c0222c236bbf..2e362ba7fe5ecc9f7b27471dccbb7dab59279134 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>
 #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,15 +100,30 @@ int spam_filter(struct CtdlMessage *msg) {
  */
 int spam_assassin(struct CtdlMessage *msg) {
        int sock = (-1);
+       char sahosts[SIZ];
+       int num_sahosts;
        char buf[SIZ];
        int is_spam = 0;
+       int sa;
 
-#define SPAMASSASSIN_HOST      "127.0.0.1"
-#define SPAMASSASSIN_PORT      "783"
+       /* 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(9, "Connecting to SpamAssassin at <%s>\n", buf);
+                sock = sock_connect(buf, SPAMASSASSIN_PORT, "tcp");
+                if (sock >= 0) lprintf(9, "Connected!\n");
+                if (sock >= 0) break;
+        }
 
-       /* 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.
@@ -111,10 +134,7 @@ int spam_assassin(struct CtdlMessage *msg) {
        /* Command */
        lprintf(9, "Transmitting command\n");
        sprintf(buf, "CHECK SPAMC/1.2\r\n\r\n");
-       lprintf(9, buf);
-       lprintf(9, "sock_write() returned %d\n",
-               sock_write(sock, buf, strlen(buf))
-       );
+       sock_write(sock, buf, strlen(buf));
 
        /* Message */
        CtdlRedirectOutput(NULL, sock);
@@ -124,9 +144,7 @@ int spam_assassin(struct CtdlMessage *msg) {
        /* 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");
@@ -162,14 +180,11 @@ bail:     close(sock);
 char *Dynamic_Module_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$";
 }