*** VERSION 5.2.0 ***
[NeonServV5.git] / src / cmd_neonspam_set.c
1 /* cmd_neonspam_set.c - NeonServ v5.2
2  * Copyright (C) 2011  Philipp Kreil (pk910)
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 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 #include "cmd_neonspam.h"
19
20 typedef char* neonspam_cmd_set_function(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
21 static char* neonspam_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
22 static char* neonspam_cmd_setflags(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
23 static char* neonspam_cmd_setexcept(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
24 static char* neonspam_cmd_set_reaction(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
25 static char* neonspam_cmd_set_reaction_time(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
26 static char* neonspam_cmd_setpercent(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
27 static char* neonspam_cmd_setsensibility(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
28 static char* neonspam_cmd_set_spamlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
29 static char* neonspam_cmd_setscanops(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
30 static char* neonspam_cmd_setscanvoice(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
31 static char* neonspam_cmd_setscanexcept(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf);
32
33 static MYSQL_ROW neonspam_settings_row, neonspam_settings_defaults;
34 #define SPAMSERV_SETTINGS_QUERY "`channel_spam_reaction`, `channel_spam_reaction_duration`, `channel_flood_reaction`, `channel_flood_reaction_duration`, `channel_join_reaction`, `channel_join_reaction_duration`, `channel_botnet_bantime`, `channel_caps_reaction`, `channel_caps_reaction_duration`, `channel_digit_reaction`, `channel_digit_reaction_duration`"
35 #define SPAMSERV_SETTINGS_RESET "\
36 `channel_scanner` = NULL, \
37 `channel_spam_limit` = NULL, \
38 `channel_spam_reaction` = NULL, \
39 `channel_spam_reaction_duration` = NULL, \
40 `channel_spam_except` = NULL, \
41 `channel_flood_limit` = NULL, \
42 `channel_flood_time` = NULL, \
43 `channel_flood_reaction` = NULL, \
44 `channel_flood_reaction_duration` = NULL, \
45 `channel_flood_except` = NULL, \
46 `channel_join_limit` = NULL, \
47 `channel_join_time` = NULL, \
48 `channel_join_reaction` = NULL, \
49 `channel_join_reaction_duration` = NULL, \
50 `channel_join_except` = NULL, \
51 `channel_botnet_bantime` = NULL, \
52 `channel_botnet_except` = NULL, \
53 `channel_caps_percent` = NULL, \
54 `channel_caps_reaction` = NULL, \
55 `channel_caps_reaction_duration` = NULL, \
56 `channel_caps_except` = NULL,\
57 `channel_digit_percent` = NULL, \
58 `channel_digit_reaction` = NULL, \
59 `channel_digit_reaction_duration` = NULL, \
60 `channel_digit_except` = NULL "
61
62 #define SET_HELP       0x0001
63 #define SET_BOOL       0x0002
64 #define SET_OPT        0x0004
65
66 #define SET_SCANOPS    0x0010
67 #define SET_SCANVOICE  0x0020
68 #define SET_SCANEXCEPT 0x0040
69
70 #define SET_OPT_MAX    0xff00
71 #define SET_OPT_SHIFT  8
72
73 static const struct {
74     unsigned int if_flag;
75     unsigned int indent;
76     const char *setting;
77     void *function;
78     int intparam;
79     char *charparam;
80     int flags;
81 } neonspam_settings[] = {
82     {0,                                                0,  "Trigger",           neonspam_cmd_set_trigger,         0,                              NULL,                             SET_HELP},
83     
84     {0,                                                0,  "SpamScan",          neonspam_cmd_setflags,            SPAMSETTINGS_SPAMSCAN,          NULL,                             SET_BOOL},
85     {SPAMSETTINGS_SPAMSCAN,                            2,  "SpamLimit",         neonspam_cmd_set_spamlimit,       0,                              NULL,                             SET_HELP},
86     {SPAMSETTINGS_SPAMSCAN | SPAMSETTINGS_SETTIMEBAN,  2,  "SpamReaction",      neonspam_cmd_set_reaction,        0,                              "channel_spam_reaction",          SET_OPT | (3 << SET_OPT_SHIFT)},
87     {SPAMSETTINGS_SPAMSCAN | SPAMSETTINGS_ISTIMEBAN,   4,  "SpamBanDuration",   neonspam_cmd_set_reaction_time,   1,                              "channel_spam_reaction_duration", 0},
88     {SPAMSETTINGS_SPAMSCAN,                            2,  "SpamScanChanOps",   neonspam_cmd_setflags,            SPAMSETTINGS_SPAMSCAN_OPS,      NULL,                             SET_BOOL | SET_SCANOPS},
89     {SPAMSETTINGS_SPAMSCAN,                            2,  "SpamScanVoiced",    neonspam_cmd_setflags,            SPAMSETTINGS_SPAMSCAN_VOICE,    NULL,                             SET_BOOL | SET_SCANVOICE},
90     {SPAMSETTINGS_SPAMSCAN,                            2,  "SpamScanExcept",    neonspam_cmd_setexcept,           SPAMSETTINGS_SPAMEXCINDEX,      "channel_spam_except",            SET_HELP | SET_SCANEXCEPT},
91     
92     {0,                                                0,  "FloodScan",         neonspam_cmd_setflags,            SPAMSETTINGS_FLOODSCAN,         NULL,                             SET_BOOL},
93     {SPAMSETTINGS_FLOODSCAN,                           2,  "FloodSensibility",  neonspam_cmd_setsensibility,      SPAMSETTINGS_FLOODSENINDEX,     "channel_flood_",                 SET_HELP},
94     {SPAMSETTINGS_FLOODSCAN | SPAMSETTINGS_SETTIMEBAN, 2,  "FloodReaction",     neonspam_cmd_set_reaction,        2,                              "channel_flood_reaction",         SET_OPT | (3 << SET_OPT_SHIFT)},
95     {SPAMSETTINGS_FLOODSCAN | SPAMSETTINGS_ISTIMEBAN,  4,  "FloodBanDuration",  neonspam_cmd_set_reaction_time,   3,                              "channel_flood_reaction_duration",0},
96     {SPAMSETTINGS_FLOODSCAN,                           2,  "FloodScanChanOps",  neonspam_cmd_setflags,            SPAMSETTINGS_FLOODSCAN_OPS,     NULL,                             SET_BOOL | SET_SCANOPS},
97     {SPAMSETTINGS_FLOODSCAN,                           2,  "FloodScanVoiced",   neonspam_cmd_setflags,            SPAMSETTINGS_FLOODSCAN_VOICE,   NULL,                             SET_BOOL | SET_SCANVOICE},
98     {SPAMSETTINGS_FLOODSCAN,                           2,  "FloodScanExcept",   neonspam_cmd_setexcept,           SPAMSETTINGS_FLOODEXCINDEX,     "channel_flood_except",           SET_HELP | SET_SCANEXCEPT},
99     
100     {0,                                                0,  "JoinScan",          neonspam_cmd_setflags,            SPAMSETTINGS_JOINSCAN,          NULL,                             SET_BOOL},
101     {SPAMSETTINGS_JOINSCAN,                            2,  "JoinSensibility",   neonspam_cmd_setsensibility,      SPAMSETTINGS_JOINSENINDEX,      "channel_join_",                  SET_HELP},
102     {SPAMSETTINGS_JOINSCAN | SPAMSETTINGS_SETTIMEBAN,  2,  "JoinReaction",      neonspam_cmd_set_reaction,        4,                              "channel_join_reaction",          SET_OPT | (3 << SET_OPT_SHIFT)},
103     {SPAMSETTINGS_JOINSCAN | SPAMSETTINGS_ISTIMEBAN,   4,  "JoinBanDuration",   neonspam_cmd_set_reaction_time,   5,                              "channel_join_reaction_duration", 0},
104     {SPAMSETTINGS_JOINSCAN,                            2,  "JoinScanChanOps",   neonspam_cmd_setflags,            SPAMSETTINGS_JOINSCAN_OPS,      NULL,                             SET_BOOL | SET_SCANOPS},
105     {SPAMSETTINGS_JOINSCAN,                            2,  "JoinScanVoiced",    neonspam_cmd_setflags,            SPAMSETTINGS_JOINSCAN_VOICE,    NULL,                             SET_BOOL | SET_SCANVOICE},
106     {SPAMSETTINGS_JOINSCAN,                            2,  "JoinScanExcept",    neonspam_cmd_setexcept,           SPAMSETTINGS_JOINEXCINDEX,      "channel_join_except",            SET_HELP | SET_SCANEXCEPT},
107     
108     {0,                                                0,  "BotNetScan",        neonspam_cmd_setflags,            SPAMSETTINGS_BOTNETSCAN,        NULL,                             SET_BOOL},
109     {SPAMSETTINGS_BOTNETSCAN,                          4,  "BotNetBanDuration", neonspam_cmd_set_reaction_time,   6,                              "channel_botnet_bantime",         0},
110     {SPAMSETTINGS_BOTNETSCAN,                          2,  "BotNetScanChanOps", neonspam_cmd_setflags,            SPAMSETTINGS_BOTNETSCAN_OPS,    NULL,                             SET_BOOL | SET_SCANOPS},
111     {SPAMSETTINGS_BOTNETSCAN,                          2,  "BotNetScanVoiced",  neonspam_cmd_setflags,            SPAMSETTINGS_BOTNETSCAN_VOICE,  NULL,                             SET_BOOL | SET_SCANVOICE},
112     //{SPAMSETTINGS_BOTNETSCAN,                          2,  "BotNetScanExcept",  neonspam_cmd_setexcept,           SPAMSETTINGS_BOTNETEXCINDEX,    "channel_botnet_except",          SET_HELP},
113     
114     {0,                                                0,  "CapsScan",          neonspam_cmd_setflags,            SPAMSETTINGS_CAPSSCAN,          NULL,                             SET_BOOL},
115     {SPAMSETTINGS_CAPSSCAN,                            2,  "CapsPercent",       neonspam_cmd_setpercent,          SPAMSETTINGS_CAPSPERCENTINDEX,  "channel_caps_percent",           SET_HELP},
116     {SPAMSETTINGS_CAPSSCAN | SPAMSETTINGS_SETTIMEBAN,  2,  "CapsReaction",      neonspam_cmd_set_reaction,        7,                              "channel_caps_reaction",          SET_OPT | (3 << SET_OPT_SHIFT)},
117     {SPAMSETTINGS_CAPSSCAN | SPAMSETTINGS_ISTIMEBAN,   4,  "CapsBanDuration",   neonspam_cmd_set_reaction_time,   8,                              "channel_caps_reaction_duration", 0},
118     {SPAMSETTINGS_CAPSSCAN,                            2,  "CapsScanChanOps",   neonspam_cmd_setflags,            SPAMSETTINGS_CAPSSCAN_OPS,      NULL,                             SET_BOOL | SET_SCANOPS},
119     {SPAMSETTINGS_CAPSSCAN,                            2,  "CapsScanVoiced",    neonspam_cmd_setflags,            SPAMSETTINGS_CAPSSCAN_VOICE,    NULL,                             SET_BOOL | SET_SCANVOICE},
120     {SPAMSETTINGS_CAPSSCAN,                            2,  "CapsScanExcept",    neonspam_cmd_setexcept,           SPAMSETTINGS_CAPSEXCINDEX,      "channel_caps_except",            SET_HELP | SET_SCANEXCEPT},
121     
122     {0,                                                0,  "DigitScan",         neonspam_cmd_setflags,            SPAMSETTINGS_DIGITSCAN,         NULL,                             SET_BOOL},
123     {SPAMSETTINGS_DIGITSCAN,                           2,  "DigitPercent",      neonspam_cmd_setpercent,          SPAMSETTINGS_DIGITPERCENTINDEX, "channel_digit_percent",          SET_HELP},
124     {SPAMSETTINGS_DIGITSCAN | SPAMSETTINGS_SETTIMEBAN, 2,  "DigitReaction",     neonspam_cmd_set_reaction,        9,                              "channel_digit_reaction",         SET_OPT | (3 << SET_OPT_SHIFT)},
125     {SPAMSETTINGS_DIGITSCAN | SPAMSETTINGS_ISTIMEBAN,  4,  "DigitBanDuration",  neonspam_cmd_set_reaction_time,   10,                             "channel_digit_reaction_duration", 0},
126     {SPAMSETTINGS_DIGITSCAN,                           2,  "DigitScanChanOps",  neonspam_cmd_setflags,            SPAMSETTINGS_DIGITSCAN_OPS,     NULL,                             SET_BOOL | SET_SCANOPS},
127     {SPAMSETTINGS_DIGITSCAN,                           2,  "DigitScanVoiced",   neonspam_cmd_setflags,            SPAMSETTINGS_DIGITSCAN_VOICE,   NULL,                             SET_BOOL | SET_SCANVOICE},
128     {SPAMSETTINGS_DIGITSCAN,                           2,  "DigitScanExcept",   neonspam_cmd_setexcept,           SPAMSETTINGS_DIGITEXCINDEX,     "channel_digit_except",           SET_HELP | SET_SCANEXCEPT},
129     
130     {0,                                                0,  "GlobalScanChanOps", neonspam_cmd_setscanops,          0,                              NULL,                             SET_BOOL},
131     {0,                                                0,  "GlobalScanVoice",   neonspam_cmd_setscanvoice,        0,                              NULL,                             SET_BOOL},
132     {0,                                                0,  "GlobalScanExcept",  neonspam_cmd_setscanexcept,       0,                              NULL,                             SET_HELP},
133     
134     {0, 0, NULL, NULL, 0, NULL, 0}
135 };
136
137 #define MAX_QUERY_LEN 1024
138 CMD_BIND(neonspam_cmd_set) {
139     int i, j;
140     if(argc && !strcmp(argv[0], "defaults")) {
141         //reset channel settings
142         int uaccess = getChannelAccess(user, chan, 0);
143         if(uaccess < 500) {
144             if(isGodMode(user)) {
145                 event->flags |= CMDFLAG_OPLOG;
146             } else {
147                 reply(getTextBot(), user, "NS_SET_DEFAULTS_OWNER", chan->name);
148                 return;
149             }
150         }
151         int seed = 0;
152         char *tmp;
153         static char defaultskey[16];
154         for(tmp = user->auth; *tmp; tmp++)
155             seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
156         for(tmp = chan->name; *tmp; tmp++)
157             seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
158         sprintf(defaultskey, "%08x", seed);
159         if(argc > 1 && !strcmp(argv[1], defaultskey)) {
160             printf_mysql_query("UPDATE `channels` SET " SPAMSERV_SETTINGS_RESET " WHERE `channel_id` = '%d'", chan->channel_id);
161             reply(getTextBot(), user, "NS_SET_DEFAULTS_DONE", chan->name);
162             logEvent(event);
163         } else {
164             reply(getTextBot(), user, "NS_SET_DEFAULTS_CODE", chan->name, defaultskey);
165         }
166     } else if(argc && strcmp(argv[0], "help")) {
167         //find the correct command
168         i = 0;
169         j = 0;
170         char *args = (argc > 1 ? merge_argv(argv, 1, argc) : NULL);
171         neonspam_settings_row = NULL;
172         neonspam_settings_defaults = NULL;
173         while(neonspam_settings[i].setting) {
174             if(!stricmp(neonspam_settings[i].setting, argv[0])) {
175                 //setting found
176                 char valueBuf[MAXLEN], nameBuf[MAXLEN];
177                 char *value, *optimized_value, *option_help;
178                 neonspam_cmd_set_function *func = neonspam_settings[i].function;
179                 value = func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, args, valueBuf);
180                 if(value) {
181                     optimized_value = value;
182                     if(neonspam_settings[i].flags & SET_BOOL) {
183                         if(!strcmp(value, "0"))
184                             optimized_value = get_language_string(user, "NS_SET_OFF");
185                         else if(!strcmp(value, "1"))
186                             optimized_value = get_language_string(user, "NS_SET_ON");
187                     }
188                     if(neonspam_settings[i].flags & SET_OPT) {
189                         sprintf(nameBuf, "SS_SET_OPTION_%s_%s", neonspam_settings[i].setting, value);
190                         option_help = get_language_string(user, nameBuf);
191                     } else
192                         option_help = NULL;
193                     reply(getTextBot(), user, "\002%s\002 %s%s%s", neonspam_settings[i].setting, optimized_value, (option_help ? " - " : ""), (option_help ? option_help : ""));
194                     if(neonspam_settings[i].flags & SET_OPT) {
195                         int maxoption = (neonspam_settings[i].flags & SET_OPT_MAX) >> SET_OPT_SHIFT;
196                         for(j = 0; j < maxoption; j++) {
197                             sprintf(nameBuf, "SS_SET_OPTION_%s_%d", neonspam_settings[i].setting, j);
198                             
199                             reply(getTextBot(), user, " \002%d\002 - %s", j, option_help);
200                         }
201                     }
202                     if((neonspam_settings[i].flags & SET_HELP) && argc && !strcmp(argv[0], "help")) {
203                         char *tmp;
204                         sprintf(nameBuf, "SS_SET_HELP_%s", neonspam_settings[i].setting);
205                         tmp = get_language_string(user, nameBuf);
206                         if(tmp) {
207                             reply(getTextBot(), user, "  %s", tmp);
208                         }
209                     }
210                 }
211                 j = 1;
212                 break;
213             }
214             i++;
215         }
216         if(j == 0) {
217             //unknown setting
218             reply(getTextBot(), user, "NS_SET_UNKNOWN_SETTING", argv[0]);
219         }
220     } else {
221         char valueBuf[MAXLEN], nameBuf[MAXLEN];
222         char *value;
223         int namePos, boolflag = 0;
224         MYSQL_RES *res, *defaults_res;
225         struct Table *table;
226         char *content[2];
227         i = 0;
228         while(neonspam_settings[i].setting)
229             i++;
230         table = table_init(2, i, 0);
231         table_set_bold(table, 0, 1);
232         printf_mysql_query("SELECT " SPAMSERV_SETTINGS_QUERY " FROM `channels` WHERE `channel_name` = 'defaults'");
233         defaults_res = mysql_use();
234         neonspam_settings_defaults = mysql_fetch_row(defaults_res);
235         printf_mysql_query("SELECT " SPAMSERV_SETTINGS_QUERY " FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
236         res = mysql_use();
237         neonspam_settings_row = mysql_fetch_row(res);
238         i = -1;
239         reply(getTextBot(), user, "NS_SET_HEADER", chan->name);
240         while(neonspam_settings[++i].setting) {
241             if((chan->spam_settings->flags & (neonspam_settings[i].if_flag & SPAMSETTINGS_FLAGS)) != (neonspam_settings[i].if_flag & SPAMSETTINGS_FLAGS))
242                 continue;
243             if((neonspam_settings[i].if_flag & SPAMSETTINGS_ISTIMEBAN) && !boolflag)
244                 continue;
245             neonspam_cmd_set_function *func = neonspam_settings[i].function;
246             value = func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, NULL, valueBuf);
247             if(neonspam_settings[i].if_flag & SPAMSETTINGS_SETTIMEBAN)
248                 boolflag = !strcmp(value, "2");
249             //TODO: append option or help info
250             strcpy(valueBuf, value);
251             if(neonspam_settings[i].flags & SET_BOOL) {
252                 if(!strcmp(value, "0"))
253                     strcpy(valueBuf, get_language_string(user, "NS_SET_OFF"));
254                 else if(!strcmp(value, "1"))
255                     strcpy(valueBuf, get_language_string(user, "NS_SET_ON"));
256             }
257             if(neonspam_settings[i].flags & SET_OPT) {
258                 char *tmp;
259                 sprintf(nameBuf, "SS_SET_OPTION_%s_%s", neonspam_settings[i].setting, value);
260                 tmp = get_language_string(user, nameBuf);
261                 if(tmp) {
262                     sprintf(valueBuf + strlen(valueBuf), " - %s", tmp);
263                 }
264             }
265             if((neonspam_settings[i].flags & SET_HELP) && argc && !strcmp(argv[0], "help")) {
266                 char *tmp;
267                 sprintf(nameBuf, "SS_SET_HELP_%s", neonspam_settings[i].setting);
268                 tmp = get_language_string(user, nameBuf);
269                 if(tmp) {
270                     sprintf(valueBuf + strlen(valueBuf), " - %s", tmp);
271                 }
272             }
273             namePos = 0;
274             for(j = 0; j < neonspam_settings[i].indent; j++) {
275                 nameBuf[namePos++] = ' ';
276             }
277             sprintf(nameBuf + namePos, "%s", neonspam_settings[i].setting);
278             content[0] = nameBuf;
279             content[1] = valueBuf;
280             table_add(table, content);
281         }
282         char **table_lines = table_end(table);
283         for(i = 0; i < table->entrys; i++) {
284             reply(getTextBot(), user, table_lines[i]);
285         }
286         table_free(table);
287     }
288 }
289
290 static char* neonspam_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf) {
291     char *trigger;
292     //get current trigger
293     MYSQL_RES *res;
294     MYSQL_ROW row;
295     printf_mysql_query("SELECT `trigger` FROM `bot_channels` WHERE `chanid` = '%d' AND `botid` = '%d'", chan->channel_id, client->clientid);
296     res = mysql_use();
297     row = mysql_fetch_row(res);
298     trigger = row[0];
299     if(argument) {
300         int uaccess = getChannelAccess(user, chan, 0);
301         if(uaccess < 500) {
302             if(isGodMode(user)) {
303                 event->flags |= CMDFLAG_OPLOG;
304             } else {
305                 reply(getTextBot(), user, "NS_SET_TRIGGER_OWNER", chan->name);
306                 return NULL;
307             }
308         }
309         if(strlen(argument) > 15)
310             argument[15] = '\0';
311         printf_mysql_query("UPDATE `bot_channels` SET `trigger` = '%s' WHERE `chanid` = '%d' AND `botid` = '%d'", escape_string(argument), chan->channel_id, client->clientid);
312         trigger = argument;
313         changeChannelTrigger(client->botid, chan, trigger);
314         logEvent(event);
315     }
316     return trigger;
317 }
318
319 static char* neonspam_cmd_setflags(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int flag, char *charparam, char *argument, char *retBuf) {
320     char *value = ((chan->spam_settings->flags & flag) ? "1" : "0");
321     if(argument) {
322         //binary argument...
323         if(!strcmp(argument, "0") || !stricmp(argument, "off") || !stricmp(argument, get_language_string(user, "NS_SET_OFF"))) {
324             chan->spam_settings->flags &= ~flag;
325         } else if(!strcmp(argument, "1") || !stricmp(argument, "on") || !stricmp(argument, get_language_string(user, "NS_SET_ON"))) {
326             chan->spam_settings->flags |= flag;
327         } else {
328             reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
329             return NULL;
330         }
331         char str_flags[50];
332         convertNeonSpamSettingsToString(chan->spam_settings->flags, str_flags);
333         printf_mysql_query("UPDATE `channels` SET `channel_scanner` = '%s' WHERE `channel_id` = '%d' ", str_flags, chan->channel_id);
334         value = argument;
335     }
336     return value;
337 }
338
339 static char* neonspam_cmd_setexcept(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int exceptlvl_index, char *field, char *argument, char *retBuf) {
340     unsigned int value = chan->spam_settings->exceptlevel[exceptlvl_index];
341     if(argument) {
342         //numeric argument... (access)
343         int caccess = atoi(argument);
344         if(caccess < 0 || caccess > 501) {
345             reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
346             return NULL;
347         }
348         int uaccess = getChannelAccess(user, chan, 0);
349         if(uaccess == 500) uaccess++;
350         if(value > uaccess) {
351             if(isGodMode(user)) {
352                 event->flags |= CMDFLAG_OPLOG;
353             } else {
354                 reply(getTextBot(), user, "NS_SET_CANNOT_SET");
355                 return NULL;
356             }
357         }
358         if(caccess > uaccess) {
359             if(isGodMode(user)) {
360                 event->flags |= CMDFLAG_OPLOG;
361             } else {
362                 reply(getTextBot(), user, "NS_SET_BADLEVEL");
363                 return NULL;
364             }
365         }
366         value = caccess;
367         chan->spam_settings->exceptlevel[exceptlvl_index] = value;
368         printf_mysql_query("UPDATE `channels` SET `%s` = '%u' WHERE `channel_id` = '%d' ", field, value, chan->channel_id);
369     }
370     sprintf(retBuf, "%u", value);
371     return retBuf;
372 }
373
374 static char* neonspam_cmd_set_reaction(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int mysqlindex, char *mysqlfield, char *argument, char *retBuf) {
375     if(argument) {
376         /* valid options:
377         * 0/kick - kick
378         * 1/kickban - kickban
379         * 2/ban - timed ban
380         */
381         if(!strcmp(argument, "0") || !stricmp(argument, "kick")) {
382             argument = "0";
383         } else if(!strcmp(argument, "1") || !stricmp(argument, "kickban")) {
384             argument = "1";
385         } else if(!strcmp(argument, "2") || !stricmp(argument, "ban")) {
386             argument = "2";
387         } else {
388             reply(getTextBot(), user, "NS_SET_INVALID_OPTION_STR", argument);
389             return NULL;
390         }
391         printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d' ", mysqlfield, argument, chan->channel_id);
392         return argument;
393     } else {
394         if(neonspam_settings_row) {
395             return (neonspam_settings_row[mysqlindex] ? neonspam_settings_row[mysqlindex] : neonspam_settings_defaults[mysqlindex]);
396         } else {
397             MYSQL_RES *res;
398             MYSQL_ROW row;
399             printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", mysqlfield, chan->channel_id);
400             res = mysql_use();
401             row = mysql_fetch_row(res);
402             return row[0];
403         }
404     }
405 }
406
407 static char* neonspam_cmd_set_reaction_time(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int mysqlindex, char *mysqlfield, char *argument, char *retBuf) {
408     int duration;
409     if(argument) {
410         duration = strToTime(user, argument);
411         if(duration < 30) {
412             reply(getTextBot(), user, "NS_TIMEBAN_DURATION_TOO_SHORT", 30);
413             return NULL;
414         }
415         printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d' ", mysqlfield, argument, chan->channel_id);
416     } else {
417         if(neonspam_settings_row) {
418             duration = atoi(neonspam_settings_row[mysqlindex] ? neonspam_settings_row[mysqlindex] : neonspam_settings_defaults[mysqlindex]);
419         } else {
420             MYSQL_RES *res;
421             MYSQL_ROW row;
422             printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", mysqlfield, chan->channel_id);
423             res = mysql_use();
424             row = mysql_fetch_row(res);
425             duration = atoi(row[0]);
426         }
427     }
428     timeToStr(user, duration, 3, retBuf);
429     return retBuf;
430 }
431
432 static char* neonspam_cmd_setpercent(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int percent_index, char *mysqlfield, char *argument, char *retBuf) {
433     unsigned int value = chan->spam_settings->percent[percent_index];
434     if(argument) {
435         //numeric argument... (access)
436         value = atoi(argument);
437         if(value < 0 || value > 100) {
438             //invalid percent value
439             reply(getTextBot(), user, "SS_SET_PERCENT", value);
440             return NULL;
441         }
442         chan->spam_settings->percent[percent_index] = value;
443         printf_mysql_query("UPDATE `channels` SET `%s` = '%u' WHERE `channel_id` = '%d' ", mysqlfield, value, chan->channel_id);
444     }
445     sprintf(retBuf, "%u", value);
446     return retBuf;
447 }
448
449 static char* neonspam_cmd_setsensibility(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int sensibility_index, char *mysqlfield, char *argument, char *retBuf) {
450     if(argument) {
451         //change value
452         char *delimiter = strstr(argument, ":");
453         if(!delimiter) {
454             //invalid format
455             reply(getTextBot(), user, "SS_SET_SENSIBILITY", argument);
456             return NULL;
457         }
458         *delimiter = '\0';
459         delimiter++;
460         int amount = atoi(argument);
461         int timep = atoi(delimiter);
462         if(amount > MAX_FLOOD_AMOUNT || amount < MIN_FLOOD_AMOUNT) {
463             //invalid amount
464             reply(getTextBot(), user, "SS_SET_SENSIBILITY_AMOUNT", amount, MIN_FLOOD_AMOUNT, MAX_FLOOD_AMOUNT);
465             return NULL;
466         }
467         if(timep > MAX_FLOOD_TIME || timep < 0) {
468             //invalid time period
469             reply(getTextBot(), user, "SS_SET_SENSIBILITY_TIME", timep, 0, MAX_FLOOD_TIME);
470             return NULL;
471         }
472         char amountfield[50], timefield[50];
473         sprintf(amountfield, "%s%s", mysqlfield, "limit");
474         sprintf(timefield, "%s%s", mysqlfield, "time");
475         printf_mysql_query("UPDATE `channels` SET `%s` = '%d', `%s` = '%d' WHERE `channel_id` = '%d' ", amountfield, amount, timefield, timep, chan->channel_id);
476         sprintf(retBuf, "%d:%d", amount, timep);
477         chan->spam_settings->sensibility_amount[sensibility_index] = amount;
478         chan->spam_settings->sensibility_time[sensibility_index] = timep;
479     } else {
480         sprintf(retBuf, "%d:%d", chan->spam_settings->sensibility_amount[sensibility_index], chan->spam_settings->sensibility_time[sensibility_index]);
481     }
482     return retBuf;
483 }
484
485 static char* neonspam_cmd_set_spamlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int intparam, char *charparam, char *argument, char *retBuf) {
486     if(argument) {
487         //change value
488         int amount = atoi(argument);
489         if(amount > 10 || amount < 2) {
490             //invalid amount
491             reply(getTextBot(), user, "SS_SET_SPAMLIMIT", amount, 2, 10);
492             return NULL;
493         }
494         printf_mysql_query("UPDATE `channels` SET `channel_maxrepeat` = '%d' WHERE `channel_id` = '%d' ", amount, chan->channel_id);
495         sprintf(retBuf, "%d", amount);
496         chan->spam_settings->spam_amount = amount;
497     } else
498         sprintf(retBuf, "%d", chan->spam_settings->spam_amount);
499     return retBuf;
500 }
501
502 static char* neonspam_cmd_setscanops(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int flag, char *charparam, char *argument, char *retBuf) {
503     int i = 0;
504     int value = -1;
505     int identical = 1;
506     while(neonspam_settings[i].setting) {
507         if(neonspam_settings[i].flags & SET_SCANOPS) {
508             if(value == -1)
509                 value = ((chan->spam_settings->flags & neonspam_settings[i].intparam) ? 1 : 0);
510             else {
511                 if(((chan->spam_settings->flags & neonspam_settings[i].intparam) ? 1 : 0) != value) {
512                     identical = 0;
513                     break;
514                 }
515             }
516         }
517         i++;
518     }
519     if(argument) {
520         //binary argument...
521         if(!strcmp(argument, "0") || !stricmp(argument, "off") || !stricmp(argument, get_language_string(user, "NS_SET_OFF"))) {
522             value = 0;
523         } else if(!strcmp(argument, "1") || !stricmp(argument, "on") || !stricmp(argument, get_language_string(user, "NS_SET_ON"))) {
524             value = 1;
525         } else {
526             reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
527             return NULL;
528         }
529         i = 0;
530         char valueBuf[MAXLEN];
531         while(neonspam_settings[i].setting) {
532             if(neonspam_settings[i].flags & SET_SCANOPS) {
533                 neonspam_cmd_set_function *func = neonspam_settings[i].function;
534                 func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, (value ? "1" : "0"), valueBuf);
535             }
536             i++;
537         }
538         identical = 1;
539     }
540     if(identical && value)
541         return "1";
542     if(identical && !value)
543         return "0";
544     return "?";
545 }
546
547 static char* neonspam_cmd_setscanvoice(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int flag, char *charparam, char *argument, char *retBuf) {
548     int i = 0;
549     int value = -1;
550     int identical = 1;
551     while(neonspam_settings[i].setting) {
552         if(neonspam_settings[i].flags & SET_SCANVOICE) {
553             if(value == -1)
554                 value = ((chan->spam_settings->flags & neonspam_settings[i].intparam) ? 1 : 0);
555             else {
556                 if(((chan->spam_settings->flags & neonspam_settings[i].intparam) ? 1 : 0) != value) {
557                     identical = 0;
558                     break;
559                 }
560             }
561         }
562         i++;
563     }
564     if(argument) {
565         //binary argument...
566         if(!strcmp(argument, "0") || !stricmp(argument, "off") || !stricmp(argument, get_language_string(user, "NS_SET_OFF"))) {
567             value = 0;
568         } else if(!strcmp(argument, "1") || !stricmp(argument, "on") || !stricmp(argument, get_language_string(user, "NS_SET_ON"))) {
569             value = 1;
570         } else {
571             reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
572             return NULL;
573         }
574         i = 0;
575         char valueBuf[MAXLEN];
576         while(neonspam_settings[i].setting) {
577             if(neonspam_settings[i].flags & SET_SCANVOICE) {
578                 neonspam_cmd_set_function *func = neonspam_settings[i].function;
579                 func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, (value ? "1" : "0"), valueBuf);
580             }
581             i++;
582         }
583         identical = 1;
584     }
585     if(identical && value)
586         return "1";
587     if(identical && !value)
588         return "0";
589     return "?";
590 }
591
592 static char* neonspam_cmd_setscanexcept(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int flag, char *charparam, char *argument, char *retBuf) {
593     int i = 0;
594     int value = -1;
595     int identical = 1;
596     while(neonspam_settings[i].setting) {
597         if(neonspam_settings[i].flags & SET_SCANEXCEPT) {
598             if(value == -1)
599                 value = chan->spam_settings->exceptlevel[neonspam_settings[i].intparam];
600             else {
601                 if(chan->spam_settings->exceptlevel[neonspam_settings[i].intparam] != value) {
602                     identical = 0;
603                     break;
604                 }
605             }
606         }
607         i++;
608     }
609     if(argument) {
610         //numeric argument... (access)
611         int caccess = atoi(argument);
612         if(caccess < 0 || caccess > 501) {
613             reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
614             return NULL;
615         }
616         int uaccess = getChannelAccess(user, chan, 0);
617         if(uaccess == 500) uaccess++;
618         if(identical && value > uaccess) {
619             if(isGodMode(user)) {
620                 event->flags |= CMDFLAG_OPLOG;
621             } else {
622                 reply(getTextBot(), user, "NS_SET_CANNOT_SET");
623                 return NULL;
624             }
625         }
626         if(caccess > uaccess) {
627             if(isGodMode(user)) {
628                 event->flags |= CMDFLAG_OPLOG;
629             } else {
630                 reply(getTextBot(), user, "NS_SET_BADLEVEL");
631                 return NULL;
632             }
633         }
634         i = 0;
635         char valueBuf[MAXLEN];
636         sprintf(retBuf, "%d", caccess);
637         while(neonspam_settings[i].setting) {
638             if(neonspam_settings[i].flags & SET_SCANEXCEPT) {
639                 neonspam_cmd_set_function *func = neonspam_settings[i].function;
640                 func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, retBuf, valueBuf);
641             }
642             i++;
643         }
644         identical = 1;
645         value = caccess;
646     }
647     if(identical) {
648         sprintf(retBuf, "%d", value);
649         return retBuf;
650     }
651     return "?";
652 }
653
654 #undef MAX_QUERY_LEN