*** VERSION 5.4.0 ***
[NeonServV5.git] / src / modules / NeonSpam.mod / cmd_neonspam_set.c
1 /* cmd_neonspam_set.c - NeonServ v5.4
2  * Copyright (C) 2011-2012  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     loadNeonSpamSettings(chan);
141     if(argc && !strcmp(argv[0], "defaults")) {
142         //reset channel settings
143         int uaccess = getChannelAccess(user, chan);
144         if(uaccess < 500) {
145             if(isGodMode(user)) {
146                 event->flags |= CMDFLAG_OPLOG;
147             } else {
148                 reply(getTextBot(), user, "NS_SET_DEFAULTS_OWNER", chan->name);
149                 return;
150             }
151         }
152         int seed = 0;
153         char *tmp;
154         static char defaultskey[16];
155         for(tmp = user->auth; *tmp; tmp++)
156             seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
157         for(tmp = chan->name; *tmp; tmp++)
158             seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
159         sprintf(defaultskey, "%08x", seed);
160         if(argc > 1 && !strcmp(argv[1], defaultskey)) {
161             printf_mysql_query("UPDATE `channels` SET " SPAMSERV_SETTINGS_RESET " WHERE `channel_id` = '%d'", chan->channel_id);
162             reply(getTextBot(), user, "NS_SET_DEFAULTS_DONE", chan->name);
163             logEvent(event);
164         } else {
165             reply(getTextBot(), user, "NS_SET_DEFAULTS_CODE", chan->name, defaultskey);
166         }
167     } else if(argc && strcmp(argv[0], "help")) {
168         //find the correct command
169         i = 0;
170         j = 0;
171         char *args = (argc > 1 ? merge_argv(argv, 1, argc) : NULL);
172         neonspam_settings_row = NULL;
173         neonspam_settings_defaults = NULL;
174         while(neonspam_settings[i].setting) {
175             if(!stricmp(neonspam_settings[i].setting, argv[0])) {
176                 //setting found
177                 char valueBuf[MAXLEN], nameBuf[MAXLEN];
178                 char *value, *optimized_value, *option_help;
179                 neonspam_cmd_set_function *func = neonspam_settings[i].function;
180                 value = func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, args, valueBuf);
181                 if(value) {
182                     optimized_value = value;
183                     if(neonspam_settings[i].flags & SET_BOOL) {
184                         if(!strcmp(value, "0"))
185                             optimized_value = get_language_string(user, "NS_SET_OFF");
186                         else if(!strcmp(value, "1"))
187                             optimized_value = get_language_string(user, "NS_SET_ON");
188                     }
189                     if(neonspam_settings[i].flags & SET_OPT) {
190                         sprintf(nameBuf, "SS_SET_OPTION_%s_%s", neonspam_settings[i].setting, value);
191                         option_help = get_language_string(user, nameBuf);
192                     } else
193                         option_help = NULL;
194                     reply(getTextBot(), user, "\002%s\002 %s%s%s", neonspam_settings[i].setting, optimized_value, (option_help ? " - " : ""), (option_help ? option_help : ""));
195                     if(neonspam_settings[i].flags & SET_OPT) {
196                         int maxoption = (neonspam_settings[i].flags & SET_OPT_MAX) >> SET_OPT_SHIFT;
197                         for(j = 0; j < maxoption; j++) {
198                             sprintf(nameBuf, "SS_SET_OPTION_%s_%d", neonspam_settings[i].setting, j);
199                             
200                             reply(getTextBot(), user, " \002%d\002 - %s", j, option_help);
201                         }
202                     }
203                     if((neonspam_settings[i].flags & SET_HELP) && argc && !strcmp(argv[0], "help")) {
204                         char *tmp;
205                         sprintf(nameBuf, "SS_SET_HELP_%s", neonspam_settings[i].setting);
206                         tmp = get_language_string(user, nameBuf);
207                         if(tmp) {
208                             reply(getTextBot(), user, "  %s", tmp);
209                         }
210                     }
211                 }
212                 j = 1;
213                 break;
214             }
215             i++;
216         }
217         if(j == 0) {
218             //unknown setting
219             reply(getTextBot(), user, "NS_SET_UNKNOWN_SETTING", argv[0]);
220         }
221     } else {
222         char valueBuf[MAXLEN], nameBuf[MAXLEN];
223         char *value;
224         int namePos, boolflag = 0;
225         MYSQL_RES *res, *defaults_res;
226         struct Table *table;
227         char *content[2];
228         i = 0;
229         while(neonspam_settings[i].setting)
230             i++;
231         table = table_init(2, i, 0);
232         table_set_bold(table, 0, 1);
233         printf_mysql_query("SELECT " SPAMSERV_SETTINGS_QUERY " FROM `channels` WHERE `channel_name` = 'defaults'");
234         defaults_res = mysql_use();
235         neonspam_settings_defaults = mysql_fetch_row(defaults_res);
236         printf_mysql_query("SELECT " SPAMSERV_SETTINGS_QUERY " FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
237         res = mysql_use();
238         neonspam_settings_row = mysql_fetch_row(res);
239         i = -1;
240         reply(getTextBot(), user, "NS_SET_HEADER", chan->name);
241         while(neonspam_settings[++i].setting) {
242             if((chan->spam_settings->flags & (neonspam_settings[i].if_flag & SPAMSETTINGS_FLAGS)) != (neonspam_settings[i].if_flag & SPAMSETTINGS_FLAGS))
243                 continue;
244             if((neonspam_settings[i].if_flag & SPAMSETTINGS_ISTIMEBAN) && !boolflag)
245                 continue;
246             neonspam_cmd_set_function *func = neonspam_settings[i].function;
247             value = func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, NULL, valueBuf);
248             if(neonspam_settings[i].if_flag & SPAMSETTINGS_SETTIMEBAN)
249                 boolflag = !strcmp(value, "2");
250             //TODO: append option or help info
251             strcpy(valueBuf, value);
252             if(neonspam_settings[i].flags & SET_BOOL) {
253                 if(!strcmp(value, "0"))
254                     strcpy(valueBuf, get_language_string(user, "NS_SET_OFF"));
255                 else if(!strcmp(value, "1"))
256                     strcpy(valueBuf, get_language_string(user, "NS_SET_ON"));
257             }
258             if(neonspam_settings[i].flags & SET_OPT) {
259                 char *tmp;
260                 sprintf(nameBuf, "SS_SET_OPTION_%s_%s", neonspam_settings[i].setting, value);
261                 tmp = get_language_string(user, nameBuf);
262                 if(tmp) {
263                     sprintf(valueBuf + strlen(valueBuf), " - %s", tmp);
264                 }
265             }
266             if((neonspam_settings[i].flags & SET_HELP) && argc && !strcmp(argv[0], "help")) {
267                 char *tmp;
268                 sprintf(nameBuf, "SS_SET_HELP_%s", neonspam_settings[i].setting);
269                 tmp = get_language_string(user, nameBuf);
270                 if(tmp) {
271                     sprintf(valueBuf + strlen(valueBuf), " - %s", tmp);
272                 }
273             }
274             namePos = 0;
275             for(j = 0; j < neonspam_settings[i].indent; j++) {
276                 nameBuf[namePos++] = ' ';
277             }
278             sprintf(nameBuf + namePos, "%s", neonspam_settings[i].setting);
279             content[0] = nameBuf;
280             content[1] = valueBuf;
281             table_add(table, content);
282         }
283         char **table_lines = table_end(table);
284         for(i = 0; i < table->entrys; i++) {
285             reply(getTextBot(), user, table_lines[i]);
286         }
287         table_free(table);
288     }
289 }
290
291 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) {
292     char *trigger;
293     //get current trigger
294     MYSQL_RES *res;
295     MYSQL_ROW row;
296     printf_mysql_query("SELECT `trigger`, `defaulttrigger` FROM `bot_channels` LEFT JOIN `bots` ON `botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botid` = '%d'", chan->channel_id, client->clientid);
297     res = mysql_use();
298     row = mysql_fetch_row(res);
299     trigger = (row[0] ? row[0] : row[1]);
300     if(argument) {
301         int uaccess = getChannelAccess(user, chan);
302         if(uaccess < 500) {
303             if(isGodMode(user)) {
304                 event->flags |= CMDFLAG_OPLOG;
305             } else {
306                 reply(getTextBot(), user, "NS_SET_TRIGGER_OWNER", chan->name);
307                 return NULL;
308             }
309         }
310         if(strlen(argument) > 15)
311             argument[15] = '\0';
312         printf_mysql_query("UPDATE `bot_channels` SET `trigger` = '%s' WHERE `chanid` = '%d' AND `botid` = '%d'", escape_string(argument), chan->channel_id, client->clientid);
313         trigger = argument;
314         changeChannelTrigger(client->botid, chan, trigger);
315         logEvent(event);
316     }
317     return trigger;
318 }
319
320 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) {
321     char *value = ((chan->spam_settings->flags & flag) ? "1" : "0");
322     if(argument) {
323         //binary argument...
324         if(!strcmp(argument, "0") || !stricmp(argument, "off") || !stricmp(argument, get_language_string(user, "NS_SET_OFF"))) {
325             chan->spam_settings->flags &= ~flag;
326         } else if(!strcmp(argument, "1") || !stricmp(argument, "on") || !stricmp(argument, get_language_string(user, "NS_SET_ON"))) {
327             chan->spam_settings->flags |= flag;
328         } else {
329             reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
330             return NULL;
331         }
332         char str_flags[50];
333         convertNeonSpamSettingsToString(chan->spam_settings->flags, str_flags);
334         printf_mysql_query("UPDATE `channels` SET `channel_scanner` = '%s' WHERE `channel_id` = '%d' ", str_flags, chan->channel_id);
335         value = argument;
336     }
337     return value;
338 }
339
340 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) {
341     unsigned int value = chan->spam_settings->exceptlevel[exceptlvl_index];
342     if(argument) {
343         //numeric argument... (access)
344         int caccess = atoi(argument);
345         if(caccess < 0 || caccess > 501) {
346             reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
347             return NULL;
348         }
349         int uaccess = getChannelAccess(user, chan);
350         if(uaccess == 500) uaccess++;
351         if(value > uaccess) {
352             if(isGodMode(user)) {
353                 event->flags |= CMDFLAG_OPLOG;
354             } else {
355                 reply(getTextBot(), user, "NS_SET_CANNOT_SET");
356                 return NULL;
357             }
358         }
359         if(caccess > uaccess) {
360             if(isGodMode(user)) {
361                 event->flags |= CMDFLAG_OPLOG;
362             } else {
363                 reply(getTextBot(), user, "NS_SET_BADLEVEL");
364                 return NULL;
365             }
366         }
367         value = caccess;
368         chan->spam_settings->exceptlevel[exceptlvl_index] = value;
369         printf_mysql_query("UPDATE `channels` SET `%s` = '%u' WHERE `channel_id` = '%d' ", field, value, chan->channel_id);
370     }
371     sprintf(retBuf, "%u", value);
372     return retBuf;
373 }
374
375 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) {
376     if(argument) {
377         /* valid options:
378         * 0/kick - kick
379         * 1/kickban - kickban
380         * 2/ban - timed ban
381         */
382         if(!strcmp(argument, "0") || !stricmp(argument, "kick")) {
383             argument = "0";
384         } else if(!strcmp(argument, "1") || !stricmp(argument, "kickban")) {
385             argument = "1";
386         } else if(!strcmp(argument, "2") || !stricmp(argument, "ban")) {
387             argument = "2";
388         } else {
389             reply(getTextBot(), user, "NS_SET_INVALID_OPTION_STR", argument);
390             return NULL;
391         }
392         printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d' ", mysqlfield, argument, chan->channel_id);
393         return argument;
394     } else {
395         if(neonspam_settings_row) {
396             return (neonspam_settings_row[mysqlindex] ? neonspam_settings_row[mysqlindex] : neonspam_settings_defaults[mysqlindex]);
397         } else {
398             MYSQL_RES *res;
399             MYSQL_ROW row;
400             printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", mysqlfield, chan->channel_id);
401             res = mysql_use();
402             row = mysql_fetch_row(res);
403             return row[0];
404         }
405     }
406 }
407
408 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) {
409     int duration;
410     if(argument) {
411         duration = strToTime(user, argument);
412         if(duration < 30) {
413             reply(getTextBot(), user, "NS_TIMEBAN_DURATION_TOO_SHORT", 30);
414             return NULL;
415         }
416         printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d' ", mysqlfield, argument, chan->channel_id);
417     } else {
418         if(neonspam_settings_row) {
419             duration = atoi(neonspam_settings_row[mysqlindex] ? neonspam_settings_row[mysqlindex] : neonspam_settings_defaults[mysqlindex]);
420         } else {
421             MYSQL_RES *res;
422             MYSQL_ROW row;
423             printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", mysqlfield, chan->channel_id);
424             res = mysql_use();
425             row = mysql_fetch_row(res);
426             duration = atoi(row[0]);
427         }
428     }
429     timeToStr(user, duration, 3, retBuf);
430     return retBuf;
431 }
432
433 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) {
434     unsigned int value = chan->spam_settings->percent[percent_index];
435     if(argument) {
436         //numeric argument... (access)
437         value = atoi(argument);
438         if(value < 0 || value > 100) {
439             //invalid percent value
440             reply(getTextBot(), user, "SS_SET_PERCENT", value);
441             return NULL;
442         }
443         chan->spam_settings->percent[percent_index] = value;
444         printf_mysql_query("UPDATE `channels` SET `%s` = '%u' WHERE `channel_id` = '%d' ", mysqlfield, value, chan->channel_id);
445     }
446     sprintf(retBuf, "%u", value);
447     return retBuf;
448 }
449
450 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) {
451     if(argument) {
452         //change value
453         char *delimiter = strstr(argument, ":");
454         if(!delimiter) {
455             //invalid format
456             reply(getTextBot(), user, "SS_SET_SENSIBILITY", argument);
457             return NULL;
458         }
459         *delimiter = '\0';
460         delimiter++;
461         int amount = atoi(argument);
462         int timep = atoi(delimiter);
463         if(amount > MAX_FLOOD_AMOUNT || amount < MIN_FLOOD_AMOUNT) {
464             //invalid amount
465             reply(getTextBot(), user, "SS_SET_SENSIBILITY_AMOUNT", amount, MIN_FLOOD_AMOUNT, MAX_FLOOD_AMOUNT);
466             return NULL;
467         }
468         if(timep > MAX_FLOOD_TIME || timep < 0) {
469             //invalid time period
470             reply(getTextBot(), user, "SS_SET_SENSIBILITY_TIME", timep, 0, MAX_FLOOD_TIME);
471             return NULL;
472         }
473         char amountfield[50], timefield[50];
474         sprintf(amountfield, "%s%s", mysqlfield, "limit");
475         sprintf(timefield, "%s%s", mysqlfield, "time");
476         printf_mysql_query("UPDATE `channels` SET `%s` = '%d', `%s` = '%d' WHERE `channel_id` = '%d' ", amountfield, amount, timefield, timep, chan->channel_id);
477         sprintf(retBuf, "%d:%d", amount, timep);
478         chan->spam_settings->sensibility_amount[sensibility_index] = amount;
479         chan->spam_settings->sensibility_time[sensibility_index] = timep;
480     } else {
481         sprintf(retBuf, "%d:%d", chan->spam_settings->sensibility_amount[sensibility_index], chan->spam_settings->sensibility_time[sensibility_index]);
482     }
483     return retBuf;
484 }
485
486 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) {
487     if(argument) {
488         //change value
489         int amount = atoi(argument);
490         if(amount > 10 || amount < 2) {
491             //invalid amount
492             reply(getTextBot(), user, "SS_SET_SPAMLIMIT", amount, 2, 10);
493             return NULL;
494         }
495         printf_mysql_query("UPDATE `channels` SET `channel_maxrepeat` = '%d' WHERE `channel_id` = '%d' ", amount, chan->channel_id);
496         sprintf(retBuf, "%d", amount);
497         chan->spam_settings->spam_amount = amount;
498     } else
499         sprintf(retBuf, "%d", chan->spam_settings->spam_amount);
500     return retBuf;
501 }
502
503 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) {
504     int i = 0;
505     int value = -1;
506     int identical = 1;
507     while(neonspam_settings[i].setting) {
508         if(neonspam_settings[i].flags & SET_SCANOPS) {
509             if(value == -1)
510                 value = ((chan->spam_settings->flags & neonspam_settings[i].intparam) ? 1 : 0);
511             else {
512                 if(((chan->spam_settings->flags & neonspam_settings[i].intparam) ? 1 : 0) != value) {
513                     identical = 0;
514                     break;
515                 }
516             }
517         }
518         i++;
519     }
520     if(argument) {
521         //binary argument...
522         if(!strcmp(argument, "0") || !stricmp(argument, "off") || !stricmp(argument, get_language_string(user, "NS_SET_OFF"))) {
523             value = 0;
524         } else if(!strcmp(argument, "1") || !stricmp(argument, "on") || !stricmp(argument, get_language_string(user, "NS_SET_ON"))) {
525             value = 1;
526         } else {
527             reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
528             return NULL;
529         }
530         i = 0;
531         char valueBuf[MAXLEN];
532         while(neonspam_settings[i].setting) {
533             if(neonspam_settings[i].flags & SET_SCANOPS) {
534                 neonspam_cmd_set_function *func = neonspam_settings[i].function;
535                 func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, (value ? "1" : "0"), valueBuf);
536             }
537             i++;
538         }
539         identical = 1;
540     }
541     if(identical && value)
542         return "1";
543     if(identical && !value)
544         return "0";
545     return "?";
546 }
547
548 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) {
549     int i = 0;
550     int value = -1;
551     int identical = 1;
552     while(neonspam_settings[i].setting) {
553         if(neonspam_settings[i].flags & SET_SCANVOICE) {
554             if(value == -1)
555                 value = ((chan->spam_settings->flags & neonspam_settings[i].intparam) ? 1 : 0);
556             else {
557                 if(((chan->spam_settings->flags & neonspam_settings[i].intparam) ? 1 : 0) != value) {
558                     identical = 0;
559                     break;
560                 }
561             }
562         }
563         i++;
564     }
565     if(argument) {
566         //binary argument...
567         if(!strcmp(argument, "0") || !stricmp(argument, "off") || !stricmp(argument, get_language_string(user, "NS_SET_OFF"))) {
568             value = 0;
569         } else if(!strcmp(argument, "1") || !stricmp(argument, "on") || !stricmp(argument, get_language_string(user, "NS_SET_ON"))) {
570             value = 1;
571         } else {
572             reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
573             return NULL;
574         }
575         i = 0;
576         char valueBuf[MAXLEN];
577         while(neonspam_settings[i].setting) {
578             if(neonspam_settings[i].flags & SET_SCANVOICE) {
579                 neonspam_cmd_set_function *func = neonspam_settings[i].function;
580                 func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, (value ? "1" : "0"), valueBuf);
581             }
582             i++;
583         }
584         identical = 1;
585     }
586     if(identical && value)
587         return "1";
588     if(identical && !value)
589         return "0";
590     return "?";
591 }
592
593 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) {
594     int i = 0;
595     int value = -1;
596     int identical = 1;
597     while(neonspam_settings[i].setting) {
598         if(neonspam_settings[i].flags & SET_SCANEXCEPT) {
599             if(value == -1)
600                 value = chan->spam_settings->exceptlevel[neonspam_settings[i].intparam];
601             else {
602                 if(chan->spam_settings->exceptlevel[neonspam_settings[i].intparam] != value) {
603                     identical = 0;
604                     break;
605                 }
606             }
607         }
608         i++;
609     }
610     if(argument) {
611         //numeric argument... (access)
612         int caccess = atoi(argument);
613         if(caccess < 0 || caccess > 501) {
614             reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
615             return NULL;
616         }
617         int uaccess = getChannelAccess(user, chan);
618         if(uaccess == 500) uaccess++;
619         if(identical && value > uaccess) {
620             if(isGodMode(user)) {
621                 event->flags |= CMDFLAG_OPLOG;
622             } else {
623                 reply(getTextBot(), user, "NS_SET_CANNOT_SET");
624                 return NULL;
625             }
626         }
627         if(caccess > uaccess) {
628             if(isGodMode(user)) {
629                 event->flags |= CMDFLAG_OPLOG;
630             } else {
631                 reply(getTextBot(), user, "NS_SET_BADLEVEL");
632                 return NULL;
633             }
634         }
635         i = 0;
636         char valueBuf[MAXLEN];
637         sprintf(retBuf, "%d", caccess);
638         while(neonspam_settings[i].setting) {
639             if(neonspam_settings[i].flags & SET_SCANEXCEPT) {
640                 neonspam_cmd_set_function *func = neonspam_settings[i].function;
641                 func(client, user, chan, event, neonspam_settings[i].intparam, neonspam_settings[i].charparam, retBuf, valueBuf);
642             }
643             i++;
644         }
645         identical = 1;
646         value = caccess;
647     }
648     if(identical) {
649         sprintf(retBuf, "%d", value);
650         return retBuf;
651     }
652     return "?";
653 }
654
655 #undef MAX_QUERY_LEN