]> code.citadel.org Git - citadel.git/blob - citadel/serv_spam.c
* Disabled the spam strings checker I wrote a few days ago.
[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         FILE *msg_fp;
97         long content_length;
98         long block_length;
99         int is_spam = 0;
100
101 #define SPAMASSASSIN_HOST       "127.0.0.1"
102 #define SPAMASSASSIN_PORT       "783"
103
104         msg_fp = tmpfile();
105         if (msg_fp == NULL) return(0);
106
107         /* Connect to the SpamAssassin server */
108         lprintf(9, "Connecting to SpamAssassin\n");
109         sock = sock_connect(SPAMASSASSIN_HOST, SPAMASSASSIN_PORT, "tcp");
110         if (sock < 0) {
111                 /* If the service isn't running, just pass the mail
112                  * through.  Potentially throwing away mails isn't good.
113                  */
114                 return(0);
115         }
116
117         /* Measure the message (I don't like doing this with a tempfile
118            but right now it's the only way)
119          */
120         lprintf(9, "Measuring message\n");
121         CtdlRedirectOutput(msg_fp, -1);
122         CtdlOutputPreLoadedMsg(msg, 0L, MT_RFC822, 0, 0, 1);
123         CtdlRedirectOutput(NULL, -1);
124         fseek(msg_fp, 0L, SEEK_END);
125         content_length = ftell(msg_fp);
126         rewind(msg_fp);
127         lprintf(9, "Content-length is %ld\n", content_length);
128
129         /* Command */
130         lprintf(9, "Transmitting command\n");
131         sprintf(buf, "CHECK SPAMC/1.2\r\nContent-length: %ld\r\n\r\n",
132                 content_length);
133         lprintf(9, buf);
134         lprintf(9, "sock_write() returned %d\n",
135                 sock_write(sock, buf, strlen(buf))
136         );
137         while (content_length > 0) {
138                 block_length = sizeof(buf);
139                 if (block_length > content_length) {
140                         block_length = content_length;
141                 }
142                 fread(buf, block_length, 1, msg_fp);
143                 sock_write(sock, buf, block_length);
144                 content_length -= block_length;
145                 lprintf(9, "Wrote %ld bytes (%ld remaining)\n",
146                         block_length, content_length);
147         }
148         fclose(msg_fp); /* this also deletes the file */
149
150         /* Close one end of the socket connection; this tells SpamAssassin
151          * that we're done.
152          */
153         lprintf(9, "sock_shutdown() returned %d\n", 
154                 sock_shutdown(sock, SHUT_WR)
155         );
156         
157         /* Response */
158         lprintf(9, "Awaiting response\n");
159         if (sock_gets(sock, buf) < 0) {
160                 goto bail;
161         }
162         lprintf(9, "<%s\n", buf);
163         if (strncasecmp(buf, "SPAMD", 5)) {
164                 goto bail;
165         }
166         if (sock_gets(sock, buf) < 0) {
167                 goto bail;
168         }
169         lprintf(9, "<%s\n", buf);
170         if (!strncasecmp(buf, "Spam: True", 10)) {
171                 is_spam = 1;
172         }
173
174         if (is_spam) {
175                 if (msg->cm_fields['0'] != NULL) {
176                         phree(msg->cm_fields['0']);
177                 }
178                 msg->cm_fields['0'] = strdoop(
179                         "Message rejected by SpamAssassin");
180         }
181
182 bail:   close(sock);
183         return(is_spam);
184 }
185
186
187
188 char *Dynamic_Module_Init(void)
189 {
190
191 /* ** This one isn't in use.  It's a spam filter I wrote, but we're going to
192       try the SpamAssassin stuff instead.
193         CtdlRegisterMessageHook(spam_filter, EVT_SMTPSCAN);
194  */
195
196
197         CtdlRegisterMessageHook(spam_assassin, EVT_SMTPSCAN);
198
199
200         return "$Id$";
201 }