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