2 * This module glues libDSpam to the Citadel server in order to implement
5 * Copyright (c) 2012 by the citadel.org team
7 * This program is open source software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 3.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
30 #include <sys/types.h>
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
37 # include <sys/time.h>
46 #include <libcitadel.h>
49 #include "citserver.h"
54 #include "internet_addressing.h"
57 #include "ctdl_module.h"
61 #define CONFIG_DEFAULT file_dpsam_conf
62 #define LOGDIR file_dspam_log
65 //#define HAVE_CONFIG_H
66 #include <dspam/libdspam.h>
67 //#define HAVE_CONFIG_H
69 typedef struct stringlist stringlist;
79 * Citadel protocol to manage sieve scripts.
80 * This is basically a simplified (read: doesn't resemble IMAP) version
81 * of the 'managesieve' protocol.
83 void cmd_tspam(char *argbuf) {
93 if (CtdlAccessCheck(ac_room_aide)) return;
94 if (atoi(argbuf) == 0) {
95 cprintf("%d Ok.\n", CIT_OK);
98 cprintf("%d Send info...\n", SEND_LISTING);
101 len = client_getln(buf, sizeof buf);
102 if (strcmp(buf, "000")) {
103 if (Messages == NULL) {
104 Messages = malloc (sizeof (stringlist));
108 Messages->Next = malloc (sizeof (stringlist));
109 NextMsg = NextMsg->Next;
111 NextMsg->Next = NULL;
112 NextMsg->Str = malloc (len+1);
114 memcpy (NextMsg->Str, buf, len + 1);/// maybe split spam /ham per line?
117 } while (strcmp(buf, "000"));
118 /// is there a way to filter foreachmessage by a list?
119 /* tag mails as spam or Ham */
120 /* probably do: dspam_init(ctdl_dspam_dir); dspam_process dspam_addattribute; dspam_destroy*/
121 // extract DSS_ERROR or DSS_CORPUS from the commandline. error->ham; corpus -> spam?
122 /// todo: send answer listing...
127 void ctdl_dspam_init(void) {
129 /// libdspam_init("bdb");/* <which database backend do we prefer? */
133 void dspam_do_msg(long msgnum, void *userdata)
136 DSPAM_CTX *CTX; /* DSPAM Context */
137 struct CtdlMessage *msg;
138 struct _ds_spam_signature SIG; /* signature */
140 CTX = *(DSPAM_CTX**) userdata;
141 msg = CtdlFetchMessage(msgnum, 0);
142 if (msg == NULL) return;
146 CC->redirect_buffer = malloc(SIZ);
147 CC->redirect_len = 0;
148 CC->redirect_alloc = SIZ;
149 CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, 0);
150 msgtext = CC->redirect_buffer;
151 // don't need? msglen = CC->redirect_len;
152 CC->redirect_buffer = NULL;
153 CC->redirect_len = 0;
154 CC->redirect_alloc = 0;
156 /* Call DSPAM's processor with the message text */
157 if (dspam_process (CTX, msgtext) != 0)
160 syslog(LOG_CRIT, "ERROR: dspam_process failed");
163 if (CTX->signature == NULL)
165 syslog(LOG_CRIT,"No signature provided\n");
169 /* Copy to a safe place */
170 // TODO: len -> cm_fields?
171 msg->cm_fields[eErrorMsg] = malloc (CTX->signature->length * 2);
172 size_t len = CtdlEncodeBase64(msg->cm_fields[eErrorMsg], CTX->signature->data, CTX->signature->length, 0);
174 if (msg->cm_fields[eErrorMsg][len - 1] == '\n') {
175 msg->cm_fields[eErrorMsg][len - 1] = '\0';
180 SIG.length = CTX->signature->length;
181 /* Print processing results */
182 syslog(LOG_DEBUG, "Probability: %2.4f Confidence: %2.4f, Result: %s\n",
185 (CTX->result == DSR_ISSPAM) ? "Spam" : "Innocent");
187 //// todo: put signature into the citadel message
188 //// todo: save message; destroy message.
191 int serv_dspam_room(struct ctdlroom *room)
193 DSPAM_CTX *CTX; /* DSPAM Context */
195 /* scan for spam; do */
196 /* probably do: dspam_init; dspam_process dspam_addattribute; dspam_destroy*/
198 //#define DSR_ISSPAM 0x01
199 //#define DSR_ISINNOCENT 0x02
200 // dspam_init (cc->username, NULL, ctdl_dspam_home, DSM_PROCESS,
201 // DSF_SIGNATURE | DSF_NOISE);
202 /// todo: if roomname = spam / ham -> learn!
203 if ((room->QRflags & QR_PRIVATE) &&/* Are we sending to a private mailbox? */
204 (strstr(room->QRname, ".Mail")!=NULL))
208 // maybe we should better get our realname here?
209 snprintf(User, 64, "%ld", room->QRroomaide);
210 extract_token(User, room->QRname, 0, '.', sizeof(User));
211 CTX = dspam_init(User,
215 DSF_SIGNATURE | DSF_NOISE);
218 /// else -> todo: global user for public rooms etc.
221 syslog(LOG_CRIT, "ERROR: dspam_init failed!\n");
222 return ERROR + INTERNAL_ERROR;
224 /* Use graham and robinson algorithms, graham's p-values */
225 CTX->algorithms = DSA_GRAHAM | DSA_BURTON | DSP_GRAHAM;
227 /* Use CHAIN tokenizer */
228 CTX->tokenizer = DSZ_CHAIN;
230 CtdlForEachMessage(MSGS_GT, 1, NULL, NULL, NULL,
237 void serv_dspam_shutdown (void)
239 libdspam_shutdown ();
241 #endif /* HAVE_LIBDSPAM */
243 CTDL_MODULE_INIT(dspam)
251 CtdlRegisterCleanupHook(serv_dspam_shutdown);
252 CtdlRegisterProtoHook(cmd_tspam, "SPAM", "Tag Message as Spam/Ham to learn DSPAM");
254 CtdlRegisterRoomHook(serv_dspam_room);
256 ///CtdlRegisterSessionHook(perform_dspam_processing, EVT_HOUSE);
258 #else /* HAVE_LIBDSPAM */
260 syslog(LOG_INFO, "This server is missing libdspam Spam filtering will be disabled.\n");
262 #endif /* HAVE_LIBDSPAM */
265 /* return our module name for the log */