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