56b9f2a7766f2fcf7908c283723fec45fb81d848
[NeonServV5.git] / src / modules / NeonServ.mod / cmd_neonserv_set.c
1 /* cmd_neonserv_set.c - NeonServ v5.6
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_neonserv.h"
19
20 typedef char* neonserv_cmd_set_function(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
21 static void neonserv_cmd_set_setting(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *argument);
22 static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
23 static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
24 static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
25 static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
26 static char* neonserv_cmd_set_backupbot(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
27
28 #define NS_VALID_FUNCTION 0x01
29 #define NS_VALID_STRING   0x02
30 #define NS_VALID_ACCESS   0x04
31 #define NS_VALID_NO501    0x08
32 #define NS_VALID_OPTIONS  0x10
33 #define NS_VALID_NUMERIC  0x20
34 #define NS_VALID_BOOLEAN  0x40
35 #define NS_VALID_IF_HALFOP 0x80
36
37 #define NS_HAS_OPT  0x100 /* options (SET_OPTION_{NAME}_{VALUE}) */
38 #define NS_HAS_HELP 0x200 /* help    (SET_HELP_{NAME}) - only shown if help is requested */
39
40 static const struct {
41     const char *setting;
42     const char *chanfield;
43     unsigned int valid;
44     void *parameter;
45 } channel_settings[] = {
46     {"TRIGGER",         NULL,                   NS_VALID_FUNCTION,                  neonserv_cmd_set_trigger},
47     {"DEFAULTTOPIC",    "channel_defaulttopic", NS_VALID_STRING,                    NULL},
48     {"TOPICMASK",       "channel_topicmask",    NS_VALID_STRING,                    NULL},
49     {"ADVANCEDTOPIC",   "channel_exttopic",     NS_VALID_BOOLEAN | NS_HAS_OPT,      NULL},
50     {"GREETING",        "channel_greeting",     NS_VALID_STRING,                    NULL},
51     {"USERGREETING",    "channel_usergreeting", NS_VALID_STRING,                    NULL},
52     {"USERINFO",        "channel_userinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
53     {"WIPEINFO",        "channel_wipeinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
54     {"MODES",           "channel_modes",        NS_VALID_FUNCTION,                  neonserv_cmd_set_modes},
55     {"INVITEME",        "channel_getinvite",    NS_VALID_ACCESS,                    NULL},
56     {"GIVEOPS",         "channel_getop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
57     {"GIVEHALFOPS",     "channel_gethalfop",    NS_VALID_ACCESS | NS_HAS_HELP | NS_VALID_IF_HALFOP, NULL},
58     {"GIVEVOICE",       "channel_getvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
59     {"ENFOPS",          "channel_canop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
60     {"ENFHALFOPS",      "channel_canhalfop",    NS_VALID_ACCESS | NS_HAS_HELP | NS_VALID_IF_HALFOP, NULL},
61     {"ENFVOICE",        "channel_canvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
62     {"KICK",            "channel_cankick",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
63     {"BAN",             "channel_canban",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
64     {"STATICBAN",       "channel_staticban",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
65     {"PUBCMD",          "channel_pubcmd",       NS_VALID_ACCESS,                    NULL},
66     {"ENFMODES",        "channel_enfmodes",     NS_VALID_ACCESS,                    NULL},
67     {"ENFTOPIC",        "channel_enftopic",     NS_VALID_ACCESS,                    NULL},
68     {"TOPICSNARF",      "channel_topicsnarf",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
69     {"CHANGETOPIC",     "channel_changetopic",  NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
70     {"SETTERS",         "channel_setters",      NS_VALID_ACCESS | NS_VALID_NO501 | NS_HAS_HELP, NULL},
71     {"ADDUSER",         "channel_canadd",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
72     {"DELUSER",         "channel_candel",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
73     {"CLVL",            "channel_canclvl",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
74     {"RESYNC",          "channel_canresync",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
75     {"SUSPEND",         "channel_cansuspend",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
76     {"NOTICEUSERS",     "channel_notice",       NS_VALID_ACCESS,                    NULL},
77     {"NOTICEREACTION",  "channel_noticereaction", NS_VALID_OPTIONS | NS_HAS_OPT,    "4"},
78     {"CTCPUSERS",       "channel_ctcp",         NS_VALID_ACCESS,                    NULL},
79     {"CTCPREACTION",    "channel_ctcpreaction", NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
80     {"PROTECT",         "channel_protect",      NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
81     {"TOYS",            "channel_toys",         NS_VALID_OPTIONS | NS_HAS_OPT,      "3"},
82     {"DYNLIMIT",        "channel_dynlimit",     NS_VALID_NUMERIC | NS_VALID_FUNCTION | NS_HAS_OPT, neonserv_cmd_set_dynlimit},
83     {"NODELETE",        "channel_nodelete",     NS_VALID_BOOLEAN | NS_VALID_FUNCTION, neonserv_cmd_set_nodelete},
84     {"BACKUPBOT",       NULL,                   NS_VALID_BOOLEAN | NS_VALID_FUNCTION, neonserv_cmd_set_backupbot},
85     {NULL, NULL, 0, NULL}
86 };
87
88 #define MAX_QUERY_LEN 1024
89 CMD_BIND(neonserv_cmd_set) {
90     int i, j;
91     if(argc && !strcmp(argv[0], "defaults")) {
92         //reset channel settings
93         int uaccess = getChannelAccess(user, chan);
94         if(uaccess < 500) {
95             if(isGodMode(user)) {
96                 event->flags |= CMDFLAG_OPLOG;
97             } else {
98                 reply(textclient, user, "NS_SET_DEFAULTS_OWNER", chan->name);
99                 return;
100             }
101         }
102         int seed = 0;
103         char *tmp;
104         static char defaultskey[16];
105         for(tmp = user->auth; *tmp; tmp++)
106             seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
107         for(tmp = chan->name; *tmp; tmp++)
108             seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
109         sprintf(defaultskey, "%08x", seed);
110         if(argc > 1 && !strcmp(argv[1], defaultskey)) {
111             char query[MAX_QUERY_LEN];
112             int querypos = 0;
113             i = 0;
114             while(channel_settings[i].setting) {
115                 if(channel_settings[i].chanfield)
116                     querypos += sprintf(query + querypos, "`%s` = NULL, ", channel_settings[i].chanfield);
117                 i++;
118             }
119             if(querypos) {
120                 query[querypos-2] = '\0';
121             }
122             printf_mysql_query("UPDATE `channels` SET %s WHERE `channel_id` = '%d'", query, chan->channel_id);
123             reply(textclient, user, "NS_SET_DEFAULTS_DONE", chan->name);
124             logEvent(event);
125         } else {
126             reply(textclient, user, "NS_SET_DEFAULTS_CODE", chan->name, defaultskey);
127         }
128     } else if(argc && strcmp(argv[0], "help")) {
129         //find the correct command
130         i = 0;
131         j = 0;
132         char *args = (argc > 1 ? merge_argv(argv, 1, argc) : NULL);
133         int with_halfops = get_int_field("General.have_halfop");
134         while(channel_settings[i].setting) {
135             if(!stricmp(channel_settings[i].setting, argv[0]) && (!(channel_settings[i].valid & NS_VALID_IF_HALFOP) || with_halfops)) {
136                 //setting found
137                 if(!stricmp(channel_settings[i].setting, "BACKUPBOT")) {
138                     char setting[128];
139                     sprintf(setting, "modules.%s.channel_backup_setting", get_module_name(module_id));
140                     if(!get_int_field(setting)) {
141                         i++;
142                         continue;
143                     }
144                 }
145                 if(channel_settings[i].valid & NS_VALID_FUNCTION) {
146                     neonserv_cmd_set_function *func = channel_settings[i].parameter;
147                     func(client, textclient, user, chan, event, channel_settings[i].setting, args);
148                 } else {
149                     neonserv_cmd_set_setting(client, textclient, user, chan, event, i, args);
150                 }
151                 j = 1;
152                 break;
153             }
154             i++;
155         }
156         if(j == 0) {
157             //unknown setting
158             reply(textclient, user, "NS_SET_UNKNOWN_SETTING", argv[0]);
159         }
160     } else {
161         char query[MAX_QUERY_LEN], *value, *org_value, *tmp, nameBuf[64];
162         int querypos = 0;
163         MYSQL_RES *res, *defaults_res;
164         MYSQL_ROW row, defaults;
165         struct Table *table;
166         char *content[2];
167         int with_halfops = get_int_field("General.have_halfop");
168         int channel_backup_setting;
169         i = 0;
170         j = 0;
171         while(channel_settings[i].setting) {
172             if((channel_settings[i].valid & NS_VALID_IF_HALFOP) && !with_halfops) {
173                 j++;
174                 i++;
175                 continue;
176             }
177             if(!stricmp(channel_settings[i].setting, "BACKUPBOT")) {
178                 char setting[128];
179                 sprintf(setting, "modules.%s.channel_backup_setting", get_module_name(module_id));
180                 channel_backup_setting = get_int_field(setting);
181                 if(!channel_backup_setting) {
182                     i++;
183                     j++;
184                     continue;
185                 }
186             }
187             if(channel_settings[i].chanfield)
188                 querypos += sprintf(query + querypos, ", `%s`", channel_settings[i].chanfield);
189             i++;
190         }
191         table = table_init(2, i-j, 0);
192         table_set_bold(table, 0, 1);
193         printf_mysql_query("SELECT `channel_id` %s FROM `channels` WHERE `channel_name` = 'defaults'", query);
194         defaults_res = mysql_use();
195         defaults = mysql_fetch_row(defaults_res);
196         printf_mysql_query("SELECT `channel_name` %s FROM `channels` WHERE `channel_id` = '%d'", query, chan->channel_id);
197         res = mysql_use();
198         row = mysql_fetch_row(res);
199         i = 0;
200         j = 0;
201         reply(textclient, user, "NS_SET_HEADER", chan->name);
202         while(channel_settings[i].setting) {
203             if((channel_settings[i].valid & NS_VALID_IF_HALFOP) && !with_halfops) {
204                 i++;
205                 continue;
206             }
207             if(!stricmp(channel_settings[i].setting, "BACKUPBOT") && !channel_backup_setting) {
208                 i++;
209                 continue;
210             }
211             if(channel_settings[i].chanfield) {
212                 j++;
213                 org_value = (row[j] ? row[j] : defaults[j]);
214             } else if(channel_settings[i].valid & NS_VALID_FUNCTION) {
215                 neonserv_cmd_set_function *func = channel_settings[i].parameter;
216                 org_value = func(client, textclient, user, chan, event, NULL, NULL);
217             } else
218                 org_value = "0";
219             value = org_value;
220             if(channel_settings[i].valid & NS_VALID_BOOLEAN) {
221                 if(!strcmp(value, "0"))
222                     value = get_language_string(user, "NS_SET_OFF");
223                 else
224                     value = get_language_string(user, "NS_SET_ON");
225             }
226             strcpy(query, value);
227             querypos = strlen(query);
228             if(channel_settings[i].valid & NS_HAS_OPT) {
229                 sprintf(nameBuf, "NS_SET_OPTION_%s_%s", channel_settings[i].setting, org_value);
230                 tmp = get_language_string(user, nameBuf);
231                 if(tmp) {
232                     querypos += sprintf(query+querypos, " - %s", tmp);
233                 }
234             }
235             if(argc && channel_settings[i].valid & NS_HAS_HELP) {
236                 sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[i].setting);
237                 tmp = get_language_string(user, nameBuf);
238                 if(tmp) {
239                     querypos += sprintf(query+querypos, " - %s", tmp);
240                 }
241             }
242             content[0] = (char*)channel_settings[i].setting;
243             content[1] = query;
244             table_add(table, content);
245             i++;
246         }
247         char **table_lines = table_end(table);
248         for(i = 0; i < table->entrys; i++) {
249             reply(textclient, user, table_lines[i]);
250         }
251         table_free(table);
252     }
253 }
254
255 static void neonserv_cmd_set_setting(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *args) {
256     char *value;
257     char nameBuf[64];
258     //get current value
259     MYSQL_RES *res;
260     MYSQL_ROW row;
261     printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, chan->channel_id);
262     res = mysql_use();
263     row = mysql_fetch_row(res);
264     if(row[0] == NULL) {
265         printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", channel_settings[setting].chanfield);
266         res = mysql_use();
267         row = mysql_fetch_row(res);
268     }
269     value = row[0];
270     if(args) {
271         //change the channel setting
272         //check the new argument
273         int valid = channel_settings[setting].valid;
274         if(valid & NS_VALID_STRING) {
275             if(!strcmp(args, "*")) {
276                 args = "";
277             }
278         }
279         if(valid & NS_VALID_ACCESS) {
280             int caccess = atoi(args);
281             int max = ((valid & NS_VALID_NO501) ? 500 : 501);
282             if(caccess < 0 || caccess > max) {
283                 reply(textclient, user, "NS_INVALID_ACCESS", caccess);
284                 return;
285             }
286             int uaccess = getChannelAccess(user, chan);
287             if(uaccess == 500) uaccess++;
288             if(atoi(value) > uaccess) {
289                 if(isGodMode(user)) {
290                     event->flags |= CMDFLAG_OPLOG;
291                 } else {
292                     reply(textclient, user, "NS_SET_CANNOT_SET");
293                     return;
294                 }
295             }
296             if(caccess > uaccess) {
297                 if(isGodMode(user)) {
298                     event->flags |= CMDFLAG_OPLOG;
299                 } else {
300                     reply(textclient, user, "NS_SET_BADLEVEL");
301                     return;
302                 }
303             }
304             sprintf(nameBuf, "%d", caccess);
305             args = nameBuf;
306         }
307         if(valid & NS_VALID_OPTIONS) {
308             int options = atoi((char *) channel_settings[setting].parameter);
309             int coption = atoi(args);
310             if(coption < 0 || coption >= options) {
311                 reply(textclient, user, "NS_SET_INVALID_OPTION", coption);
312                 int i;
313                 int nameBufPos = 0;
314                 if(valid & NS_HAS_OPT) {
315                     for(i = 0; i < options; i++) {
316                         sprintf(nameBuf, "NS_SET_OPTION_%s_%d", channel_settings[setting].setting, i);
317                         reply(textclient, user, "\002%d\002 - %s", i, get_language_string(user, nameBuf));
318                     }
319                 } else {
320                     for(i = 0; i < options; i++) {
321                         nameBufPos += sprintf(nameBuf + nameBufPos, "\002%d\002, ", i);
322                     }
323                     if(nameBufPos) {
324                         nameBuf[nameBufPos-2] = '\0';
325                         reply(textclient, user, nameBuf);
326                     }
327                 }
328                 return;
329             }
330         }
331         if(valid & NS_VALID_NUMERIC) {
332             sprintf(nameBuf, "%d", atoi(args));
333             args = nameBuf;
334         }
335         if(valid & NS_VALID_BOOLEAN) {
336             if(!strcmp(args, "0") || !stricmp(args, "off") || !stricmp(args, get_language_string(user, "NS_SET_OFF"))) {
337                 args = "0";
338             } else if(!strcmp(args, "1") || !stricmp(args, "on") || !stricmp(args, get_language_string(user, "NS_SET_ON"))) {
339                 args = "1";
340             } else {
341                 reply(textclient, user, "NS_SET_INVALID_BOOLEAN", args);
342                 return;
343             }
344         }
345         //valid - set it
346         value = args;
347         printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, escape_string(value), chan->channel_id);
348         logEvent(event);
349     }
350     if(channel_settings[setting].valid & NS_HAS_OPT) {
351         sprintf(nameBuf, "NS_SET_OPTION_%s_%s", channel_settings[setting].setting, value);
352         char *tmp = get_language_string(user, nameBuf);
353         if(tmp)
354             reply(textclient, user, "\002%s\002 %s - %s", channel_settings[setting].setting, value, tmp);
355         else
356             reply(textclient, user, "\002%s\002 %s", channel_settings[setting].setting, value);
357     } else
358         reply(textclient, user, "\002%s\002 %s", channel_settings[setting].setting, value);
359     if(channel_settings[setting].valid & NS_HAS_HELP) {
360          sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[setting].setting);
361          reply(textclient, user, "  %s", get_language_string(user, nameBuf));
362     }
363 }
364
365 static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
366     char *trigger;
367     //get current trigger
368     MYSQL_RES *res;
369     MYSQL_ROW row;
370     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);
371     res = mysql_use();
372     row = mysql_fetch_row(res);
373     trigger = (row[0] ? row[0] : row[1]);
374     if(argument) {
375         int uaccess = getChannelAccess(user, chan);
376         if(uaccess < 500) {
377             if(isGodMode(user)) {
378                 event->flags |= CMDFLAG_OPLOG;
379             } else {
380                 reply(textclient, user, "NS_SET_TRIGGER_OWNER", chan->name);
381                 return NULL;
382             }
383         }
384         if(strlen(argument) > 15)
385             argument[15] = '\0';
386         printf_mysql_query("UPDATE `bot_channels` SET `trigger` = '%s' WHERE `chanid` = '%d' AND `botid` = '%d'", escape_string(argument), chan->channel_id, client->clientid);
387         trigger = argument;
388         changeChannelTrigger(client->botid, chan, trigger);
389         logEvent(event);
390     }
391     if(setting) {
392         reply(textclient, user, "\002%s\002 %s", setting, trigger);
393     }
394     return trigger;
395 }
396
397 static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
398     char *value;
399     char valueBuf[MAXLEN];
400     //get current value
401     MYSQL_RES *res;
402     MYSQL_ROW row;
403     printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
404     res = mysql_use();
405     row = mysql_fetch_row(res);
406     if(row[0] == NULL) {
407         printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
408         res = mysql_use();
409         row = mysql_fetch_row(res);
410     }
411     value = row[0];
412     if(argument) {
413         //change the channel setting
414         struct ModeNode *modenode = createModeNode(NULL);
415         parseModeString(modenode, argument);
416         getFullModeString(modenode, valueBuf);
417         value = valueBuf;
418         printf_mysql_query("UPDATE `channels` SET `channel_modes` = '%s' WHERE `channel_id` = '%d'", escape_string(value), chan->channel_id);
419         //TODO: set modelock
420         freeModeNode(modenode);
421     }
422     if(setting) {
423         reply(textclient, user, "\002%s\002 %s", setting, value);
424     }
425     return value;
426 }
427
428 static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
429     char *value;
430     char tmp[64];
431     //get current value
432     MYSQL_RES *res;
433     MYSQL_ROW row;
434     printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
435     res = mysql_use();
436     row = mysql_fetch_row(res);
437     if(row[0] == NULL) {
438         printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_name` = 'defaults'");
439         res = mysql_use();
440         row = mysql_fetch_row(res);
441     }
442     value = row[0];
443     if(argument) {
444         //change the channel setting
445         sprintf(tmp, "%d", atoi(argument));
446         argument = tmp;
447         printf_mysql_query("UPDATE `channels` SET `channel_dynlimit` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
448         if(strcmp(argument, "0"))
449             putsock(client, "MODE %s +l %d", chan->name, (chan->usercount + atoi(argument)));
450         else if(isModeSet(chan->modes, 'l'))
451             putsock(client, "MODE %s -l", chan->name);
452         value = argument;
453         logEvent(event);
454     }
455     if(setting) {
456         reply(textclient, user, "\002%s\002 %s", setting, value);
457     }
458     return value;
459 }
460
461 static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
462     char *value;
463     //get current value
464     MYSQL_RES *res;
465     MYSQL_ROW row;
466     printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
467     res = mysql_use();
468     row = mysql_fetch_row(res);
469     if(row[0] == NULL) {
470         printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_name` = 'defaults'");
471         res = mysql_use();
472         row = mysql_fetch_row(res);
473     }
474     value = row[0];
475     if(argument && isGodMode(user)) {
476         //change the channel setting
477         if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
478             argument = "0";
479         } else if(!strcmp(argument, "1") || !strcmp(argument, "on") || !strcmp(argument, get_language_string(user, "NS_SET_ON"))) {
480             argument = "1";
481         } else {
482             reply(textclient, user, "NS_SET_INVALID_BOOLEAN", argument);
483             return NULL;
484         }
485         printf_mysql_query("UPDATE `channels` SET `channel_nodelete` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
486         event->flags |= CMDFLAG_OPLOG;
487         value = argument;
488         logEvent(event);
489     }
490     if(setting) {
491         reply(textclient, user, "\002%s\002 %s", setting, value);
492     }
493     return value;
494 }
495
496 static char* neonserv_cmd_set_backupbot(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
497     int backupbot;
498     //get current trigger
499     MYSQL_RES *res;
500     printf_mysql_query("SELECT `botid` FROM `bot_channels` LEFT JOIN `bots` ON `botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, NEONBACKUP_BOTID);
501     res = mysql_use();
502     if(mysql_fetch_row(res))
503         backupbot = 1;
504     else 
505         backupbot = 0;
506     if(argument) {
507         //change the channel setting
508         if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
509             if(backupbot) {
510                 module_global_cmd_unregister_neonbackup(chan->name);
511                 backupbot = 0;
512             }
513         } else if(!strcmp(argument, "1") || !strcmp(argument, "on") || !strcmp(argument, get_language_string(user, "NS_SET_ON"))) {
514             if(!backupbot) {
515                 module_global_cmd_register_neonbackup(chan->name);
516                 backupbot = 1;
517             }
518         } else {
519             reply(textclient, user, "NS_SET_INVALID_BOOLEAN", argument);
520             return NULL;
521         }
522         logEvent(event);
523     }
524     if(setting) {
525         reply(textclient, user, "\002%s\002 %s", setting, (backupbot ? "1" : "0"));
526     }
527     return (backupbot ? "1" : "0");
528 }
529
530 #undef MAX_QUERY_LEN