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