#include "timeq.h"
#include "gline.h"
+#include <ctype.h>
+
#define SPAMSERV_CONF_NAME "services/spamserv"
#define KEY_EXCEPTIONS "exceptions"
#define KEY_FLAGS "flags"
#define KEY_INFO "info"
#define KEY_EXPIRY "expiry"
-
+#define KEY_TRUSTED_HOSTS "trusted"
+#define KEY_CHANNELS "channel"
+#define KEY_ISSUER "issuer"
+#define KEY_ISSUED "issued"
+#define KEY_TRUSTED_ACCOUNTS "trusted"
#define KEY_DEBUG_CHANNEL "debug_channel"
#define KEY_GLOBAL_EXCEPTIONS "global_exceptions"
#define KEY_GLOBAL_BADWORDS "global_badwords"
#define KEY_ADV_CHAN_MUST_EXIST "adv_chan_must_exist"
#define KEY_STRIP_MIRC_CODES "strip_mirc_codes"
#define KEY_ALLOW_MOVE_MERGE "allow_move_merge"
+#define KEY_CAPSMIN "capsmin"
+#define KEY_CAPSPERCENT "capspercent"
+#define KEY_EXCEPTLEVEL "exceptlevel"
+#define KEY_EXCEPTSPAMLEVEL "exceptspamlevel"
+#define KEY_EXCEPTFLOODLEVEL "exceptfloodlevel"
+#define KEY_EXCEPTADVLEVEL "exceptadvlevel"
+#define KEY_EXCEPTBADWORDLEVEL "exceptbadwordlevel"
+#define KEY_EXCEPTCAPSLEVEL "exceptcapslevel"
#define SPAMSERV_FUNC(NAME) MODCMD_FUNC(NAME)
#define SPAMSERV_SYNTAX() svccmd_send_help(user, spamserv, cmd)
dict_t connected_users_dict;
dict_t killed_users_dict;
+#define SSFUNC_ARGS user, channel, argc, argv, cmd
+
#define spamserv_notice(target, format...) send_message(target , spamserv , ## format)
#define spamserv_debug(format...) do { if(spamserv_conf.debug_channel) send_channel_notice(spamserv_conf.debug_channel , spamserv , ## format); } while(0)
#define ss_reply(format...) send_message(user , spamserv , ## format)
-#define SET_SUBCMDS_SIZE 13
+#define SET_SUBCMDS_SIZE 20
-const char *set_subcommands[SET_SUBCMDS_SIZE] = {"SPAMLIMIT", "BADREACTION", "ADVREACTION", "WARNREACTION", "ADVSCAN", "SPAMSCAN", "BADWORDSCAN", "CHANFLOODSCAN", "JOINFLOODSCAN", "SCANCHANOPS", "SCANHALFOPS", "SCANVOICED"};
+const char *set_subcommands[SET_SUBCMDS_SIZE] = {"EXCEPTLEVEL", "EXCEPTADVLEVEL", "EXCEPTBADWORDLEVEL", "EXCEPTCAPSLEVEL", "EXCEPTFLOODLEVEL", "EXCEPTSPAMLEVEL", "SPAMLIMIT", "BADREACTION", "CAPSREACTION", "ADVREACTION", "WARNREACTION", "ADVSCAN", "CAPSSCAN", "SPAMSCAN", "BADWORDSCAN", "CHANFLOODSCAN", "JOINFLOODSCAN", "CAPSMIN", "CAPSPERCENT"};
extern struct string_list *autojoin_channels;
static void spamserv_clear_spamNodes(struct chanNode *channel);
{ "SSMSG_WARNING_RULES_T", "%s is against the network rules. Read the network rules at %s" },
{ "SSMSG_WARNING_RULES_2_T", "You are violating the network rules. Read the network rules at %s" },
+ { "SSMSG_ALREADY_TRUSTED", "Account $b%s$b is already trusted." },
+ { "SSMSG_NOT_TRUSTED", "Account $b%s$b is not trusted." },
+ { "SSMSG_ADDED_TRUSTED", "Added %s to the global trusted-accounts list" },
+ { "SSMSG_ADDED_TRUSTED_CHANNEL", "Added %s to the trusted-accounts list for channel %s." },
+ { "SSMSG_REMOVED_TRUSTED", "Removed %s from the global trusted-accounts list." },
+ { "SSMSG_REMOVED_TRUSTED_CHANNEL", "Removed %s from channel %s trusted-account list." },
+ { "SSMSG_TRUSTED_LIST", "$bTrusted Accounts$b" },
+ { "SSMSG_TRUSTED_LIST_HEADER", "Account Added By Time" },
+ { "SSMSG_HOST_IS_TRUSTED", "%-15s %-10s set %s ago" },
+ { "SSMSG_TRUSTED_LIST_BAR", "----------------------------------------" },
+ { "SSMSG_TRUSTED_LIST_END", "---------End of Trusted Accounts--------" },
+ { "SSMSG_HOST_NOT_TRUSTED", "%s does not have a special trust." },
+
+ { "SSMSG_MUST_BE_HELPING", "You must have security override (helping mode) on to use this command." },
+
+ { "SSMSG_SET_CAPSMIN", "$bCapsMin$b %d - atleast this min caps and atleast CapsPercent of the total line." },
+ { "SSMSG_SET_CAPSPERCENT", "$bCapsPercent$b %d - atleast CapsPercent of the total line." },
+ { "SSMSG_SET_EXCEPTLEVEL" , "$bExceptLevel$b %d - level and above will be excepted from all checks." },
+ { "SSMSG_SET_EXCEPTADVLEVEL", "$bExceptAdvLevel$b %d - and above will be excepted from advertising checks." },
+ { "SSMSG_SET_EXCEPTBADWORDLEVEL", "$bExceptBadWordLevel$b %d - and above will be excepted from badword checks." },
+ { "SSMSG_SET_EXCEPTCAPSLEVEL" , "$bExceptCapsLevel$b %d - and above will be excepted from caps checks." },
+ { "SSMSG_SET_EXCEPTFLOODLEVEL", "$bExceptFloodLevel$b %d - and above will be excepted from flood checks." },
+ { "SSMSG_SET_EXCEPTSPAMLEVEL", "$bExceptSpamLevel$b %d - and above will be excepted from spam checks." },
+
{ NULL, NULL }
};
#define SSMSG_FLOOD "Flooding the channel/network"
#define SSMSG_ADV "Advertising"
#define SSMSG_BAD "Badwords"
+#define SSMSG_CAPS "Caps"
#define SSMSG_JOINFLOOD "Join flooding the channel"
#define SSMSG_WARNING "%s is against the network rules"
#define SSMSG_WARNING_RULES_2 "SSMSG_WARNING_RULES_2_T"
*/
+static dict_t spamserv_trusted_accounts;
+
static struct
{
struct chanNode *debug_channel;
unsigned int adv_chan_must_exist : 1;
unsigned int strip_mirc_codes : 1;
unsigned int allow_move_merge : 1;
+ unsigned long untrusted_max;
} spamserv_conf;
+struct trusted_account {
+ char *account;
+ struct string_list *channel;
+ char *issuer;
+ unsigned long limit;
+ time_t issued;
+};
+
/***********************************************/
/* Channel */
/***********************************************/
cInfo->exceptions = exceptions ? string_list_copy(exceptions) : alloc_string_list(1);
cInfo->badwords = badwords ? string_list_copy(badwords) : alloc_string_list(1);
cInfo->flags = flags;
+ cInfo->exceptlevel = 300;
+ cInfo->exceptspamlevel = 100;
+ cInfo->exceptadvlevel = 100;
+ cInfo->exceptbadwordlevel = 100;
+ cInfo->exceptcapslevel = 100;
+ cInfo->exceptfloodlevel = 100;
+ cInfo->capsmin = 10;
+ cInfo->capspercent = 25;
+
+ /* XXX Rewrite the flag system */
+ if (strlen(info) < 5)
+ strcat(info, "s");
+ if (strlen(info) < 6)
+ strcat(info, "s");
+
safestrncpy(cInfo->info, info, sizeof(cInfo->info));
cInfo->suspend_expiry = 0;
dict_insert(registered_channels_dict, strdup(cInfo->channel->name), cInfo);
if(!cInfo)
return;
- dict_remove(registered_channels_dict, cInfo->channel->name);
free_string_list(cInfo->exceptions);
free_string_list(cInfo->badwords);
+ dict_remove(registered_channels_dict, cInfo->channel->name);
free(cInfo);
}
uInfo->warnlevel = kNode ? kNode->warnlevel : 0;
uInfo->lastadv = 0;
uInfo->lastbad = 0;
+ uInfo->lastcaps = 0;
dict_insert(connected_users_dict, strdup(user->nick), uInfo);
if(kNode)
{
- dict_remove(killed_users_dict, irc_ntoa(&user->ip));
free(kNode);
+ dict_remove(killed_users_dict, irc_ntoa(&user->ip));
}
}
{
struct userInfo *uInfo = get_userInfo(old_nick);
- dict_remove(connected_users_dict, old_nick);
- dict_insert(connected_users_dict, strdup(user->nick), uInfo);
+ if(uInfo) {
+ dict_remove(connected_users_dict, old_nick);
+ dict_insert(connected_users_dict, strdup(user->nick), uInfo);
+ }
}
static int
{
dict_iterator_t it;
struct userInfo *uInfo;
- struct floodNode *fNode;
+ struct floodNode *fNode, *nextnode;
for(it = dict_first(connected_users_dict); it; it = iter_next(it))
{
if(!(fNode = uInfo->joinflood))
continue;
- for(; fNode; fNode = fNode->next)
+ for(; fNode; fNode = nextnode)
{
+ nextnode = fNode->next;
if(now - fNode->time > JOINFLOOD_EXPIRE)
{
if(!(--fNode->count))
timeq_add(now + BAD_TIMEQ_FREQ, timeq_bad, NULL);
}
+static void
+timeq_caps(UNUSED_ARG(void *data))
+{
+ dict_iterator_t it;
+ struct userInfo *uInfo;
+
+ for(it = dict_first(connected_users_dict); it; it = iter_next(it))
+ {
+ uInfo = iter_data(it);
+
+ if(uInfo->lastcaps && uInfo->lastcaps - now > CAPS_EXPIRE)
+ {
+ uInfo->lastcaps = 0;
+ uInfo->flags &= ~USER_CAPS_WARNED;
+ }
+ }
+
+ timeq_add(now + CAPS_TIMEQ_FREQ, timeq_caps, NULL);
+}
+
static void
timeq_adv(UNUSED_ARG(void *data))
{
dict_iterator_t it;
struct killNode *kNode;
- for(it = dict_first(killed_users_dict); it; it = iter_next(it))
- {
- kNode = iter_data(it);
-
- if(kNode->time - now > KILL_EXPIRE)
- free(kNode);
- }
+ while(1) {
+ for(it = dict_first(killed_users_dict); it; it = iter_next(it))
+ {
+ kNode = iter_data(it);
+
+ if(now - kNode->time > KILL_EXPIRE) {
+ dict_remove(killed_users_dict, iter_key(it));
+ /* have to restart the loop because next is
+ * now invalid. FIXME: how could we do this better? */
+ break; /* out of for() loop */
+ }
+ }
+ /* no more killed_users to delete, so stop while loop */
+ break; /* out of while() loop */
+ }
timeq_add(now + KILL_TIMEQ_FREQ, timeq_kill, NULL);
}
return subcmd->command->func(user, channel, argc - 1, argv + 1, subcmd);
}
+int ss_check_user_level(struct chanNode *channel, struct userNode *user, unsigned int minimum, int allow_override, int exempt_owner)
+{
+ struct userData *uData;
+ struct chanData *cData = channel->channel_info;
+ if(!minimum)
+ return 1;
+ uData = _GetChannelUser(cData, user->handle_info, allow_override, 0);
+ if(!uData)
+ return 0;
+ if(minimum <= uData->access)
+ return 1;
+ if((minimum > UL_OWNER) && (uData->access == UL_OWNER) && exempt_owner)
+ return 1;
+ return 0;
+}
+
+
+static int
+channel_except_level(struct userNode *user, struct chanNode *channel, int argc, char *argv[], struct svccmd *cmd)
+{
+ struct chanData *cData = channel->channel_info;
+ struct chanInfo *cInfo;
+ struct userData *uData;
+ unsigned short value;
+
+ cInfo = get_chanInfo(channel->name);
+
+ if(argc > 1)
+ {
+ if(!ss_check_user_level(channel, user, cInfo->exceptlevel, 1, 1))
+ {
+ reply("SSMSG_CANNOT_SET");
+ return 0;
+ }
+ value = user_level_from_name(argv[1], UL_OWNER+1);
+ if(!value && strcmp(argv[1], "0"))
+ {
+ reply("SSMSG_INVALID_ACCESS", argv[1]);
+ return 0;
+ }
+ uData = GetChannelUser(cData, user->handle_info);
+ if(!uData || ((uData->access < UL_OWNER) && (value > uData->access)))
+ {
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ cInfo->exceptlevel = value;
+ }
+ reply("SSMSG_SET_EXCEPTLEVEL", cInfo->exceptlevel);
+ return 0;
+}
+
+static int
+channel_except_adv_level(struct userNode *user, struct chanNode *channel, int argc, char *argv[], struct svccmd *cmd)
+{
+ struct chanData *cData = channel->channel_info;
+ struct chanInfo *cInfo;
+ struct userData *uData;
+ unsigned short value;
+
+ cInfo = get_chanInfo(channel->name);
+
+ if(argc > 1)
+ {
+ if(!ss_check_user_level(channel, user, cInfo->exceptadvlevel, 1, 1))
+ {
+ reply("SSMSG_CANNOT_SET");
+ return 0;
+ }
+ value = user_level_from_name(argv[1], UL_OWNER+1);
+ if(!value && strcmp(argv[1], "0"))
+ {
+ reply("SSMSG_INVALID_ACCESS", argv[1]);
+ return 0;
+ }
+ uData = GetChannelUser(cData, user->handle_info);
+ if(!uData || ((uData->access < UL_OWNER) && (value > uData->access)))
+ {
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ cInfo->exceptadvlevel = value;
+ }
+ reply("SSMSG_SET_EXCEPTADVLEVEL", cInfo->exceptadvlevel);
+ return 0;
+}
+
+static int
+channel_except_badword_level(struct userNode *user, struct chanNode *channel, int argc, char *argv[], struct svccmd *cmd)
+{
+ struct chanData *cData = channel->channel_info;
+ struct chanInfo *cInfo;
+ struct userData *uData;
+ unsigned short value;
+
+ cInfo = get_chanInfo(channel->name);
+
+ if(argc > 1)
+ {
+ if(!ss_check_user_level(channel, user, cInfo->exceptbadwordlevel, 1, 1))
+ {
+ reply("SSMSG_CANNOT_SET");
+ return 0;
+ }
+ value = user_level_from_name(argv[1], UL_OWNER+1);
+ if(!value && strcmp(argv[1], "0"))
+ {
+ reply("SSMSG_INVALID_ACCESS", argv[1]);
+ return 0;
+ }
+ uData = GetChannelUser(cData, user->handle_info);
+ if(!uData || ((uData->access < UL_OWNER) && (value > uData->access)))
+ {
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ cInfo->exceptbadwordlevel = value;
+ }
+ reply("SSMSG_SET_EXCEPTBADWORDLEVEL", cInfo->exceptbadwordlevel);
+ return 0;
+}
+
+static int
+channel_except_caps_level(struct userNode *user, struct chanNode *channel, int argc, char *argv[], struct svccmd *cmd)
+{
+ struct chanData *cData = channel->channel_info;
+ struct chanInfo *cInfo;
+ struct userData *uData;
+ unsigned short value;
+
+ cInfo = get_chanInfo(channel->name);
+
+ if(argc > 1)
+ {
+ if(!ss_check_user_level(channel, user, cInfo->exceptcapslevel, 1, 1))
+ {
+ reply("SSMSG_CANNOT_SET");
+ return 0;
+ }
+ value = user_level_from_name(argv[1], UL_OWNER+1);
+ if(!value && strcmp(argv[1], "0"))
+ {
+ reply("SSMSG_INVALID_ACCESS", argv[1]);
+ return 0;
+ }
+ uData = GetChannelUser(cData, user->handle_info);
+ if(!uData || ((uData->access < UL_OWNER) && (value > uData->access)))
+ {
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ cInfo->exceptcapslevel = value;
+ }
+ reply("SSMSG_SET_EXCEPTCAPSLEVEL", cInfo->exceptcapslevel);
+ return 0;
+}
+
+static int
+channel_except_flood_level(struct userNode *user, struct chanNode *channel, int argc, char *argv[], struct svccmd *cmd)
+{
+ struct chanData *cData = channel->channel_info;
+ struct chanInfo *cInfo;
+ struct userData *uData;
+ unsigned short value;
+
+ cInfo = get_chanInfo(channel->name);
+
+ if(argc > 1)
+ {
+ if(!ss_check_user_level(channel, user, cInfo->exceptfloodlevel, 1, 1))
+ {
+ reply("SSMSG_CANNOT_SET");
+ return 0;
+ }
+ value = user_level_from_name(argv[1], UL_OWNER+1);
+ if(!value && strcmp(argv[1], "0"))
+ {
+ reply("SSMSG_INVALID_ACCESS", argv[1]);
+ return 0;
+ }
+ uData = GetChannelUser(cData, user->handle_info);
+ if(!uData || ((uData->access < UL_OWNER) && (value > uData->access)))
+ {
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ cInfo->exceptfloodlevel = value;
+ }
+ reply("SSMSG_SET_EXCEPTFLOODLEVEL", cInfo->exceptfloodlevel);
+ return 0;
+}
+
+static int
+channel_except_spam_level(struct userNode *user, struct chanNode *channel, int argc, char *argv[], struct svccmd *cmd)
+{
+ struct chanData *cData = channel->channel_info;
+ struct chanInfo *cInfo;
+ struct userData *uData;
+ unsigned short value;
+
+ cInfo = get_chanInfo(channel->name);
+
+ if(argc > 1)
+ {
+ if(!ss_check_user_level(channel, user, cInfo->exceptspamlevel, 1, 1))
+ {
+ reply("SSMSG_CANNOT_SET");
+ return 0;
+ }
+ value = user_level_from_name(argv[1], UL_OWNER+1);
+ if(!value && strcmp(argv[1], "0"))
+ {
+ reply("SSMSG_INVALID_ACCESS", argv[1]);
+ return 0;
+ }
+ uData = GetChannelUser(cData, user->handle_info);
+ if(!uData || ((uData->access < UL_OWNER) && (value > uData->access)))
+ {
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ cInfo->exceptspamlevel = value;
+ }
+ reply("SSMSG_SET_EXCEPTSPAMLEVEL", cInfo->exceptspamlevel);
+ return 0;
+}
+
+static
+SPAMSERV_FUNC(opt_capsmin)
+{
+ struct chanInfo *cInfo;
+
+ cInfo = get_chanInfo(channel->name);
+
+ if(argc > 1)
+ {
+ char *mask = strdup(argv[1]);
+ unsigned int old = cInfo->capsmin;
+
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ cInfo->capsmin = mask ? strtoul(mask, NULL, 0) : 10;
+
+ if (cInfo->capsmin < 0) {
+ cInfo->capsmin = old;
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ } else {
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ }
+ reply("SSMSG_SET_CAPSMIN", cInfo->capsmin);
+ return 0;
+}
+
+static
+SPAMSERV_FUNC(opt_capspercent)
+{
+ struct chanInfo *cInfo;
+
+ cInfo = get_chanInfo(channel->name);
+
+ if(argc > 1)
+ {
+ char *mask = strdup(argv[1]);
+ unsigned int old = cInfo->capspercent;
+
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ cInfo->capspercent = mask ? strtoul(mask, NULL, 0) : 10;
+
+ if ((cInfo->capspercent < 0) || (cInfo->capspercent > 100)) {
+ cInfo->capspercent = old;
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ } else {
+ reply("SSMSG_BAD_SETLEVEL");
+ return 0;
+ }
+ }
+ reply("SSMSG_SET_CAPSPERCENT", cInfo->capspercent);
+ return 0;
+}
+
+static
+SPAMSERV_FUNC(opt_exceptlevel)
+{
+ return channel_except_level(SSFUNC_ARGS);
+}
+
+static
+SPAMSERV_FUNC(opt_exceptadvlevel)
+{
+ return channel_except_adv_level(SSFUNC_ARGS);
+}
+
+static
+SPAMSERV_FUNC(opt_exceptbadwordlevel)
+{
+ return channel_except_badword_level(SSFUNC_ARGS);
+}
+
+static
+SPAMSERV_FUNC(opt_exceptcapslevel)
+{
+ return channel_except_caps_level(SSFUNC_ARGS);
+}
+
+static
+SPAMSERV_FUNC(opt_exceptfloodlevel)
+{
+ return channel_except_flood_level(SSFUNC_ARGS);
+}
+
+static
+SPAMSERV_FUNC(opt_exceptspamlevel)
+{
+ return channel_except_spam_level(SSFUNC_ARGS);
+}
+
static
SPAMSERV_FUNC(opt_spamlimit)
{
MULTIPLE_OPTION("BadReaction ", "BadReaction", ci_BadReaction);
}
+static
+SPAMSERV_FUNC(opt_capsreaction)
+{
+ struct valueData values[] =
+ {
+ {"Kick on disallowed caps.", 'k', 0},
+ {"Kickban on disallowed caps.", 'b', 0},
+ {"Short timed ban on disallowed caps.", 's', 0},
+ {"Long timed ban on disallowed caps.", 'l', 0},
+ {"Kill on disallowed caps.", 'd', 1}
+ };
+
+ MULTIPLE_OPTION("CapsReaction ", "CapsReaction", ci_CapsReaction);
+}
+
static
SPAMSERV_FUNC(opt_advscan)
{
BINARY_OPTION("AdvScan ", CHAN_ADV_SCAN);
}
+static
+SPAMSERV_FUNC(opt_capsscan)
+{
+ BINARY_OPTION("CapsScan ", CHAN_CAPSSCAN);
+}
+
static
SPAMSERV_FUNC(opt_spamscan)
{
BINARY_OPTION("JoinFloodScan ", CHAN_JOINFLOOD);
}
-static
-SPAMSERV_FUNC(opt_scanops)
+static void
+spamserv_add_trusted_account(const char *account, struct string_list *channel, const char *issuer, time_t issued)
{
- BINARY_OPTION("ScanChanOps ", CHAN_SCAN_CHANOPS);
+ struct trusted_account *ta;
+ ta = calloc(1, sizeof(*ta));
+ if (!ta)
+ return;
+ ta->account = strdup(account);
+ ta->channel = channel ? string_list_copy(channel) : alloc_string_list(1);
+ ta->issuer = strdup(issuer);
+ ta->issued = issued;
+ dict_insert(spamserv_trusted_accounts, strdup(ta->account), ta);
}
-static
-SPAMSERV_FUNC(opt_scanhalfops)
+/*
+static void
+free_trusted_account(void *data)
{
- BINARY_OPTION("ScanHalfOps ", CHAN_SCAN_HALFOPS);
+ struct trusted_account *ta = data;
+ free(ta->account);
+ free_string_list(ta->channel);
+ free(ta->issuer);
+ free(ta);
}
+*/
-static
-SPAMSERV_FUNC(opt_scanvoiced)
+static SPAMSERV_FUNC(cmd_addtrust)
+{
+ unsigned int i;
+ struct userData *uData;
+ struct chanData *cData;
+ struct chanInfo *cInfo;
+ struct trusted_account *ta;
+ struct string_list *templist;
+ struct handle_info *hi;
+
+ if (!(channel = GetChannel(argv[2]))) {
+ ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+ return 0;
+ }
+
+ cInfo = get_chanInfo(channel->name);
+ cData = channel->channel_info;
+ uData = GetChannelUser(cData, user->handle_info);
+
+ if (!cInfo || !channel->channel_info) {
+ ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+ return 0;
+ }
+
+ if (CHECK_SUSPENDED(cInfo)) {
+ ss_reply("SSMSG_SUSPENDED", channel->name);
+ return 0;
+ }
+
+ if (!uData || (uData->access < UL_MANAGER)) {
+ ss_reply("SSMSG_NO_ACCESS");
+ return 0;
+ }
+
+ if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
+ return 0;
+ }
+
+ if ((ta = dict_find(spamserv_trusted_accounts, argv[1], NULL))) {
+ if (ta->channel->used && (argc > 1)) {
+ for (i=0; i < ta->channel->used; i++) {
+ if (!strcmp(ta->channel->list[i], argv[2])) {
+ ss_reply("SSMSG_ALREADY_TRUSTED", hi->handle);
+ return 0;
+ }
+ }
+ }
+
+ string_list_append(ta->channel, argv[2]);
+ ss_reply("SSMSG_ADDED_TRUSTED_CHANNEL", hi->handle, argv[2]);
+ return 1;
+ }
+
+ templist = alloc_string_list(sizeof(argv[2])+1);
+// templist = alloc_string_list(1);
+ string_list_append(templist, argv[2]);
+
+ spamserv_add_trusted_account(hi->handle, templist, user->handle_info->handle, now);
+ ss_reply("SSMSG_ADDED_TRUSTED_CHANNEL", hi->handle, argv[2]);
+ return 1;
+}
+
+static SPAMSERV_FUNC(cmd_oaddtrust)
+{
+ unsigned int i, global = 0;
+ struct chanInfo *cInfo;
+ struct chanData *cData;
+ struct trusted_account *ta;
+ struct string_list *templist;
+ struct handle_info *hi;
+
+ if (!strcmp(argv[2], "global"))
+ global = 1;
+
+ if (!(channel = GetChannel(argv[2])) && (global == 0)) {
+ ss_reply("SSMSG_NOT_REGISTERED", channel ? channel->name : (global ? "global" : ""));
+ return 0;
+ }
+
+ if (channel) {
+ cInfo = get_chanInfo(channel->name);
+ cData = channel->channel_info;
+
+ if (!cInfo || !channel->channel_info) {
+ ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+ return 0;
+ }
+ }
+
+ if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
+ return 0;
+ }
+
+ if ((ta = dict_find(spamserv_trusted_accounts, argv[1], NULL))) {
+ if (ta->channel->used && (argc > 1)) {
+ for (i=0; i < ta->channel->used; i++) {
+ if (!strcmp(ta->channel->list[i], argv[2])) {
+ ss_reply("SSMSG_ALREADY_TRUSTED", argv[1]);
+ return 0;
+ }
+ }
+ }
+
+ string_list_append(ta->channel, argv[2]);
+
+ if (global == 1)
+ ss_reply("SSMSG_ADDED_TRUSTED", argv[1]);
+ else
+ ss_reply("SSMSG_ADDED_TRUSTED_CHANNEL", argv[1], argv[2]);
+
+ return 1;
+ }
+
+ templist = alloc_string_list(sizeof(argv[2])+1);
+// templist = alloc_string_list(1);
+ string_list_append(templist, argv[2]);
+
+ spamserv_add_trusted_account(hi->handle, templist, user->handle_info->handle, now);
+
+ if (global == 1)
+ ss_reply("SSMSG_ADDED_TRUSTED", hi->handle);
+ else
+ ss_reply("SSMSG_ADDED_TRUSTED_CHANNEL", hi->handle, argv[2]);
+
+ return 1;
+}
+
+static SPAMSERV_FUNC(cmd_deltrust)
+{
+ unsigned int i;
+ int rem = 0;
+ struct trusted_account *ta;
+ struct userData *uData;
+ struct chanData *cData;
+ struct chanInfo *cInfo;
+ struct handle_info *hi;
+
+ if (!(channel = GetChannel(argv[2]))) {
+ ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+ return 0;
+ }
+
+ cInfo = get_chanInfo(channel->name);
+ cData = channel->channel_info;
+ uData = GetChannelUser(cData, user->handle_info);
+
+ if (!cInfo || !channel->channel_info) {
+ ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+ return 0;
+ }
+
+ if (CHECK_SUSPENDED(cInfo)) {
+ ss_reply("SSMSG_SUSPENDED", channel->name);
+ return 0;
+ }
+
+ if (!uData || (uData->access < UL_MANAGER)) {
+ ss_reply("SSMSG_NO_ACCESS");
+ return 0;
+ }
+
+ if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
+ return 0;
+ }
+
+ ta = dict_find(spamserv_trusted_accounts, hi->handle, NULL);
+
+ if (!ta) {
+ ss_reply("SSMSG_NOT_TRUSTED", argv[2]);
+ return 0;
+ }
+
+ if (argc > 1) {
+ if (ta->channel->used) {
+ for (i=0; i < ta->channel->used; i++) {
+ if (!strcmp(ta->channel->list[i], argv[2])) {
+ string_list_delete(ta->channel, i);
+ rem = 1;
+ }
+ }
+ }
+
+ if (rem == 1)
+ ss_reply("SSMSG_REMOVED_TRUSTED_CHANNEL", hi->handle, argv[2]);
+ else {
+ ss_reply("SSMSG_NOT_TRUSTED", hi->handle, argv[2]);
+ return 0;
+ }
+ } else {
+ dict_remove(spamserv_trusted_accounts, hi->handle);
+ ss_reply("SSMSG_REMOVED_TRUSTED", hi->handle);
+ }
+
+ return 1;
+}
+
+static SPAMSERV_FUNC(cmd_odeltrust)
{
- BINARY_OPTION("ScanVoiced ", CHAN_SCAN_VOICED);
+ unsigned int i;
+ int rem = 0, global = 0;
+ struct trusted_account *ta;
+ struct chanInfo *cInfo;
+ struct chanData *cData;
+ struct handle_info *hi;
+
+ if (!strcmp(argv[2], "global"))
+ global = 1;
+
+ if (!(channel = GetChannel(argv[2])) && (global == 0)) {
+ ss_reply("SSMSG_NOT_REGISTERED", channel ? channel->name : (global ? "global" : ""));
+ return 0;
+ }
+
+ if (channel) {
+ cInfo = get_chanInfo(channel->name);
+ cData = channel->channel_info;
+
+ if (!cInfo || !channel->channel_info) {
+ ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+ return 0;
+ }
+ }
+
+ if (!(hi = modcmd_get_handle_info(user, argv[1]))) {
+ return 0;
+ }
+
+ ta = dict_find(spamserv_trusted_accounts, hi->handle, NULL);
+
+ if (!ta) {
+ ss_reply("SSMSG_NOT_TRUSTED", argv[2]);
+ return 0;
+ }
+
+ if (argc > 1) {
+ if (ta->channel->used) {
+ for (i=0; i < ta->channel->used; i++) {
+ if (!strcmp(ta->channel->list[i], argv[2])) {
+ string_list_delete(ta->channel, i);
+ rem = 1;
+ }
+ }
+ }
+
+ if (rem == 1)
+ ss_reply("SSMSG_REMOVED_TRUSTED_CHANNEL", hi->handle, argv[2]);
+ else {
+ ss_reply("SSMSG_NOT_TRUSTED", argv[2]);
+ return 0;
+ }
+ } else {
+ dict_remove(spamserv_trusted_accounts, hi->handle);
+ ss_reply("SSMSG_REMOVED_TRUSTED", hi->handle);
+ }
+
+ return 1;
+}
+
+static SPAMSERV_FUNC(cmd_listtrust) {
+ dict_iterator_t it;
+ struct trusted_account *ta;
+ char issued[INTERVALLEN];
+ char *chan;
+ unsigned int i;
+
+ if (argc > 0) {
+ if (!strcmp(argv[1], "global")) {
+ if (!IsHelping(user)) {
+ reply("SSMSG_MUST_BE_HELPING");
+ return 0;
+ } else
+ chan = "global";
+ } else {
+ channel = GetChannel(argv[1]);
+ if (channel)
+ chan = strdup(channel->name);
+ else {
+ ss_reply("SSMSG_NOT_REGISTERED", argv[1]);
+ return 0;
+ }
+ }
+ } else {
+ reply("MSG_INVALID_CHANNEL");
+ return 0;
+ }
+
+ reply("SSMSG_TRUSTED_LIST");
+ reply("SSMSG_TRUSTED_LIST_BAR");
+ reply("SSMSG_TRUSTED_LIST_HEADER");
+ reply("SSMSG_TRUSTED_LIST_BAR");
+ for (it = dict_first(spamserv_trusted_accounts); it; it = iter_next(it)) {
+ ta = iter_data(it);
+
+ if (ta->channel->used) {
+ for (i=0; i < ta->channel->used; i++) {
+
+ if (!strcmp(ta->channel->list[i], chan)) {
+ if (ta->issued)
+ intervalString(issued, now - ta->issued, user->handle_info);
+
+ ss_reply("SSMSG_HOST_IS_TRUSTED", iter_key(it),
+ (ta->issuer ? ta->issuer : "<unknown>"),
+ (ta->issued ? issued : "some time"));
+
+ } else if (!strcmp(ta->channel->list[i], "global") && (!strcmp(chan, "global"))) {
+ if (ta->issued)
+ intervalString(issued, now - ta->issued, user->handle_info);
+
+ ss_reply("SSMSG_HOST_IS_TRUSTED", iter_key(it),
+ (ta->issuer ? ta->issuer : "<unknown>"),
+ (ta->issued ? issued : 0));
+ }
+ }
+ }
+ }
+ ss_reply("SSMSG_TRUSTED_LIST_END");
+ return 1;
}
static void
return 0;
}
+static int
+check_caps(struct chanInfo *cInfo, char *message)
+{
+ int c;
+
+ if ( (c = strlen(message)) >= cInfo->capsmin) {
+ int i = 0;
+ char *s = strdup(message);
+
+ do {
+ if (isupper(*s))
+ i++;
+ } while (*s++);
+
+ if (i >= cInfo->capsmin && i * 100 / c >= cInfo->capspercent)
+ return 1;
+ }
+
+ return 0;
+}
+
static int
check_badwords(struct chanInfo *cInfo, char *message)
{
struct userData *uData;
struct spamNode *sNode;
struct floodNode *fNode;
+ struct trusted_account *ta;
unsigned int violation = 0;
char reason[MAXLEN];
cData = channel->channel_info;
uData = GetChannelUser(cData, user->handle_info);
- if(!CHECK_CHANOPS(cInfo))
- {
- struct modeNode *mn = GetUserMode(channel, user);
- if (mn && (mn->modes & MODE_CHANOP))
- return;
+ if (user->handle_info) {
+ ta = dict_find(spamserv_trusted_accounts, user->handle_info->handle, NULL);
+ if (ta) {
+ unsigned int i = 0;
+ for (i=0; i < ta->channel->used; i++) {
+ if (!strcmp(ta->channel->list[i], channel->name))
+ return;
+
+ if (!strcmp(ta->channel->list[i], "global"))
+ return;
+ }
+ }
+ }
- /* Chan Ops covers all levels except peon and half op */
- if(uData && ((uData->access < UL_OP) || (uData->access < UL_MANAGER) ||
- (uData->access < UL_COOWNER) || (uData->access < UL_OWNER)))
- return;
- }
- if(!CHECK_HALFOPS(cInfo))
- {
- struct modeNode *mn = GetUserMode(channel, user);
- if (mn && (mn->modes & MODE_HALFOP))
- return;
+ if(uData && (uData->access >= cInfo->exceptlevel))
+ return;
- if(uData && (uData->access < UL_HALFOP))
- return;
- }
-
- if(!CHECK_VOICED(cInfo))
+ if(CHECK_CAPSSCAN(cInfo) && check_caps(cInfo, text))
{
- struct modeNode *mn = GetUserMode(channel, user);
- if (mn && ((mn->modes & MODE_VOICE) && !(mn->modes & MODE_CHANOP) && !(mn->modes & MODE_HALFOP)))
- return;
+ if(uData && (uData->access >= cInfo->exceptcapslevel))
+ return;
- if(uData && (uData->access < UL_PEON))
- return;
- }
+ if(CHECK_CAPS_WARNED(uInfo))
+ {
+ switch(cInfo->info[ci_CapsReaction])
+ {
+ case 'k': uInfo->flags |= USER_KICK; break;
+ case 'b': uInfo->flags |= USER_KICKBAN; break;
+ case 's': uInfo->flags |= USER_SHORT_TBAN; break;
+ case 'l': uInfo->flags |= USER_LONG_TBAN; break;
+ case 'd': uInfo->flags |= CHECK_KILLED(uInfo) ? USER_GLINE : USER_KILL; break;
+ }
+
+ uInfo->warnlevel += CAPS_WARNLEVEL;
+ violation = 5;
+ }
+ else
+ {
+ uInfo->flags |= USER_CAPS_WARNED;
+ uInfo->lastcaps = now;
+ uInfo->warnlevel += CAPS_WARNLEVEL;
+
+ if(uInfo->warnlevel < MAX_WARNLEVEL) {
+ if (spamserv_conf.network_rules)
+ spamserv_notice(user, "SSMSG_WARNING_RULES_T", SSMSG_CAPS, spamserv_conf.network_rules);
+ else
+ spamserv_notice(user, "SSMSG_WARNING_T", SSMSG_CAPS, spamserv_conf.network_rules);
+ }
+ }
+
+ }
to_lower(text);
if(CHECK_SPAM(cInfo))
{
+ if(uData && (uData->access >= cInfo->exceptspamlevel))
+ return;
+
if(!(sNode = uInfo->spam))
{
spamserv_create_spamNode(channel, uInfo, text);
if(CHECK_FLOOD(cInfo))
{
+ if(uData && (uData->access >= cInfo->exceptfloodlevel))
+ return;
+
if(!(fNode = uInfo->flood))
{
spamserv_create_floodNode(channel, user, &uInfo->flood);
if(fNode->channel == channel)
break;
- if(!fNode)
- {
+ if(!fNode) {
spamserv_create_floodNode(channel, user, &uInfo->flood);
- }
- else
- {
- if(((now - fNode->time) < FLOOD_EXPIRE))
- {
+ } else {
+ if(((now - fNode->time) < FLOOD_EXPIRE)) {
fNode->count++;
- if(fNode->count == FLOOD_MAX_LINES - 1)
- {
- uInfo->warnlevel += FLOOD_WARNLEVEL;
-
- if(uInfo->warnlevel < MAX_WARNLEVEL) {
- if (spamserv_conf.network_rules)
- spamserv_notice(user, "SSMSG_WARNING_RULES_T", SSMSG_FLOOD, spamserv_conf.network_rules);
- else
- spamserv_notice(user, "SSMSG_WARNING_T", SSMSG_FLOOD, spamserv_conf.network_rules);
- }
+ if(fNode->count == FLOOD_MAX_LINES - 1) {
+ uInfo->warnlevel += FLOOD_WARNLEVEL;
+
+ if(uInfo->warnlevel < MAX_WARNLEVEL) {
+ if (spamserv_conf.network_rules)
+ spamserv_notice(user, "SSMSG_WARNING_RULES_T", SSMSG_FLOOD, spamserv_conf.network_rules);
+ else
+ spamserv_notice(user, "SSMSG_WARNING_T", SSMSG_FLOOD, spamserv_conf.network_rules);
+ }
+ fNode->time = now;
}
- else if(fNode->count > FLOOD_MAX_LINES)
- {
- switch(cInfo->info[ci_WarnReaction])
- {
+ else if(fNode->count > FLOOD_MAX_LINES) {
+ switch(cInfo->info[ci_WarnReaction]) {
case 'k': uInfo->flags |= USER_KICK; break;
case 'b': uInfo->flags |= USER_KICKBAN; break;
case 's': uInfo->flags |= USER_SHORT_TBAN; break;
uInfo->warnlevel += FLOOD_WARNLEVEL;
violation = 2;
}
- }
-
- fNode->time = now;
+ } else {
+ fNode->time = now;
+ }
}
}
}
if(CHECK_BADWORDSCAN(cInfo) && check_badwords(cInfo, text))
{
+ if(uData && (uData->access >= cInfo->exceptbadwordlevel))
+ return;
+
if(CHECK_BAD_WARNED(uInfo))
{
switch(cInfo->info[ci_BadReaction])
if(CHECK_ADV(cInfo) && check_advertising(cInfo, text))
{
+ if(uData && (uData->access >= cInfo->exceptspamlevel))
+ return;
+
if(CHECK_ADV_WARNED(uInfo))
{
switch(cInfo->info[ci_AdvReaction])
else
uInfo->flags |= USER_KILL;
- violation = 5;
+ violation = 6;
}
if(!violation)
case 2: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_FLOOD, spamserv_conf.network_rules); break;
case 3: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_ADV, spamserv_conf.network_rules); break;
case 4: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_BAD, spamserv_conf.network_rules); break;
+ case 5: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES : SSMSG_WARNING, SSMSG_CAPS, spamserv_conf.network_rules); break;
default: snprintf(reason, sizeof(reason), spamserv_conf.network_rules ? SSMSG_WARNING_RULES_2 : SSMSG_WARNING_2, spamserv_conf.network_rules); break;
}
}
}
+static int
+trusted_account_read(const char *account, void *data, UNUSED_ARG(void *extra))
+{
+ struct record_data *rd = data;
+ const char *str, *issuer;
+ struct string_list *strlist;
+ time_t issued;
+
+ if (rd->type == RECDB_OBJECT) {
+ dict_t obj = GET_RECORD_OBJECT(rd);
+ /* new style structure */
+ strlist = database_get_data(obj, KEY_CHANNELS, RECDB_STRING_LIST);
+ issuer = database_get_data(obj, KEY_ISSUER, RECDB_QSTRING);
+ str = database_get_data(obj, KEY_ISSUED, RECDB_QSTRING);
+ issued = str ? ParseInterval(str) : 0;
+ } else
+ return 0;
+
+ spamserv_add_trusted_account(account, strlist, issuer, issued);
+ return 0;
+}
+
static int
spamserv_saxdb_read(struct dict *database)
{
struct chanInfo *cInfo;
struct string_list *strlist, *strlist2;
unsigned int flags;
+ unsigned int exceptlevel, exceptadvlevel, exceptbadwordlevel;
+ unsigned int exceptfloodlevel, exceptspamlevel, exceptcapslevel;
+ unsigned int capsmin, capspercent;
char *str, *info;
time_t expiry;
+ dict_t object;
+
+ if ((object = database_get_data(database, KEY_TRUSTED_HOSTS, RECDB_OBJECT)))
+ dict_foreach(object, trusted_account_read, spamserv_trusted_accounts);
for(it = dict_first(database); it; it = iter_next(it))
{
}
channel = GetChannel(iter_key(it));
+ if (!strcmp("trusted", iter_key(it)))
+ continue;
strlist = database_get_data(hir->d.object, KEY_EXCEPTIONS, RECDB_STRING_LIST);
strlist2 = database_get_data(hir->d.object, KEY_BADWORDS, RECDB_STRING_LIST);
str = database_get_data(hir->d.object, KEY_EXPIRY, RECDB_QSTRING);
expiry = str ? strtoul(str, NULL, 0) : 0;
+ str = database_get_data(hir->d.object, KEY_CAPSMIN, RECDB_QSTRING);
+ capsmin = str ? strtoul(str, NULL, 0) : 10;
+
+ str = database_get_data(hir->d.object, KEY_CAPSPERCENT, RECDB_QSTRING);
+ capspercent = str ? strtoul(str, NULL, 0) : 25;
+
+ str = database_get_data(hir->d.object, KEY_EXCEPTLEVEL, RECDB_QSTRING);
+ exceptlevel = str ? strtoul(str, NULL, 0) : UL_MANAGER;
+
+ str = database_get_data(hir->d.object, KEY_EXCEPTADVLEVEL, RECDB_QSTRING);
+ exceptadvlevel = str ? strtoul(str, NULL, 0) : UL_OP;
+
+ str = database_get_data(hir->d.object, KEY_EXCEPTBADWORDLEVEL, RECDB_QSTRING);
+ exceptbadwordlevel = str ? strtoul(str, NULL, 0) : UL_OP;
+
+ str = database_get_data(hir->d.object, KEY_EXCEPTCAPSLEVEL, RECDB_QSTRING);
+ exceptcapslevel = str ? strtoul(str, NULL, 0) : UL_OP;
+
+ str = database_get_data(hir->d.object, KEY_EXCEPTFLOODLEVEL, RECDB_QSTRING);
+ exceptfloodlevel = str ? strtoul(str, NULL, 0) : UL_OP;
+
+ str = database_get_data(hir->d.object, KEY_EXCEPTSPAMLEVEL, RECDB_QSTRING);
+ exceptspamlevel = str ? strtoul(str, NULL, 0) : UL_OP;
+
if(channel && info)
{
if((cInfo = spamserv_register_channel(channel, strlist, strlist2, flags, info)))
else if(!CHECK_SUSPENDED(cInfo))
spamserv_join_channel(cInfo->channel);
else
- cInfo->suspend_expiry = expiry;
+ cInfo->suspend_expiry = expiry;
+
+ cInfo->capsmin = capsmin;
+ cInfo->capspercent = capspercent;
+ cInfo->exceptlevel = exceptlevel;
+ cInfo->exceptadvlevel = exceptadvlevel;
+ cInfo->exceptbadwordlevel = exceptbadwordlevel;
+ cInfo->exceptcapslevel = exceptcapslevel;
+ cInfo->exceptfloodlevel = exceptfloodlevel;
+ cInfo->exceptspamlevel = exceptspamlevel;
}
}
else
{
dict_iterator_t it;
+ if (dict_size(spamserv_trusted_accounts)) {
+ saxdb_start_record(ctx, KEY_TRUSTED_ACCOUNTS, 1);
+ for (it = dict_first(spamserv_trusted_accounts); it; it = iter_next(it)) {
+ struct trusted_account *ta = iter_data(it);
+ saxdb_start_record(ctx, iter_key(it), 0);
+ if (ta->channel) saxdb_write_string_list(ctx, KEY_CHANNELS, ta->channel);
+ if (ta->issued) saxdb_write_int(ctx, KEY_ISSUED, ta->issued);
+ if (ta->issuer) saxdb_write_string(ctx, KEY_ISSUER, ta->issuer);
+ saxdb_end_record(ctx);
+ }
+ saxdb_end_record(ctx);
+ }
+
for(it = dict_first(registered_channels_dict); it; it = iter_next(it))
{
struct chanInfo *cInfo = iter_data(it);
saxdb_write_string_list(ctx, KEY_BADWORDS, cInfo->badwords);
if(cInfo->flags)
- saxdb_write_int(ctx, KEY_FLAGS, cInfo->flags);
+ saxdb_write_int(ctx, KEY_FLAGS, cInfo->flags);
+
+ if(cInfo->capsmin)
+ saxdb_write_int(ctx, KEY_CAPSMIN, cInfo->capsmin);
+
+ if(cInfo->capspercent)
+ saxdb_write_int(ctx, KEY_CAPSPERCENT, cInfo->capspercent);
+
+ if(cInfo->exceptlevel)
+ saxdb_write_int(ctx, KEY_EXCEPTLEVEL, cInfo->exceptlevel);
+
+ if(cInfo->exceptadvlevel)
+ saxdb_write_int(ctx, KEY_EXCEPTADVLEVEL, cInfo->exceptadvlevel);
+
+ if(cInfo->exceptbadwordlevel)
+ saxdb_write_int(ctx, KEY_EXCEPTBADWORDLEVEL, cInfo->exceptbadwordlevel);
+
+ if(cInfo->exceptcapslevel)
+ saxdb_write_int(ctx, KEY_EXCEPTCAPSLEVEL, cInfo->exceptcapslevel);
+
+ if(cInfo->exceptfloodlevel)
+ saxdb_write_int(ctx, KEY_EXCEPTFLOODLEVEL, cInfo->exceptfloodlevel);
+
+ if(cInfo->exceptspamlevel)
+ saxdb_write_int(ctx, KEY_EXCEPTSPAMLEVEL, cInfo->exceptspamlevel);
saxdb_write_string(ctx, KEY_INFO, cInfo->info);
spamserv_unregister_channel(iter_data(it));
}
- while((it = dict_first(killed_users_dict)))
+/* now handled automatically
+ * while((it = dict_first(killed_users_dict)))
{
free(iter_data(it));
}
+*/
dict_delete(registered_channels_dict);
dict_delete(connected_users_dict);
dict_delete(killed_users_dict);
+ dict_delete(spamserv_trusted_accounts);
}
void
SS_LOG = log_register_type("SpamServ", "file:spamserv.log");
+ /* auto-free the keys for these dicts,
+ * and auto-free the keys AND data for killed_users_dict.
+ * other data need free'd manually. */
registered_channels_dict = dict_new();
+ dict_set_free_keys(registered_channels_dict, free);
connected_users_dict = dict_new();
+ dict_set_free_keys(connected_users_dict, free);
killed_users_dict = dict_new();
+ dict_set_free_keys(killed_users_dict, free);
+ dict_set_free_data(killed_users_dict, free);
+ spamserv_trusted_accounts = dict_new();
+ dict_set_free_keys(spamserv_trusted_accounts, free);
+ dict_set_free_data(spamserv_trusted_accounts, free);
saxdb_register("SpamServ", spamserv_saxdb_read, spamserv_saxdb_write);
timeq_add(now + JOINFLOOD_TIMEQ_FREQ, timeq_joinflood, NULL);
timeq_add(now + ADV_TIMEQ_FREQ, timeq_adv, NULL);
timeq_add(now + BAD_TIMEQ_FREQ, timeq_bad, NULL);
+ timeq_add(now + CAPS_TIMEQ_FREQ, timeq_caps, NULL);
timeq_add(now + WARNLEVEL_TIMEQ_FREQ, timeq_warnlevel, NULL);
timeq_add(now + KILL_TIMEQ_FREQ, timeq_kill, NULL);
spamserv_module = module_register("SpamServ", SS_LOG, "spamserv.help", NULL);
+
+ modcmd_register(spamserv_module, "ADDTRUST", cmd_addtrust, 3, MODCMD_REQUIRE_AUTHED, "flags", "+acceptchan", NULL);
+ modcmd_register(spamserv_module, "DELTRUST", cmd_deltrust, 3, MODCMD_REQUIRE_AUTHED, "flags", "+acceptchan", NULL);
+ modcmd_register(spamserv_module, "OADDTRUST", cmd_oaddtrust, 3, MODCMD_REQUIRE_AUTHED, "flags", "+acceptchan,+helping", NULL);
+ modcmd_register(spamserv_module, "ODELTRUST", cmd_odeltrust, 3, MODCMD_REQUIRE_AUTHED, "flags", "+acceptchan,+helping", NULL);
+ modcmd_register(spamserv_module, "LISTTRUST", cmd_listtrust, 2, MODCMD_REQUIRE_AUTHED, NULL);
modcmd_register(spamserv_module, "REGISTER", cmd_register, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, "flags", "+acceptchan,+helping", NULL);
modcmd_register(spamserv_module, "UNREGISTER", cmd_unregister, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, "flags", "+loghostmask", NULL);
modcmd_register(spamserv_module, "ADDEXCEPTION", cmd_addexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "DELBADWORD", cmd_delbadword, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "STATUS", cmd_status, 1, 0, NULL);
modcmd_register(spamserv_module, "SET", cmd_set, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET EXCEPTLEVEL", opt_exceptlevel, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET EXCEPTADVLEVEL", opt_exceptadvlevel, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET EXCEPTBADWORDLEVEL", opt_exceptbadwordlevel, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET EXCEPTCAPSLEVEL", opt_exceptcapslevel, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET EXCEPTFLOODLEVEL", opt_exceptfloodlevel, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET EXCEPTSPAMLEVEL", opt_exceptspamlevel, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET SPAMLIMIT", opt_spamlimit, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET BADREACTION", opt_badreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET CAPSREACTION", opt_capsreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET ADVREACTION", opt_advreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET WARNREACTION", opt_warnreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET ADVSCAN", opt_advscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET CAPSSCAN", opt_capsscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET BADWORDSCAN", opt_badwordscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET SPAMSCAN", opt_spamscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET CHANFLOODSCAN", opt_chanfloodscan, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
modcmd_register(spamserv_module, "SET JOINFLOODSCAN", opt_joinflood, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
- modcmd_register(spamserv_module, "SET SCANCHANOPS", opt_scanops, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
- modcmd_register(spamserv_module, "SET SCANHALFOPS", opt_scanhalfops, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
- modcmd_register(spamserv_module, "SET SCANVOICED", opt_scanvoiced, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET CAPSMIN", opt_capsmin, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+ modcmd_register(spamserv_module, "SET CAPSPERCENT", opt_capspercent, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
spamserv_service->trigger = spamserv_conf.trigger;