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