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