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