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