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