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