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