e0f478f6c79042cdf80541004ec6b1943d073482
[citadel.git] / citadel / modules / dspam / serv_dspam.c
1 /*
2  * $Id: serv_dspam.c 5876 2007-12-10 23:22:03Z dothebart $
3  *
4  * This module glues libDSpam to the Citadel server in order to implement
5  * DSPAM Spamchecking 
6  *
7  * This code is released under the terms of the GNU General Public License. 
8  */
9
10 #include "sysdep.h"
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <ctype.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 <libcitadel.h>
35 #include "citadel.h"
36 #include "server.h"
37 #include "citserver.h"
38 #include "support.h"
39 #include "config.h"
40 #include "room_ops.h"
41 #include "policy.h"
42 #include "database.h"
43 #include "msgbase.h"
44 #include "internet_addressing.h"
45
46
47 #include "ctdl_module.h"
48
49
50 #ifdef HAVE_LIBDSPAM
51 #define CONFIG_DEFAULT file_dpsam_conf
52 #define LOGDIR file_dspam_log
53
54
55 //#define HAVE_CONFIG_H
56 #include <dspam/libdspam.h>
57 //#define HAVE_CONFIG_H
58
59 typedef struct stringlist stringlist;
60
61 struct stringlist {
62         char *Str;
63         long len;
64         stringlist *Next;
65 };
66         
67
68 /*
69  * Citadel protocol to manage sieve scripts.
70  * This is basically a simplified (read: doesn't resemble IMAP) version
71  * of the 'managesieve' protocol.
72  */
73 void cmd_tspam(char *argbuf) {
74         char buf[SIZ];
75         long len;
76         long count;
77         stringlist *Messages; 
78         stringlist *NextMsg; 
79
80         Messages = NULL;
81         NextMsg = NULL;
82         count = 0;
83         if (CtdlAccessCheck(ac_room_aide)) return;
84         if (atoi(argbuf) == 0) {
85                 cprintf("%d Ok.\n", CIT_OK);
86                 return;
87         }
88         cprintf("%d Send info...\n", SEND_LISTING);
89
90         do {
91                 len = client_getln(buf, sizeof buf);
92                 if (strcmp(buf, "000")) {
93                         if (Messages == NULL) {
94                                 Messages = malloc (sizeof (stringlist));
95                                 NextMsg = Messages;
96                         }
97                         else {
98                                 Messages->Next = malloc (sizeof (stringlist));
99                                 NextMsg = NextMsg->Next;
100                         }
101                         NextMsg->Next = NULL;
102                         NextMsg->Str = malloc (len+1);
103                         NextMsg->len = len;
104                         memcpy (NextMsg->Str, buf, len + 1);/// maybe split spam /ham per line?
105                         count++;
106                 }
107         } while (strcmp(buf, "000"));
108 /// is there a way to filter foreachmessage by a list?
109         /* tag mails as spam or Ham */
110         /* probably do: dspam_init(ctdl_dspam_dir); dspam_process dspam_addattribute; dspam_destroy*/
111         // extract DSS_ERROR or DSS_CORPUS from the commandline. error->ham; corpus -> spam?
112         /// todo: send answer listing...
113 }
114
115
116
117 void ctdl_dspam_init(void) {
118
119 ///     libdspam_init("bdb");/* <which database backend do we prefer? */
120
121 }
122
123 void dspam_do_msg(long msgnum, void *userdata) 
124 {
125         char *msgtext;
126         DSPAM_CTX *CTX;                 /* DSPAM Context */
127         struct CtdlMessage *msg;
128         struct _ds_spam_signature SIG;        /* signature */
129
130         CTX = *(DSPAM_CTX**) userdata;
131         msg = CtdlFetchMessage(msgnum, 0);
132         if (msg == NULL) return;
133
134
135         /* Message */
136         CC->redirect_buffer = malloc(SIZ);
137         CC->redirect_len = 0;
138         CC->redirect_alloc = SIZ;
139         CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1);
140         msgtext = CC->redirect_buffer;
141 // don't need?  msglen = CC->redirect_len;
142         CC->redirect_buffer = NULL;
143         CC->redirect_len = 0;
144         CC->redirect_alloc = 0;
145
146         /* Call DSPAM's processor with the message text */
147         if (dspam_process (CTX, msgtext) != 0)
148         {
149                 free(msgtext);
150                 CtdlLogPrintf(CTDL_CRIT, "ERROR: dspam_process failed");
151                 return;
152         }
153         if (CTX->signature == NULL)
154         {
155                 CtdlLogPrintf(CTDL_CRIT,"No signature provided\n");
156         }
157         else
158         {
159 /* Copy to a safe place */
160
161                 msg->cm_fields['G'] = malloc (CTX->signature->length * 2);
162                 CtdlEncodeBase64(msg->cm_fields['G'], CTX->signature->data, CTX->signature->length, 0);
163         }
164         free(msgtext);
165
166         SIG.length = CTX->signature->length;
167         /* Print processing results */
168         CtdlLogPrintf (CTDL_DEBUG, "Probability: %2.4f Confidence: %2.4f, Result: %s\n",
169                 CTX->probability,
170                 CTX->confidence,
171                 (CTX->result == DSR_ISSPAM) ? "Spam" : "Innocent");
172
173         //// todo: put signature into the citadel message
174         //// todo: save message; destroy message.
175 }
176
177 int serv_dspam_room(struct ctdlroom *room)
178 {
179         DSPAM_CTX *CTX;                 /* DSPAM Context */
180
181         /* scan for spam; do */
182         /* probably do: dspam_init; dspam_process dspam_addattribute; dspam_destroy*/
183 //DSS_NONE
184 //#define       DSR_ISSPAM              0x01
185 //#define DSR_ISINNOCENT                0x02
186 // dspam_init (cc->username, NULL, ctdl_dspam_home, DSM_PROCESS,
187         //                  DSF_SIGNATURE | DSF_NOISE);
188         /// todo: if roomname = spam / ham -> learn!
189         if ((room->QRflags & QR_PRIVATE) &&/* Are we sending to a private mailbox? */
190             (strstr(room->QRname, ".Mail")!=NULL))
191
192         {
193                 char User[64];
194                 // maybe we should better get our realname here?
195                 snprintf(User, 64, "%ld", room->QRroomaide);
196                 extract_token(User, room->QRname, 0, '.', sizeof(User));
197                 CTX = dspam_init(User, 
198                                  NULL,
199                                  ctdl_dspam_dir, 
200                                  DSM_PROCESS, 
201                                  DSF_SIGNATURE | DSF_NOISE);
202         }
203         else return 0;//// 
204         /// else -> todo: global user for public rooms etc.
205         if (CTX == NULL)
206         {
207                 CtdlLogPrintf(CTDL_CRIT, "ERROR: dspam_init failed!\n");
208                 return ERROR + INTERNAL_ERROR;
209         }
210         /* Use graham and robinson algorithms, graham's p-values */
211         CTX->algorithms = DSA_GRAHAM | DSA_BURTON | DSP_GRAHAM;
212
213         /* Use CHAIN tokenizer */
214         CTX->tokenizer = DSZ_CHAIN;
215
216         CtdlForEachMessage(MSGS_GT, 1, NULL, NULL, NULL,
217                            dspam_do_msg,
218                            (void *) &CTX);
219
220         return 0;
221 }
222
223 void serv_dspam_shutdown (void)
224 {
225         libdspam_shutdown ();
226 }
227 #endif  /* HAVE_LIBDSPAM */
228
229 CTDL_MODULE_INIT(dspam)
230 {
231         return "$Id: serv_dspam.c 5876 2007-12-10 23:22:03Z dothebart $" "disabled.";
232         if (!threading)
233         {
234 #ifdef HAVE_LIBDSPAM
235
236                 ctdl_dspam_init();
237                 CtdlRegisterCleanupHook(serv_dspam_shutdown);
238                 CtdlRegisterProtoHook(cmd_tspam, "SPAM", "Tag Message as Spam/Ham to learn DSPAM");
239
240                 CtdlRegisterRoomHook(serv_dspam_room);
241
242                 ///CtdlRegisterSessionHook(perform_dspam_processing, EVT_HOUSE);
243
244 #else   /* HAVE_LIBDSPAM */
245
246                 CtdlLogPrintf(CTDL_INFO, "This server is missing libdspam Spam filtering will be disabled.\n");
247
248 #endif  /* HAVE_LIBDSPAM */
249         }
250         
251         /* return our Subversion id for the Log */
252         return "$Id: serv_dspam.c 5876 2007-12-10 23:22:03Z dothebart $";
253 }
254