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