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