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