35cf836afaa72cf0864ddcd3fd8de0f67603439b
[srvx.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 srvx-maintainers@srvx.net.
17  *
18  * $Id: spamserv.c,v 1.08 2004/06/27 22:21:00 feigling Exp $
19  */
20
21 #include "conf.h"
22 #include "spamserv.h"
23 #include "chanserv.h"
24 #include "global.h"
25 #include "modcmd.h"
26 #include "saxdb.h"
27 #include "timeq.h"
28 #include "gline.h"
29
30 #define SPAMSERV_CONF_NAME           "services/spamserv"
31
32 #define KEY_EXCEPTIONS               "exceptions"
33 #define KEY_FLAGS                    "flags"
34 #define KEY_INFO                     "info"
35 #define KEY_EXCEPTLEVEL              "exceptlevel"
36 #define KEY_EXPIRY                   "expiry"
37
38 #define KEY_DEBUG_CHANNEL            "debug_channel"
39 #define KEY_GLOBAL_EXCEPTIONS        "global_exceptions"
40 #define KEY_NETWORK_RULES            "network_rules"
41 #define KEY_TRIGGER                  "trigger"
42 #define KEY_SHORT_BAN_DURATION       "short_ban_duration"
43 #define KEY_LONG_BAN_DURATION        "long_ban_duration"
44 #define KEY_GLINE_DURATION           "gline_duration"
45 #define KEY_EXCEPTION_MAX            "exception_max"
46 #define KEY_EXCEPTION_MIN_LEN        "exception_min_len"
47 #define KEY_EXCEPTION_MAX_LEN        "exception_max_len"
48 #define KEY_ADV_CHAN_MUST_EXIST      "adv_chan_must_exist"
49 #define KEY_STRIP_MIRC_CODES         "strip_mirc_codes"
50 #define KEY_ALLOW_MOVE_MERGE         "allow_move_merge"
51
52 #define SPAMSERV_FUNC(NAME)     MODCMD_FUNC(NAME)
53 #define SPAMSERV_SYNTAX()       svccmd_send_help(user, spamserv, cmd)
54 #define SPAMSERV_MIN_PARMS(N) do { \
55 (void)argv; \
56   if(argc < N) { \
57     ss_reply(MSG_MISSING_PARAMS, argv[0]); \
58     SPAMSERV_SYNTAX(); \
59     return 0; } } while(0)
60
61 struct userNode                 *spamserv;
62 static struct module    *spamserv_module;
63 static struct service   *spamserv_service;
64 static struct log_type  *SS_LOG;
65 static unsigned long    crc_table[256];
66
67 dict_t registered_channels_dict;
68 dict_t connected_users_dict;
69 dict_t killed_users_dict;
70
71 #define spamserv_notice(target, format...) send_message(target , spamserv , ## format)
72 #define spamserv_debug(format...) do { if(spamserv_conf.debug_channel) send_channel_notice(spamserv_conf.debug_channel , spamserv , ## format); } while(0)
73 #define ss_reply(format...)     send_message(user , spamserv , ## format)
74
75 #define SET_SUBCMDS_SIZE 10
76
77 const char *set_subcommands[SET_SUBCMDS_SIZE] = {"SPAMLIMIT", "ADVREACTION", "WARNREACTION", "ADVSCAN", "SPAMSCAN", "FLOODSCAN", "JOINFLOODSCAN", "EXCEPTLEVEL","SCANCHANOPS", "SCANVOICED"};
78
79 static void spamserv_clear_spamNodes(struct chanNode *channel);
80 static void spamserv_punish(struct chanNode *channel, struct userNode *user, time_t expires, char *reason, int ban);
81 static unsigned long crc32(const char *text);
82
83 #define BINARY_OPTION(arguments...)     return binary_option(arguments, user, channel, argc, argv);
84 #define MULTIPLE_OPTION(arguments...)   return multiple_option(arguments, values, ArrayLength(values), user, channel, argc, argv);
85
86 static const struct message_entry msgtab[] = {
87     { "SSMSG_CHANNEL_OPTIONS",         "Channel Options:" },
88     { "SSMSG_STRING_VALUE",            "$b%s$b%s" },
89     { "SSMSG_NUMERIC_VALUE",           "$b%s$b%d - %s" },
90     { "SSMSG_EASYNUMERIC_VALUE",       "$b%s$b%d" },
91     { "SSMSG_INVALID_NUM_SET",         "$b'%d'$b is an invalid %s setting." },
92     { "SSMSG_INVALID_OPTION",          "$b%s$b is not a valid %s option." },
93     { "SSMSG_INVALID_BINARY",          "$b%s$b is an invalid binary value." },
94
95     { "SSMSG_NOT_REGISTERED",          "$b%s$b has not been registered with $b$X$b." },
96     { "SSMSG_NOT_REGISTERED_CS",       "$b%s$b has not been registered with $b$C$b." },
97     { "SSMSG_ALREADY_REGISTERED",      "$b%s$b is already registered." },
98     { "SSMSG_DEBUG_CHAN",              "You may not register the debug channel." },
99     { "SSMSG_SUSPENDED_CS",            "$b$C$b access to $b%s$b has been temporarily suspended, thus you can't %s it." },
100     { "SSMSG_SUSPENDED",               "$b$X$b access to $b%s$b has been temporarily suspended." },
101     { "SSMSG_NO_REGISTER",             "Due to an error it was not possible to register $b%s$b." },
102     { "SSMSG_REG_SUCCESS",             "Channel $b%s$b registered." },
103     { "SSMSG_UNREG_SUCCESS",           "$b%s$b has been unregistered." },
104     { "SSMSG_NO_ACCESS",               "You lack sufficient access to use this command." },
105     { "SSMSG_MUST_BE_OPER",            "You must be an irc operator to set this option." },
106     { "SSMSG_CONFIRM_UNREG",           "To confirm this unregistration, you must append 'CONFIRM' to the end of your command. For example, 'unregister CONFIRM'." },
107
108     { "SSMSG_NO_EXCEPTIONS",           "No words found in the exception list." },
109     { "SSMSG_NO_SUCH_EXCEPTION",       "Word $b%s$b not found in the exception list." },
110     { "SSMSG_EXCEPTION_LIST",          "The following words are in the exception list:" },
111     { "SSMSG_EXCEPTION_ADDED",         "Word $b%s$b added to the exception list." },
112     { "SSMSG_EXCEPTION_DELETED",       "Word $b%s$b deleted from the exception list." },
113     { "SSMSG_EXCEPTION_IN_LIST",       "The word $b%s$b is already in the exception list." },
114     { "SSMSG_EXCEPTION_MAX",           "The exception list has reached the maximum exceptions (max %lu). Delete a word to add another one." },
115     { "SSMSG_EXCEPTION_TOO_SHORT",     "The word must be at least %lu characters long." },
116     { "SSMSG_EXCEPTION_TOO_LONG",      "The word may not be longer than %lu characters." },
117
118     { "SSMSG_STATUS",                  "$bStatus:$b" },
119     { "SSMSG_STATUS_USERS",            "Total Users Online:  %u" },
120     { "SSMSG_STATUS_CHANNELS",         "Registered Channels: %u" },
121     { "SSMSG_STATUS_MEMORY",           "$bMemory Information:$b" },
122     { "SSMSG_STATUS_CHANNEL_LIST",     "$bRegistered Channels:$b" },
123     { "SSMSG_STATUS_NO_CHANNEL",       "No channels registered." },
124         { NULL, NULL }
125 };
126
127 #define SSMSG_DEBUG_KICK              "Kicked user $b%s$b from $b%s$b, reason: %s"
128 #define SSMSG_DEBUG_BAN               "Banned user $b%s$b from $b%s$b, reason: %s"
129 #define SSMSG_DEBUG_KILL              "Killed user $b%s$b, last violation in $b%s$b"
130 #define SSMSG_DEBUG_GLINE             "Glined user $b%s$b, host $b%s$b, last violation in $b%s$b"
131 #define SSMSG_DEBUG_RECONNECT         "Killed user $b%s$b reconnected to the network"
132 #define SSMSG_SPAM                    "Spamming"
133 #define SSMSG_FLOOD                   "Flooding the channel/network"
134 #define SSMSG_ADV                     "Advertising"
135 #define SSMSG_JOINFLOOD               "Join flooding the channel"
136 #define SSMSG_WARNING                 "%s is against the network rules"
137 #define SSMSG_WARNING_2               "You are violating the network rules"
138 #define SSMSG_WARNING_RULES           "%s is against the network rules. Read the network rules at %s"
139 #define SSMSG_WARNING_RULES_2         "You are violating the network rules. Read the network rules at %s"
140
141 static struct
142 {
143         struct chanNode *debug_channel;
144         struct string_list *global_exceptions;
145         const char *network_rules;
146         unsigned char trigger;
147         unsigned long short_ban_duration;
148         unsigned long long_ban_duration;
149         unsigned long gline_duration;
150         unsigned long exception_max;
151         unsigned long exception_min_len;
152         unsigned long exception_max_len;
153         unsigned int adv_chan_must_exist : 1;
154         unsigned int strip_mirc_codes : 1;
155         unsigned int allow_move_merge : 1;
156 } spamserv_conf;
157
158 /***********************************************/
159 /*                   Channel                   */
160 /***********************************************/
161
162 struct chanInfo*
163 get_chanInfo(const char *channelname)
164 {
165         return dict_find(registered_channels_dict, channelname, 0);
166 }
167
168 static void
169 spamserv_join_channel(struct chanNode *channel)
170 {
171         struct mod_chanmode change;
172         mod_chanmode_init(&change);
173         change.argc = 1;
174         change.args[0].mode = MODE_CHANOP;
175         change.args[0].u.member = AddChannelUser(spamserv, channel);
176         mod_chanmode_announce(spamserv, channel, &change);
177 }
178
179 static void
180 spamserv_part_channel(struct chanNode *channel, char *reason)
181 {
182         /* we only have to clear the spamNodes because every other node expires on it's own */
183         spamserv_clear_spamNodes(channel);
184         DelChannelUser(spamserv, channel, reason, 0);
185 }
186
187 static struct chanInfo*
188 spamserv_register_channel(struct chanNode *channel, struct string_list *exceptions, unsigned int flags, char *info)
189 {
190         struct chanInfo *cInfo = malloc(sizeof(struct chanInfo));
191         
192         if(!cInfo)
193         {
194                 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for cInfo; channel: %s", channel->name);
195                 return NULL;
196         }
197
198         cInfo->channel = channel;
199         cInfo->exceptions = exceptions ? string_list_copy(exceptions) : alloc_string_list(1);
200         cInfo->flags = flags;
201     cInfo->exceptlevel = 400;
202         safestrncpy(cInfo->info, info, sizeof(cInfo->info));
203         cInfo->suspend_expiry = 0;
204         dict_insert(registered_channels_dict, cInfo->channel->name, cInfo);
205
206         return cInfo;
207 }
208
209 static void
210 spamserv_unregister_channel(struct chanInfo *cInfo)
211 {
212         if(!cInfo)
213                 return;
214
215         dict_remove(registered_channels_dict, cInfo->channel->name);
216         free_string_list(cInfo->exceptions);
217         free(cInfo);
218 }
219
220 void
221 spamserv_cs_suspend(struct chanNode *channel, time_t expiry, int suspend, char *reason)
222 {
223         struct chanInfo *cInfo = get_chanInfo(channel->name);
224
225         if(cInfo)
226         {
227                 if(suspend)
228                 {
229                         cInfo->flags |= CHAN_SUSPENDED;
230                         cInfo->suspend_expiry = expiry;
231                         spamserv_part_channel(channel, reason);
232                 }
233                 else
234                 {
235                         if(CHECK_SUSPENDED(cInfo))
236                         {
237                                 cInfo->flags &= ~CHAN_SUSPENDED;
238                                 cInfo->suspend_expiry = 0;
239                         }
240                 }
241         }
242 }
243
244 int
245 spamserv_cs_move_merge(struct userNode *user, struct chanNode *channel, struct chanNode *target, int move)
246 {
247         struct chanInfo *cInfo = get_chanInfo(channel->name);
248
249         if(cInfo)
250         {
251                 char reason[MAXLEN];
252
253                 if(!spamserv_conf.allow_move_merge || get_chanInfo(target->name))
254                 {
255                         if(move)
256                                 snprintf(reason, sizeof(reason), "unregistered due to a channel move to %s", target->name);
257                         else
258                                 snprintf(reason, sizeof(reason), "unregistered due to a channel merge into %s", target->name);
259
260                         spamserv_cs_unregister(user, channel, manually, reason);
261                         return 0;
262                 }
263
264                 cInfo->channel = target;
265
266                 dict_remove(registered_channels_dict, channel->name);
267                 dict_insert(registered_channels_dict, target->name, cInfo);
268
269                 if(move)
270                 {
271                         snprintf(reason, sizeof(reason), "Channel moved to %s by %s.", target->name, user->handle_info->handle);
272                 }
273                 else
274                 {
275                         spamserv_join_channel(target);
276                         snprintf(reason, sizeof(reason), "%s merged into %s by %s.", channel->name, target->name, user->handle_info->handle);   
277                 }
278
279                 if(!CHECK_SUSPENDED(cInfo))
280                         spamserv_part_channel(channel, reason);
281
282                 if(move)
283                         snprintf(reason, sizeof(reason), "$X (channel %s) moved to %s by %s.", channel->name, target->name, user->handle_info->handle);
284                 else
285                         snprintf(reason, sizeof(reason), "$X (channel %s) merged into %s by %s.", channel->name, target->name, user->handle_info->handle);
286
287                 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
288                 return 1;
289         }
290
291         return 0;
292 }
293
294 void
295 spamserv_cs_unregister(struct userNode *user, struct chanNode *channel, enum cs_unreg type, char *reason)
296 {
297         struct chanInfo *cInfo = get_chanInfo(channel->name);
298
299         if(cInfo)
300         {
301                 char global[MAXLEN], partmsg[MAXLEN];
302
303                 switch (type)
304                 {
305                 case manually:
306                         snprintf(global, sizeof(global), "$X (channel %s) %s by %s.", channel->name, reason, user->handle_info->handle);
307                         snprintf(partmsg, sizeof(partmsg), "%s %s by %s.", channel->name, reason, user->handle_info->handle);                   
308                         break;
309                 case expire:
310                         snprintf(global, sizeof(global), "$X (channel %s) registration expired.", channel->name);
311                         snprintf(partmsg, sizeof(partmsg), "%s registration expired.", channel->name);                  
312                         break;
313                 case lost_all_users:
314                         snprintf(global, sizeof(global), "$X (channel %s) lost all users.", channel->name);
315                         snprintf(partmsg, sizeof(partmsg), "%s lost all users.", channel->name);                        
316                         break;
317                 }
318
319                 if(!CHECK_SUSPENDED(cInfo))
320                         spamserv_part_channel(channel, partmsg);
321                 
322                 spamserv_unregister_channel(cInfo);
323                 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, global);
324         }
325 }
326
327 /***********************************************/
328 /*                    User                     */
329 /***********************************************/
330
331 static struct userInfo*
332 get_userInfo(const char *nickname)
333 {
334         return dict_find(connected_users_dict, nickname, 0);
335 }
336
337 static void
338 spamserv_create_spamNode(struct chanNode *channel, struct userInfo *uInfo, char *text)
339 {
340         struct spamNode *sNode = malloc(sizeof(struct spamNode));
341
342         if(!sNode)
343         {
344                 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for sNode; channel: %s; user: %s", channel->name, uInfo->user->nick);
345                 return;
346         }
347
348         sNode->channel = channel;       
349         sNode->crc32 = crc32(text);
350         sNode->count = 1;
351         sNode->next = NULL;
352
353         if(uInfo->spam)
354         {
355                 struct spamNode *temp = uInfo->spam;
356                 
357                 while(temp->next)
358                         temp = temp->next;
359
360                 sNode->prev = temp;
361                 temp->next = sNode;
362         }
363         else
364         {
365                 sNode->prev = NULL;
366                 uInfo->spam = sNode;
367         }
368 }
369
370 static void
371 spamserv_delete_spamNode(struct userInfo *uInfo, struct spamNode *sNode)
372 {
373         if(!sNode)
374                 return;
375
376         if(sNode == uInfo->spam)
377                 uInfo->spam = sNode->next;
378         
379         if(sNode->next)
380                  sNode->next->prev = sNode->prev;
381         if(sNode->prev)
382                  sNode->prev->next = sNode->next;
383
384         free(sNode);
385 }
386
387 static void
388 spamserv_clear_spamNodes(struct chanNode *channel)
389 {
390         struct userInfo *uInfo;
391         struct spamNode *sNode;
392         unsigned int i;
393
394         for(i = 0; i < channel->members.used; i++)
395         {
396                 if((uInfo = get_userInfo(channel->members.list[i]->user->nick)))
397                 {
398                         if((sNode = uInfo->spam))
399                         {
400                                 for(; sNode; sNode = sNode->next)
401                                         if(sNode->channel == channel)
402                                                 break;
403                                         
404                                 if(sNode)
405                                         spamserv_delete_spamNode(uInfo, sNode);
406                         }
407                 }
408         }
409 }
410
411 static void
412 spamserv_create_floodNode(struct chanNode *channel, struct userNode *user, struct floodNode **uI_fNode)
413 {
414         struct floodNode *fNode = malloc(sizeof(struct floodNode));
415
416         if(!fNode)
417         {
418                 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for fNode; channel: %s; user: %s", channel->name, user->nick);
419                 return;
420         }
421
422         fNode->channel = channel;
423         fNode->owner = user;
424         fNode->count = 1;
425         fNode->time = now;      
426         fNode->next = NULL;
427
428         if(*uI_fNode)
429         {
430                 struct floodNode *temp = *uI_fNode;
431                 
432                 while(temp->next)
433                         temp = temp->next;
434                 
435                 fNode->prev = temp;
436                 temp->next = fNode;
437         }
438         else
439         {
440                 fNode->prev = NULL;
441                 *uI_fNode = fNode;
442         }
443 }
444
445 static void
446 spamserv_delete_floodNode(struct floodNode **uI_fNode, struct floodNode *fNode)
447 {
448         if(!fNode)
449                 return;
450
451         if(fNode == *uI_fNode)
452                 *uI_fNode = fNode->next;
453         
454         if(fNode->next)
455                  fNode->next->prev = fNode->prev;
456         if(fNode->prev)
457                  fNode->prev->next = fNode->next;
458
459         free(fNode);
460 }
461
462 static void
463 spamserv_create_user(struct userNode *user)
464 {
465         struct userInfo *uInfo = malloc(sizeof(struct userInfo));
466         struct killNode *kNode = dict_find(killed_users_dict, irc_ntoa(&user->ip), 0);
467
468         if(!uInfo)
469         {
470                 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for uInfo; nick: %s", user->nick);
471                 return;
472         }
473
474         if(kNode)
475                 spamserv_debug(SSMSG_DEBUG_RECONNECT, user->nick);
476
477         uInfo->user = user;
478         uInfo->spam = NULL;
479         uInfo->flood = NULL;
480         uInfo->joinflood = NULL;
481         uInfo->flags = kNode ? USER_KILLED : 0;
482         uInfo->warnlevel = kNode ? kNode->warnlevel : 0;
483         uInfo->lastadv = 0;
484
485         dict_insert(connected_users_dict, user->nick, uInfo);
486
487         if(kNode)
488         {
489                 dict_remove(killed_users_dict, irc_ntoa(&user->ip));
490                 free(kNode);
491         }
492 }
493
494 static void
495 spamserv_delete_user(struct userInfo *uInfo)
496 {
497         if(!uInfo)
498                 return;
499
500         if(uInfo->spam)
501                 while(uInfo->spam)
502                         spamserv_delete_spamNode(uInfo, uInfo->spam);   
503
504         if(uInfo->flood)
505                 while(uInfo->flood)
506                         spamserv_delete_floodNode(&uInfo->flood, uInfo->flood);
507
508         if(uInfo->joinflood)
509                 while(uInfo->joinflood)
510                         spamserv_delete_floodNode(&uInfo->joinflood, uInfo->joinflood);
511
512         dict_remove(connected_users_dict, uInfo->user->nick);
513         free(uInfo);
514 }
515
516 static void
517 spamserv_new_user_func(struct userNode *user)
518 {
519         if(!IsLocal(user))
520                 spamserv_create_user(user);
521 }
522
523 static void
524 spamserv_del_user_func(struct userNode *user, struct userNode *killer, UNUSED_ARG(const char *why))
525 {
526         struct userInfo *uInfo = get_userInfo(user->nick);
527         struct killNode *kNode;
528
529         if(killer == spamserv)
530         {
531                 kNode = malloc(sizeof(struct killNode));
532
533                 if(!kNode)
534                 {
535                         log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for killNode - nickname %s", user->nick);
536                         spamserv_delete_user(uInfo);                    
537                         return;
538                 }
539
540                 if(uInfo->warnlevel > KILL_WARNLEVEL)
541                         kNode->warnlevel = uInfo->warnlevel - KILL_WARNLEVEL;
542                 else
543                         kNode->warnlevel = 0;
544
545                 kNode->time = now;
546
547                 dict_insert(killed_users_dict, irc_ntoa(&user->ip), kNode);
548         }
549
550         spamserv_delete_user(uInfo);    
551 }
552
553 static void
554 spamserv_nick_change_func(struct userNode *user, const char *old_nick)
555 {
556         struct userInfo *uInfo = get_userInfo(old_nick);
557
558         dict_remove(connected_users_dict, old_nick);
559         dict_insert(connected_users_dict, user->nick, uInfo);
560 }
561
562 static int
563 spamserv_user_join(struct modeNode *mNode)
564 {
565         struct chanNode *channel = mNode->channel;
566         struct userNode *user = mNode->user;    
567         struct chanInfo *cInfo;
568         struct userInfo *uInfo;
569         struct floodNode *jfNode;
570
571         if(user->uplink->burst || !(cInfo = get_chanInfo(channel->name)) || !CHECK_JOINFLOOD(cInfo) || !(uInfo = get_userInfo(user->nick)))
572                 return 0;
573         
574         
575     if(!CHECK_CHANOPS(cInfo))
576         {
577                 //struct modeNode *mn = GetUserMode(channel, user);
578                 //if(mn->modes & MODE_CHANOP)
579                 //      return;
580         if(check_user_level(channel, user, lvlGiveOps, 1, 0)) 
581             return 0;
582         }
583     
584     if(!CHECK_VOICED(cInfo))
585         {
586         if(check_user_level(channel, user, lvlGiveVoice, 1, 0)) 
587             return 0;
588     }
589     
590     if(cInfo->exceptlevel == 0)
591         return 0;
592     if(cInfo->exceptlevel < 501) {
593       struct userData *uData;
594        if((uData = GetChannelUser(channel->channel_info, user->handle_info)) && (uData->access >= cInfo->exceptlevel)) {
595         return 0;
596        }
597     }
598
599         if(!(jfNode = uInfo->joinflood))
600         {
601                 spamserv_create_floodNode(channel, user, &uInfo->joinflood);
602         }
603         else
604         {
605                 for(; jfNode; jfNode = jfNode->next)
606                         if(jfNode->channel == channel)
607                                 break;
608
609                 if(!jfNode)
610                 {
611                         spamserv_create_floodNode(channel, user, &uInfo->joinflood);
612                 }
613                 else
614                 {
615                         jfNode->count++;
616                         jfNode->time = now;             
617
618                         if(jfNode->count > JOINFLOOD_MAX)
619                         {
620                                 char reason[MAXLEN];
621
622                                 spamserv_delete_floodNode(&uInfo->joinflood, jfNode);
623                                 snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_JOINFLOOD, spamserv_conf.network_rules);
624                                 spamserv_punish(channel, user, JOINFLOOD_B_DURATION, reason, 1);
625                         }
626                 }
627         }
628
629         return 0;
630 }
631
632 static void
633 spamserv_user_part(struct modeNode *mn, UNUSED_ARG(const char *reason))
634 {
635         struct userNode *user = mn->user;
636         struct chanNode *channel = mn->channel;
637         struct userInfo *uInfo;
638         struct spamNode *sNode;
639         struct floodNode *fNode;
640
641         if(user->dead || !get_chanInfo(channel->name) || !(uInfo = get_userInfo(user->nick)))
642                 return;
643
644         if((sNode = uInfo->spam))
645         {
646                 for(; sNode; sNode = sNode->next)
647                         if(sNode->channel == channel)
648                                 break;
649
650                 if(sNode)
651                         spamserv_delete_spamNode(uInfo, sNode);
652         }
653
654         if((fNode = uInfo->flood))
655         {
656                 for(; fNode; fNode = fNode->next)
657                         if(fNode->channel == channel)
658                                 break;
659
660                 if(fNode)
661                         spamserv_delete_floodNode(&uInfo->flood, fNode);
662         }
663 }
664
665 /***********************************************/
666 /*                 Other Stuff                 */
667 /***********************************************/
668
669 static void
670 crc32_init(void)
671 {
672         unsigned long crc;
673         int i, j;
674
675         for(i = 0; i < 256; i++)
676         {
677                 crc = i;
678
679                 for(j = 8; j > 0; j--)
680                 {
681                         if(crc & 1)
682                         {
683                                 crc = (crc >> 1) ^ 0xEDB88320L;
684                         }
685                         else
686                         {
687                                 crc >>= 1;
688                         }
689                 }
690
691                 crc_table[i] = crc;
692         }
693 }
694
695 static unsigned long
696 crc32(const char *text)
697 {
698         register unsigned long crc = 0xFFFFFFFF;
699         unsigned int c, i = 0;
700         
701         while((c = (unsigned int)text[i++]) != 0)
702                 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_table[(crc^c) & 0xFF];
703  
704         return (crc^0xFFFFFFFF);
705 }
706
707 static void
708 timeq_flood(UNUSED_ARG(void *data))
709 {
710         dict_iterator_t         it;
711         struct userInfo         *uInfo;
712         struct floodNode        *fNode;
713
714         for(it = dict_first(connected_users_dict); it; it = iter_next(it))
715         {
716                 uInfo = iter_data(it);
717
718                 if(!(fNode = uInfo->flood))
719                         continue;
720
721                 for(; fNode; fNode = fNode->next)
722                 {
723                         if(now - fNode->time > FLOOD_EXPIRE)
724                         {
725                                 if(!(--fNode->count))
726                                         spamserv_delete_floodNode(&uInfo->flood, fNode);
727                         }
728                 }
729         }
730         
731         timeq_add(now + FLOOD_TIMEQ_FREQ, timeq_flood, NULL);
732 }
733
734 static void
735 timeq_joinflood(UNUSED_ARG(void *data))
736 {
737         dict_iterator_t it;
738         struct userInfo *uInfo;
739         struct floodNode *fNode;
740
741         for(it = dict_first(connected_users_dict); it; it = iter_next(it))
742         {
743                 uInfo = iter_data(it);
744
745                 if(!(fNode = uInfo->joinflood))
746                         continue;
747
748                 for(; fNode; fNode = fNode->next)
749                 {
750                         if(now - fNode->time > JOINFLOOD_EXPIRE)
751                         {
752                                 if(!(--fNode->count))
753                                         spamserv_delete_floodNode(&uInfo->joinflood, fNode);                            
754                         }
755                 }
756         }
757
758         timeq_add(now + JOINFLOOD_TIMEQ_FREQ, timeq_joinflood, NULL);
759 }
760
761 static void
762 timeq_adv(UNUSED_ARG(void *data))
763 {
764         dict_iterator_t it;
765         struct userInfo *uInfo;
766
767         for(it = dict_first(connected_users_dict); it; it = iter_next(it))
768         {
769                 uInfo = iter_data(it);
770
771                 if(uInfo->lastadv && uInfo->lastadv - now > ADV_EXPIRE)
772                 {
773                         uInfo->lastadv = 0;
774                         uInfo->flags &= ~USER_ADV_WARNED;
775                 }
776         }
777
778         timeq_add(now + ADV_TIMEQ_FREQ, timeq_adv, NULL);
779 }
780
781 static void
782 timeq_warnlevel(UNUSED_ARG(void *data))
783 {
784         dict_iterator_t it;
785         struct userInfo *uInfo;
786
787         for(it = dict_first(connected_users_dict); it; it = iter_next(it))
788         {
789                 uInfo = iter_data(it);
790
791                 if(uInfo->warnlevel > 0)
792                         uInfo->warnlevel--;
793         }
794
795         timeq_add(now + WARNLEVEL_TIMEQ_FREQ, timeq_warnlevel, NULL);
796 }
797
798 static void
799 timeq_kill(UNUSED_ARG(void *data))
800 {
801         dict_iterator_t it;
802         struct killNode *kNode;
803
804         for(it = dict_first(killed_users_dict); it; it = iter_next(it))
805         {
806                 kNode = iter_data(it);
807
808                 if(kNode->time - now > KILL_EXPIRE)
809                         free(kNode);
810         }
811
812         timeq_add(now + KILL_TIMEQ_FREQ, timeq_kill, NULL);
813 }
814
815 static int
816 binary_option(char *name, unsigned long mask, struct userNode *user, struct chanNode *channel, int argc, char *argv[])
817 {
818         struct chanInfo *cInfo = get_chanInfo(channel->name);
819         int value;
820
821         if(argc > 1)
822         {
823                 if(enabled_string(argv[1]))
824                 {
825                         cInfo->flags |= mask;
826                         value = 1;
827                 }
828                 else if(disabled_string(argv[1]))
829                 {
830                     cInfo->flags &= ~mask;
831                     value = 0;
832                 }
833                 else
834                 {
835                    spamserv_notice(user, "SSMSG_INVALID_BINARY", argv[1]);
836                    return 0;
837                 }
838         }
839         else
840         {
841                 value = (cInfo->flags & mask) ? 1 : 0;
842         }
843
844         spamserv_notice(user, "SSMSG_STRING_VALUE", name, value ? "Enabled." : "Disabled.");
845         return 1;
846 }
847
848 struct valueData
849 {
850         char *description;
851         char value;
852         int  oper_only : 1;
853 };
854
855 static int
856 multiple_option(char *name, char *description, enum channelinfo info, struct valueData *values, int count, struct userNode *user, struct chanNode *channel, int argc, char *argv[])
857 {
858         struct chanInfo *cInfo = get_chanInfo(channel->name);
859         int index;
860
861         if(argc > 1)
862         {
863                 index = atoi(argv[1]);
864                 
865                 if(index < 0 || index >= count)
866                 {
867                         spamserv_notice(user, "SSMSG_INVALID_NUM_SET", index, description);
868
869             for(index = 0; index < count; index++)
870                 spamserv_notice(user, "SSMSG_NUMERIC_VALUE", name, index, values[index].description);
871
872                         return 0;
873                 }
874
875                 if(values[index].oper_only && !IsOper(user))
876                 {
877                         spamserv_notice(user, "SSMSG_MUST_BE_OPER");
878                         return 0;
879                 }
880                 
881                 cInfo->info[info] = values[index].value;
882         }
883         else
884         {
885                 for(index = 0; index < count && cInfo->info[info] != values[index].value; index++);
886         }
887
888         spamserv_notice(user, "SSMSG_NUMERIC_VALUE", name, index, values[index].description);
889         return 1;
890 }
891
892 static int
893 show_exceptions(struct userNode *user, struct chanInfo *cInfo)
894 {
895         struct helpfile_table table;
896         unsigned int i;
897
898         if(!cInfo->exceptions->used)
899         {
900                 spamserv_notice(user, "SSMSG_NO_EXCEPTIONS");
901                 return 0;
902         }
903
904         spamserv_notice(user, "SSMSG_EXCEPTION_LIST");
905
906         table.length = 0;
907         table.width = 1;
908         table.flags = TABLE_REPEAT_ROWS | TABLE_NO_FREE | TABLE_NO_HEADERS;
909         table.contents = alloca(cInfo->exceptions->used * sizeof(*table.contents));
910
911         for(i = 0; i < cInfo->exceptions->used; i++)
912         {
913                 table.contents[table.length] = alloca(table.width * sizeof(**table.contents));
914                 table.contents[table.length][0] = cInfo->exceptions->list[i];
915                 table.length++;
916         }
917         
918         table_send(spamserv, user->nick, 0, NULL, table);
919
920         return 1;
921 }
922
923 static void
924 show_memory_usage(struct userNode *user)
925 {
926         dict_iterator_t it;
927         struct helpfile_table table;
928         struct chanInfo *cInfo;
929         struct userInfo *uInfo;
930         struct spamNode *sNode;
931         struct floodNode *fNode;
932         double channel_size = 0, user_size, size;
933         unsigned int spamcount = 0, floodcount = 0, i, j;
934         char buffer[64];
935
936         for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
937         {
938                 cInfo = iter_data(it);
939
940                 if(!cInfo->exceptions->used)
941                         continue;
942
943                 for(i = 0; i < cInfo->exceptions->used; i++)
944                         channel_size += strlen(cInfo->exceptions->list[i]) * sizeof(char);              
945         }
946
947         for(it = dict_first(connected_users_dict); it; it = iter_next(it))
948         {
949                 uInfo = iter_data(it);
950
951                 for(sNode = uInfo->spam; sNode; sNode = sNode->next, spamcount++);
952                 for(fNode = uInfo->flood; fNode; fNode = fNode->next, floodcount++);
953                 for(fNode = uInfo->joinflood; fNode; fNode = fNode->next, floodcount++);
954         }
955
956         channel_size += dict_size(registered_channels_dict) * sizeof(struct chanInfo);
957         
958         user_size = dict_size(connected_users_dict) * sizeof(struct userInfo) +
959                                 dict_size(killed_users_dict) * sizeof(struct killNode) +
960                                 spamcount * sizeof(struct spamNode)     +
961                                 floodcount *  sizeof(struct floodNode);
962
963         size = channel_size + user_size;
964         
965         ss_reply("SSMSG_STATUS_MEMORY");
966         
967         table.length = 3;
968         table.width = 4;
969         table.flags = TABLE_NO_FREE | TABLE_NO_HEADERS | TABLE_PAD_LEFT;
970         table.contents = calloc(table.length, sizeof(char**));
971
972         // chanInfo
973         table.contents[0] = calloc(table.width, sizeof(char*));
974         snprintf(buffer, sizeof(buffer), "Channel Memory Usage:");
975         table.contents[0][0] = strdup(buffer);
976         snprintf(buffer, sizeof(buffer), " %g Byte; ", channel_size);
977         table.contents[0][1] = strdup(buffer);
978         snprintf(buffer, sizeof(buffer), "%g KiloByte; ", channel_size / 1024);
979         table.contents[0][2] = strdup(buffer);
980         snprintf(buffer, sizeof(buffer), "%g MegaByte", channel_size / 1024 / 1024);
981         table.contents[0][3] = strdup(buffer);
982
983         // userInfo
984         table.contents[1] = calloc(table.width, sizeof(char*));
985         snprintf(buffer, sizeof(buffer), "User Memory Usage   :");
986         table.contents[1][0] = strdup(buffer);
987         snprintf(buffer, sizeof(buffer), " %g Byte; ", user_size);
988         table.contents[1][1] = strdup(buffer);
989         snprintf(buffer, sizeof(buffer), "%g KiloByte; ", user_size / 1024);
990         table.contents[1][2] = strdup(buffer);
991         snprintf(buffer, sizeof(buffer), "%g MegaByte", user_size / 1024 / 1024);
992         table.contents[1][3] = strdup(buffer);
993
994         // total memory usage
995         table.contents[2] = calloc(table.width, sizeof(char*));
996         snprintf(buffer, sizeof(buffer), "Total Memory Usage  :");
997         table.contents[2][0] = strdup(buffer);
998         snprintf(buffer, sizeof(buffer), " %g Byte; ", size);
999         table.contents[2][1] = strdup(buffer);
1000         snprintf(buffer, sizeof(buffer), "%g KiloByte; ", size / 1024);
1001         table.contents[2][2] = strdup(buffer);
1002         snprintf(buffer, sizeof(buffer), "%g MegaByte", size / 1024 / 1024);
1003         table.contents[2][3] = strdup(buffer);
1004
1005         table_send(spamserv, user->nick, 0, NULL, table);
1006         
1007         for(i = 0; i < table.length; i++)
1008         {
1009                 for(j = 0; j < table.width; j++)
1010                         free((char*)table.contents[i][j]);
1011
1012         free(table.contents[i]);
1013         }
1014
1015         free(table.contents);
1016 }
1017
1018 static void
1019 show_registered_channels(struct userNode *user)
1020 {
1021         struct helpfile_table table;
1022         dict_iterator_t it;
1023
1024         spamserv_notice(user, "SSMSG_STATUS_CHANNEL_LIST");
1025
1026         if(!dict_size(registered_channels_dict))
1027         {
1028                 spamserv_notice(user, "SSMSG_STATUS_NO_CHANNEL");
1029                 return;
1030         }
1031
1032         table.length = 0;
1033         table.width = 1;
1034         table.flags = TABLE_REPEAT_ROWS | TABLE_NO_FREE | TABLE_NO_HEADERS;
1035         table.contents = alloca(dict_size(registered_channels_dict) * sizeof(*table.contents));
1036
1037         for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
1038         {
1039                 struct chanInfo *cInfo = iter_data(it);
1040
1041                 table.contents[table.length] = alloca(table.width * sizeof(**table.contents));
1042                 table.contents[table.length][0] = cInfo->channel->name;
1043                 table.length++;
1044         }
1045         
1046         table_send(spamserv, user->nick, 0, NULL, table);
1047 }
1048
1049 /***********************************************/
1050 /*                SpamServ_Func                */
1051 /***********************************************/
1052
1053 static 
1054 SPAMSERV_FUNC(cmd_register)
1055 {
1056         struct chanInfo *cInfo;
1057         char reason[MAXLEN];
1058
1059         if(!channel || !channel->channel_info)
1060         {
1061                 ss_reply("SSMSG_NOT_REGISTERED_CS", channel->name);
1062                 return 0;
1063         }
1064
1065         if(get_chanInfo(channel->name))
1066         {
1067                 ss_reply("SSMSG_ALREADY_REGISTERED", channel->name);
1068                 return 0;
1069         }
1070
1071         if(IsSuspended(channel->channel_info))
1072         {
1073                 ss_reply("SSMSG_SUSPENDED_CS", channel->name, "register");
1074                 return 0;
1075         }
1076
1077         if(channel == spamserv_conf.debug_channel)
1078         {
1079                 ss_reply("SSMSG_DEBUG_CHAN");
1080                 return 0;
1081         }
1082
1083         if(!(cInfo = spamserv_register_channel(channel, spamserv_conf.global_exceptions, CHAN_FLAGS_DEFAULT , CHAN_INFO_DEFAULT)))
1084         {
1085                 ss_reply("SSMSG_NO_REGISTER", channel->name);
1086                 return 0;
1087         }
1088
1089         spamserv_join_channel(cInfo->channel);
1090         
1091         snprintf(reason, sizeof(reason), "%s (channel %s) registered by %s.", spamserv->nick, channel->name, user->handle_info->handle);
1092         global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
1093         ss_reply("SSMSG_REG_SUCCESS", channel->name);
1094
1095         return 1;
1096 }
1097
1098 static 
1099 SPAMSERV_FUNC(cmd_unregister)
1100 {
1101         struct chanInfo *cInfo;
1102         struct chanData *cData;
1103         struct userData *uData;
1104         char reason[MAXLEN];
1105
1106         if(!channel || !(cData = channel->channel_info) || !(cInfo = get_chanInfo(channel->name)))
1107         {
1108                 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1109                 return 0;
1110         }
1111
1112         if(!(uData = GetChannelUser(cData, user->handle_info)) || (uData->access < UL_OWNER))
1113         {
1114         ss_reply("SSMSG_NO_ACCESS");
1115         return 0;
1116         }
1117
1118         if(!IsHelping(user))
1119         {
1120         if(IsSuspended(cData))
1121         {
1122             ss_reply("SSMSG_SUSPENDED_CS", channel->name, "unregister");
1123             return 0;
1124         }
1125
1126                 if(argc < 2 || strcasecmp(argv[1], "CONFIRM"))
1127                 {
1128                         ss_reply("SSMSG_CONFIRM_UNREG");
1129                         return 0;
1130                 }
1131         }
1132
1133         if(!CHECK_SUSPENDED(cInfo))
1134         {
1135                 snprintf(reason, sizeof(reason), "%s unregistered by %s.", spamserv->nick, user->handle_info->handle);          
1136                 spamserv_part_channel(channel, reason);
1137         }
1138         
1139         spamserv_unregister_channel(cInfo);     
1140
1141         snprintf(reason, sizeof(reason), "%s (channel %s) unregistered by %s.", spamserv->nick, channel->name, user->handle_info->handle);
1142         global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
1143         ss_reply("SSMSG_UNREG_SUCCESS", channel->name);
1144
1145         return 1;
1146 }
1147
1148 static 
1149 SPAMSERV_FUNC(cmd_status)
1150 {
1151         ss_reply("SSMSG_STATUS");
1152         ss_reply("SSMSG_STATUS_USERS", dict_size(connected_users_dict));
1153         ss_reply("SSMSG_STATUS_CHANNELS", dict_size(registered_channels_dict));
1154
1155         if(IsOper(user) && argc > 1)
1156         {
1157                 if(!irccasecmp(argv[1], "memory"))
1158                         show_memory_usage(user);
1159                 else if(!irccasecmp(argv[1], "channels"))
1160                         show_registered_channels(user);         
1161         }
1162         
1163         return 1;
1164 }
1165
1166 static 
1167 SPAMSERV_FUNC(cmd_addexception)
1168 {
1169         struct chanInfo *cInfo = get_chanInfo(channel->name);
1170         struct userData *uData;
1171         unsigned int i;
1172
1173         if(!cInfo || !channel->channel_info)
1174         {
1175                 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1176                 return 0;
1177         }
1178
1179         if(CHECK_SUSPENDED(cInfo))
1180         {
1181                 ss_reply("SSMSG_SUSPENDED", channel->name);
1182                 return 0;
1183         }
1184
1185         if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1186         {
1187                 ss_reply("SSMSG_NO_ACCESS");
1188                 return 0;
1189         }
1190
1191         if(argc < 2)
1192                 return show_exceptions(user, cInfo);
1193
1194         if(cInfo->exceptions->used == spamserv_conf.exception_max && !IsOper(user))
1195         {
1196                 ss_reply("SSMSG_EXCEPTION_MAX", spamserv_conf.exception_max);
1197                 return 0;
1198         }
1199
1200         if(strlen(argv[1]) < spamserv_conf.exception_min_len)
1201         {
1202                 ss_reply("SSMSG_EXCEPTION_TOO_SHORT", spamserv_conf.exception_min_len);
1203                 return 0;
1204         }
1205         else if(strlen(argv[1]) > spamserv_conf.exception_max_len)
1206         {
1207                 ss_reply("SSMSG_EXCEPTION_TOO_LONG", spamserv_conf.exception_max_len);
1208                 return 0;
1209         }
1210
1211         for(i = 0; i < cInfo->exceptions->used; i++)
1212         {
1213                 if(!irccasecmp(argv[1], cInfo->exceptions->list[i]))
1214                 {
1215                         ss_reply("SSMSG_EXCEPTION_IN_LIST", argv[1]);
1216                         return 0;
1217                 }
1218         }
1219
1220         string_list_append(cInfo->exceptions, strdup(argv[1]));
1221         ss_reply("SSMSG_EXCEPTION_ADDED", argv[1]);
1222
1223         return 1;
1224 }
1225
1226 static 
1227 SPAMSERV_FUNC(cmd_delexception)
1228 {
1229         struct chanInfo *cInfo = get_chanInfo(channel->name);
1230         struct userData *uData;
1231         unsigned int i;
1232         int found = -1;
1233
1234         if(!cInfo || !channel->channel_info)
1235         {
1236                 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1237                 return 0;
1238         }
1239
1240         if(CHECK_SUSPENDED(cInfo))
1241         {
1242                 ss_reply("SSMSG_SUSPENDED", channel->name);
1243                 return 0;
1244         }
1245
1246         if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1247         {
1248                 ss_reply("SSMSG_NO_ACCESS");
1249                 return 0;
1250         }
1251
1252         if(argc < 2)
1253                 return show_exceptions(user, cInfo);
1254
1255         for(i = 0; i < cInfo->exceptions->used; i++)
1256         {
1257                 if(!irccasecmp(argv[1], cInfo->exceptions->list[i]))
1258                 {
1259                         found = i;
1260                         break;
1261                 }
1262         }
1263         
1264         if(found == -1)
1265         {
1266                 ss_reply("SSMSG_NO_SUCH_EXCEPTION", argv[1]);
1267                 return 0;
1268         }
1269
1270         string_list_delete(cInfo->exceptions, i);
1271         ss_reply("SSMSG_EXCEPTION_DELETED", argv[1]);
1272
1273         return 1;
1274 }
1275
1276 static 
1277 SPAMSERV_FUNC(cmd_set)
1278 {
1279         struct chanInfo *cInfo = get_chanInfo(channel->name);
1280         struct svccmd   *subcmd;        
1281         char cmd_name[MAXLEN];
1282         unsigned int i;
1283
1284         if(!cInfo)
1285         {
1286                 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1287                 return 0;
1288         }
1289
1290         if(CHECK_SUSPENDED(cInfo))
1291         {
1292                 ss_reply("SSMSG_SUSPENDED", channel->name);
1293                 return 0;
1294         }
1295
1296     if(!check_user_level(channel,user,lvlSetters,1,0))
1297         {
1298                 ss_reply("SSMSG_NO_ACCESS");
1299                 return 0;
1300         }
1301         
1302         if(argc < 2)
1303         {
1304                 ss_reply("SSMSG_CHANNEL_OPTIONS");
1305
1306                 for(i = 0; i < SET_SUBCMDS_SIZE; i++)
1307                 {
1308                         sprintf(cmd_name, "%s %s", cmd->name, set_subcommands[i]);
1309
1310                         if((subcmd = dict_find(cmd->parent->commands, cmd_name, NULL)))
1311                                 subcmd->command->func(user, channel, 1, argv + 1, subcmd);
1312                 }
1313
1314                 return 1;
1315         }
1316
1317         sprintf(cmd_name, "%s %s", cmd->name, argv[1]);
1318         subcmd = dict_find(cmd->parent->commands, cmd_name, NULL);
1319
1320         if(!subcmd)
1321         {
1322                 reply("SSMSG_INVALID_OPTION", argv[1], argv[0]);
1323                 return 0;
1324         }
1325
1326         return subcmd->command->func(user, channel, argc - 1, argv + 1, subcmd);
1327 }
1328
1329 static 
1330 SPAMSERV_FUNC(opt_spamlimit)
1331 {
1332         struct valueData values[] =
1333         {
1334                 {"Users may send the same message $b2$b times.", 'a', 0},
1335                 {"Users may send the same message $b3$b times.", 'b', 0},
1336                 {"Users may send the same message $b4$b times.", 'c', 0},
1337                 {"Users may send the same message $b5$b times.", 'd', 0},
1338                 {"Users may send the same message $b6$b times.", 'e', 0}
1339         };
1340
1341         MULTIPLE_OPTION("SpamLimit     ", "SpamLimit", ci_SpamLimit);
1342 }
1343
1344 static 
1345 SPAMSERV_FUNC(opt_advreaction)
1346 {
1347         struct valueData values[] =
1348         {
1349                 {"Kick on disallowed advertising.", 'k', 0},
1350                 {"Kickban on disallowed advertising.", 'b', 0},
1351                 {"Short timed ban on disallowed advertising.", 's', 0},
1352                 {"Long timed ban on disallowed advertising.", 'l', 0},
1353                 {"Kill on disallowed advertising.", 'd', 1}
1354         };
1355
1356         MULTIPLE_OPTION("AdvReaction   ", "AdvReaction", ci_AdvReaction);
1357 }
1358
1359 static 
1360 SPAMSERV_FUNC(opt_warnreaction)
1361 {
1362         struct valueData values[] =
1363         {
1364                 {"Kick after warning.", 'k', 0},
1365                 {"Kickban after warning.", 'b', 0},
1366                 {"Short timed ban after warning.", 's', 0},
1367                 {"Long timed ban after warning.", 'l', 0},
1368                 {"Kill after warning.", 'd', 1}
1369         };
1370
1371         MULTIPLE_OPTION("WarnReaction  ", "WarnReaction", ci_WarnReaction);
1372 }
1373
1374 static 
1375 SPAMSERV_FUNC(opt_advscan)
1376 {
1377         BINARY_OPTION("AdvScan       ", CHAN_ADV_SCAN);
1378 }
1379
1380 static 
1381 SPAMSERV_FUNC(opt_spamscan)
1382 {
1383         BINARY_OPTION("SpamScan      ", CHAN_SPAMSCAN);
1384 }
1385
1386 static 
1387 SPAMSERV_FUNC(opt_floodscan)
1388 {
1389         BINARY_OPTION("FloodScan     ", CHAN_FLOODSCAN);
1390 }
1391
1392 static 
1393 SPAMSERV_FUNC(opt_joinflood)
1394 {
1395         BINARY_OPTION("JoinFloodScan ", CHAN_JOINFLOOD);
1396 }
1397
1398 static 
1399 SPAMSERV_FUNC(opt_scanops)
1400 {
1401         BINARY_OPTION("ScanChanOps   ", CHAN_SCAN_CHANOPS);
1402 }
1403
1404 static 
1405 SPAMSERV_FUNC(opt_scanvoiced)
1406 {
1407         BINARY_OPTION("ScanVoiced    ", CHAN_SCAN_VOICED);
1408 }
1409
1410 static 
1411 SPAMSERV_FUNC(opt_exceptlevel)
1412 {
1413  struct chanInfo *cInfo = get_chanInfo(channel->name);
1414  struct userData *uData;
1415  int index;
1416  if(argc > 1)
1417         {
1418                 index = atoi(argv[1]);
1419                 if(index < 1 || index > 501)
1420                 {
1421                         spamserv_notice(user, "SSMSG_INVALID_NUM_SET", index, "ExceptLevel");
1422                         return 0;
1423                 }
1424         if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < cInfo->exceptlevel || index > uData->access))
1425         {
1426             ss_reply("SSMSG_NO_ACCESS");
1427             return 0;
1428         }
1429         cInfo->exceptlevel=index;
1430     } else {
1431      index=cInfo->exceptlevel;
1432     }
1433     spamserv_notice(user, "SSMSG_EASYNUMERIC_VALUE", "ExceptLevel   ", index);
1434     return 1;
1435 }
1436
1437 static void 
1438 to_lower(char *message)
1439 {
1440         unsigned int i, diff = 'a' - 'A';
1441
1442         for(i = 0; i < strlen(message); i++)
1443         {
1444                 if((message[i] >= 'A') && (message[i] <= 'Z'))
1445                         message[i] = message[i] + diff;
1446         }
1447 }
1448
1449 static char *
1450 strip_mirc_codes(char *text)
1451 {
1452         // taken from xchat and modified
1453         int nc = 0, i = 0, col = 0, len = strlen(text);
1454         static char new_str[MAXLEN];
1455
1456         while(len > 0)
1457         {
1458                 if((col && isdigit(*text) && nc < 2) ||
1459                         (col && *text == ',' && isdigit(*(text + 1)) && nc < 3))
1460                 {
1461                         nc++;
1462
1463                         if(*text == ',')
1464                                 nc = 0;
1465                 }
1466                 else
1467                 {
1468                         col = 0;
1469
1470                         switch(*text)
1471                         {
1472                         case '\003':
1473                                 col = 1;
1474                                 nc = 0;
1475                                 break;
1476                         case '\002':
1477                         case '\022':
1478                         case '\026':                    
1479                         case '\031':
1480                         case '\037':
1481                                 break;
1482                         default:
1483                                 new_str[i] = *text;
1484                                 i++;
1485                         }
1486                 }
1487
1488                 text++;
1489                 len--;
1490         }
1491
1492         new_str[i] = '\0';
1493
1494         return new_str;
1495 }
1496
1497 static int
1498 is_in_exception_list(struct chanInfo *cInfo, char *message)
1499 {
1500         unsigned int i;
1501
1502         for(i = 0; i < cInfo->exceptions->used; i++)
1503                 if(strstr(message, cInfo->exceptions->list[i]))
1504                         return 1;
1505
1506         return 0;
1507 }
1508
1509 static int
1510 check_advertising(struct chanInfo *cInfo, char *message)
1511 {
1512         unsigned int i = 0;
1513
1514         if(spamserv_conf.strip_mirc_codes)
1515                 message = strip_mirc_codes(message);
1516
1517         if(is_in_exception_list(cInfo, message))
1518                 return 0;
1519
1520         while(message[i] != 0)
1521         {
1522                 if(message[i] == '#')
1523                 {
1524                         char channelname[CHANNELLEN];
1525                         unsigned int j = 0;
1526
1527                         if(!spamserv_conf.adv_chan_must_exist)
1528                                 return 1;
1529
1530                         /* only return 1, if the channel does exist */  
1531
1532                         while((message[i] != 0) && (message[i] != ' '))
1533                         {
1534                                 channelname[j] = message[i];
1535                                 i++;
1536                                 j++;                            
1537                         }
1538
1539                         channelname[j] = '\0';
1540
1541                         if(GetChannel(channelname))
1542                                 return 1;
1543                 }
1544                 else if((message[i] == 'w') && (message[i+1] == 'w') && (message[i+2] == 'w') && (message[i+3] == '.'))
1545                         return 1;
1546                 else if((message[i] == 'h') && (message[i+1] == 't') && (message[i+2] == 't') && (message[i+3] == 'p') && (message[i+4] == ':'))
1547                         return 1;
1548                 else if((message[i] == 'f') && (message[i+1] == 't') && (message[i+2] == 'p') && ((message[i+3] == '.') || (message[i+3] == ':')))
1549                         return 1;
1550
1551                 i++;
1552         }
1553
1554         return 0;
1555 }
1556
1557 struct banData *add_channel_ban(struct chanData *channel, const char *mask, char *owner, unsigned long set, unsigned long triggered, unsigned long expires, char *reason);
1558
1559 static void
1560 spamserv_punish(struct chanNode *channel, struct userNode *user, time_t expires, char *reason, int ban)
1561 {
1562         if(ban)
1563         {
1564                 struct mod_chanmode change;
1565                 char *hostmask = generate_hostmask(user, GENMASK_STRICT_HOST | GENMASK_ANY_IDENT);
1566
1567                 sanitize_ircmask(hostmask);
1568
1569                 if(expires)
1570                         add_channel_ban(channel->channel_info, hostmask, spamserv->nick, now, now, now + expires, reason);
1571
1572                 mod_chanmode_init(&change);
1573                 change.argc = 1;
1574                 change.args[0].mode = MODE_BAN;
1575       change.args[0].u.hostmask = hostmask;
1576                 mod_chanmode_announce(spamserv, channel, &change);        
1577
1578                 free(hostmask);
1579
1580                 spamserv_debug(SSMSG_DEBUG_BAN, user->nick, channel->name, reason);
1581         }
1582         else
1583                 spamserv_debug(SSMSG_DEBUG_KICK, user->nick, channel->name, reason);
1584
1585         KickChannelUser(user, channel, spamserv, reason);       
1586 }
1587
1588 void
1589 spamserv_channel_message(struct chanNode *channel, struct userNode *user, char *text)
1590 {
1591         struct chanInfo *cInfo;
1592         struct userInfo *uInfo;
1593         struct spamNode *sNode;
1594         struct floodNode *fNode;
1595         unsigned int violation = 0;
1596         char reason[MAXLEN];
1597
1598         /* make sure: spamserv is not disabled; srvx is running; spamserv is in the chan; chan is regged, user does exist */
1599         if(!spamserv || quit_services || !GetUserMode(channel, spamserv) || !(cInfo = get_chanInfo(channel->name)) || !(uInfo = get_userInfo(user->nick)))
1600                 return;
1601
1602         if(!CHECK_CHANOPS(cInfo))
1603         {
1604                 struct modeNode *mn = GetUserMode(channel, user);
1605                 if(mn && mn->modes & MODE_CHANOP)
1606                         return;
1607         //if(check_user_level(channel, user, lvlGiveOps, 1, 0)) 
1608         //    return;
1609         }
1610         
1611         if(!CHECK_VOICED(cInfo))
1612         {
1613                 struct modeNode *mn = GetUserMode(channel, user);
1614                 if(mn && (mn->modes & MODE_VOICE) && !(mn->modes & MODE_CHANOP))
1615                         return;
1616         }
1617     
1618     if(cInfo->exceptlevel == 0)
1619         return;
1620     if(cInfo->exceptlevel < 501) {
1621       struct userData *uData;
1622        if((uData = GetChannelUser(channel->channel_info, user->handle_info)) && (uData->access >= cInfo->exceptlevel)) {
1623         return;
1624        }
1625     }
1626
1627         to_lower(text);
1628
1629         if(CHECK_SPAM(cInfo))
1630         {
1631                 if(!(sNode = uInfo->spam))
1632                 {
1633                         spamserv_create_spamNode(channel, uInfo, text);
1634                 }
1635                 else
1636                 {
1637                         for(; sNode; sNode = sNode->next)
1638                                 if(sNode->channel == channel)
1639                                         break;
1640
1641                         if(!sNode)
1642                         {
1643                                 spamserv_create_spamNode(channel, uInfo, text);
1644                         }
1645                         else
1646                         {
1647                                 unsigned long crc = crc32(text);
1648
1649                                 if(crc == sNode->crc32)
1650                                 {
1651                                         unsigned int spamlimit = 2;
1652                                         sNode->count++;
1653
1654                                         switch(cInfo->info[ci_SpamLimit])
1655                                         {
1656                                                 case 'a': spamlimit = 2; break;
1657                                                 case 'b': spamlimit = 3; break;
1658                                                 case 'c': spamlimit = 4; break;
1659                                                 case 'd': spamlimit = 5; break;
1660                                                 case 'e': spamlimit = 6; break;
1661                                         }
1662
1663                                         if(sNode->count == spamlimit)
1664                                         {
1665                                                 uInfo->warnlevel += SPAM_WARNLEVEL;
1666
1667                                                 if(uInfo->warnlevel < MAX_WARNLEVEL)
1668                                                         spamserv_notice(user, spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_SPAM, spamserv_conf.network_rules);
1669                                         }
1670                                         else if(sNode->count > spamlimit)
1671                                         {
1672                                                 switch(cInfo->info[ci_WarnReaction])
1673                                                 {
1674                                                         case 'k': uInfo->flags |= USER_KICK; break;
1675                                                         case 'b': uInfo->flags |= USER_KICKBAN; break;
1676                                                         case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1677                                                         case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1678                                                         case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1679                                                 }
1680
1681                                                 spamserv_delete_spamNode(uInfo, sNode);
1682                                                 uInfo->warnlevel += SPAM_WARNLEVEL;
1683                                                 violation = 1;
1684                                         }
1685                                 }
1686                                 else
1687                                 {
1688                                         sNode->crc32 = crc;                                     
1689                                         sNode->count = 1;
1690                                 }
1691                         }
1692                 }
1693         }
1694
1695         if(CHECK_FLOOD(cInfo))
1696         {
1697                 if(!(fNode = uInfo->flood))
1698                 {
1699                         spamserv_create_floodNode(channel, user, &uInfo->flood);
1700                 }
1701                 else
1702                 {
1703                         for(; fNode; fNode = fNode->next)
1704                                 if(fNode->channel == channel)
1705                                         break;
1706                                 
1707                         if(!fNode)
1708                         {
1709                                 spamserv_create_floodNode(channel, user, &uInfo->flood);
1710                         }
1711                         else
1712                         {
1713                                 if(((now - fNode->time) < FLOOD_EXPIRE))
1714                                 {
1715                                         fNode->count++;
1716                                         
1717                                         if(fNode->count == FLOOD_MAX_LINES - 1)
1718                                         {
1719                                                 uInfo->warnlevel += FLOOD_WARNLEVEL;
1720
1721                                                 if(uInfo->warnlevel < MAX_WARNLEVEL)
1722                                                         spamserv_notice(user, spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_FLOOD, spamserv_conf.network_rules);
1723                                         }
1724                                         else if(fNode->count > FLOOD_MAX_LINES)
1725                                         {
1726                                                 switch(cInfo->info[ci_WarnReaction])
1727                                                 {
1728                                                         case 'k': uInfo->flags |= USER_KICK; break;
1729                                                         case 'b': uInfo->flags |= USER_KICKBAN; break;
1730                                                         case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1731                                                         case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1732                                                         case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1733                                                 }
1734
1735                                                 spamserv_delete_floodNode(&uInfo->flood, fNode);
1736                                                 uInfo->warnlevel += FLOOD_WARNLEVEL;
1737                                                 violation = 2;                                          
1738                                         }
1739                                 }
1740
1741                                 fNode->time = now;
1742                         }
1743                 }
1744         }
1745
1746         if(CHECK_ADV(cInfo) && check_advertising(cInfo, text))
1747         {
1748                 if(CHECK_ADV_WARNED(uInfo))
1749                 {
1750                         switch(cInfo->info[ci_AdvReaction])
1751                         {
1752                                 case 'k': uInfo->flags |= USER_KICK; break;
1753                                 case 'b': uInfo->flags |= USER_KICKBAN; break;
1754                                 case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1755                                 case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1756                                 case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1757                         }
1758
1759                         uInfo->warnlevel += ADV_WARNLEVEL;
1760                         violation = 3;
1761                 }
1762                 else
1763                 {               
1764                         uInfo->flags |= USER_ADV_WARNED;
1765                         uInfo->lastadv = now;
1766                         uInfo->warnlevel += ADV_WARNLEVEL;
1767
1768                         if(uInfo->warnlevel < MAX_WARNLEVEL)
1769                                 spamserv_notice(user, spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_ADV, spamserv_conf.network_rules);
1770                 }               
1771         }
1772
1773         if(!CHECK_WARNED(uInfo) && !CHECK_KILL(uInfo) && !CHECK_GLINE(uInfo) && uInfo->warnlevel == MAX_WARNLEVEL)
1774         {
1775                 uInfo->flags |= USER_WARNED;
1776                 snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES_2 : SSMSG_WARNING_2, spamserv_conf.network_rules);
1777                 irc_notice(spamserv, user->numeric, reason);
1778                 irc_privmsg(spamserv, user->numeric, reason);
1779         }
1780         else if(uInfo->warnlevel > MAX_WARNLEVEL)
1781         {
1782                 if(CHECK_KILLED(uInfo))
1783                         uInfo->flags |= USER_GLINE;
1784                 else
1785                         uInfo->flags |= USER_KILL;
1786
1787                 violation = 5;
1788         }
1789
1790         if(!violation)
1791                 return;
1792
1793         switch(violation)
1794         {
1795                 case 1: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_SPAM, spamserv_conf.network_rules); break;
1796                 case 2: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_FLOOD, spamserv_conf.network_rules); break;
1797                 case 3: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_ADV, spamserv_conf.network_rules); break;
1798                 default: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES_2 : SSMSG_WARNING_2, spamserv_conf.network_rules); break;
1799         }
1800
1801         if(CHECK_GLINE(uInfo))
1802         {
1803                 int size = strlen(user->hostname) + 3;
1804                 char *mask = alloca(size);
1805                 snprintf(mask, size, "*@%s", user->hostname);
1806                 gline_add(spamserv->nick, mask, spamserv_conf.gline_duration, reason, now, now, 0, 1);
1807                 spamserv_debug(SSMSG_DEBUG_GLINE, user->nick, user->hostname, channel->name);
1808         }
1809         else if(CHECK_KILL(uInfo))
1810         {
1811                 DelUser(user, spamserv, 1, reason);
1812                 spamserv_debug(SSMSG_DEBUG_KILL, user->nick, channel->name);
1813         }
1814         else if(CHECK_LONG_TBAN(uInfo))
1815         {
1816                 spamserv_punish(channel, user, spamserv_conf.long_ban_duration, reason, 1);
1817         }
1818         else if(CHECK_SHORT_TBAN(uInfo))
1819         {
1820                 spamserv_punish(channel, user, spamserv_conf.short_ban_duration, reason, 1);
1821         }
1822         else if(CHECK_KICKBAN(uInfo))
1823         {
1824                 spamserv_punish(channel, user, 0, reason, 1);
1825         }
1826         else if(CHECK_KICK(uInfo))
1827         {
1828                 spamserv_punish(channel, user, 0, reason, 0);
1829         }
1830 }
1831
1832 static int
1833 spamserv_saxdb_read(struct dict *database)
1834 {
1835         dict_iterator_t it;
1836         struct record_data *hir;
1837         struct chanNode *channel;
1838         struct chanInfo *cInfo;
1839         struct string_list *strlist;
1840         unsigned int flags,exceptlevel;
1841         char *str, *info;       
1842         time_t expiry;    
1843
1844         for(it = dict_first(database); it; it = iter_next(it))
1845         {
1846                 hir = iter_data(it);
1847
1848                 if(hir->type != RECDB_OBJECT)
1849                 {
1850                         log_module(SS_LOG, LOG_WARNING, "Unexpected rectype %d for %s.", hir->type, iter_key(it));
1851                         continue;
1852                 }
1853
1854                 channel = GetChannel(iter_key(it));
1855                 strlist = database_get_data(hir->d.object, KEY_EXCEPTIONS, RECDB_STRING_LIST);
1856
1857                 str = database_get_data(hir->d.object, KEY_FLAGS, RECDB_QSTRING);
1858                 flags = str ? atoi(str) : 0;
1859
1860                 info = database_get_data(hir->d.object, KEY_INFO, RECDB_QSTRING);
1861         str = database_get_data(hir->d.object, KEY_EXCEPTLEVEL, RECDB_QSTRING);
1862         exceptlevel = str ? atoi(str) : 400;
1863         
1864                 str = database_get_data(hir->d.object, KEY_EXPIRY, RECDB_QSTRING);
1865                 expiry = str ? strtoul(str, NULL, 0) : 0;
1866
1867                 if(channel && info)
1868                 {
1869                         if((cInfo = spamserv_register_channel(channel, strlist, flags, info)))
1870                         {
1871                                 /* if the channel is suspended and expiry = 0 it means: channel will
1872                                    never expire ! it does NOT mean, the channel is not suspended */
1873                                 if(CHECK_SUSPENDED(cInfo) && expiry && (expiry < now))
1874                                 {
1875                                         cInfo->flags &= ~CHAN_SUSPENDED;
1876                                         spamserv_join_channel(cInfo->channel);
1877                                 }
1878                                 else if(!CHECK_SUSPENDED(cInfo))
1879                                         spamserv_join_channel(cInfo->channel);
1880                                 else
1881                                         cInfo->suspend_expiry = expiry;                 
1882                 cInfo->exceptlevel=exceptlevel;
1883                         }
1884                 }
1885                 else
1886                         log_module(SS_LOG, LOG_ERROR, "Couldn't register channel %s. Channel or info invalid.", iter_key(it));  
1887         }
1888
1889         return 0;
1890 }
1891
1892 static int
1893 spamserv_saxdb_write(struct saxdb_context *ctx)
1894 {
1895         dict_iterator_t it;
1896
1897         for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
1898         {
1899                 struct chanInfo *cInfo = iter_data(it);
1900
1901                 saxdb_start_record(ctx, cInfo->channel->name, 1);
1902
1903                 if(cInfo->exceptions->used)
1904                         saxdb_write_string_list(ctx, KEY_EXCEPTIONS, cInfo->exceptions);
1905
1906                 if(cInfo->flags)
1907                         saxdb_write_int(ctx, KEY_FLAGS, cInfo->flags);  
1908
1909                 saxdb_write_string(ctx, KEY_INFO, cInfo->info);         
1910         saxdb_write_int(ctx, KEY_EXCEPTLEVEL, cInfo->exceptlevel);              
1911
1912                 if(cInfo->suspend_expiry)
1913                         saxdb_write_int(ctx, KEY_EXPIRY, cInfo->suspend_expiry);                
1914
1915                 saxdb_end_record(ctx);          
1916         }
1917         return 0;
1918 }
1919
1920 static void
1921 spamserv_conf_read(void)
1922 {
1923         dict_t conf_node;
1924         const char *str; 
1925
1926         if(!(conf_node = conf_get_data(SPAMSERV_CONF_NAME, RECDB_OBJECT)))
1927         {
1928                 log_module(SS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", SPAMSERV_CONF_NAME);
1929                 return;
1930         }
1931
1932         str = database_get_data(conf_node, KEY_DEBUG_CHANNEL, RECDB_QSTRING);
1933
1934         if(str)
1935         {
1936                 spamserv_conf.debug_channel = AddChannel(str, now, "+tinms", NULL);
1937
1938                 if(spamserv_conf.debug_channel)
1939                         spamserv_join_channel(spamserv_conf.debug_channel);
1940         }
1941         else
1942         {
1943                 spamserv_conf.debug_channel = NULL;
1944         }
1945
1946         spamserv_conf.global_exceptions = database_get_data(conf_node, KEY_GLOBAL_EXCEPTIONS, RECDB_STRING_LIST);
1947
1948         str = database_get_data(conf_node, KEY_NETWORK_RULES, RECDB_QSTRING);
1949         spamserv_conf.network_rules = str ? str : NULL;
1950
1951         str = database_get_data(conf_node, KEY_TRIGGER, RECDB_QSTRING);
1952         spamserv_conf.trigger = str ? str[0] : 0;
1953
1954         str = database_get_data(conf_node, KEY_SHORT_BAN_DURATION, RECDB_QSTRING);
1955         spamserv_conf.short_ban_duration = str ? ParseInterval(str) : ParseInterval("15m");
1956
1957         str = database_get_data(conf_node, KEY_LONG_BAN_DURATION, RECDB_QSTRING);
1958         spamserv_conf.long_ban_duration = str ? ParseInterval(str) : ParseInterval("1h");
1959
1960         str = database_get_data(conf_node, KEY_GLINE_DURATION, RECDB_QSTRING);
1961         spamserv_conf.gline_duration = str ? ParseInterval(str) : ParseInterval("1h");
1962
1963         str = database_get_data(conf_node, KEY_EXCEPTION_MAX, RECDB_QSTRING);
1964         spamserv_conf.exception_max = str ? strtoul(str, NULL, 0) : 10;
1965
1966         str = database_get_data(conf_node, KEY_EXCEPTION_MIN_LEN, RECDB_QSTRING);
1967         spamserv_conf.exception_min_len = str ? strtoul(str, NULL, 0) : 4;
1968
1969         str = database_get_data(conf_node, KEY_EXCEPTION_MAX_LEN, RECDB_QSTRING);
1970         spamserv_conf.exception_max_len = str ? strtoul(str, NULL, 0) : 15;
1971
1972         str = database_get_data(conf_node, KEY_ADV_CHAN_MUST_EXIST, RECDB_QSTRING);
1973         spamserv_conf.adv_chan_must_exist = str ? enabled_string(str) : 1;
1974
1975         str = database_get_data(conf_node, KEY_STRIP_MIRC_CODES, RECDB_QSTRING);
1976         spamserv_conf.strip_mirc_codes = str ? enabled_string(str) : 0;
1977
1978         str = database_get_data(conf_node, KEY_ALLOW_MOVE_MERGE, RECDB_QSTRING);
1979         spamserv_conf.allow_move_merge = str ? enabled_string(str) : 0;
1980 }
1981
1982 static void
1983 spamserv_db_cleanup(void)
1984 {
1985         dict_iterator_t it;
1986
1987         while((it = dict_first(registered_channels_dict)))
1988         {
1989                 spamserv_unregister_channel(iter_data(it));
1990         }
1991
1992         while((it = dict_first(killed_users_dict)))
1993         {
1994                 free(iter_data(it));
1995         }
1996         
1997         dict_delete(registered_channels_dict);
1998         dict_delete(connected_users_dict);
1999         dict_delete(killed_users_dict);
2000 }
2001
2002 void
2003 init_spamserv(const char *nick)
2004 {
2005         if(!nick)
2006                 return;
2007
2008         const char *modes = conf_get_data("services/spamserv/modes", RECDB_QSTRING);    
2009         spamserv = AddLocalUser(nick, nick, NULL, "Anti Spam Services", modes);
2010         spamserv_service = service_register(spamserv);
2011         service_register(spamserv)->trigger = spamserv_conf.trigger;
2012
2013         conf_register_reload(spamserv_conf_read);
2014
2015         SS_LOG = log_register_type("SpamServ", "file:spamserv.log");    
2016
2017         registered_channels_dict = dict_new();
2018         connected_users_dict = dict_new();
2019         killed_users_dict = dict_new();
2020
2021         reg_new_user_func(spamserv_new_user_func);
2022         reg_del_user_func(spamserv_del_user_func);
2023         reg_nick_change_func(spamserv_nick_change_func);
2024         reg_join_func(spamserv_user_join);
2025         reg_part_func(spamserv_user_part);
2026
2027         timeq_add(now + FLOOD_TIMEQ_FREQ, timeq_flood, NULL);
2028         timeq_add(now + JOINFLOOD_TIMEQ_FREQ, timeq_joinflood, NULL);
2029         timeq_add(now + ADV_TIMEQ_FREQ, timeq_adv, NULL);
2030         timeq_add(now + WARNLEVEL_TIMEQ_FREQ, timeq_warnlevel, NULL);
2031         timeq_add(now + KILL_TIMEQ_FREQ, timeq_kill, NULL);
2032
2033         spamserv_module = module_register("SpamServ", SS_LOG, "spamserv.help", NULL);
2034         modcmd_register(spamserv_module, "REGISTER", cmd_register, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, "flags", "+acceptchan,+helping", NULL);
2035         modcmd_register(spamserv_module, "UNREGISTER", cmd_unregister, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, "flags", "+loghostmask", NULL);
2036         modcmd_register(spamserv_module, "ADDEXCEPTION", cmd_addexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2037         modcmd_register(spamserv_module, "DELEXCEPTION", cmd_delexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2038         modcmd_register(spamserv_module, "STATUS", cmd_status, 1, 0, NULL);
2039         modcmd_register(spamserv_module, "SET", cmd_set, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2040         modcmd_register(spamserv_module, "SET SPAMLIMIT", opt_spamlimit, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2041         modcmd_register(spamserv_module, "SET ADVREACTION", opt_advreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2042         modcmd_register(spamserv_module, "SET WARNREACTION", opt_warnreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2043         modcmd_register(spamserv_module, "SET ADVSCAN", opt_advscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2044         modcmd_register(spamserv_module, "SET SPAMSCAN", opt_spamscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2045         modcmd_register(spamserv_module, "SET FLOODSCAN", opt_floodscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2046         modcmd_register(spamserv_module, "SET JOINFLOODSCAN", opt_joinflood, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2047         modcmd_register(spamserv_module, "SET SCANCHANOPS", opt_scanops, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2048         modcmd_register(spamserv_module, "SET SCANVOICED", opt_scanvoiced, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2049     modcmd_register(spamserv_module, "SET EXCEPTLEVEL", opt_exceptlevel, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2050
2051         saxdb_register("SpamServ", spamserv_saxdb_read, spamserv_saxdb_write);
2052         reg_exit_func(spamserv_db_cleanup);
2053         message_register_table(msgtab);
2054         crc32_init();
2055 }