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