]> jfr.im git - irc/evilnet/x3.git/blame - src/spamserv.c
make chanserv.c use global_message_args
[irc/evilnet/x3.git] / src / spamserv.c
CommitLineData
63c95a47 1/* spamserv.c - anti spam service
2 * Copyright 2004 feigling
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version. Important limitations are
8 * listed in the COPYING file that accompanies this software.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, email evilnet-devel@lists.sourceforge.net.
17 *
18 * $Id$
19 */
20
21#include "conf.h"
22#include "spamserv.h"
23#include "chanserv.h"
24#include "helpfile.h"
25#include "global.h"
26#include "modcmd.h"
27#include "saxdb.h"
28#include "timeq.h"
29#include "gline.h"
30
31#define SPAMSERV_CONF_NAME "services/spamserv"
32
33#define KEY_EXCEPTIONS "exceptions"
34#define KEY_BADWORDS "badwords"
35#define KEY_FLAGS "flags"
36#define KEY_INFO "info"
37#define KEY_EXPIRY "expiry"
38
39#define KEY_DEBUG_CHANNEL "debug_channel"
40#define KEY_GLOBAL_EXCEPTIONS "global_exceptions"
41#define KEY_GLOBAL_BADWORDS "global_badwords"
42#define KEY_NETWORK_RULES "network_rules"
43#define KEY_TRIGGER "trigger"
44#define KEY_SHORT_BAN_DURATION "short_ban_duration"
45#define KEY_LONG_BAN_DURATION "long_ban_duration"
46#define KEY_GLINE_DURATION "gline_duration"
47#define KEY_EXCEPTION_MAX "exception_max"
48#define KEY_EXCEPTION_MIN_LEN "exception_min_len"
49#define KEY_EXCEPTION_MAX_LEN "exception_max_len"
50#define KEY_BADWORD_MAX "badword_max"
51#define KEY_BADWORD_MIN_LEN "badword_min_len"
52#define KEY_BADWORD_MAX_LEN "badword_max_len"
53#define KEY_ADV_CHAN_MUST_EXIST "adv_chan_must_exist"
54#define KEY_STRIP_MIRC_CODES "strip_mirc_codes"
55#define KEY_ALLOW_MOVE_MERGE "allow_move_merge"
56
57#define SPAMSERV_FUNC(NAME) MODCMD_FUNC(NAME)
58#define SPAMSERV_SYNTAX() svccmd_send_help(user, spamserv, cmd)
59#define SPAMSERV_MIN_PARMS(N) do { \
60(void)argv; \
61 if(argc < N) { \
62 ss_reply(MSG_MISSING_PARAMS, argv[0]); \
63 SPAMSERV_SYNTAX(); \
64 return 0; } } while(0)
65
66struct userNode *spamserv;
67static struct module *spamserv_module;
68static struct service *spamserv_service;
69static struct log_type *SS_LOG;
70static unsigned long crc_table[256];
71
72dict_t registered_channels_dict;
73dict_t connected_users_dict;
74dict_t killed_users_dict;
75
76#define spamserv_notice(target, format...) send_message(target , spamserv , ## format)
77#define spamserv_debug(format...) do { if(spamserv_conf.debug_channel) send_channel_notice(spamserv_conf.debug_channel , spamserv , ## format); } while(0)
78#define ss_reply(format...) send_message(user , spamserv , ## format)
79
80#define SET_SUBCMDS_SIZE 13
81
82const char *set_subcommands[SET_SUBCMDS_SIZE] = {"SPAMLIMIT", "BADREACTION", "ADVREACTION", "WARNREACTION", "ADVSCAN", "SPAMSCAN", "BADWORDSCAN", "CHANFLOODSCAN", "JOINFLOODSCAN", "SCANCHANOPS", "SCANHALFOPS", "SCANVOICED"};
83
84extern struct string_list *autojoin_channels;
85static void spamserv_clear_spamNodes(struct chanNode *channel);
86static void spamserv_punish(struct chanNode *channel, struct userNode *user, time_t expires, char *reason, int ban);
87static unsigned long crc32(const char *text);
88
89#define BINARY_OPTION(arguments...) return binary_option(arguments, user, channel, argc, argv);
90#define MULTIPLE_OPTION(arguments...) return multiple_option(arguments, values, ArrayLength(values), user, channel, argc, argv);
91
92static const struct message_entry msgtab[] = {
93 { "SSMSG_CHANNEL_OPTIONS", "Channel Options:" },
94 { "SSMSG_STRING_VALUE", "$b%s$b%s" },
95 { "SSMSG_NUMERIC_VALUE", "$b%s$b%d - %s" },
96 { "SSMSG_INVALID_NUM_SET", "$b'%d'$b is an invalid %s setting." },
97 { "SSMSG_INVALID_OPTION", "$b%s$b is not a valid %s option." },
98 { "SSMSG_INVALID_BINARY", "$b%s$b is an invalid binary value." },
99
100 { "SSMSG_NOT_REGISTERED", "$b%s$b has not been registered with $b$X$b." },
101 { "SSMSG_NOT_REGISTERED_CS", "$b%s$b has not been registered with $b$C$b." },
102 { "SSMSG_ALREADY_REGISTERED", "$b%s$b is already registered." },
103 { "SSMSG_DEBUG_CHAN", "You may not register the debug channel." },
104 { "SSMSG_SUSPENDED_CS", "$b$C$b access to $b%s$b has been temporarily suspended, thus you can't %s it." },
105 { "SSMSG_SUSPENDED", "$b$X$b access to $b%s$b has been temporarily suspended." },
106 { "SSMSG_NO_REGISTER", "Due to an error it was not possible to register $b%s$b." },
107 { "SSMSG_REG_SUCCESS", "Channel $b%s$b registered." },
108 { "SSMSG_UNREG_SUCCESS", "$b%s$b has been unregistered." },
109 { "SSMSG_NO_ACCESS", "You lack sufficient access to use this command." },
110 { "SSMSG_MUST_BE_OPER", "You must be an irc operator to set this option." },
111 { "SSMSG_CONFIRM_UNREG", "To confirm this unregistration, you must append 'CONFIRM' to the end of your command. For example, 'unregister CONFIRM'." },
112
113 { "SSMSG_NO_EXCEPTIONS", "No words found in the exception list." },
114 { "SSMSG_NO_SUCH_EXCEPTION", "Word $b%s$b not found in the exception list." },
115 { "SSMSG_EXCEPTION_LIST", "The following words are in the exception list:" },
116 { "SSMSG_EXCEPTION_ADDED", "Word $b%s$b added to the exception list." },
117 { "SSMSG_EXCEPTION_DELETED", "Word $b%s$b deleted from the exception list." },
118 { "SSMSG_EXCEPTION_IN_LIST", "The word $b%s$b is already in the exception list." },
119 { "SSMSG_EXCEPTION_MAX", "The exception list has reached the maximum exceptions (max %lu). Delete a word to add another one." },
120 { "SSMSG_EXCEPTION_TOO_SHORT", "The word must be at least %lu characters long." },
121 { "SSMSG_EXCEPTION_TOO_LONG", "The word may not be longer than %lu characters." },
122
123 { "SSMSG_NO_BADWORDS", "No words found in the badword list." },
124 { "SSMSG_NO_SUCH_BADWORD", "Word $b%s$b not found in the badword list." },
125 { "SSMSG_BADWORD_LIST", "The following words are in the badword list:" },
126 { "SSMSG_BADWORD_ADDED", "Word $b%s$b added to the badword list." },
127 { "SSMSG_BADWORD_DELETED", "Word $b%s$b deleted from the badword list." },
128 { "SSMSG_BADWORD_IN_LIST", "The word $b%s$b is already in the badword list." },
129 { "SSMSG_BADWORD_MAX", "The badword list has reached the maximum badwords (max %lu). Delete a word to add another one." },
130 { "SSMSG_BADWORD_TOO_SHORT", "The word must be at least %lu characters long." },
131 { "SSMSG_BADWORD_TOO_LONG", "The word may not be longer than %lu characters." },
132
133 { "SSMSG_STATUS", "$bStatus:$b" },
134 { "SSMSG_STATUS_USERS", "Total Users Online: %u" },
135 { "SSMSG_STATUS_CHANNELS", "Registered Channels: %u" },
136 { "SSMSG_STATUS_MEMORY", "$bMemory Information:$b" },
137 { "SSMSG_STATUS_CHANNEL_LIST", "$bRegistered Channels:$b" },
138 { "SSMSG_STATUS_NO_CHANNEL", "No channels registered." },
139
140 { "SSMSG_WARNING_T", "%s is against the network rules" },
141 { "SSMSG_WARNING_2_T", "You are violating the network rules" },
142 { "SSMSG_WARNING_RULES_T", "%s is against the network rules. Read the network rules at %s" },
143 { "SSMSG_WARNING_RULES_2_T", "You are violating the network rules. Read the network rules at %s" },
144
145 { NULL, NULL }
146};
147
148#define SSMSG_DEBUG_KICK "Kicked user $b%s$b from $b%s$b, reason: %s"
149#define SSMSG_DEBUG_BAN "Banned user $b%s$b from $b%s$b, reason: %s"
150#define SSMSG_DEBUG_KILL "Killed user $b%s$b, last violation in $b%s$b"
151#define SSMSG_DEBUG_GLINE "Glined user $b%s$b, host $b%s$b, last violation in $b%s$b"
152#define SSMSG_DEBUG_RECONNECT "Killed user $b%s$b reconnected to the network"
153
154#define SSMSG_SPAM "Spamming"
155#define SSMSG_FLOOD "Flooding the channel/network"
156#define SSMSG_ADV "Advertising"
157#define SSMSG_BAD "Badwords"
158#define SSMSG_JOINFLOOD "Join flooding the channel"
159
160#define SSMSG_WARNING "%s is against the network rules"
161#define SSMSG_WARNING_2 "You are violating the network rules"
162#define SSMSG_WARNING_RULES "%s is against the network rules. Read the network rules at %s"
163#define SSMSG_WARNING_RULES_2 "You are violating the network rules. Read the network rules at %s"
164
165/*
166#define SSMSG_WARNING "SSMSG_WARNING_T"
167#define SSMSG_WARNING_2 "SSMSG_WARNING_2_T"
168#define SSMSG_WARNING_RULES "SSMSG_WARNING_RULES_T"
169#define SSMSG_WARNING_RULES_2 "SSMSG_WARNING_RULES_2_T"
170*/
171
172static struct
173{
174 struct chanNode *debug_channel;
175 struct string_list *global_exceptions;
176 struct string_list *global_badwords;
177 const char *network_rules;
178 unsigned char trigger;
179 unsigned long short_ban_duration;
180 unsigned long long_ban_duration;
181 unsigned long gline_duration;
182 unsigned long exception_max;
183 unsigned long exception_min_len;
184 unsigned long exception_max_len;
185 unsigned long badword_max;
186 unsigned long badword_min_len;
187 unsigned long badword_max_len;
188 unsigned int adv_chan_must_exist : 1;
189 unsigned int strip_mirc_codes : 1;
190 unsigned int allow_move_merge : 1;
191} spamserv_conf;
192
193/***********************************************/
194/* Channel */
195/***********************************************/
196
197struct chanInfo*
198get_chanInfo(const char *channelname)
199{
200 return dict_find(registered_channels_dict, channelname, 0);
201}
202
203static void
204spamserv_join_channel(struct chanNode *channel)
205{
206 struct mod_chanmode change;
207 mod_chanmode_init(&change);
208 change.argc = 1;
209 change.args[0].mode = MODE_CHANOP;
210 change.args[0].u.member = AddChannelUser(spamserv, channel);
211 mod_chanmode_announce(spamserv, channel, &change);
212}
213
214static void
215spamserv_part_channel(struct chanNode *channel, char *reason)
216{
217 /* we only have to clear the spamNodes because every other node expires on it's own */
218 spamserv_clear_spamNodes(channel);
219 DelChannelUser(spamserv, channel, reason, 0);
220}
221
222static struct chanInfo*
223spamserv_register_channel(struct chanNode *channel, struct string_list *exceptions, struct string_list *badwords, unsigned int flags, char *info)
224{
225 struct chanInfo *cInfo = malloc(sizeof(struct chanInfo));
226
227 if(!cInfo)
228 {
229 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for cInfo; channel: %s", channel->name);
230 return NULL;
231 }
232
233 cInfo->channel = channel;
234 cInfo->exceptions = exceptions ? string_list_copy(exceptions) : alloc_string_list(1);
235 cInfo->badwords = badwords ? string_list_copy(badwords) : alloc_string_list(1);
236 cInfo->flags = flags;
237 safestrncpy(cInfo->info, info, sizeof(cInfo->info));
238 cInfo->suspend_expiry = 0;
239 dict_insert(registered_channels_dict, cInfo->channel->name, cInfo);
240
241 return cInfo;
242}
243
244static void
245spamserv_unregister_channel(struct chanInfo *cInfo)
246{
247 if(!cInfo)
248 return;
249
250 dict_remove(registered_channels_dict, cInfo->channel->name);
251 free_string_list(cInfo->exceptions);
252 free_string_list(cInfo->badwords);
253 free(cInfo);
254}
255
256void
257spamserv_cs_suspend(struct chanNode *channel, time_t expiry, int suspend, char *reason)
258{
259 struct chanInfo *cInfo = get_chanInfo(channel->name);
260
261 if(cInfo)
262 {
263 if(suspend)
264 {
265 cInfo->flags |= CHAN_SUSPENDED;
266 cInfo->suspend_expiry = expiry;
267 spamserv_part_channel(channel, reason);
268 }
269 else
270 {
271 if(CHECK_SUSPENDED(cInfo))
272 {
273 cInfo->flags &= ~CHAN_SUSPENDED;
274 cInfo->suspend_expiry = 0;
275 }
276 }
277 }
278}
279
280int
281spamserv_cs_move_merge(struct userNode *user, struct chanNode *channel, struct chanNode *target, int move)
282{
283 struct chanInfo *cInfo = get_chanInfo(channel->name);
284
285 if(cInfo)
286 {
287 char reason[MAXLEN];
288
289 if(!spamserv_conf.allow_move_merge || get_chanInfo(target->name))
290 {
291 if(move)
292 snprintf(reason, sizeof(reason), "unregistered due to a channel move to %s", target->name);
293 else
294 snprintf(reason, sizeof(reason), "unregistered due to a channel merge into %s", target->name);
295
296 spamserv_cs_unregister(user, channel, manually, reason);
297 return 0;
298 }
299
300 cInfo->channel = target;
301
302 dict_remove(registered_channels_dict, channel->name);
303 dict_insert(registered_channels_dict, target->name, cInfo);
304
305 if(move)
306 {
307 snprintf(reason, sizeof(reason), "Channel moved to %s by %s.", target->name, user->handle_info->handle);
308 }
309 else
310 {
311 spamserv_join_channel(target);
312 snprintf(reason, sizeof(reason), "%s merged into %s by %s.", channel->name, target->name, user->handle_info->handle);
313 }
314
315 if(!CHECK_SUSPENDED(cInfo))
316 spamserv_part_channel(channel, reason);
317
318 if(move)
319 snprintf(reason, sizeof(reason), "$X (channel %s) moved to %s by %s.", channel->name, target->name, user->handle_info->handle);
320 else
321 snprintf(reason, sizeof(reason), "$X (channel %s) merged into %s by %s.", channel->name, target->name, user->handle_info->handle);
322
323 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
324 return 1;
325 }
326
327 return 0;
328}
329
330void
331spamserv_cs_unregister(struct userNode *user, struct chanNode *channel, enum cs_unreg type, char *reason)
332{
333 struct chanInfo *cInfo = get_chanInfo(channel->name);
334
335 if(cInfo)
336 {
337 char global[MAXLEN], partmsg[MAXLEN];
338
339 switch (type)
340 {
341 case manually:
342 snprintf(global, sizeof(global), "$X (channel %s) %s by %s.", channel->name, reason, user->handle_info->handle);
343 snprintf(partmsg, sizeof(partmsg), "%s %s by %s.", channel->name, reason, user->handle_info->handle);
344 break;
345 case expire:
346 snprintf(global, sizeof(global), "$X (channel %s) registration expired.", channel->name);
347 snprintf(partmsg, sizeof(partmsg), "%s registration expired.", channel->name);
348 break;
349 case lost_all_users:
350 snprintf(global, sizeof(global), "$X (channel %s) lost all users.", channel->name);
351 snprintf(partmsg, sizeof(partmsg), "%s lost all users.", channel->name);
352 break;
353 }
354
355 if(!CHECK_SUSPENDED(cInfo))
356 spamserv_part_channel(channel, partmsg);
357
358 spamserv_unregister_channel(cInfo);
359 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, global);
360 }
361}
362
363/***********************************************/
364/* User */
365/***********************************************/
366
367static struct userInfo*
368get_userInfo(const char *nickname)
369{
370 return dict_find(connected_users_dict, nickname, 0);
371}
372
373static void
374spamserv_create_spamNode(struct chanNode *channel, struct userInfo *uInfo, char *text)
375{
376 struct spamNode *sNode = malloc(sizeof(struct spamNode));
377
378 if(!sNode)
379 {
380 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for sNode; channel: %s; user: %s", channel->name, uInfo->user->nick);
381 return;
382 }
383
384 sNode->channel = channel;
385 sNode->crc32 = crc32(text);
386 sNode->count = 1;
387 sNode->next = NULL;
388
389 if(uInfo->spam)
390 {
391 struct spamNode *temp = uInfo->spam;
392
393 while(temp->next)
394 temp = temp->next;
395
396 sNode->prev = temp;
397 temp->next = sNode;
398 }
399 else
400 {
401 sNode->prev = NULL;
402 uInfo->spam = sNode;
403 }
404}
405
406static void
407spamserv_delete_spamNode(struct userInfo *uInfo, struct spamNode *sNode)
408{
409 if(!sNode)
410 return;
411
412 if(sNode == uInfo->spam)
413 uInfo->spam = sNode->next;
414
415 if(sNode->next)
416 sNode->next->prev = sNode->prev;
417 if(sNode->prev)
418 sNode->prev->next = sNode->next;
419
420 free(sNode);
421}
422
423static void
424spamserv_clear_spamNodes(struct chanNode *channel)
425{
426 struct userInfo *uInfo;
427 struct spamNode *sNode;
428 unsigned int i;
429
430 for(i = 0; i < channel->members.used; i++)
431 {
432 if((uInfo = get_userInfo(channel->members.list[i]->user->nick)))
433 {
434 if((sNode = uInfo->spam))
435 {
436 for(; sNode; sNode = sNode->next)
437 if(sNode->channel == channel)
438 break;
439
440 if(sNode)
441 spamserv_delete_spamNode(uInfo, sNode);
442 }
443 }
444 }
445}
446
447static void
448spamserv_create_floodNode(struct chanNode *channel, struct userNode *user, struct floodNode **uI_fNode)
449{
450 struct floodNode *fNode = malloc(sizeof(struct floodNode));
451
452 if(!fNode)
453 {
454 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for fNode; channel: %s; user: %s", channel->name, user->nick);
455 return;
456 }
457
458 fNode->channel = channel;
459 fNode->owner = user;
460 fNode->count = 1;
461 fNode->time = now;
462 fNode->next = NULL;
463
464 if(*uI_fNode)
465 {
466 struct floodNode *temp = *uI_fNode;
467
468 while(temp->next)
469 temp = temp->next;
470
471 fNode->prev = temp;
472 temp->next = fNode;
473 }
474 else
475 {
476 fNode->prev = NULL;
477 *uI_fNode = fNode;
478 }
479}
480
481static void
482spamserv_delete_floodNode(struct floodNode **uI_fNode, struct floodNode *fNode)
483{
484 if(!fNode)
485 return;
486
487 if(fNode == *uI_fNode)
488 *uI_fNode = fNode->next;
489
490 if(fNode->next)
491 fNode->next->prev = fNode->prev;
492 if(fNode->prev)
493 fNode->prev->next = fNode->next;
494
495 free(fNode);
496}
497
498static void
499spamserv_create_user(struct userNode *user)
500{
501 struct userInfo *uInfo = malloc(sizeof(struct userInfo));
502 struct killNode *kNode = dict_find(killed_users_dict, irc_ntoa(&user->ip), 0);
503
504 if(!uInfo)
505 {
506 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for uInfo; nick: %s", user->nick);
507 return;
508 }
509
510 if(kNode)
511 spamserv_debug(SSMSG_DEBUG_RECONNECT, user->nick);
512
513 uInfo->user = user;
514 uInfo->spam = NULL;
515 uInfo->flood = NULL;
516 uInfo->joinflood = NULL;
517 uInfo->flags = kNode ? USER_KILLED : 0;
518 uInfo->warnlevel = kNode ? kNode->warnlevel : 0;
519 uInfo->lastadv = 0;
520 uInfo->lastbad = 0;
521
522 dict_insert(connected_users_dict, user->nick, uInfo);
523
524 if(kNode)
525 {
526 dict_remove(killed_users_dict, irc_ntoa(&user->ip));
527 free(kNode);
528 }
529}
530
531static void
532spamserv_delete_user(struct userInfo *uInfo)
533{
534 if(!uInfo)
535 return;
536
537 if(uInfo->spam)
538 while(uInfo->spam)
539 spamserv_delete_spamNode(uInfo, uInfo->spam);
540
541 if(uInfo->flood)
542 while(uInfo->flood)
543 spamserv_delete_floodNode(&uInfo->flood, uInfo->flood);
544
545 if(uInfo->joinflood)
546 while(uInfo->joinflood)
547 spamserv_delete_floodNode(&uInfo->joinflood, uInfo->joinflood);
548
549 dict_remove(connected_users_dict, uInfo->user->nick);
550 free(uInfo);
551}
552
553static int
554spamserv_new_user_func(struct userNode *user)
555{
556 if(!IsLocal(user))
557 spamserv_create_user(user);
558
559 return 0;
560}
561
562static void
563spamserv_del_user_func(struct userNode *user, struct userNode *killer, UNUSED_ARG(const char *why))
564{
565 struct userInfo *uInfo = get_userInfo(user->nick);
566 struct killNode *kNode;
567
568 if(killer == spamserv)
569 {
570 kNode = malloc(sizeof(struct killNode));
571
572 if(!kNode)
573 {
574 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for killNode - nickname %s", user->nick);
575 spamserv_delete_user(uInfo);
576 return;
577 }
578
579 if(uInfo->warnlevel > KILL_WARNLEVEL)
580 kNode->warnlevel = uInfo->warnlevel - KILL_WARNLEVEL;
581 else
582 kNode->warnlevel = 0;
583
584 kNode->time = now;
585
586 dict_insert(killed_users_dict, irc_ntoa(&user->ip), kNode);
587 }
588
589 spamserv_delete_user(uInfo);
590}
591
592static void
593spamserv_nick_change_func(struct userNode *user, const char *old_nick)
594{
595 struct userInfo *uInfo = get_userInfo(old_nick);
596
597 dict_remove(connected_users_dict, old_nick);
598 dict_insert(connected_users_dict, user->nick, uInfo);
599}
600
601static int
602spamserv_user_join(struct modeNode *mNode)
603{
604 struct chanNode *channel = mNode->channel;
605 struct userNode *user = mNode->user;
606 struct chanInfo *cInfo;
607 struct userInfo *uInfo;
608 struct floodNode *jfNode;
609
610 if(user->uplink->burst || !(cInfo = get_chanInfo(channel->name)) || !CHECK_JOINFLOOD(cInfo) || !(uInfo = get_userInfo(user->nick)))
611 return 0;
612
613 if(!(jfNode = uInfo->joinflood))
614 {
615 spamserv_create_floodNode(channel, user, &uInfo->joinflood);
616 }
617 else
618 {
619 for(; jfNode; jfNode = jfNode->next)
620 if(jfNode->channel == channel)
621 break;
622
623 if(!jfNode)
624 {
625 spamserv_create_floodNode(channel, user, &uInfo->joinflood);
626 }
627 else
628 {
629 jfNode->count++;
630 jfNode->time = now;
631
632 if(jfNode->count > JOINFLOOD_MAX)
633 {
634 char reason[MAXLEN];
635
636 spamserv_delete_floodNode(&uInfo->joinflood, jfNode);
637 snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_JOINFLOOD, spamserv_conf.network_rules);
638 spamserv_punish(channel, user, JOINFLOOD_B_DURATION, reason, 1);
639 }
640 }
641 }
642
643 return 0;
644}
645
646static void
647spamserv_user_part(struct modeNode *mn, UNUSED_ARG(const char *reason))
648{
649 struct userNode *user = mn->user;
650 struct chanNode *channel = mn->channel;
651 struct userInfo *uInfo;
652 struct spamNode *sNode;
653 struct floodNode *fNode;
654
655 if(user->dead || !get_chanInfo(channel->name) || !(uInfo = get_userInfo(user->nick)))
656 return;
657
658 if((sNode = uInfo->spam))
659 {
660 for(; sNode; sNode = sNode->next)
661 if(sNode->channel == channel)
662 break;
663
664 if(sNode)
665 spamserv_delete_spamNode(uInfo, sNode);
666 }
667
668 if((fNode = uInfo->flood))
669 {
670 for(; fNode; fNode = fNode->next)
671 if(fNode->channel == channel)
672 break;
673
674 if(fNode)
675 spamserv_delete_floodNode(&uInfo->flood, fNode);
676 }
677}
678
679/***********************************************/
680/* Other Stuff */
681/***********************************************/
682
683static void
684crc32_init(void)
685{
686 unsigned long crc;
687 int i, j;
688
689 for(i = 0; i < 256; i++)
690 {
691 crc = i;
692
693 for(j = 8; j > 0; j--)
694 {
695 if(crc & 1)
696 {
697 crc = (crc >> 1) ^ 0xEDB88320L;
698 }
699 else
700 {
701 crc >>= 1;
702 }
703 }
704
705 crc_table[i] = crc;
706 }
707}
708
709static unsigned long
710crc32(const char *text)
711{
712 register unsigned long crc = 0xFFFFFFFF;
713 unsigned int c, i = 0;
714
715 while((c = (unsigned int)text[i++]) != 0)
716 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_table[(crc^c) & 0xFF];
717
718 return (crc^0xFFFFFFFF);
719}
720
721static void
722timeq_flood(UNUSED_ARG(void *data))
723{
724 dict_iterator_t it;
725 struct userInfo *uInfo;
726 struct floodNode *fNode;
727
728 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
729 {
730 uInfo = iter_data(it);
731
6546e922 732 if (!uInfo)
733 continue;
734
63c95a47 735 if(!(fNode = uInfo->flood))
736 continue;
737
738 for(; fNode; fNode = fNode->next)
739 {
740 if(now - fNode->time > FLOOD_EXPIRE)
741 {
742 if(!(--fNode->count))
743 spamserv_delete_floodNode(&uInfo->flood, fNode);
744 }
745 }
746 }
747
748 timeq_add(now + FLOOD_TIMEQ_FREQ, timeq_flood, NULL);
749}
750
751static void
752timeq_joinflood(UNUSED_ARG(void *data))
753{
754 dict_iterator_t it;
755 struct userInfo *uInfo;
756 struct floodNode *fNode;
757
758 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
759 {
760 uInfo = iter_data(it);
761
762 if(!(fNode = uInfo->joinflood))
763 continue;
764
765 for(; fNode; fNode = fNode->next)
766 {
767 if(now - fNode->time > JOINFLOOD_EXPIRE)
768 {
769 if(!(--fNode->count))
770 spamserv_delete_floodNode(&uInfo->joinflood, fNode);
771 }
772 }
773 }
774
775 timeq_add(now + JOINFLOOD_TIMEQ_FREQ, timeq_joinflood, NULL);
776}
777
778static void
779timeq_bad(UNUSED_ARG(void *data))
780{
781 dict_iterator_t it;
782 struct userInfo *uInfo;
783
784 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
785 {
786 uInfo = iter_data(it);
787
788 if(uInfo->lastbad && uInfo->lastbad - now > BAD_EXPIRE)
789 {
790 uInfo->lastbad = 0;
791 uInfo->flags &= ~USER_BAD_WARNED;
792 }
793 }
794
795 timeq_add(now + BAD_TIMEQ_FREQ, timeq_bad, NULL);
796}
797
798static void
799timeq_adv(UNUSED_ARG(void *data))
800{
801 dict_iterator_t it;
802 struct userInfo *uInfo;
803
804 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
805 {
806 uInfo = iter_data(it);
807
808 if(uInfo->lastadv && uInfo->lastadv - now > ADV_EXPIRE)
809 {
810 uInfo->lastadv = 0;
811 uInfo->flags &= ~USER_ADV_WARNED;
812 }
813 }
814
815 timeq_add(now + ADV_TIMEQ_FREQ, timeq_adv, NULL);
816}
817
818static void
819timeq_warnlevel(UNUSED_ARG(void *data))
820{
821 dict_iterator_t it;
822 struct userInfo *uInfo;
823
824 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
825 {
826 uInfo = iter_data(it);
827
828 if(uInfo->warnlevel > 0)
829 uInfo->warnlevel--;
830 }
831
832 timeq_add(now + WARNLEVEL_TIMEQ_FREQ, timeq_warnlevel, NULL);
833}
834
835static void
836timeq_kill(UNUSED_ARG(void *data))
837{
838 dict_iterator_t it;
839 struct killNode *kNode;
840
841 for(it = dict_first(killed_users_dict); it; it = iter_next(it))
842 {
843 kNode = iter_data(it);
844
845 if(kNode->time - now > KILL_EXPIRE)
846 free(kNode);
847 }
848
849 timeq_add(now + KILL_TIMEQ_FREQ, timeq_kill, NULL);
850}
851
852static int
853binary_option(char *name, unsigned long mask, struct userNode *user, struct chanNode *channel, int argc, char *argv[])
854{
855 struct chanInfo *cInfo = get_chanInfo(channel->name);
856 int value;
857
858 if(argc > 1)
859 {
860 if(enabled_string(argv[1]))
861 {
862 cInfo->flags |= mask;
863 value = 1;
864 }
865 else if(disabled_string(argv[1]))
866 {
867 cInfo->flags &= ~mask;
868 value = 0;
869 }
870 else
871 {
872 spamserv_notice(user, "SSMSG_INVALID_BINARY", argv[1]);
873 return 0;
874 }
875 }
876 else
877 {
878 value = (cInfo->flags & mask) ? 1 : 0;
879 }
880
881 spamserv_notice(user, "SSMSG_STRING_VALUE", name, value ? "Enabled." : "Disabled.");
882 return 1;
883}
884
885struct valueData
886{
887 char *description;
888 char value;
889 int oper_only : 1;
890};
891
892static int
893multiple_option(char *name, char *description, enum channelinfo info, struct valueData *values, int count, struct userNode *user, struct chanNode *channel, int argc, char *argv[])
894{
895 struct chanInfo *cInfo = get_chanInfo(channel->name);
896 int index;
897
898 if(argc > 1)
899 {
900 index = atoi(argv[1]);
901
902 if(index < 0 || index >= count)
903 {
904 spamserv_notice(user, "SSMSG_INVALID_NUM_SET", index, description);
905
906 for(index = 0; index < count; index++)
907 spamserv_notice(user, "SSMSG_NUMERIC_VALUE", name, index, values[index].description);
908
909 return 0;
910 }
911
912 if(values[index].oper_only && !IsOper(user))
913 {
914 spamserv_notice(user, "SSMSG_MUST_BE_OPER");
915 return 0;
916 }
917
918 cInfo->info[info] = values[index].value;
919 }
920 else
921 {
922 for(index = 0; index < count && cInfo->info[info] != values[index].value; index++);
923 }
924
925 spamserv_notice(user, "SSMSG_NUMERIC_VALUE", name, index, values[index].description);
926 return 1;
927}
928
929static int
930show_exceptions(struct userNode *user, struct chanInfo *cInfo)
931{
932 struct helpfile_table table;
933 unsigned int i;
934
935 if(!cInfo->exceptions->used)
936 {
937 spamserv_notice(user, "SSMSG_NO_EXCEPTIONS");
938 return 0;
939 }
940
941 spamserv_notice(user, "SSMSG_EXCEPTION_LIST");
942
943 table.length = 0;
944 table.width = 1;
945 table.flags = TABLE_REPEAT_ROWS | TABLE_NO_FREE | TABLE_NO_HEADERS;
946 table.contents = alloca(cInfo->exceptions->used * sizeof(*table.contents));
947
948 for(i = 0; i < cInfo->exceptions->used; i++)
949 {
950 table.contents[table.length] = alloca(table.width * sizeof(**table.contents));
951 table.contents[table.length][0] = cInfo->exceptions->list[i];
952 table.length++;
953 }
954
955 table_send(spamserv, user->nick, 0, NULL, table);
956
957 return 1;
958}
959
960static int
961show_badwords(struct userNode *user, struct chanInfo *cInfo)
962{
963 struct helpfile_table table;
964 unsigned int i;
965
966 if(!cInfo->badwords->used)
967 {
968 spamserv_notice(user, "SSMSG_NO_BADWORDS");
969 return 0;
970 }
971
972 spamserv_notice(user, "SSMSG_BADWORD_LIST");
973
974 table.length = 0;
975 table.width = 1;
976 table.flags = TABLE_REPEAT_ROWS | TABLE_NO_FREE | TABLE_NO_HEADERS;
977 table.contents = alloca(cInfo->badwords->used * sizeof(*table.contents));
978
979 for(i = 0; i < cInfo->badwords->used; i++)
980 {
981 table.contents[table.length] = alloca(table.width * sizeof(**table.contents));
982 table.contents[table.length][0] = cInfo->badwords->list[i];
983 table.length++;
984 }
985
986 table_send(spamserv, user->nick, 0, NULL, table);
987
988 return 1;
989}
990
991static void
992show_memory_usage(struct userNode *user)
993{
994 dict_iterator_t it;
995 struct helpfile_table table;
996 struct chanInfo *cInfo;
997 struct userInfo *uInfo;
998 struct spamNode *sNode;
999 struct floodNode *fNode;
1000 double channel_size = 0, user_size, size;
1001 unsigned int spamcount = 0, floodcount = 0, i, j;
1002 char buffer[64];
1003
1004 for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
1005 {
1006 cInfo = iter_data(it);
1007
1008 if(!cInfo->exceptions->used)
1009 continue;
1010
1011 if(!cInfo->badwords->used)
1012 continue;
1013
1014 for(i = 0; i < cInfo->exceptions->used; i++)
1015 channel_size += strlen(cInfo->exceptions->list[i]) * sizeof(char);
1016
1017 for(i = 0; i < cInfo->badwords->used; i++)
1018 channel_size += strlen(cInfo->badwords->list[i]) * sizeof(char);
1019 }
1020
1021 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
1022 {
1023 uInfo = iter_data(it);
1024
1025 for(sNode = uInfo->spam; sNode; sNode = sNode->next, spamcount++);
1026 for(fNode = uInfo->flood; fNode; fNode = fNode->next, floodcount++);
1027 for(fNode = uInfo->joinflood; fNode; fNode = fNode->next, floodcount++);
1028 }
1029
1030 channel_size += dict_size(registered_channels_dict) * sizeof(struct chanInfo);
1031
1032 user_size = dict_size(connected_users_dict) * sizeof(struct userInfo) +
1033 dict_size(killed_users_dict) * sizeof(struct killNode) +
1034 spamcount * sizeof(struct spamNode) +
1035 floodcount * sizeof(struct floodNode);
1036
1037 size = channel_size + user_size;
1038
1039 ss_reply("SSMSG_STATUS_MEMORY");
1040
1041 table.length = 3;
1042 table.width = 4;
1043 table.flags = TABLE_NO_FREE | TABLE_NO_HEADERS | TABLE_PAD_LEFT;
1044 table.contents = calloc(table.length, sizeof(char**));
1045
1046 // chanInfo
1047 table.contents[0] = calloc(table.width, sizeof(char*));
1048 snprintf(buffer, sizeof(buffer), "Channel Memory Usage:");
1049 table.contents[0][0] = strdup(buffer);
1050 snprintf(buffer, sizeof(buffer), " %g Byte; ", channel_size);
1051 table.contents[0][1] = strdup(buffer);
1052 snprintf(buffer, sizeof(buffer), "%g KiloByte; ", channel_size / 1024);
1053 table.contents[0][2] = strdup(buffer);
1054 snprintf(buffer, sizeof(buffer), "%g MegaByte", channel_size / 1024 / 1024);
1055 table.contents[0][3] = strdup(buffer);
1056
1057 // userInfo
1058 table.contents[1] = calloc(table.width, sizeof(char*));
1059 snprintf(buffer, sizeof(buffer), "User Memory Usage :");
1060 table.contents[1][0] = strdup(buffer);
1061 snprintf(buffer, sizeof(buffer), " %g Byte; ", user_size);
1062 table.contents[1][1] = strdup(buffer);
1063 snprintf(buffer, sizeof(buffer), "%g KiloByte; ", user_size / 1024);
1064 table.contents[1][2] = strdup(buffer);
1065 snprintf(buffer, sizeof(buffer), "%g MegaByte", user_size / 1024 / 1024);
1066 table.contents[1][3] = strdup(buffer);
1067
1068 // total memory usage
1069 table.contents[2] = calloc(table.width, sizeof(char*));
1070 snprintf(buffer, sizeof(buffer), "Total Memory Usage :");
1071 table.contents[2][0] = strdup(buffer);
1072 snprintf(buffer, sizeof(buffer), " %g Byte; ", size);
1073 table.contents[2][1] = strdup(buffer);
1074 snprintf(buffer, sizeof(buffer), "%g KiloByte; ", size / 1024);
1075 table.contents[2][2] = strdup(buffer);
1076 snprintf(buffer, sizeof(buffer), "%g MegaByte", size / 1024 / 1024);
1077 table.contents[2][3] = strdup(buffer);
1078
1079 table_send(spamserv, user->nick, 0, NULL, table);
1080
1081 for(i = 0; i < table.length; i++)
1082 {
1083 for(j = 0; j < table.width; j++)
1084 free((char*)table.contents[i][j]);
1085
1086 free(table.contents[i]);
1087 }
1088
1089 free(table.contents);
1090}
1091
1092static void
1093show_registered_channels(struct userNode *user)
1094{
1095 struct helpfile_table table;
1096 dict_iterator_t it;
1097
1098 spamserv_notice(user, "SSMSG_STATUS_CHANNEL_LIST");
1099
1100 if(!dict_size(registered_channels_dict))
1101 {
1102 spamserv_notice(user, "SSMSG_STATUS_NO_CHANNEL");
1103 return;
1104 }
1105
1106 table.length = 0;
1107 table.width = 1;
1108 table.flags = TABLE_REPEAT_ROWS | TABLE_NO_FREE | TABLE_NO_HEADERS;
1109 table.contents = alloca(dict_size(registered_channels_dict) * sizeof(*table.contents));
1110
1111 for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
1112 {
1113 struct chanInfo *cInfo = iter_data(it);
1114
1115 table.contents[table.length] = alloca(table.width * sizeof(**table.contents));
1116 table.contents[table.length][0] = cInfo->channel->name;
1117 table.length++;
1118 }
1119
1120 table_send(spamserv, user->nick, 0, NULL, table);
1121}
1122
1123/***********************************************/
1124/* SpamServ_Func */
1125/***********************************************/
1126
1127static
1128SPAMSERV_FUNC(cmd_register)
1129{
1130 struct chanInfo *cInfo;
1131 char reason[MAXLEN];
1132
1133 if(!channel || !channel->channel_info)
1134 {
1135 ss_reply("SSMSG_NOT_REGISTERED_CS", channel->name);
1136 return 0;
1137 }
1138
1139 if(get_chanInfo(channel->name))
1140 {
1141 ss_reply("SSMSG_ALREADY_REGISTERED", channel->name);
1142 return 0;
1143 }
1144
1145 if(IsSuspended(channel->channel_info))
1146 {
1147 ss_reply("SSMSG_SUSPENDED_CS", channel->name, "register");
1148 return 0;
1149 }
1150
1151 if(channel == spamserv_conf.debug_channel)
1152 {
1153 ss_reply("SSMSG_DEBUG_CHAN");
1154 return 0;
1155 }
1156
1157 if(!(cInfo = spamserv_register_channel(channel, spamserv_conf.global_exceptions, spamserv_conf.global_badwords, CHAN_FLAGS_DEFAULT , CHAN_INFO_DEFAULT)))
1158 {
1159 ss_reply("SSMSG_NO_REGISTER", channel->name);
1160 return 0;
1161 }
1162
1163 spamserv_join_channel(cInfo->channel);
1164
1165 snprintf(reason, sizeof(reason), "%s (channel %s) registered by %s.", spamserv->nick, channel->name, user->handle_info->handle);
1166 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
1167 ss_reply("SSMSG_REG_SUCCESS", channel->name);
1168
1169 return 1;
1170}
1171
1172static
1173SPAMSERV_FUNC(cmd_unregister)
1174{
1175 struct chanInfo *cInfo;
1176 struct chanData *cData;
1177 struct userData *uData;
1178 char reason[MAXLEN];
1179
1180 if(!channel || !(cData = channel->channel_info) || !(cInfo = get_chanInfo(channel->name)))
1181 {
1182 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1183 return 0;
1184 }
1185
1186 if(!(uData = GetChannelUser(cData, user->handle_info)) || (uData->access < UL_OWNER))
1187 {
1188 ss_reply("SSMSG_NO_ACCESS");
1189 return 0;
1190 }
1191
1192 if(!IsHelping(user))
1193 {
1194 if(IsSuspended(cData))
1195 {
1196 ss_reply("SSMSG_SUSPENDED_CS", channel->name, "unregister");
1197 return 0;
1198 }
1199
1200 if(argc < 2 || strcasecmp(argv[1], "CONFIRM"))
1201 {
1202 ss_reply("SSMSG_CONFIRM_UNREG");
1203 return 0;
1204 }
1205 }
1206
1207 if(!CHECK_SUSPENDED(cInfo))
1208 {
1209 snprintf(reason, sizeof(reason), "%s unregistered by %s.", spamserv->nick, user->handle_info->handle);
1210 spamserv_part_channel(channel, reason);
1211 }
1212
1213 spamserv_unregister_channel(cInfo);
1214
1215 snprintf(reason, sizeof(reason), "%s (channel %s) unregistered by %s.", spamserv->nick, channel->name, user->handle_info->handle);
1216 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
1217 ss_reply("SSMSG_UNREG_SUCCESS", channel->name);
1218
1219 return 1;
1220}
1221
1222static
1223SPAMSERV_FUNC(cmd_status)
1224{
1225 ss_reply("SSMSG_STATUS");
1226 ss_reply("SSMSG_STATUS_USERS", dict_size(connected_users_dict));
1227 ss_reply("SSMSG_STATUS_CHANNELS", dict_size(registered_channels_dict));
1228
1229 if(IsOper(user) && argc > 1)
1230 {
1231 if(!irccasecmp(argv[1], "memory"))
1232 show_memory_usage(user);
1233 else if(!irccasecmp(argv[1], "channels"))
1234 show_registered_channels(user);
1235 }
1236
1237 return 1;
1238}
1239
1240static
1241SPAMSERV_FUNC(cmd_addexception)
1242{
1243 struct chanInfo *cInfo = get_chanInfo(channel->name);
1244 struct userData *uData;
1245 unsigned int i;
1246
1247 if(!cInfo || !channel->channel_info)
1248 {
1249 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1250 return 0;
1251 }
1252
1253 if(CHECK_SUSPENDED(cInfo))
1254 {
1255 ss_reply("SSMSG_SUSPENDED", channel->name);
1256 return 0;
1257 }
1258
1259 if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1260 {
1261 ss_reply("SSMSG_NO_ACCESS");
1262 return 0;
1263 }
1264
1265 if(argc < 2)
1266 return show_exceptions(user, cInfo);
1267
1268 if(cInfo->exceptions->used == spamserv_conf.exception_max && !IsOper(user))
1269 {
1270 ss_reply("SSMSG_EXCEPTION_MAX", spamserv_conf.exception_max);
1271 return 0;
1272 }
1273
1274 if(strlen(argv[1]) < spamserv_conf.exception_min_len)
1275 {
1276 ss_reply("SSMSG_EXCEPTION_TOO_SHORT", spamserv_conf.exception_min_len);
1277 return 0;
1278 }
1279 else if(strlen(argv[1]) > spamserv_conf.exception_max_len)
1280 {
1281 ss_reply("SSMSG_EXCEPTION_TOO_LONG", spamserv_conf.exception_max_len);
1282 return 0;
1283 }
1284
1285 for(i = 0; i < cInfo->exceptions->used; i++)
1286 {
1287 if(!irccasecmp(argv[1], cInfo->exceptions->list[i]))
1288 {
1289 ss_reply("SSMSG_EXCEPTION_IN_LIST", argv[1]);
1290 return 0;
1291 }
1292 }
1293
1294 string_list_append(cInfo->exceptions, strdup(argv[1]));
1295 ss_reply("SSMSG_EXCEPTION_ADDED", argv[1]);
1296
1297 return 1;
1298}
1299
1300static
1301SPAMSERV_FUNC(cmd_delexception)
1302{
1303 struct chanInfo *cInfo = get_chanInfo(channel->name);
1304 struct userData *uData;
1305 unsigned int i;
1306 int found = -1;
1307
1308 if(!cInfo || !channel->channel_info)
1309 {
1310 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1311 return 0;
1312 }
1313
1314 if(CHECK_SUSPENDED(cInfo))
1315 {
1316 ss_reply("SSMSG_SUSPENDED", channel->name);
1317 return 0;
1318 }
1319
1320 if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1321 {
1322 ss_reply("SSMSG_NO_ACCESS");
1323 return 0;
1324 }
1325
1326 if(argc < 2)
1327 return show_exceptions(user, cInfo);
1328
1329 for(i = 0; i < cInfo->exceptions->used; i++)
1330 {
1331 if(!irccasecmp(argv[1], cInfo->exceptions->list[i]))
1332 {
1333 found = i;
1334 break;
1335 }
1336 }
1337
1338 if(found == -1)
1339 {
1340 ss_reply("SSMSG_NO_SUCH_EXCEPTION", argv[1]);
1341 return 0;
1342 }
1343
1344 string_list_delete(cInfo->exceptions, i);
1345 ss_reply("SSMSG_EXCEPTION_DELETED", argv[1]);
1346
1347 return 1;
1348}
1349
1350static
1351SPAMSERV_FUNC(cmd_addbadword)
1352{
1353 struct chanInfo *cInfo = get_chanInfo(channel->name);
1354 struct userData *uData;
1355 unsigned int i;
1356
1357 if(!cInfo || !channel->channel_info)
1358 {
1359 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1360 return 0;
1361 }
1362
1363 if(CHECK_SUSPENDED(cInfo))
1364 {
1365 ss_reply("SSMSG_SUSPENDED", channel->name);
1366 return 0;
1367 }
1368
1369 if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1370 {
1371 ss_reply("SSMSG_NO_ACCESS");
1372 return 0;
1373 }
1374
1375 if(argc < 2)
1376 return show_badwords(user, cInfo);
1377
1378 if(cInfo->badwords->used == spamserv_conf.badword_max && !IsOper(user))
1379 {
1380 ss_reply("SSMSG_BADWORD_MAX", spamserv_conf.badword_max);
1381 return 0;
1382 }
1383
1384 if(strlen(argv[1]) < spamserv_conf.badword_min_len)
1385 {
1386 ss_reply("SSMSG_BADWORD_TOO_SHORT", spamserv_conf.badword_min_len);
1387 return 0;
1388 }
1389 else if(strlen(argv[1]) > spamserv_conf.badword_max_len)
1390 {
1391 ss_reply("SSMSG_BADWORD_TOO_LONG", spamserv_conf.badword_max_len);
1392 return 0;
1393 }
1394
1395 for(i = 0; i < cInfo->badwords->used; i++)
1396 {
1397 if(!irccasecmp(argv[1], cInfo->badwords->list[i]))
1398 {
1399 ss_reply("SSMSG_BADWORD_IN_LIST", argv[1]);
1400 return 0;
1401 }
1402 }
1403
1404 string_list_append(cInfo->badwords, strdup(argv[1]));
1405 ss_reply("SSMSG_BADWORD_ADDED", argv[1]);
1406
1407 return 1;
1408}
1409
1410static
1411SPAMSERV_FUNC(cmd_delbadword)
1412{
1413 struct chanInfo *cInfo = get_chanInfo(channel->name);
1414 struct userData *uData;
1415 unsigned int i;
1416 int found = -1;
1417
1418 if(!cInfo || !channel->channel_info)
1419 {
1420 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1421 return 0;
1422 }
1423
1424 if(CHECK_SUSPENDED(cInfo))
1425 {
1426 ss_reply("SSMSG_SUSPENDED", channel->name);
1427 return 0;
1428 }
1429
1430 if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1431 {
1432 ss_reply("SSMSG_NO_ACCESS");
1433 return 0;
1434 }
1435
1436 if(argc < 2)
1437 return show_badwords(user, cInfo);
1438
1439 for(i = 0; i < cInfo->badwords->used; i++)
1440 {
1441 if(!irccasecmp(argv[1], cInfo->badwords->list[i]))
1442 {
1443 found = i;
1444 break;
1445 }
1446 }
1447
1448 if(found == -1)
1449 {
1450 ss_reply("SSMSG_NO_SUCH_BADWORD", argv[1]);
1451 return 0;
1452 }
1453
1454 string_list_delete(cInfo->badwords, i);
1455 ss_reply("SSMSG_BADWORD_DELETED", argv[1]);
1456
1457 return 1;
1458}
1459
1460static
1461SPAMSERV_FUNC(cmd_set)
1462{
1463 struct chanInfo *cInfo = get_chanInfo(channel->name);
1464 struct userData *uData;
1465 struct svccmd *subcmd;
1466 char cmd_name[MAXLEN];
1467 unsigned int i;
1468
1469 if(!cInfo)
1470 {
1471 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1472 return 0;
1473 }
1474
1475 if(CHECK_SUSPENDED(cInfo))
1476 {
1477 ss_reply("SSMSG_SUSPENDED", channel->name);
1478 return 0;
1479 }
1480
1481 if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1482 {
1483 ss_reply("SSMSG_NO_ACCESS");
1484 return 0;
1485 }
1486
1487 if(argc < 2)
1488 {
1489 ss_reply("SSMSG_CHANNEL_OPTIONS");
1490
1491 for(i = 0; i < SET_SUBCMDS_SIZE; i++)
1492 {
1493 sprintf(cmd_name, "%s %s", cmd->name, set_subcommands[i]);
1494
1495 if((subcmd = dict_find(cmd->parent->commands, cmd_name, NULL)))
1496 subcmd->command->func(user, channel, 1, argv + 1, subcmd);
1497 }
1498
1499 return 1;
1500 }
1501
1502 sprintf(cmd_name, "%s %s", cmd->name, argv[1]);
1503 subcmd = dict_find(cmd->parent->commands, cmd_name, NULL);
1504
1505 if(!subcmd)
1506 {
1507 reply("SSMSG_INVALID_OPTION", argv[1], argv[0]);
1508 return 0;
1509 }
1510
1511 return subcmd->command->func(user, channel, argc - 1, argv + 1, subcmd);
1512}
1513
1514static
1515SPAMSERV_FUNC(opt_spamlimit)
1516{
1517 struct valueData values[] =
1518 {
1519 {"Users may send the same message $b2$b times.", 'a', 0},
1520 {"Users may send the same message $b3$b times.", 'b', 0},
1521 {"Users may send the same message $b4$b times.", 'c', 0},
1522 {"Users may send the same message $b5$b times.", 'd', 0},
1523 {"Users may send the same message $b6$b times.", 'e', 0}
1524 };
1525
1526 MULTIPLE_OPTION("SpamLimit ", "SpamLimit", ci_SpamLimit);
1527}
1528
1529static
1530SPAMSERV_FUNC(opt_advreaction)
1531{
1532 struct valueData values[] =
1533 {
1534 {"Kick on disallowed advertising.", 'k', 0},
1535 {"Kickban on disallowed advertising.", 'b', 0},
1536 {"Short timed ban on disallowed advertising.", 's', 0},
1537 {"Long timed ban on disallowed advertising.", 'l', 0},
1538 {"Kill on disallowed advertising.", 'd', 1}
1539 };
1540
1541 MULTIPLE_OPTION("AdvReaction ", "AdvReaction", ci_AdvReaction);
1542}
1543
1544static
1545SPAMSERV_FUNC(opt_warnreaction)
1546{
1547 struct valueData values[] =
1548 {
1549 {"Kick after warning.", 'k', 0},
1550 {"Kickban after warning.", 'b', 0},
1551 {"Short timed ban after warning.", 's', 0},
1552 {"Long timed ban after warning.", 'l', 0},
1553 {"Kill after warning.", 'd', 1}
1554 };
1555
1556 MULTIPLE_OPTION("WarnReaction ", "WarnReaction", ci_WarnReaction);
1557}
1558
1559static
1560SPAMSERV_FUNC(opt_badreaction)
1561{
1562 struct valueData values[] =
1563 {
1564 {"Kick on disallowed badwords.", 'k', 0},
1565 {"Kickban on disallowed badwords.", 'b', 0},
1566 {"Short timed ban on disallowed badwords.", 's', 0},
1567 {"Long timed ban on disallowed badwords.", 'l', 0},
1568 {"Kill on disallowed badwords.", 'd', 1}
1569 };
1570
1571 MULTIPLE_OPTION("BadReaction ", "BadReaction", ci_BadReaction);
1572}
1573
1574static
1575SPAMSERV_FUNC(opt_advscan)
1576{
1577 BINARY_OPTION("AdvScan ", CHAN_ADV_SCAN);
1578}
1579
1580static
1581SPAMSERV_FUNC(opt_spamscan)
1582{
1583 BINARY_OPTION("SpamScan ", CHAN_SPAMSCAN);
1584}
1585
1586static
1587SPAMSERV_FUNC(opt_badwordscan)
1588{
1589 BINARY_OPTION("BadWordScan ", CHAN_BADWORDSCAN);
1590}
1591
1592static
1593SPAMSERV_FUNC(opt_chanfloodscan)
1594{
1595 BINARY_OPTION("ChanFloodScan ", CHAN_CHANFLOODSCAN);
1596}
1597
1598static
1599SPAMSERV_FUNC(opt_joinflood)
1600{
1601 BINARY_OPTION("JoinFloodScan ", CHAN_JOINFLOOD);
1602}
1603
1604static
1605SPAMSERV_FUNC(opt_scanops)
1606{
1607 BINARY_OPTION("ScanChanOps ", CHAN_SCAN_CHANOPS);
1608}
1609
1610static
1611SPAMSERV_FUNC(opt_scanhalfops)
1612{
1613 BINARY_OPTION("ScanHalfOps ", CHAN_SCAN_HALFOPS);
1614}
1615
1616static
1617SPAMSERV_FUNC(opt_scanvoiced)
1618{
1619 BINARY_OPTION("ScanVoiced ", CHAN_SCAN_VOICED);
1620}
1621
1622static void
1623to_lower(char *message)
1624{
1625 unsigned int i, diff = 'a' - 'A';
1626
1627 for(i = 0; i < strlen(message); i++)
1628 {
1629 if((message[i] >= 'A') && (message[i] <= 'Z'))
1630 message[i] = message[i] + diff;
1631 }
1632}
1633
1634static char *
1635strip_mirc_codes(char *text)
1636{
1637 // taken from xchat and modified
1638 int nc = 0, i = 0, col = 0, len = strlen(text);
1639 static char new_str[MAXLEN];
1640
1641 while(len > 0)
1642 {
1643 if((col && isdigit(*text) && nc < 2) ||
1644 (col && *text == ',' && isdigit(*(text + 1)) && nc < 3))
1645 {
1646 nc++;
1647
1648 if(*text == ',')
1649 nc = 0;
1650 }
1651 else
1652 {
1653 col = 0;
1654
1655 switch(*text)
1656 {
1657 case '\003':
1658 col = 1;
1659 nc = 0;
1660 break;
1661 case '\002':
1662 case '\022':
1663 case '\026':
1664 case '\031':
1665 case '\037':
1666 break;
1667 default:
1668 new_str[i] = *text;
1669 i++;
1670 }
1671 }
1672
1673 text++;
1674 len--;
1675 }
1676
1677 new_str[i] = '\0';
1678
1679 return new_str;
1680}
1681
1682static int
1683is_in_exception_list(struct chanInfo *cInfo, char *message)
1684{
1685 unsigned int i;
1686
1687 for(i = 0; i < cInfo->exceptions->used; i++)
1688 if(strstr(message, cInfo->exceptions->list[i]))
1689 return 1;
1690
1691 return 0;
1692}
1693
1694static int
1695is_in_badword_list(struct chanInfo *cInfo, char *message)
1696{
1697 unsigned int i;
1698
1699 for(i = 0; i < cInfo->badwords->used; i++)
1700 if(strstr(message, cInfo->badwords->list[i]))
1701 return 1;
1702
1703 return 0;
1704}
1705
1706static int
1707check_badwords(struct chanInfo *cInfo, char *message)
1708{
1709 if(spamserv_conf.strip_mirc_codes)
1710 message = strip_mirc_codes(message);
1711
1712 /* This needs improving */
1713 if(is_in_exception_list(cInfo, message))
1714 return 0;
1715
1716 if(is_in_badword_list(cInfo, message))
1717 return 1;
1718
1719 return 0;
1720}
1721
1722static int
1723check_advertising(struct chanInfo *cInfo, char *message)
1724{
1725 unsigned int i = 0;
1726
1727 if(spamserv_conf.strip_mirc_codes)
1728 message = strip_mirc_codes(message);
1729
1730 if(is_in_exception_list(cInfo, message))
1731 return 0;
1732
1733 while(message[i] != 0)
1734 {
1735 if(message[i] == '#')
1736 {
1737 char channelname[CHANNELLEN];
1738 unsigned int j = 0;
1739
1740 if(!spamserv_conf.adv_chan_must_exist)
1741 return 1;
1742
1743 /* only return 1, if the channel does exist */
1744
1745 while((message[i] != 0) && (message[i] != ' '))
1746 {
1747 channelname[j] = message[i];
1748 i++;
1749 j++;
1750 }
1751
1752 channelname[j] = '\0';
1753
1754 if(GetChannel(channelname))
1755 return 1;
1756 }
1757 else if((message[i] == 'w') && (message[i+1] == 'w') && (message[i+2] == 'w') && (message[i+3] == '.'))
1758 return 1;
1759 else if((message[i] == 'h') && (message[i+1] == 't') && (message[i+2] == 't') && (message[i+3] == 'p') && (message[i+4] == ':'))
1760 return 1;
1761 else if((message[i] == 'f') && (message[i+1] == 't') && (message[i+2] == 'p') && ((message[i+3] == '.') || (message[i+3] == ':')))
1762 return 1;
1763
1764 i++;
1765 }
1766
1767 return 0;
1768}
1769
1770static void
1771spamserv_punish(struct chanNode *channel, struct userNode *user, time_t expires, char *reason, int ban)
1772{
1773 if(ban)
1774 {
1775 struct mod_chanmode change;
1776 char *hostmask = generate_hostmask(user, GENMASK_STRICT_HOST | GENMASK_ANY_IDENT);
1777
1778 sanitize_ircmask(hostmask);
1779
1780 if(expires)
1781 add_channel_ban(channel->channel_info, hostmask, spamserv->nick, now, now, now + expires, reason);
1782
1783 mod_chanmode_init(&change);
1784 change.argc = 1;
1785 change.args[0].mode = MODE_BAN;
1786 change.args[0].u.hostmask = hostmask;
1787 mod_chanmode_announce(spamserv, channel, &change);
1788
1789 free(hostmask);
1790
1791 spamserv_debug(SSMSG_DEBUG_BAN, user->nick, channel->name, reason);
1792 }
1793 else
1794 spamserv_debug(SSMSG_DEBUG_KICK, user->nick, channel->name, reason);
1795
1796 KickChannelUser(user, channel, spamserv, reason);
1797}
1798
1799void
1800spamserv_channel_message(struct chanNode *channel, struct userNode *user, char *text)
1801{
1802 struct chanInfo *cInfo;
1803 struct userInfo *uInfo;
1804 struct spamNode *sNode;
1805 struct floodNode *fNode;
1806 unsigned int violation = 0;
1807 char reason[MAXLEN];
1808
1809 /* make sure: spamserv is not disabled; x3 is running; spamserv is in the chan; chan is regged, user does exist */
1810 if(!spamserv || quit_services || !GetUserMode(channel, spamserv) || !(cInfo = get_chanInfo(channel->name)) || !(uInfo = get_userInfo(user->nick)))
1811 return;
1812
1813 if(!CHECK_CHANOPS(cInfo))
1814 {
1815 struct modeNode *mn = GetUserMode(channel, user);
1816 if(mn->modes & MODE_CHANOP)
1817 return;
1818 }
1819
1820 if(!CHECK_HALFOPS(cInfo))
1821 {
1822 struct modeNode *mn = GetUserMode(channel, user);
1823 if(mn->modes & MODE_HALFOP)
1824 return;
1825 }
1826
1827 if(!CHECK_VOICED(cInfo))
1828 {
1829 struct modeNode *mn = GetUserMode(channel, user);
1830 if((mn->modes & MODE_VOICE) && !(mn->modes & MODE_CHANOP) && !(mn->modes & MODE_HALFOP))
1831 return;
1832 }
1833
1834 to_lower(text);
1835
1836 if(CHECK_SPAM(cInfo))
1837 {
1838 if(!(sNode = uInfo->spam))
1839 {
1840 spamserv_create_spamNode(channel, uInfo, text);
1841 }
1842 else
1843 {
1844 for(; sNode; sNode = sNode->next)
1845 if(sNode->channel == channel)
1846 break;
1847
1848 if(!sNode)
1849 {
1850 spamserv_create_spamNode(channel, uInfo, text);
1851 }
1852 else
1853 {
1854 unsigned long crc = crc32(text);
1855
1856 if(crc == sNode->crc32)
1857 {
1858 unsigned int spamlimit = 2;
1859 sNode->count++;
1860
1861 switch(cInfo->info[ci_SpamLimit])
1862 {
1863 case 'a': spamlimit = 2; break;
1864 case 'b': spamlimit = 3; break;
1865 case 'c': spamlimit = 4; break;
1866 case 'd': spamlimit = 5; break;
1867 case 'e': spamlimit = 6; break;
1868 }
1869
1870 if(sNode->count == spamlimit)
1871 {
1872 uInfo->warnlevel += SPAM_WARNLEVEL;
1873
1874 if(uInfo->warnlevel < MAX_WARNLEVEL) {
1875 if (spamserv_conf.network_rules)
1876 spamserv_notice(user, "SSMSG_WARNING_RULES_T", SSMSG_SPAM, spamserv_conf.network_rules);
1877 else
1878 spamserv_notice(user, "SSMSG_WARNING_T", SSMSG_SPAM, spamserv_conf.network_rules);
1879 }
1880 }
1881 else if(sNode->count > spamlimit)
1882 {
1883 switch(cInfo->info[ci_WarnReaction])
1884 {
1885 case 'k': uInfo->flags |= USER_KICK; break;
1886 case 'b': uInfo->flags |= USER_KICKBAN; break;
1887 case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1888 case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1889 case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1890 }
1891
1892 spamserv_delete_spamNode(uInfo, sNode);
1893 uInfo->warnlevel += SPAM_WARNLEVEL;
1894 violation = 1;
1895 }
1896 }
1897 else
1898 {
1899 sNode->crc32 = crc;
1900 sNode->count = 1;
1901 }
1902 }
1903 }
1904 }
1905
1906 if(CHECK_FLOOD(cInfo))
1907 {
1908 if(!(fNode = uInfo->flood))
1909 {
1910 spamserv_create_floodNode(channel, user, &uInfo->flood);
1911 }
1912 else
1913 {
1914 for(; fNode; fNode = fNode->next)
1915 if(fNode->channel == channel)
1916 break;
1917
1918 if(!fNode)
1919 {
1920 spamserv_create_floodNode(channel, user, &uInfo->flood);
1921 }
1922 else
1923 {
1924 if(((now - fNode->time) < FLOOD_EXPIRE))
1925 {
1926 fNode->count++;
1927
1928 if(fNode->count == FLOOD_MAX_LINES - 1)
1929 {
1930 uInfo->warnlevel += FLOOD_WARNLEVEL;
1931
1932 if(uInfo->warnlevel < MAX_WARNLEVEL) {
1933 if (spamserv_conf.network_rules)
1934 spamserv_notice(user, "SSMSG_WARNING_RULES_T", SSMSG_FLOOD, spamserv_conf.network_rules);
1935 else
1936 spamserv_notice(user, "SSMSG_WARNING_T", SSMSG_FLOOD, spamserv_conf.network_rules);
1937 }
1938 }
1939 else if(fNode->count > FLOOD_MAX_LINES)
1940 {
1941 switch(cInfo->info[ci_WarnReaction])
1942 {
1943 case 'k': uInfo->flags |= USER_KICK; break;
1944 case 'b': uInfo->flags |= USER_KICKBAN; break;
1945 case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1946 case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1947 case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1948 }
1949
1950 spamserv_delete_floodNode(&uInfo->flood, fNode);
1951 uInfo->warnlevel += FLOOD_WARNLEVEL;
1952 violation = 2;
1953 }
1954 }
1955
1956 fNode->time = now;
1957 }
1958 }
1959 }
1960
1961 if(CHECK_BADWORDSCAN(cInfo) && check_badwords(cInfo, text))
1962 {
1963 if(CHECK_BAD_WARNED(uInfo))
1964 {
1965 switch(cInfo->info[ci_BadReaction])
1966 {
1967 case 'k': uInfo->flags |= USER_KICK; break;
1968 case 'b': uInfo->flags |= USER_KICKBAN; break;
1969 case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1970 case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1971 case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1972 }
1973
1974 uInfo->warnlevel += BAD_WARNLEVEL;
1975 violation = 4;
1976 }
1977 else
1978 {
1979 uInfo->flags |= USER_BAD_WARNED;
1980 uInfo->lastbad = now;
1981 uInfo->warnlevel += BAD_WARNLEVEL;
1982
1983 if(uInfo->warnlevel < MAX_WARNLEVEL) {
1984 if (spamserv_conf.network_rules)
1985 spamserv_notice(user, "SSMSG_WARNING_RULES_T", SSMSG_BAD, spamserv_conf.network_rules);
1986 else
1987 spamserv_notice(user, "SSMSG_WARNING_T", SSMSG_BAD, spamserv_conf.network_rules);
1988 }
1989 }
1990 }
1991
1992 if(CHECK_ADV(cInfo) && check_advertising(cInfo, text))
1993 {
1994 if(CHECK_ADV_WARNED(uInfo))
1995 {
1996 switch(cInfo->info[ci_AdvReaction])
1997 {
1998 case 'k': uInfo->flags |= USER_KICK; break;
1999 case 'b': uInfo->flags |= USER_KICKBAN; break;
2000 case 's': uInfo->flags |= USER_SHORT_TBAN; break;
2001 case 'l': uInfo->flags |= USER_LONG_TBAN; break;
2002 case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
2003 }
2004
2005 uInfo->warnlevel += ADV_WARNLEVEL;
2006 violation = 3;
2007 }
2008 else
2009 {
2010 uInfo->flags |= USER_ADV_WARNED;
2011 uInfo->lastadv = now;
2012 uInfo->warnlevel += ADV_WARNLEVEL;
2013
2014 if(uInfo->warnlevel < MAX_WARNLEVEL) {
2015 if (spamserv_conf.network_rules)
2016 spamserv_notice(user, "SSMSG_WARNING_RULES_T", SSMSG_ADV, spamserv_conf.network_rules);
2017 else
2018 spamserv_notice(user, "SSMSG_WARNING_T", SSMSG_ADV, spamserv_conf.network_rules);
2019 }
2020 }
2021 }
2022
2023 if(!CHECK_WARNED(uInfo) && !CHECK_KILL(uInfo) && !CHECK_GLINE(uInfo) && uInfo->warnlevel == MAX_WARNLEVEL)
2024 {
2025 uInfo->flags |= USER_WARNED;
2026 if (spamserv_conf.network_rules)
2027 snprintf(reason, sizeof(reason), SSMSG_WARNING_RULES_2, spamserv_conf.network_rules);
2028 else
2029 snprintf(reason, sizeof(reason), SSMSG_WARNING_2);
2030 irc_notice(spamserv, user->numeric, reason);
2031 irc_privmsg(spamserv, user->numeric, reason);
2032 }
2033 else if(uInfo->warnlevel > MAX_WARNLEVEL)
2034 {
2035 if(CHECK_KILLED(uInfo))
2036 uInfo->flags |= USER_GLINE;
2037 else
2038 uInfo->flags |= USER_KILL;
2039
2040 violation = 5;
2041 }
2042
2043 if(!violation)
2044 return;
2045
2046 switch(violation)
2047 {
2048
2049 case 1: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_SPAM, spamserv_conf.network_rules); break;
2050 case 2: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_FLOOD, spamserv_conf.network_rules); break;
2051 case 3: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_ADV, spamserv_conf.network_rules); break;
2052 case 4: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_BAD, spamserv_conf.network_rules); break;
2053 default: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES_2 : SSMSG_WARNING_2, spamserv_conf.network_rules); break;
2054 }
2055
2056 if(CHECK_GLINE(uInfo))
2057 {
2058 int size = strlen(user->hostname) + 3;
2059 char *mask = alloca(size);
2060 snprintf(mask, size, "*@%s", user->hostname);
2061 gline_add(spamserv->nick, mask, spamserv_conf.gline_duration, reason, now, 1, 0);
2062 spamserv_debug(SSMSG_DEBUG_GLINE, user->nick, user->hostname, channel->name);
2063 }
2064 else if(CHECK_KILL(uInfo))
2065 {
2066 DelUser(user, spamserv, 1, reason);
2067 spamserv_debug(SSMSG_DEBUG_KILL, user->nick, channel->name);
2068 }
2069 else if(CHECK_LONG_TBAN(uInfo))
2070 {
2071 spamserv_punish(channel, user, spamserv_conf.long_ban_duration, reason, 1);
2072 }
2073 else if(CHECK_SHORT_TBAN(uInfo))
2074 {
2075 spamserv_punish(channel, user, spamserv_conf.short_ban_duration, reason, 1);
2076 }
2077 else if(CHECK_KICKBAN(uInfo))
2078 {
2079 spamserv_punish(channel, user, 0, reason, 1);
2080 }
2081 else if(CHECK_KICK(uInfo))
2082 {
2083 spamserv_punish(channel, user, 0, reason, 0);
2084 }
2085}
2086
2087static int
2088spamserv_saxdb_read(struct dict *database)
2089{
2090 dict_iterator_t it;
2091 struct record_data *hir;
2092 struct chanNode *channel;
2093 struct chanInfo *cInfo;
2094 struct string_list *strlist, *strlist2;
2095 unsigned int flags;
2096 char *str, *info;
2097 time_t expiry;
2098
2099 for(it = dict_first(database); it; it = iter_next(it))
2100 {
2101 hir = iter_data(it);
2102
2103 if(hir->type != RECDB_OBJECT)
2104 {
2105 log_module(SS_LOG, LOG_WARNING, "Unexpected rectype %d for %s.", hir->type, iter_key(it));
2106 continue;
2107 }
2108
2109 channel = GetChannel(iter_key(it));
3ec42e29 2110
63c95a47 2111 strlist = database_get_data(hir->d.object, KEY_EXCEPTIONS, RECDB_STRING_LIST);
2112 strlist2 = database_get_data(hir->d.object, KEY_BADWORDS, RECDB_STRING_LIST);
2113
2114 str = database_get_data(hir->d.object, KEY_FLAGS, RECDB_QSTRING);
2115 flags = str ? atoi(str) : 0;
2116
2117 info = database_get_data(hir->d.object, KEY_INFO, RECDB_QSTRING);
2118
2119 str = database_get_data(hir->d.object, KEY_EXPIRY, RECDB_QSTRING);
2120 expiry = str ? strtoul(str, NULL, 0) : 0;
2121
2122 if(channel && info)
2123 {
2124 if((cInfo = spamserv_register_channel(channel, strlist, strlist2, flags, info)))
2125 {
2126 /* if the channel is suspended and expiry = 0 it means: channel will
2127 never expire ! it does NOT mean, the channel is not suspended */
2128 if(CHECK_SUSPENDED(cInfo) && expiry && (expiry < now))
2129 {
2130 cInfo->flags &= ~CHAN_SUSPENDED;
2131 spamserv_join_channel(cInfo->channel);
2132 }
2133 else if(!CHECK_SUSPENDED(cInfo))
2134 spamserv_join_channel(cInfo->channel);
2135 else
2136 cInfo->suspend_expiry = expiry;
2137 }
2138 }
2139 else
2140 log_module(SS_LOG, LOG_ERROR, "Couldn't register channel %s. Channel or info invalid.", iter_key(it));
2141 }
2142
2143 return 0;
2144}
2145
2146static int
2147spamserv_saxdb_write(struct saxdb_context *ctx)
2148{
2149 dict_iterator_t it;
2150
2151 for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
2152 {
2153 struct chanInfo *cInfo = iter_data(it);
2154
2155 saxdb_start_record(ctx, cInfo->channel->name, 1);
2156
2157 if(cInfo->exceptions->used)
2158 saxdb_write_string_list(ctx, KEY_EXCEPTIONS, cInfo->exceptions);
2159
2160 if(cInfo->badwords->used)
2161 saxdb_write_string_list(ctx, KEY_BADWORDS, cInfo->badwords);
2162
2163 if(cInfo->flags)
2164 saxdb_write_int(ctx, KEY_FLAGS, cInfo->flags);
2165
2166 saxdb_write_string(ctx, KEY_INFO, cInfo->info);
2167
2168 if(cInfo->suspend_expiry)
2169 saxdb_write_int(ctx, KEY_EXPIRY, cInfo->suspend_expiry);
2170
2171 saxdb_end_record(ctx);
2172 }
2173 return 0;
2174}
2175
2176static void
2177spamserv_conf_read(void)
2178{
2179 dict_t conf_node;
2180 const char *str;
2181
2182 if(!(conf_node = conf_get_data(SPAMSERV_CONF_NAME, RECDB_OBJECT)))
2183 {
2184 log_module(SS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", SPAMSERV_CONF_NAME);
2185 return;
2186 }
2187
2188 str = database_get_data(conf_node, KEY_DEBUG_CHANNEL, RECDB_QSTRING);
2189
2190 if(str)
2191 {
2192 spamserv_conf.debug_channel = AddChannel(str, now, "+tinms", NULL, NULL);
2193
2194 if(spamserv_conf.debug_channel)
2195 spamserv_join_channel(spamserv_conf.debug_channel);
2196 }
2197 else
2198 {
2199 spamserv_conf.debug_channel = NULL;
2200 }
2201
2202 spamserv_conf.global_exceptions = database_get_data(conf_node, KEY_GLOBAL_EXCEPTIONS, RECDB_STRING_LIST);
2203
2204 spamserv_conf.global_badwords = database_get_data(conf_node, KEY_GLOBAL_BADWORDS, RECDB_STRING_LIST);
2205
2206 str = database_get_data(conf_node, KEY_NETWORK_RULES, RECDB_QSTRING);
2207 spamserv_conf.network_rules = str ? str : NULL;
2208
2209 str = database_get_data(conf_node, KEY_TRIGGER, RECDB_QSTRING);
2210 spamserv_conf.trigger = str ? str[0] : 0;
2211
2212 str = database_get_data(conf_node, KEY_SHORT_BAN_DURATION, RECDB_QSTRING);
2213 spamserv_conf.short_ban_duration = str ? ParseInterval(str) : ParseInterval("15m");
2214
2215 str = database_get_data(conf_node, KEY_LONG_BAN_DURATION, RECDB_QSTRING);
2216 spamserv_conf.long_ban_duration = str ? ParseInterval(str) : ParseInterval("1h");
2217
2218 str = database_get_data(conf_node, KEY_GLINE_DURATION, RECDB_QSTRING);
2219 spamserv_conf.gline_duration = str ? ParseInterval(str) : ParseInterval("1h");
2220
2221 str = database_get_data(conf_node, KEY_EXCEPTION_MAX, RECDB_QSTRING);
2222 spamserv_conf.exception_max = str ? strtoul(str, NULL, 0) : 10;
2223
2224 str = database_get_data(conf_node, KEY_EXCEPTION_MIN_LEN, RECDB_QSTRING);
2225 spamserv_conf.exception_min_len = str ? strtoul(str, NULL, 0) : 4;
2226
2227 str = database_get_data(conf_node, KEY_EXCEPTION_MAX_LEN, RECDB_QSTRING);
2228 spamserv_conf.exception_max_len = str ? strtoul(str, NULL, 0) : 15;
2229
2230 str = database_get_data(conf_node, KEY_BADWORD_MAX, RECDB_QSTRING);
2231 spamserv_conf.badword_max = str ? strtoul(str, NULL, 0) : 10;
2232
2233 str = database_get_data(conf_node, KEY_BADWORD_MIN_LEN, RECDB_QSTRING);
2234 spamserv_conf.badword_min_len = str ? strtoul(str, NULL, 0) : 4;
2235
2236 str = database_get_data(conf_node, KEY_BADWORD_MAX_LEN, RECDB_QSTRING);
2237 spamserv_conf.badword_max_len = str ? strtoul(str, NULL, 0) : 15;
2238
2239 str = database_get_data(conf_node, KEY_ADV_CHAN_MUST_EXIST, RECDB_QSTRING);
2240 spamserv_conf.adv_chan_must_exist = str ? enabled_string(str) : 1;
2241
2242 str = database_get_data(conf_node, KEY_STRIP_MIRC_CODES, RECDB_QSTRING);
2243 spamserv_conf.strip_mirc_codes = str ? enabled_string(str) : 0;
2244
2245 str = database_get_data(conf_node, KEY_ALLOW_MOVE_MERGE, RECDB_QSTRING);
2246 spamserv_conf.allow_move_merge = str ? enabled_string(str) : 0;
2247}
2248
2249static void
2250spamserv_db_cleanup(void)
2251{
2252 dict_iterator_t it;
2253
2254 while((it = dict_first(registered_channels_dict)))
2255 {
2256 spamserv_unregister_channel(iter_data(it));
2257 }
2258
2259 while((it = dict_first(killed_users_dict)))
2260 {
2261 free(iter_data(it));
2262 }
2263
2264 dict_delete(registered_channels_dict);
2265 dict_delete(connected_users_dict);
2266 dict_delete(killed_users_dict);
2267}
2268
2269void
2270init_spamserv(const char *nick)
2271{
2272 struct chanNode *chan;
2273 unsigned int i;
2274
2275 if(!nick)
2276 return;
2277
2278 const char *modes = conf_get_data("services/spamserv/modes", RECDB_QSTRING);
2279 spamserv = AddService(nick, modes ? modes : NULL, "Anti Spam Services", NULL);
2280 spamserv_service = service_register(spamserv);
2281
2282 conf_register_reload(spamserv_conf_read);
2283
2284 SS_LOG = log_register_type("SpamServ", "file:spamserv.log");
2285
2286 registered_channels_dict = dict_new();
2287 connected_users_dict = dict_new();
2288 killed_users_dict = dict_new();
2289
3ec42e29 2290 saxdb_register("SpamServ", spamserv_saxdb_read, spamserv_saxdb_write);
2291
63c95a47 2292 reg_new_user_func(spamserv_new_user_func);
2293 reg_del_user_func(spamserv_del_user_func);
2294 reg_nick_change_func(spamserv_nick_change_func);
2295 reg_join_func(spamserv_user_join);
2296 reg_part_func(spamserv_user_part);
2297
2298 timeq_add(now + FLOOD_TIMEQ_FREQ, timeq_flood, NULL);
2299 timeq_add(now + JOINFLOOD_TIMEQ_FREQ, timeq_joinflood, NULL);
2300 timeq_add(now + ADV_TIMEQ_FREQ, timeq_adv, NULL);
2301 timeq_add(now + BAD_TIMEQ_FREQ, timeq_bad, NULL);
2302 timeq_add(now + WARNLEVEL_TIMEQ_FREQ, timeq_warnlevel, NULL);
2303 timeq_add(now + KILL_TIMEQ_FREQ, timeq_kill, NULL);
2304
2305 spamserv_module = module_register("SpamServ", SS_LOG, "spamserv.help", NULL);
2306 modcmd_register(spamserv_module, "REGISTER", cmd_register, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, "flags", "+acceptchan,+helping", NULL);
2307 modcmd_register(spamserv_module, "UNREGISTER", cmd_unregister, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, "flags", "+loghostmask", NULL);
2308 modcmd_register(spamserv_module, "ADDEXCEPTION", cmd_addexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2309 modcmd_register(spamserv_module, "DELEXCEPTION", cmd_delexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2310 modcmd_register(spamserv_module, "ADDBADWORD", cmd_addbadword, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2311 modcmd_register(spamserv_module, "DELBADWORD", cmd_delbadword, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2312 modcmd_register(spamserv_module, "STATUS", cmd_status, 1, 0, NULL);
2313 modcmd_register(spamserv_module, "SET", cmd_set, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2314 modcmd_register(spamserv_module, "SET SPAMLIMIT", opt_spamlimit, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2315 modcmd_register(spamserv_module, "SET BADREACTION", opt_badreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2316 modcmd_register(spamserv_module, "SET ADVREACTION", opt_advreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2317 modcmd_register(spamserv_module, "SET WARNREACTION", opt_warnreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2318 modcmd_register(spamserv_module, "SET ADVSCAN", opt_advscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2319 modcmd_register(spamserv_module, "SET BADWORDSCAN", opt_badwordscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2320 modcmd_register(spamserv_module, "SET SPAMSCAN", opt_spamscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2321 modcmd_register(spamserv_module, "SET CHANFLOODSCAN", opt_chanfloodscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2322 modcmd_register(spamserv_module, "SET JOINFLOODSCAN", opt_joinflood, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2323 modcmd_register(spamserv_module, "SET SCANCHANOPS", opt_scanops, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2324 modcmd_register(spamserv_module, "SET SCANHALFOPS", opt_scanhalfops, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2325 modcmd_register(spamserv_module, "SET SCANVOICED", opt_scanvoiced, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2326
2327 spamserv_service->trigger = spamserv_conf.trigger;
2328
2329
2330 if (autojoin_channels && spamserv) {
2331 for (i = 0; i < autojoin_channels->used; i++) {
2332 chan = AddChannel(autojoin_channels->list[i], now, "+nt", NULL, NULL);
2333 AddChannelUser(spamserv, chan)->modes |= MODE_CHANOP;
2334 }
2335 }
2336
63c95a47 2337 reg_exit_func(spamserv_db_cleanup);
2338 message_register_table(msgtab);
2339 crc32_init();
2340}