]> code.citadel.org Git - citadel.git/blob - citadel/serv_spam.c
* Discovered that spamd works even without the Content-length: command, so I
[citadel.git] / citadel / serv_spam.c
1 /*
2  * $Id$
3  *
4  * Reject incoming SMTP messages containing strings that tell us that the
5  * message is probably spam.
6  *
7  */
8
9
10 #include "sysdep.h"
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <signal.h>
16 #include <pwd.h>
17 #include <errno.h>
18 #include <sys/types.h>
19
20 #if TIME_WITH_SYS_TIME
21 # include <sys/time.h>
22 # include <time.h>
23 #else
24 # if HAVE_SYS_TIME_H
25 #  include <sys/time.h>
26 # else
27 #  include <time.h>
28 # endif
29 #endif
30
31 #include <sys/wait.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <sys/socket.h>
35 #include "citadel.h"
36 #include "server.h"
37 #include "sysdep_decls.h"
38 #include "citserver.h"
39 #include "support.h"
40 #include "config.h"
41 #include "control.h"
42 #include "dynloader.h"
43 #include "room_ops.h"
44 #include "user_ops.h"
45 #include "policy.h"
46 #include "database.h"
47 #include "msgbase.h"
48 #include "tools.h"
49 #include "internet_addressing.h"
50 #include "clientsocket.h"
51
52
53
54 #ifdef ___NOT_CURRENTLY_IN_USE___
55 /* Scan a message for spam */
56 int spam_filter(struct CtdlMessage *msg) {
57         int spam_strings_found = 0;
58         struct spamstrings_t *sptr;
59         char *ptr;
60
61         /* Bail out if there's no message text */
62         if (msg->cm_fields['M'] == NULL) return(0);
63
64
65         /* Scan! */
66         ptr = msg->cm_fields['M'];
67         while (ptr++[0] != 0) {
68                 for (sptr = spamstrings; sptr != NULL; sptr = sptr->next) {
69                         if (!strncasecmp(ptr, sptr->string,
70                            strlen(sptr->string))) {
71                                 ++spam_strings_found;
72                         }
73                 }
74         }
75
76         if (spam_strings_found) {
77                 if (msg->cm_fields['0'] != NULL) {
78                         phree(msg->cm_fields['0']);
79                 }
80                 msg->cm_fields['0'] = strdoop("Unsolicited spam rejected");
81                 return(spam_strings_found);
82         }
83
84         return(0);
85 }
86 #endif
87
88
89
90 /*
91  * Connect to the SpamAssassin server and scan a message.
92  */
93 int spam_assassin(struct CtdlMessage *msg) {
94         int sock = (-1);
95         char buf[SIZ];
96         int is_spam = 0;
97
98 #define SPAMASSASSIN_HOST       "127.0.0.1"
99 #define SPAMASSASSIN_PORT       "783"
100
101         /* Connect to the SpamAssassin server */
102         lprintf(9, "Connecting to SpamAssassin\n");
103         sock = sock_connect(SPAMASSASSIN_HOST, SPAMASSASSIN_PORT, "tcp");
104         if (sock < 0) {
105                 /* If the service isn't running, just pass the mail
106                  * through.  Potentially throwing away mails isn't good.
107                  */
108                 return(0);
109         }
110
111         /* Command */
112         lprintf(9, "Transmitting command\n");
113         sprintf(buf, "CHECK SPAMC/1.2\r\n\r\n");
114         lprintf(9, buf);
115         lprintf(9, "sock_write() returned %d\n",
116                 sock_write(sock, buf, strlen(buf))
117         );
118
119         /* Message */
120         CtdlRedirectOutput(NULL, sock);
121         CtdlOutputPreLoadedMsg(msg, 0L, MT_RFC822, 0, 0, 1);
122         CtdlRedirectOutput(NULL, -1);
123
124         /* Close one end of the socket connection; this tells SpamAssassin
125          * that we're done.
126          */
127         lprintf(9, "sock_shutdown() returned %d\n", 
128                 sock_shutdown(sock, SHUT_WR)
129         );
130         
131         /* Response */
132         lprintf(9, "Awaiting response\n");
133         if (sock_gets(sock, buf) < 0) {
134                 goto bail;
135         }
136         lprintf(9, "<%s\n", buf);
137         if (strncasecmp(buf, "SPAMD", 5)) {
138                 goto bail;
139         }
140         if (sock_gets(sock, buf) < 0) {
141                 goto bail;
142         }
143         lprintf(9, "<%s\n", buf);
144         if (!strncasecmp(buf, "Spam: True", 10)) {
145                 is_spam = 1;
146         }
147
148         if (is_spam) {
149                 if (msg->cm_fields['0'] != NULL) {
150                         phree(msg->cm_fields['0']);
151                 }
152                 msg->cm_fields['0'] = strdoop(
153                         "Message rejected by SpamAssassin");
154         }
155
156 bail:   close(sock);
157         return(is_spam);
158 }
159
160
161
162 char *Dynamic_Module_Init(void)
163 {
164
165 /* ** This one isn't in use.  It's a spam filter I wrote, but we're going to
166       try the SpamAssassin stuff instead.
167         CtdlRegisterMessageHook(spam_filter, EVT_SMTPSCAN);
168  */
169
170
171         CtdlRegisterMessageHook(spam_assassin, EVT_SMTPSCAN);
172
173
174         return "$Id$";
175 }