1 /* spamserv.c - anti spam service
2 * Copyright 2004 feigling
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.
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.
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.
18 * $Id: spamserv.c,v 1.08 2004/06/27 22:21:00 feigling Exp $
30 #define SPAMSERV_CONF_NAME "services/spamserv"
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"
38 #define KEY_DEBUG_CHANNEL "debug_channel"
39 #define KEY_GLOBAL_EXCEPTIONS "global_exceptions"
40 #define KEY_NETWORK_RULES "network_rules"
41 #define KEY_TRIGGER "trigger"
42 #define KEY_SHORT_BAN_DURATION "short_ban_duration"
43 #define KEY_LONG_BAN_DURATION "long_ban_duration"
44 #define KEY_GLINE_DURATION "gline_duration"
45 #define KEY_EXCEPTION_MAX "exception_max"
46 #define KEY_EXCEPTION_MIN_LEN "exception_min_len"
47 #define KEY_EXCEPTION_MAX_LEN "exception_max_len"
48 #define KEY_ADV_CHAN_MUST_EXIST "adv_chan_must_exist"
49 #define KEY_STRIP_MIRC_CODES "strip_mirc_codes"
50 #define KEY_ALLOW_MOVE_MERGE "allow_move_merge"
52 #define SPAMSERV_FUNC(NAME) MODCMD_FUNC(NAME)
53 #define SPAMSERV_SYNTAX() svccmd_send_help(user, spamserv, cmd)
54 #define SPAMSERV_MIN_PARMS(N) do { \
57 ss_reply(MSG_MISSING_PARAMS, argv[0]); \
59 return 0; } } while(0)
61 struct userNode *spamserv;
62 static struct module *spamserv_module;
63 static struct service *spamserv_service;
64 static struct log_type *SS_LOG;
65 static unsigned long crc_table[256];
67 dict_t registered_channels_dict;
68 dict_t connected_users_dict;
69 dict_t killed_users_dict;
71 #define spamserv_notice(target, format...) send_message(target , spamserv , ## format)
72 #define spamserv_debug(format...) do { if(spamserv_conf.debug_channel) send_channel_notice(spamserv_conf.debug_channel , spamserv , ## format); } while(0)
73 #define ss_reply(format...) send_message(user , spamserv , ## format)
75 #define SET_SUBCMDS_SIZE 10
77 const char *set_subcommands[SET_SUBCMDS_SIZE] = {"SPAMLIMIT", "ADVREACTION", "WARNREACTION", "ADVSCAN", "SPAMSCAN", "FLOODSCAN", "JOINFLOODSCAN", "EXCEPTLEVEL","SCANCHANOPS", "SCANVOICED"};
79 static void spamserv_clear_spamNodes(struct chanNode *channel);
80 static void spamserv_punish(struct chanNode *channel, struct userNode *user, time_t expires, char *reason, int ban);
81 static unsigned long crc32(const char *text);
83 #define BINARY_OPTION(arguments...) return binary_option(arguments, user, channel, argc, argv);
84 #define MULTIPLE_OPTION(arguments...) return multiple_option(arguments, values, ArrayLength(values), user, channel, argc, argv);
86 static const struct message_entry msgtab[] = {
87 { "SSMSG_CHANNEL_OPTIONS", "Channel Options:" },
88 { "SSMSG_STRING_VALUE", "$b%s$b%s" },
89 { "SSMSG_NUMERIC_VALUE", "$b%s$b%d - %s" },
90 { "SSMSG_EASYNUMERIC_VALUE", "$b%s$b%d" },
91 { "SSMSG_INVALID_NUM_SET", "$b'%d'$b is an invalid %s setting." },
92 { "SSMSG_INVALID_OPTION", "$b%s$b is not a valid %s option." },
93 { "SSMSG_INVALID_BINARY", "$b%s$b is an invalid binary value." },
95 { "SSMSG_NOT_REGISTERED", "$b%s$b has not been registered with $b$X$b." },
96 { "SSMSG_NOT_REGISTERED_CS", "$b%s$b has not been registered with $b$C$b." },
97 { "SSMSG_ALREADY_REGISTERED", "$b%s$b is already registered." },
98 { "SSMSG_DEBUG_CHAN", "You may not register the debug channel." },
99 { "SSMSG_SUSPENDED_CS", "$b$C$b access to $b%s$b has been temporarily suspended, thus you can't %s it." },
100 { "SSMSG_SUSPENDED", "$b$X$b access to $b%s$b has been temporarily suspended." },
101 { "SSMSG_NO_REGISTER", "Due to an error it was not possible to register $b%s$b." },
102 { "SSMSG_REG_SUCCESS", "Channel $b%s$b registered." },
103 { "SSMSG_UNREG_SUCCESS", "$b%s$b has been unregistered." },
104 { "SSMSG_NO_ACCESS", "You lack sufficient access to use this command." },
105 { "SSMSG_MUST_BE_OPER", "You must be an irc operator to set this option." },
106 { "SSMSG_CONFIRM_UNREG", "To confirm this unregistration, you must append 'CONFIRM' to the end of your command. For example, 'unregister CONFIRM'." },
108 { "SSMSG_NO_EXCEPTIONS", "No words found in the exception list." },
109 { "SSMSG_NO_SUCH_EXCEPTION", "Word $b%s$b not found in the exception list." },
110 { "SSMSG_EXCEPTION_LIST", "The following words are in the exception list:" },
111 { "SSMSG_EXCEPTION_ADDED", "Word $b%s$b added to the exception list." },
112 { "SSMSG_EXCEPTION_DELETED", "Word $b%s$b deleted from the exception list." },
113 { "SSMSG_EXCEPTION_IN_LIST", "The word $b%s$b is already in the exception list." },
114 { "SSMSG_EXCEPTION_MAX", "The exception list has reached the maximum exceptions (max %lu). Delete a word to add another one." },
115 { "SSMSG_EXCEPTION_TOO_SHORT", "The word must be at least %lu characters long." },
116 { "SSMSG_EXCEPTION_TOO_LONG", "The word may not be longer than %lu characters." },
118 { "SSMSG_STATUS", "$bStatus:$b" },
119 { "SSMSG_STATUS_USERS", "Total Users Online: %u" },
120 { "SSMSG_STATUS_CHANNELS", "Registered Channels: %u" },
121 { "SSMSG_STATUS_MEMORY", "$bMemory Information:$b" },
122 { "SSMSG_STATUS_CHANNEL_LIST", "$bRegistered Channels:$b" },
123 { "SSMSG_STATUS_NO_CHANNEL", "No channels registered." },
127 #define SSMSG_DEBUG_KICK "Kicked user $b%s$b from $b%s$b, reason: %s"
128 #define SSMSG_DEBUG_BAN "Banned user $b%s$b from $b%s$b, reason: %s"
129 #define SSMSG_DEBUG_KILL "Killed user $b%s$b, last violation in $b%s$b"
130 #define SSMSG_DEBUG_GLINE "Glined user $b%s$b, host $b%s$b, last violation in $b%s$b"
131 #define SSMSG_DEBUG_RECONNECT "Killed user $b%s$b reconnected to the network"
132 #define SSMSG_SPAM "Spamming"
133 #define SSMSG_FLOOD "Flooding the channel/network"
134 #define SSMSG_ADV "Advertising"
135 #define SSMSG_JOINFLOOD "Join flooding the channel"
136 #define SSMSG_WARNING "%s is against the network rules"
137 #define SSMSG_WARNING_2 "You are violating the network rules"
138 #define SSMSG_WARNING_RULES "%s is against the network rules. Read the network rules at %s"
139 #define SSMSG_WARNING_RULES_2 "You are violating the network rules. Read the network rules at %s"
143 struct chanNode *debug_channel;
144 struct string_list *global_exceptions;
145 const char *network_rules;
146 unsigned char trigger;
147 unsigned long short_ban_duration;
148 unsigned long long_ban_duration;
149 unsigned long gline_duration;
150 unsigned long exception_max;
151 unsigned long exception_min_len;
152 unsigned long exception_max_len;
153 unsigned int adv_chan_must_exist : 1;
154 unsigned int strip_mirc_codes : 1;
155 unsigned int allow_move_merge : 1;
158 /***********************************************/
160 /***********************************************/
163 get_chanInfo(const char *channelname)
165 return dict_find(registered_channels_dict, channelname, 0);
169 spamserv_join_channel(struct chanNode *channel)
171 struct mod_chanmode change;
172 mod_chanmode_init(&change);
174 change.args[0].mode = MODE_CHANOP;
175 change.args[0].u.member = AddChannelUser(spamserv, channel);
176 mod_chanmode_announce(spamserv, channel, &change);
180 spamserv_part_channel(struct chanNode *channel, char *reason)
182 /* we only have to clear the spamNodes because every other node expires on it's own */
183 spamserv_clear_spamNodes(channel);
184 DelChannelUser(spamserv, channel, reason, 0);
187 static struct chanInfo*
188 spamserv_register_channel(struct chanNode *channel, struct string_list *exceptions, unsigned int flags, char *info)
190 struct chanInfo *cInfo = malloc(sizeof(struct chanInfo));
194 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for cInfo; channel: %s", channel->name);
198 cInfo->channel = channel;
199 cInfo->exceptions = exceptions ? string_list_copy(exceptions) : alloc_string_list(1);
200 cInfo->flags = flags;
201 cInfo->exceptlevel = 400;
202 safestrncpy(cInfo->info, info, sizeof(cInfo->info));
203 cInfo->suspend_expiry = 0;
204 dict_insert(registered_channels_dict, cInfo->channel->name, cInfo);
210 spamserv_unregister_channel(struct chanInfo *cInfo)
215 dict_remove(registered_channels_dict, cInfo->channel->name);
216 free_string_list(cInfo->exceptions);
221 spamserv_cs_suspend(struct chanNode *channel, time_t expiry, int suspend, char *reason)
223 struct chanInfo *cInfo = get_chanInfo(channel->name);
229 cInfo->flags |= CHAN_SUSPENDED;
230 cInfo->suspend_expiry = expiry;
231 spamserv_part_channel(channel, reason);
235 if(CHECK_SUSPENDED(cInfo))
237 cInfo->flags &= ~CHAN_SUSPENDED;
238 cInfo->suspend_expiry = 0;
245 spamserv_cs_move_merge(struct userNode *user, struct chanNode *channel, struct chanNode *target, int move)
247 struct chanInfo *cInfo = get_chanInfo(channel->name);
253 if(!spamserv_conf.allow_move_merge || get_chanInfo(target->name))
256 snprintf(reason, sizeof(reason), "unregistered due to a channel move to %s", target->name);
258 snprintf(reason, sizeof(reason), "unregistered due to a channel merge into %s", target->name);
260 spamserv_cs_unregister(user, channel, manually, reason);
264 cInfo->channel = target;
266 dict_remove(registered_channels_dict, channel->name);
267 dict_insert(registered_channels_dict, target->name, cInfo);
271 snprintf(reason, sizeof(reason), "Channel moved to %s by %s.", target->name, user->handle_info->handle);
275 spamserv_join_channel(target);
276 snprintf(reason, sizeof(reason), "%s merged into %s by %s.", channel->name, target->name, user->handle_info->handle);
279 if(!CHECK_SUSPENDED(cInfo))
280 spamserv_part_channel(channel, reason);
283 snprintf(reason, sizeof(reason), "$X (channel %s) moved to %s by %s.", channel->name, target->name, user->handle_info->handle);
285 snprintf(reason, sizeof(reason), "$X (channel %s) merged into %s by %s.", channel->name, target->name, user->handle_info->handle);
287 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
295 spamserv_cs_unregister(struct userNode *user, struct chanNode *channel, enum cs_unreg type, char *reason)
297 struct chanInfo *cInfo = get_chanInfo(channel->name);
301 char global[MAXLEN], partmsg[MAXLEN];
306 snprintf(global, sizeof(global), "$X (channel %s) %s by %s.", channel->name, reason, user->handle_info->handle);
307 snprintf(partmsg, sizeof(partmsg), "%s %s by %s.", channel->name, reason, user->handle_info->handle);
310 snprintf(global, sizeof(global), "$X (channel %s) registration expired.", channel->name);
311 snprintf(partmsg, sizeof(partmsg), "%s registration expired.", channel->name);
314 snprintf(global, sizeof(global), "$X (channel %s) lost all users.", channel->name);
315 snprintf(partmsg, sizeof(partmsg), "%s lost all users.", channel->name);
319 if(!CHECK_SUSPENDED(cInfo))
320 spamserv_part_channel(channel, partmsg);
322 spamserv_unregister_channel(cInfo);
323 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, global);
327 /***********************************************/
329 /***********************************************/
331 static struct userInfo*
332 get_userInfo(const char *nickname)
334 return dict_find(connected_users_dict, nickname, 0);
338 spamserv_create_spamNode(struct chanNode *channel, struct userInfo *uInfo, char *text)
340 struct spamNode *sNode = malloc(sizeof(struct spamNode));
344 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for sNode; channel: %s; user: %s", channel->name, uInfo->user->nick);
348 sNode->channel = channel;
349 sNode->crc32 = crc32(text);
355 struct spamNode *temp = uInfo->spam;
371 spamserv_delete_spamNode(struct userInfo *uInfo, struct spamNode *sNode)
376 if(sNode == uInfo->spam)
377 uInfo->spam = sNode->next;
380 sNode->next->prev = sNode->prev;
382 sNode->prev->next = sNode->next;
388 spamserv_clear_spamNodes(struct chanNode *channel)
390 struct userInfo *uInfo;
391 struct spamNode *sNode;
394 for(i = 0; i < channel->members.used; i++)
396 if((uInfo = get_userInfo(channel->members.list[i]->user->nick)))
398 if((sNode = uInfo->spam))
400 for(; sNode; sNode = sNode->next)
401 if(sNode->channel == channel)
405 spamserv_delete_spamNode(uInfo, sNode);
412 spamserv_create_floodNode(struct chanNode *channel, struct userNode *user, struct floodNode **uI_fNode)
414 struct floodNode *fNode = malloc(sizeof(struct floodNode));
418 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for fNode; channel: %s; user: %s", channel->name, user->nick);
422 fNode->channel = channel;
430 struct floodNode *temp = *uI_fNode;
446 spamserv_delete_floodNode(struct floodNode **uI_fNode, struct floodNode *fNode)
451 if(fNode == *uI_fNode)
452 *uI_fNode = fNode->next;
455 fNode->next->prev = fNode->prev;
457 fNode->prev->next = fNode->next;
463 spamserv_create_user(struct userNode *user)
465 struct userInfo *uInfo = malloc(sizeof(struct userInfo));
466 struct killNode *kNode = dict_find(killed_users_dict, irc_ntoa(&user->ip), 0);
470 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for uInfo; nick: %s", user->nick);
475 spamserv_debug(SSMSG_DEBUG_RECONNECT, user->nick);
480 uInfo->joinflood = NULL;
481 uInfo->flags = kNode ? USER_KILLED : 0;
482 uInfo->warnlevel = kNode ? kNode->warnlevel : 0;
485 dict_insert(connected_users_dict, user->nick, uInfo);
489 dict_remove(killed_users_dict, irc_ntoa(&user->ip));
495 spamserv_delete_user(struct userInfo *uInfo)
502 spamserv_delete_spamNode(uInfo, uInfo->spam);
506 spamserv_delete_floodNode(&uInfo->flood, uInfo->flood);
509 while(uInfo->joinflood)
510 spamserv_delete_floodNode(&uInfo->joinflood, uInfo->joinflood);
512 dict_remove(connected_users_dict, uInfo->user->nick);
517 spamserv_new_user_func(struct userNode *user)
520 spamserv_create_user(user);
524 spamserv_del_user_func(struct userNode *user, struct userNode *killer, UNUSED_ARG(const char *why))
526 struct userInfo *uInfo = get_userInfo(user->nick);
527 struct killNode *kNode;
529 if(killer == spamserv)
531 kNode = malloc(sizeof(struct killNode));
535 log_module(SS_LOG, LOG_ERROR, "Couldn't allocate memory for killNode - nickname %s", user->nick);
536 spamserv_delete_user(uInfo);
540 if(uInfo->warnlevel > KILL_WARNLEVEL)
541 kNode->warnlevel = uInfo->warnlevel - KILL_WARNLEVEL;
543 kNode->warnlevel = 0;
547 dict_insert(killed_users_dict, irc_ntoa(&user->ip), kNode);
550 spamserv_delete_user(uInfo);
554 spamserv_nick_change_func(struct userNode *user, const char *old_nick)
556 struct userInfo *uInfo = get_userInfo(old_nick);
558 dict_remove(connected_users_dict, old_nick);
559 dict_insert(connected_users_dict, user->nick, uInfo);
563 spamserv_user_join(struct modeNode *mNode)
565 struct chanNode *channel = mNode->channel;
566 struct userNode *user = mNode->user;
567 struct chanInfo *cInfo;
568 struct userInfo *uInfo;
569 struct floodNode *jfNode;
571 if(user->uplink->burst || !(cInfo = get_chanInfo(channel->name)) || !CHECK_JOINFLOOD(cInfo) || !(uInfo = get_userInfo(user->nick)))
575 if(!CHECK_CHANOPS(cInfo))
577 //struct modeNode *mn = GetUserMode(channel, user);
578 //if(mn->modes & MODE_CHANOP)
580 if(check_user_level(channel, user, lvlGiveOps, 1, 0))
584 if(!CHECK_VOICED(cInfo))
586 if(check_user_level(channel, user, lvlGiveVoice, 1, 0))
590 if(cInfo->exceptlevel == 0)
592 if(cInfo->exceptlevel < 501) {
593 struct userData *uData;
594 if((uData = GetChannelUser(channel->channel_info, user->handle_info)) && (uData->access >= cInfo->exceptlevel)) {
599 if(!(jfNode = uInfo->joinflood))
601 spamserv_create_floodNode(channel, user, &uInfo->joinflood);
605 for(; jfNode; jfNode = jfNode->next)
606 if(jfNode->channel == channel)
611 spamserv_create_floodNode(channel, user, &uInfo->joinflood);
618 if(jfNode->count > JOINFLOOD_MAX)
622 spamserv_delete_floodNode(&uInfo->joinflood, jfNode);
623 snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_JOINFLOOD, spamserv_conf.network_rules);
624 spamserv_punish(channel, user, JOINFLOOD_B_DURATION, reason, 1);
633 spamserv_user_part(struct modeNode *mn, UNUSED_ARG(const char *reason))
635 struct userNode *user = mn->user;
636 struct chanNode *channel = mn->channel;
637 struct userInfo *uInfo;
638 struct spamNode *sNode;
639 struct floodNode *fNode;
641 if(user->dead || !get_chanInfo(channel->name) || !(uInfo = get_userInfo(user->nick)))
644 if((sNode = uInfo->spam))
646 for(; sNode; sNode = sNode->next)
647 if(sNode->channel == channel)
651 spamserv_delete_spamNode(uInfo, sNode);
654 if((fNode = uInfo->flood))
656 for(; fNode; fNode = fNode->next)
657 if(fNode->channel == channel)
661 spamserv_delete_floodNode(&uInfo->flood, fNode);
665 /***********************************************/
667 /***********************************************/
675 for(i = 0; i < 256; i++)
679 for(j = 8; j > 0; j--)
683 crc = (crc >> 1) ^ 0xEDB88320L;
696 crc32(const char *text)
698 register unsigned long crc = 0xFFFFFFFF;
699 unsigned int c, i = 0;
701 while((c = (unsigned int)text[i++]) != 0)
702 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_table[(crc^c) & 0xFF];
704 return (crc^0xFFFFFFFF);
708 timeq_flood(UNUSED_ARG(void *data))
711 struct userInfo *uInfo;
712 struct floodNode *fNode;
714 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
716 uInfo = iter_data(it);
718 if(!(fNode = uInfo->flood))
721 for(; fNode; fNode = fNode->next)
723 if(now - fNode->time > FLOOD_EXPIRE)
725 if(!(--fNode->count))
726 spamserv_delete_floodNode(&uInfo->flood, fNode);
731 timeq_add(now + FLOOD_TIMEQ_FREQ, timeq_flood, NULL);
735 timeq_joinflood(UNUSED_ARG(void *data))
738 struct userInfo *uInfo;
739 struct floodNode *fNode;
741 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
743 uInfo = iter_data(it);
745 if(!(fNode = uInfo->joinflood))
748 for(; fNode; fNode = fNode->next)
750 if(now - fNode->time > JOINFLOOD_EXPIRE)
752 if(!(--fNode->count))
753 spamserv_delete_floodNode(&uInfo->joinflood, fNode);
758 timeq_add(now + JOINFLOOD_TIMEQ_FREQ, timeq_joinflood, NULL);
762 timeq_adv(UNUSED_ARG(void *data))
765 struct userInfo *uInfo;
767 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
769 uInfo = iter_data(it);
771 if(uInfo->lastadv && uInfo->lastadv - now > ADV_EXPIRE)
774 uInfo->flags &= ~USER_ADV_WARNED;
778 timeq_add(now + ADV_TIMEQ_FREQ, timeq_adv, NULL);
782 timeq_warnlevel(UNUSED_ARG(void *data))
785 struct userInfo *uInfo;
787 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
789 uInfo = iter_data(it);
791 if(uInfo->warnlevel > 0)
795 timeq_add(now + WARNLEVEL_TIMEQ_FREQ, timeq_warnlevel, NULL);
799 timeq_kill(UNUSED_ARG(void *data))
802 struct killNode *kNode;
804 for(it = dict_first(killed_users_dict); it; it = iter_next(it))
806 kNode = iter_data(it);
808 if(kNode->time - now > KILL_EXPIRE)
812 timeq_add(now + KILL_TIMEQ_FREQ, timeq_kill, NULL);
816 binary_option(char *name, unsigned long mask, struct userNode *user, struct chanNode *channel, int argc, char *argv[])
818 struct chanInfo *cInfo = get_chanInfo(channel->name);
823 if(enabled_string(argv[1]))
825 cInfo->flags |= mask;
828 else if(disabled_string(argv[1]))
830 cInfo->flags &= ~mask;
835 spamserv_notice(user, "SSMSG_INVALID_BINARY", argv[1]);
841 value = (cInfo->flags & mask) ? 1 : 0;
844 spamserv_notice(user, "SSMSG_STRING_VALUE", name, value ? "Enabled." : "Disabled.");
856 multiple_option(char *name, char *description, enum channelinfo info, struct valueData *values, int count, struct userNode *user, struct chanNode *channel, int argc, char *argv[])
858 struct chanInfo *cInfo = get_chanInfo(channel->name);
863 index = atoi(argv[1]);
865 if(index < 0 || index >= count)
867 spamserv_notice(user, "SSMSG_INVALID_NUM_SET", index, description);
869 for(index = 0; index < count; index++)
870 spamserv_notice(user, "SSMSG_NUMERIC_VALUE", name, index, values[index].description);
875 if(values[index].oper_only && !IsOper(user))
877 spamserv_notice(user, "SSMSG_MUST_BE_OPER");
881 cInfo->info[info] = values[index].value;
885 for(index = 0; index < count && cInfo->info[info] != values[index].value; index++);
888 spamserv_notice(user, "SSMSG_NUMERIC_VALUE", name, index, values[index].description);
893 show_exceptions(struct userNode *user, struct chanInfo *cInfo)
895 struct helpfile_table table;
898 if(!cInfo->exceptions->used)
900 spamserv_notice(user, "SSMSG_NO_EXCEPTIONS");
904 spamserv_notice(user, "SSMSG_EXCEPTION_LIST");
908 table.flags = TABLE_REPEAT_ROWS | TABLE_NO_FREE | TABLE_NO_HEADERS;
909 table.contents = alloca(cInfo->exceptions->used * sizeof(*table.contents));
911 for(i = 0; i < cInfo->exceptions->used; i++)
913 table.contents[table.length] = alloca(table.width * sizeof(**table.contents));
914 table.contents[table.length][0] = cInfo->exceptions->list[i];
918 table_send(spamserv, user->nick, 0, NULL, table);
924 show_memory_usage(struct userNode *user)
927 struct helpfile_table table;
928 struct chanInfo *cInfo;
929 struct userInfo *uInfo;
930 struct spamNode *sNode;
931 struct floodNode *fNode;
932 double channel_size = 0, user_size, size;
933 unsigned int spamcount = 0, floodcount = 0, i, j;
936 for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
938 cInfo = iter_data(it);
940 if(!cInfo->exceptions->used)
943 for(i = 0; i < cInfo->exceptions->used; i++)
944 channel_size += strlen(cInfo->exceptions->list[i]) * sizeof(char);
947 for(it = dict_first(connected_users_dict); it; it = iter_next(it))
949 uInfo = iter_data(it);
951 for(sNode = uInfo->spam; sNode; sNode = sNode->next, spamcount++);
952 for(fNode = uInfo->flood; fNode; fNode = fNode->next, floodcount++);
953 for(fNode = uInfo->joinflood; fNode; fNode = fNode->next, floodcount++);
956 channel_size += dict_size(registered_channels_dict) * sizeof(struct chanInfo);
958 user_size = dict_size(connected_users_dict) * sizeof(struct userInfo) +
959 dict_size(killed_users_dict) * sizeof(struct killNode) +
960 spamcount * sizeof(struct spamNode) +
961 floodcount * sizeof(struct floodNode);
963 size = channel_size + user_size;
965 ss_reply("SSMSG_STATUS_MEMORY");
969 table.flags = TABLE_NO_FREE | TABLE_NO_HEADERS | TABLE_PAD_LEFT;
970 table.contents = calloc(table.length, sizeof(char**));
973 table.contents[0] = calloc(table.width, sizeof(char*));
974 snprintf(buffer, sizeof(buffer), "Channel Memory Usage:");
975 table.contents[0][0] = strdup(buffer);
976 snprintf(buffer, sizeof(buffer), " %g Byte; ", channel_size);
977 table.contents[0][1] = strdup(buffer);
978 snprintf(buffer, sizeof(buffer), "%g KiloByte; ", channel_size / 1024);
979 table.contents[0][2] = strdup(buffer);
980 snprintf(buffer, sizeof(buffer), "%g MegaByte", channel_size / 1024 / 1024);
981 table.contents[0][3] = strdup(buffer);
984 table.contents[1] = calloc(table.width, sizeof(char*));
985 snprintf(buffer, sizeof(buffer), "User Memory Usage :");
986 table.contents[1][0] = strdup(buffer);
987 snprintf(buffer, sizeof(buffer), " %g Byte; ", user_size);
988 table.contents[1][1] = strdup(buffer);
989 snprintf(buffer, sizeof(buffer), "%g KiloByte; ", user_size / 1024);
990 table.contents[1][2] = strdup(buffer);
991 snprintf(buffer, sizeof(buffer), "%g MegaByte", user_size / 1024 / 1024);
992 table.contents[1][3] = strdup(buffer);
994 // total memory usage
995 table.contents[2] = calloc(table.width, sizeof(char*));
996 snprintf(buffer, sizeof(buffer), "Total Memory Usage :");
997 table.contents[2][0] = strdup(buffer);
998 snprintf(buffer, sizeof(buffer), " %g Byte; ", size);
999 table.contents[2][1] = strdup(buffer);
1000 snprintf(buffer, sizeof(buffer), "%g KiloByte; ", size / 1024);
1001 table.contents[2][2] = strdup(buffer);
1002 snprintf(buffer, sizeof(buffer), "%g MegaByte", size / 1024 / 1024);
1003 table.contents[2][3] = strdup(buffer);
1005 table_send(spamserv, user->nick, 0, NULL, table);
1007 for(i = 0; i < table.length; i++)
1009 for(j = 0; j < table.width; j++)
1010 free((char*)table.contents[i][j]);
1012 free(table.contents[i]);
1015 free(table.contents);
1019 show_registered_channels(struct userNode *user)
1021 struct helpfile_table table;
1024 spamserv_notice(user, "SSMSG_STATUS_CHANNEL_LIST");
1026 if(!dict_size(registered_channels_dict))
1028 spamserv_notice(user, "SSMSG_STATUS_NO_CHANNEL");
1034 table.flags = TABLE_REPEAT_ROWS | TABLE_NO_FREE | TABLE_NO_HEADERS;
1035 table.contents = alloca(dict_size(registered_channels_dict) * sizeof(*table.contents));
1037 for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
1039 struct chanInfo *cInfo = iter_data(it);
1041 table.contents[table.length] = alloca(table.width * sizeof(**table.contents));
1042 table.contents[table.length][0] = cInfo->channel->name;
1046 table_send(spamserv, user->nick, 0, NULL, table);
1049 /***********************************************/
1051 /***********************************************/
1054 SPAMSERV_FUNC(cmd_register)
1056 struct chanInfo *cInfo;
1057 char reason[MAXLEN];
1059 if(!channel || !channel->channel_info)
1061 ss_reply("SSMSG_NOT_REGISTERED_CS", channel->name);
1065 if(get_chanInfo(channel->name))
1067 ss_reply("SSMSG_ALREADY_REGISTERED", channel->name);
1071 if(IsSuspended(channel->channel_info))
1073 ss_reply("SSMSG_SUSPENDED_CS", channel->name, "register");
1077 if(channel == spamserv_conf.debug_channel)
1079 ss_reply("SSMSG_DEBUG_CHAN");
1083 if(!(cInfo = spamserv_register_channel(channel, spamserv_conf.global_exceptions, CHAN_FLAGS_DEFAULT , CHAN_INFO_DEFAULT)))
1085 ss_reply("SSMSG_NO_REGISTER", channel->name);
1089 spamserv_join_channel(cInfo->channel);
1091 snprintf(reason, sizeof(reason), "%s (channel %s) registered by %s.", spamserv->nick, channel->name, user->handle_info->handle);
1092 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
1093 ss_reply("SSMSG_REG_SUCCESS", channel->name);
1099 SPAMSERV_FUNC(cmd_unregister)
1101 struct chanInfo *cInfo;
1102 struct chanData *cData;
1103 struct userData *uData;
1104 char reason[MAXLEN];
1106 if(!channel || !(cData = channel->channel_info) || !(cInfo = get_chanInfo(channel->name)))
1108 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1112 if(!(uData = GetChannelUser(cData, user->handle_info)) || (uData->access < UL_OWNER))
1114 ss_reply("SSMSG_NO_ACCESS");
1118 if(!IsHelping(user))
1120 if(IsSuspended(cData))
1122 ss_reply("SSMSG_SUSPENDED_CS", channel->name, "unregister");
1126 if(argc < 2 || strcasecmp(argv[1], "CONFIRM"))
1128 ss_reply("SSMSG_CONFIRM_UNREG");
1133 if(!CHECK_SUSPENDED(cInfo))
1135 snprintf(reason, sizeof(reason), "%s unregistered by %s.", spamserv->nick, user->handle_info->handle);
1136 spamserv_part_channel(channel, reason);
1139 spamserv_unregister_channel(cInfo);
1141 snprintf(reason, sizeof(reason), "%s (channel %s) unregistered by %s.", spamserv->nick, channel->name, user->handle_info->handle);
1142 global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
1143 ss_reply("SSMSG_UNREG_SUCCESS", channel->name);
1149 SPAMSERV_FUNC(cmd_status)
1151 ss_reply("SSMSG_STATUS");
1152 ss_reply("SSMSG_STATUS_USERS", dict_size(connected_users_dict));
1153 ss_reply("SSMSG_STATUS_CHANNELS", dict_size(registered_channels_dict));
1155 if(IsOper(user) && argc > 1)
1157 if(!irccasecmp(argv[1], "memory"))
1158 show_memory_usage(user);
1159 else if(!irccasecmp(argv[1], "channels"))
1160 show_registered_channels(user);
1167 SPAMSERV_FUNC(cmd_addexception)
1169 struct chanInfo *cInfo = get_chanInfo(channel->name);
1170 struct userData *uData;
1173 if(!cInfo || !channel->channel_info)
1175 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1179 if(CHECK_SUSPENDED(cInfo))
1181 ss_reply("SSMSG_SUSPENDED", channel->name);
1185 if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1187 ss_reply("SSMSG_NO_ACCESS");
1192 return show_exceptions(user, cInfo);
1194 if(cInfo->exceptions->used == spamserv_conf.exception_max && !IsOper(user))
1196 ss_reply("SSMSG_EXCEPTION_MAX", spamserv_conf.exception_max);
1200 if(strlen(argv[1]) < spamserv_conf.exception_min_len)
1202 ss_reply("SSMSG_EXCEPTION_TOO_SHORT", spamserv_conf.exception_min_len);
1205 else if(strlen(argv[1]) > spamserv_conf.exception_max_len)
1207 ss_reply("SSMSG_EXCEPTION_TOO_LONG", spamserv_conf.exception_max_len);
1211 for(i = 0; i < cInfo->exceptions->used; i++)
1213 if(!irccasecmp(argv[1], cInfo->exceptions->list[i]))
1215 ss_reply("SSMSG_EXCEPTION_IN_LIST", argv[1]);
1220 string_list_append(cInfo->exceptions, strdup(argv[1]));
1221 ss_reply("SSMSG_EXCEPTION_ADDED", argv[1]);
1227 SPAMSERV_FUNC(cmd_delexception)
1229 struct chanInfo *cInfo = get_chanInfo(channel->name);
1230 struct userData *uData;
1234 if(!cInfo || !channel->channel_info)
1236 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1240 if(CHECK_SUSPENDED(cInfo))
1242 ss_reply("SSMSG_SUSPENDED", channel->name);
1246 if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < 400))
1248 ss_reply("SSMSG_NO_ACCESS");
1253 return show_exceptions(user, cInfo);
1255 for(i = 0; i < cInfo->exceptions->used; i++)
1257 if(!irccasecmp(argv[1], cInfo->exceptions->list[i]))
1266 ss_reply("SSMSG_NO_SUCH_EXCEPTION", argv[1]);
1270 string_list_delete(cInfo->exceptions, i);
1271 ss_reply("SSMSG_EXCEPTION_DELETED", argv[1]);
1277 SPAMSERV_FUNC(cmd_set)
1279 struct chanInfo *cInfo = get_chanInfo(channel->name);
1280 struct svccmd *subcmd;
1281 char cmd_name[MAXLEN];
1286 ss_reply("SSMSG_NOT_REGISTERED", channel->name);
1290 if(CHECK_SUSPENDED(cInfo))
1292 ss_reply("SSMSG_SUSPENDED", channel->name);
1296 if(!check_user_level(channel,user,lvlSetters,1,0))
1298 ss_reply("SSMSG_NO_ACCESS");
1304 ss_reply("SSMSG_CHANNEL_OPTIONS");
1306 for(i = 0; i < SET_SUBCMDS_SIZE; i++)
1308 sprintf(cmd_name, "%s %s", cmd->name, set_subcommands[i]);
1310 if((subcmd = dict_find(cmd->parent->commands, cmd_name, NULL)))
1311 subcmd->command->func(user, channel, 1, argv + 1, subcmd);
1317 sprintf(cmd_name, "%s %s", cmd->name, argv[1]);
1318 subcmd = dict_find(cmd->parent->commands, cmd_name, NULL);
1322 reply("SSMSG_INVALID_OPTION", argv[1], argv[0]);
1326 return subcmd->command->func(user, channel, argc - 1, argv + 1, subcmd);
1330 SPAMSERV_FUNC(opt_spamlimit)
1332 struct valueData values[] =
1334 {"Users may send the same message $b2$b times.", 'a', 0},
1335 {"Users may send the same message $b3$b times.", 'b', 0},
1336 {"Users may send the same message $b4$b times.", 'c', 0},
1337 {"Users may send the same message $b5$b times.", 'd', 0},
1338 {"Users may send the same message $b6$b times.", 'e', 0}
1341 MULTIPLE_OPTION("SpamLimit ", "SpamLimit", ci_SpamLimit);
1345 SPAMSERV_FUNC(opt_advreaction)
1347 struct valueData values[] =
1349 {"Kick on disallowed advertising.", 'k', 0},
1350 {"Kickban on disallowed advertising.", 'b', 0},
1351 {"Short timed ban on disallowed advertising.", 's', 0},
1352 {"Long timed ban on disallowed advertising.", 'l', 0},
1353 {"Kill on disallowed advertising.", 'd', 1}
1356 MULTIPLE_OPTION("AdvReaction ", "AdvReaction", ci_AdvReaction);
1360 SPAMSERV_FUNC(opt_warnreaction)
1362 struct valueData values[] =
1364 {"Kick after warning.", 'k', 0},
1365 {"Kickban after warning.", 'b', 0},
1366 {"Short timed ban after warning.", 's', 0},
1367 {"Long timed ban after warning.", 'l', 0},
1368 {"Kill after warning.", 'd', 1}
1371 MULTIPLE_OPTION("WarnReaction ", "WarnReaction", ci_WarnReaction);
1375 SPAMSERV_FUNC(opt_advscan)
1377 BINARY_OPTION("AdvScan ", CHAN_ADV_SCAN);
1381 SPAMSERV_FUNC(opt_spamscan)
1383 BINARY_OPTION("SpamScan ", CHAN_SPAMSCAN);
1387 SPAMSERV_FUNC(opt_floodscan)
1389 BINARY_OPTION("FloodScan ", CHAN_FLOODSCAN);
1393 SPAMSERV_FUNC(opt_joinflood)
1395 BINARY_OPTION("JoinFloodScan ", CHAN_JOINFLOOD);
1399 SPAMSERV_FUNC(opt_scanops)
1401 BINARY_OPTION("ScanChanOps ", CHAN_SCAN_CHANOPS);
1405 SPAMSERV_FUNC(opt_scanvoiced)
1407 BINARY_OPTION("ScanVoiced ", CHAN_SCAN_VOICED);
1411 SPAMSERV_FUNC(opt_exceptlevel)
1413 struct chanInfo *cInfo = get_chanInfo(channel->name);
1414 struct userData *uData;
1418 index = atoi(argv[1]);
1419 if(index < 1 || index > 501)
1421 spamserv_notice(user, "SSMSG_INVALID_NUM_SET", index, "ExceptLevel");
1424 if(!(uData = GetChannelUser(channel->channel_info, user->handle_info)) || (uData->access < cInfo->exceptlevel || index > uData->access))
1426 ss_reply("SSMSG_NO_ACCESS");
1429 cInfo->exceptlevel=index;
1431 index=cInfo->exceptlevel;
1433 spamserv_notice(user, "SSMSG_EASYNUMERIC_VALUE", "ExceptLevel ", index);
1438 to_lower(char *message)
1440 unsigned int i, diff = 'a' - 'A';
1442 for(i = 0; i < strlen(message); i++)
1444 if((message[i] >= 'A') && (message[i] <= 'Z'))
1445 message[i] = message[i] + diff;
1450 strip_mirc_codes(char *text)
1452 // taken from xchat and modified
1453 int nc = 0, i = 0, col = 0, len = strlen(text);
1454 static char new_str[MAXLEN];
1458 if((col && isdigit(*text) && nc < 2) ||
1459 (col && *text == ',' && isdigit(*(text + 1)) && nc < 3))
1498 is_in_exception_list(struct chanInfo *cInfo, char *message)
1502 for(i = 0; i < cInfo->exceptions->used; i++)
1503 if(strstr(message, cInfo->exceptions->list[i]))
1510 check_advertising(struct chanInfo *cInfo, char *message)
1514 if(spamserv_conf.strip_mirc_codes)
1515 message = strip_mirc_codes(message);
1517 if(is_in_exception_list(cInfo, message))
1520 while(message[i] != 0)
1522 if(message[i] == '#')
1524 char channelname[CHANNELLEN];
1527 if(!spamserv_conf.adv_chan_must_exist)
1530 /* only return 1, if the channel does exist */
1532 while((message[i] != 0) && (message[i] != ' '))
1534 channelname[j] = message[i];
1539 channelname[j] = '\0';
1541 if(GetChannel(channelname))
1544 else if((message[i] == 'w') && (message[i+1] == 'w') && (message[i+2] == 'w') && (message[i+3] == '.'))
1546 else if((message[i] == 'h') && (message[i+1] == 't') && (message[i+2] == 't') && (message[i+3] == 'p') && (message[i+4] == ':'))
1548 else if((message[i] == 'f') && (message[i+1] == 't') && (message[i+2] == 'p') && ((message[i+3] == '.') || (message[i+3] == ':')))
1557 struct banData *add_channel_ban(struct chanData *channel, const char *mask, char *owner, unsigned long set, unsigned long triggered, unsigned long expires, char *reason);
1560 spamserv_punish(struct chanNode *channel, struct userNode *user, time_t expires, char *reason, int ban)
1564 struct mod_chanmode change;
1565 char *hostmask = generate_hostmask(user, GENMASK_STRICT_HOST | GENMASK_ANY_IDENT);
1567 sanitize_ircmask(hostmask);
1570 add_channel_ban(channel->channel_info, hostmask, spamserv->nick, now, now, now + expires, reason);
1572 mod_chanmode_init(&change);
1574 change.args[0].mode = MODE_BAN;
1575 change.args[0].u.hostmask = hostmask;
1576 mod_chanmode_announce(spamserv, channel, &change);
1580 spamserv_debug(SSMSG_DEBUG_BAN, user->nick, channel->name, reason);
1583 spamserv_debug(SSMSG_DEBUG_KICK, user->nick, channel->name, reason);
1585 KickChannelUser(user, channel, spamserv, reason);
1589 spamserv_channel_message(struct chanNode *channel, struct userNode *user, char *text)
1591 struct chanInfo *cInfo;
1592 struct userInfo *uInfo;
1593 struct spamNode *sNode;
1594 struct floodNode *fNode;
1595 unsigned int violation = 0;
1596 char reason[MAXLEN];
1598 /* make sure: spamserv is not disabled; srvx is running; spamserv is in the chan; chan is regged, user does exist */
1599 if(!spamserv || quit_services || !GetUserMode(channel, spamserv) || !(cInfo = get_chanInfo(channel->name)) || !(uInfo = get_userInfo(user->nick)))
1602 if(!CHECK_CHANOPS(cInfo))
1604 struct modeNode *mn = GetUserMode(channel, user);
1605 if(mn && mn->modes & MODE_CHANOP)
1607 //if(check_user_level(channel, user, lvlGiveOps, 1, 0))
1611 if(!CHECK_VOICED(cInfo))
1613 struct modeNode *mn = GetUserMode(channel, user);
1614 if(mn && (mn->modes & MODE_VOICE) && !(mn->modes & MODE_CHANOP))
1618 if(cInfo->exceptlevel == 0)
1620 if(cInfo->exceptlevel < 501) {
1621 struct userData *uData;
1622 if((uData = GetChannelUser(channel->channel_info, user->handle_info)) && (uData->access >= cInfo->exceptlevel)) {
1629 if(CHECK_SPAM(cInfo))
1631 if(!(sNode = uInfo->spam))
1633 spamserv_create_spamNode(channel, uInfo, text);
1637 for(; sNode; sNode = sNode->next)
1638 if(sNode->channel == channel)
1643 spamserv_create_spamNode(channel, uInfo, text);
1647 unsigned long crc = crc32(text);
1649 if(crc == sNode->crc32)
1651 unsigned int spamlimit = 2;
1654 switch(cInfo->info[ci_SpamLimit])
1656 case 'a': spamlimit = 2; break;
1657 case 'b': spamlimit = 3; break;
1658 case 'c': spamlimit = 4; break;
1659 case 'd': spamlimit = 5; break;
1660 case 'e': spamlimit = 6; break;
1663 if(sNode->count == spamlimit)
1665 uInfo->warnlevel += SPAM_WARNLEVEL;
1667 if(uInfo->warnlevel < MAX_WARNLEVEL)
1668 spamserv_notice(user, spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_SPAM, spamserv_conf.network_rules);
1670 else if(sNode->count > spamlimit)
1672 switch(cInfo->info[ci_WarnReaction])
1674 case 'k': uInfo->flags |= USER_KICK; break;
1675 case 'b': uInfo->flags |= USER_KICKBAN; break;
1676 case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1677 case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1678 case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1681 spamserv_delete_spamNode(uInfo, sNode);
1682 uInfo->warnlevel += SPAM_WARNLEVEL;
1695 if(CHECK_FLOOD(cInfo))
1697 if(!(fNode = uInfo->flood))
1699 spamserv_create_floodNode(channel, user, &uInfo->flood);
1703 for(; fNode; fNode = fNode->next)
1704 if(fNode->channel == channel)
1709 spamserv_create_floodNode(channel, user, &uInfo->flood);
1713 if(((now - fNode->time) < FLOOD_EXPIRE))
1717 if(fNode->count == FLOOD_MAX_LINES - 1)
1719 uInfo->warnlevel += FLOOD_WARNLEVEL;
1721 if(uInfo->warnlevel < MAX_WARNLEVEL)
1722 spamserv_notice(user, spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_FLOOD, spamserv_conf.network_rules);
1724 else if(fNode->count > FLOOD_MAX_LINES)
1726 switch(cInfo->info[ci_WarnReaction])
1728 case 'k': uInfo->flags |= USER_KICK; break;
1729 case 'b': uInfo->flags |= USER_KICKBAN; break;
1730 case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1731 case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1732 case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1735 spamserv_delete_floodNode(&uInfo->flood, fNode);
1736 uInfo->warnlevel += FLOOD_WARNLEVEL;
1746 if(CHECK_ADV(cInfo) && check_advertising(cInfo, text))
1748 if(CHECK_ADV_WARNED(uInfo))
1750 switch(cInfo->info[ci_AdvReaction])
1752 case 'k': uInfo->flags |= USER_KICK; break;
1753 case 'b': uInfo->flags |= USER_KICKBAN; break;
1754 case 's': uInfo->flags |= USER_SHORT_TBAN; break;
1755 case 'l': uInfo->flags |= USER_LONG_TBAN; break;
1756 case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
1759 uInfo->warnlevel += ADV_WARNLEVEL;
1764 uInfo->flags |= USER_ADV_WARNED;
1765 uInfo->lastadv = now;
1766 uInfo->warnlevel += ADV_WARNLEVEL;
1768 if(uInfo->warnlevel < MAX_WARNLEVEL)
1769 spamserv_notice(user, spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_ADV, spamserv_conf.network_rules);
1773 if(!CHECK_WARNED(uInfo) && !CHECK_KILL(uInfo) && !CHECK_GLINE(uInfo) && uInfo->warnlevel == MAX_WARNLEVEL)
1775 uInfo->flags |= USER_WARNED;
1776 snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES_2 : SSMSG_WARNING_2, spamserv_conf.network_rules);
1777 irc_notice(spamserv, user->numeric, reason);
1778 irc_privmsg(spamserv, user->numeric, reason);
1780 else if(uInfo->warnlevel > MAX_WARNLEVEL)
1782 if(CHECK_KILLED(uInfo))
1783 uInfo->flags |= USER_GLINE;
1785 uInfo->flags |= USER_KILL;
1795 case 1: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_SPAM, spamserv_conf.network_rules); break;
1796 case 2: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_FLOOD, spamserv_conf.network_rules); break;
1797 case 3: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_ADV, spamserv_conf.network_rules); break;
1798 default: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES_2 : SSMSG_WARNING_2, spamserv_conf.network_rules); break;
1801 if(CHECK_GLINE(uInfo))
1803 int size = strlen(user->hostname) + 3;
1804 char *mask = alloca(size);
1805 snprintf(mask, size, "*@%s", user->hostname);
1806 gline_add(spamserv->nick, mask, spamserv_conf.gline_duration, reason, now, now, 0, 1);
1807 spamserv_debug(SSMSG_DEBUG_GLINE, user->nick, user->hostname, channel->name);
1809 else if(CHECK_KILL(uInfo))
1811 DelUser(user, spamserv, 1, reason);
1812 spamserv_debug(SSMSG_DEBUG_KILL, user->nick, channel->name);
1814 else if(CHECK_LONG_TBAN(uInfo))
1816 spamserv_punish(channel, user, spamserv_conf.long_ban_duration, reason, 1);
1818 else if(CHECK_SHORT_TBAN(uInfo))
1820 spamserv_punish(channel, user, spamserv_conf.short_ban_duration, reason, 1);
1822 else if(CHECK_KICKBAN(uInfo))
1824 spamserv_punish(channel, user, 0, reason, 1);
1826 else if(CHECK_KICK(uInfo))
1828 spamserv_punish(channel, user, 0, reason, 0);
1833 spamserv_saxdb_read(struct dict *database)
1836 struct record_data *hir;
1837 struct chanNode *channel;
1838 struct chanInfo *cInfo;
1839 struct string_list *strlist;
1840 unsigned int flags,exceptlevel;
1844 for(it = dict_first(database); it; it = iter_next(it))
1846 hir = iter_data(it);
1848 if(hir->type != RECDB_OBJECT)
1850 log_module(SS_LOG, LOG_WARNING, "Unexpected rectype %d for %s.", hir->type, iter_key(it));
1854 channel = GetChannel(iter_key(it));
1855 strlist = database_get_data(hir->d.object, KEY_EXCEPTIONS, RECDB_STRING_LIST);
1857 str = database_get_data(hir->d.object, KEY_FLAGS, RECDB_QSTRING);
1858 flags = str ? atoi(str) : 0;
1860 info = database_get_data(hir->d.object, KEY_INFO, RECDB_QSTRING);
1861 str = database_get_data(hir->d.object, KEY_EXCEPTLEVEL, RECDB_QSTRING);
1862 exceptlevel = str ? atoi(str) : 400;
1864 str = database_get_data(hir->d.object, KEY_EXPIRY, RECDB_QSTRING);
1865 expiry = str ? strtoul(str, NULL, 0) : 0;
1869 if((cInfo = spamserv_register_channel(channel, strlist, flags, info)))
1871 /* if the channel is suspended and expiry = 0 it means: channel will
1872 never expire ! it does NOT mean, the channel is not suspended */
1873 if(CHECK_SUSPENDED(cInfo) && expiry && (expiry < now))
1875 cInfo->flags &= ~CHAN_SUSPENDED;
1876 spamserv_join_channel(cInfo->channel);
1878 else if(!CHECK_SUSPENDED(cInfo))
1879 spamserv_join_channel(cInfo->channel);
1881 cInfo->suspend_expiry = expiry;
1882 cInfo->exceptlevel=exceptlevel;
1886 log_module(SS_LOG, LOG_ERROR, "Couldn't register channel %s. Channel or info invalid.", iter_key(it));
1893 spamserv_saxdb_write(struct saxdb_context *ctx)
1897 for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
1899 struct chanInfo *cInfo = iter_data(it);
1901 saxdb_start_record(ctx, cInfo->channel->name, 1);
1903 if(cInfo->exceptions->used)
1904 saxdb_write_string_list(ctx, KEY_EXCEPTIONS, cInfo->exceptions);
1907 saxdb_write_int(ctx, KEY_FLAGS, cInfo->flags);
1909 saxdb_write_string(ctx, KEY_INFO, cInfo->info);
1910 saxdb_write_int(ctx, KEY_EXCEPTLEVEL, cInfo->exceptlevel);
1912 if(cInfo->suspend_expiry)
1913 saxdb_write_int(ctx, KEY_EXPIRY, cInfo->suspend_expiry);
1915 saxdb_end_record(ctx);
1921 spamserv_conf_read(void)
1926 if(!(conf_node = conf_get_data(SPAMSERV_CONF_NAME, RECDB_OBJECT)))
1928 log_module(SS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", SPAMSERV_CONF_NAME);
1932 str = database_get_data(conf_node, KEY_DEBUG_CHANNEL, RECDB_QSTRING);
1936 spamserv_conf.debug_channel = AddChannel(str, now, "+tinms", NULL);
1938 if(spamserv_conf.debug_channel)
1939 spamserv_join_channel(spamserv_conf.debug_channel);
1943 spamserv_conf.debug_channel = NULL;
1946 spamserv_conf.global_exceptions = database_get_data(conf_node, KEY_GLOBAL_EXCEPTIONS, RECDB_STRING_LIST);
1948 str = database_get_data(conf_node, KEY_NETWORK_RULES, RECDB_QSTRING);
1949 spamserv_conf.network_rules = str ? str : NULL;
1951 str = database_get_data(conf_node, KEY_TRIGGER, RECDB_QSTRING);
1952 spamserv_conf.trigger = str ? str[0] : 0;
1954 str = database_get_data(conf_node, KEY_SHORT_BAN_DURATION, RECDB_QSTRING);
1955 spamserv_conf.short_ban_duration = str ? ParseInterval(str) : ParseInterval("15m");
1957 str = database_get_data(conf_node, KEY_LONG_BAN_DURATION, RECDB_QSTRING);
1958 spamserv_conf.long_ban_duration = str ? ParseInterval(str) : ParseInterval("1h");
1960 str = database_get_data(conf_node, KEY_GLINE_DURATION, RECDB_QSTRING);
1961 spamserv_conf.gline_duration = str ? ParseInterval(str) : ParseInterval("1h");
1963 str = database_get_data(conf_node, KEY_EXCEPTION_MAX, RECDB_QSTRING);
1964 spamserv_conf.exception_max = str ? strtoul(str, NULL, 0) : 10;
1966 str = database_get_data(conf_node, KEY_EXCEPTION_MIN_LEN, RECDB_QSTRING);
1967 spamserv_conf.exception_min_len = str ? strtoul(str, NULL, 0) : 4;
1969 str = database_get_data(conf_node, KEY_EXCEPTION_MAX_LEN, RECDB_QSTRING);
1970 spamserv_conf.exception_max_len = str ? strtoul(str, NULL, 0) : 15;
1972 str = database_get_data(conf_node, KEY_ADV_CHAN_MUST_EXIST, RECDB_QSTRING);
1973 spamserv_conf.adv_chan_must_exist = str ? enabled_string(str) : 1;
1975 str = database_get_data(conf_node, KEY_STRIP_MIRC_CODES, RECDB_QSTRING);
1976 spamserv_conf.strip_mirc_codes = str ? enabled_string(str) : 0;
1978 str = database_get_data(conf_node, KEY_ALLOW_MOVE_MERGE, RECDB_QSTRING);
1979 spamserv_conf.allow_move_merge = str ? enabled_string(str) : 0;
1983 spamserv_db_cleanup(void)
1987 while((it = dict_first(registered_channels_dict)))
1989 spamserv_unregister_channel(iter_data(it));
1992 while((it = dict_first(killed_users_dict)))
1994 free(iter_data(it));
1997 dict_delete(registered_channels_dict);
1998 dict_delete(connected_users_dict);
1999 dict_delete(killed_users_dict);
2003 init_spamserv(const char *nick)
2008 const char *modes = conf_get_data("services/spamserv/modes", RECDB_QSTRING);
2009 spamserv = AddLocalUser(nick, nick, NULL, "Anti Spam Services", modes);
2010 spamserv_service = service_register(spamserv);
2011 service_register(spamserv)->trigger = spamserv_conf.trigger;
2013 conf_register_reload(spamserv_conf_read);
2015 SS_LOG = log_register_type("SpamServ", "file:spamserv.log");
2017 registered_channels_dict = dict_new();
2018 connected_users_dict = dict_new();
2019 killed_users_dict = dict_new();
2021 reg_new_user_func(spamserv_new_user_func);
2022 reg_del_user_func(spamserv_del_user_func);
2023 reg_nick_change_func(spamserv_nick_change_func);
2024 reg_join_func(spamserv_user_join);
2025 reg_part_func(spamserv_user_part);
2027 timeq_add(now + FLOOD_TIMEQ_FREQ, timeq_flood, NULL);
2028 timeq_add(now + JOINFLOOD_TIMEQ_FREQ, timeq_joinflood, NULL);
2029 timeq_add(now + ADV_TIMEQ_FREQ, timeq_adv, NULL);
2030 timeq_add(now + WARNLEVEL_TIMEQ_FREQ, timeq_warnlevel, NULL);
2031 timeq_add(now + KILL_TIMEQ_FREQ, timeq_kill, NULL);
2033 spamserv_module = module_register("SpamServ", SS_LOG, "spamserv.help", NULL);
2034 modcmd_register(spamserv_module, "REGISTER", cmd_register, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, "flags", "+acceptchan,+helping", NULL);
2035 modcmd_register(spamserv_module, "UNREGISTER", cmd_unregister, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, "flags", "+loghostmask", NULL);
2036 modcmd_register(spamserv_module, "ADDEXCEPTION", cmd_addexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2037 modcmd_register(spamserv_module, "DELEXCEPTION", cmd_delexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2038 modcmd_register(spamserv_module, "STATUS", cmd_status, 1, 0, NULL);
2039 modcmd_register(spamserv_module, "SET", cmd_set, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2040 modcmd_register(spamserv_module, "SET SPAMLIMIT", opt_spamlimit, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2041 modcmd_register(spamserv_module, "SET ADVREACTION", opt_advreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2042 modcmd_register(spamserv_module, "SET WARNREACTION", opt_warnreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2043 modcmd_register(spamserv_module, "SET ADVSCAN", opt_advscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2044 modcmd_register(spamserv_module, "SET SPAMSCAN", opt_spamscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2045 modcmd_register(spamserv_module, "SET FLOODSCAN", opt_floodscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2046 modcmd_register(spamserv_module, "SET JOINFLOODSCAN", opt_joinflood, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2047 modcmd_register(spamserv_module, "SET SCANCHANOPS", opt_scanops, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2048 modcmd_register(spamserv_module, "SET SCANVOICED", opt_scanvoiced, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2049 modcmd_register(spamserv_module, "SET EXCEPTLEVEL", opt_exceptlevel, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
2051 saxdb_register("SpamServ", spamserv_saxdb_read, spamserv_saxdb_write);
2052 reg_exit_func(spamserv_db_cleanup);
2053 message_register_table(msgtab);