rearranged NeonServ code to be modular
[NeonServV5.git] / src / modules / NeonServ.mod / cmd_neonserv_set.c
diff --git a/src/modules/NeonServ.mod/cmd_neonserv_set.c b/src/modules/NeonServ.mod/cmd_neonserv_set.c
new file mode 100644 (file)
index 0000000..ec21e44
--- /dev/null
@@ -0,0 +1,471 @@
+/* cmd_neonserv_set.c - NeonServ v5.3
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include "cmd_neonserv.h"
+
+typedef char* neonserv_cmd_set_function(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+static void neonserv_cmd_set_setting(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *argument);
+static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument);
+
+#define NS_VALID_FUNCTION 0x01
+#define NS_VALID_STRING   0x02
+#define NS_VALID_ACCESS   0x04
+#define NS_VALID_NO501    0x08
+#define NS_VALID_OPTIONS  0x10
+#define NS_VALID_NUMERIC  0x20
+#define NS_VALID_BOOLEAN  0x40
+#define NS_VALID_IF_HALFOP 0x80
+
+#define NS_HAS_OPT  0x100 /* options (SET_OPTION_{NAME}_{VALUE}) */
+#define NS_HAS_HELP 0x200 /* help    (SET_HELP_{NAME}) - only shown if help is requested */
+
+static const struct {
+    const char *setting;
+    const char *chanfield;
+    unsigned int valid;
+    void *parameter;
+} channel_settings[] = {
+    {"TRIGGER",         NULL,                   NS_VALID_FUNCTION,                  neonserv_cmd_set_trigger},
+    {"DEFAULTTOPIC",    "channel_defaulttopic", NS_VALID_STRING,                    NULL},
+    {"TOPICMASK",       "channel_topicmask",    NS_VALID_STRING,                    NULL},
+    {"ADVANCEDTOPIC",   "channel_exttopic",     NS_VALID_BOOLEAN | NS_HAS_OPT,      NULL},
+    {"GREETING",        "channel_greeting",     NS_VALID_STRING,                    NULL},
+    {"USERGREETING",    "channel_usergreeting", NS_VALID_STRING,                    NULL},
+    {"USERINFO",        "channel_userinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"WIPEINFO",        "channel_wipeinfo",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"MODES",           "channel_modes",        NS_VALID_FUNCTION,                  neonserv_cmd_set_modes},
+    {"INVITEME",        "channel_getinvite",    NS_VALID_ACCESS,                    NULL},
+    {"GIVEOPS",         "channel_getop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"GIVEHALFOPS",     "channel_gethalfop",    NS_VALID_ACCESS | NS_HAS_HELP | NS_VALID_IF_HALFOP, NULL},
+    {"GIVEVOICE",       "channel_getvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"ENFOPS",          "channel_canop",        NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"ENFHALFOPS",      "channel_canhalfop",    NS_VALID_ACCESS | NS_HAS_HELP | NS_VALID_IF_HALFOP, NULL},
+    {"ENFVOICE",        "channel_canvoice",     NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"KICK",            "channel_cankick",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"BAN",             "channel_canban",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"STATICBAN",       "channel_staticban",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"PUBCMD",          "channel_pubcmd",       NS_VALID_ACCESS,                    NULL},
+    {"ENFMODES",        "channel_enfmodes",     NS_VALID_ACCESS,                    NULL},
+    {"ENFTOPIC",        "channel_enftopic",     NS_VALID_ACCESS,                    NULL},
+    {"TOPICSNARF",      "channel_topicsnarf",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"CHANGETOPIC",     "channel_changetopic",  NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"SETTERS",         "channel_setters",      NS_VALID_ACCESS | NS_VALID_NO501 | NS_HAS_HELP, NULL},
+    {"ADDUSER",         "channel_canadd",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"DELUSER",         "channel_candel",       NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"CLVL",            "channel_canclvl",      NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"RESYNC",          "channel_canresync",    NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"SUSPEND",         "channel_cansuspend",   NS_VALID_ACCESS | NS_HAS_HELP,      NULL},
+    {"NOTICEUSERS",     "channel_notice",       NS_VALID_ACCESS,                    NULL},
+    {"NOTICEREACTION",  "channel_noticereaction", NS_VALID_OPTIONS | NS_HAS_OPT,    "4"},
+    {"CTCPUSERS",       "channel_ctcp",         NS_VALID_ACCESS,                    NULL},
+    {"CTCPREACTION",    "channel_ctcpreaction", NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
+    {"PROTECT",         "channel_protect",      NS_VALID_OPTIONS | NS_HAS_OPT,      "4"},
+    {"TOYS",            "channel_toys",         NS_VALID_OPTIONS | NS_HAS_OPT,      "3"},
+    {"DYNLIMIT",        "channel_dynlimit",     NS_VALID_NUMERIC | NS_VALID_FUNCTION | NS_HAS_OPT, neonserv_cmd_set_dynlimit},
+    {"NODELETE",        "channel_nodelete",     NS_VALID_BOOLEAN | NS_VALID_FUNCTION, neonserv_cmd_set_nodelete},
+    {NULL, NULL, 0, NULL}
+};
+
+#define MAX_QUERY_LEN 1024
+CMD_BIND(neonserv_cmd_set) {
+    int i, j;
+    if(argc && !strcmp(argv[0], "defaults")) {
+        //reset channel settings
+        int uaccess = getChannelAccess(user, chan);
+        if(uaccess < 500) {
+            if(isGodMode(user)) {
+                event->flags |= CMDFLAG_OPLOG;
+            } else {
+                reply(getTextBot(), user, "NS_SET_DEFAULTS_OWNER", chan->name);
+                return;
+            }
+        }
+        int seed = 0;
+        char *tmp;
+        static char defaultskey[16];
+        for(tmp = user->auth; *tmp; tmp++)
+            seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+        for(tmp = chan->name; *tmp; tmp++)
+            seed = (seed * 0xEECE66DL ^ ((*tmp << 24) | (*tmp << 16) | (*tmp << 8) | *tmp));
+        sprintf(defaultskey, "%08x", seed);
+        if(argc > 1 && !strcmp(argv[1], defaultskey)) {
+            char query[MAX_QUERY_LEN];
+            int querypos = 0;
+            i = 0;
+            while(channel_settings[i].setting) {
+                if(channel_settings[i].chanfield)
+                    querypos += sprintf(query + querypos, "`%s` = NULL, ", channel_settings[i].chanfield);
+                i++;
+            }
+            if(querypos) {
+                query[querypos-2] = '\0';
+            }
+            printf_mysql_query("UPDATE `channels` SET %s WHERE `channel_id` = '%d'", query, chan->channel_id);
+            reply(getTextBot(), user, "NS_SET_DEFAULTS_DONE", chan->name);
+            logEvent(event);
+        } else {
+            reply(getTextBot(), user, "NS_SET_DEFAULTS_CODE", chan->name, defaultskey);
+        }
+    } else if(argc && strcmp(argv[0], "help")) {
+        //find the correct command
+        i = 0;
+        j = 0;
+        char *args = (argc > 1 ? merge_argv(argv, 1, argc) : NULL);
+        int with_halfops = get_int_field("General.have_halfop");
+        while(channel_settings[i].setting) {
+            if(!stricmp(channel_settings[i].setting, argv[0]) && (!(channel_settings[i].valid & NS_VALID_IF_HALFOP) || with_halfops)) {
+                //setting found
+                if(channel_settings[i].valid & NS_VALID_FUNCTION) {
+                    neonserv_cmd_set_function *func = channel_settings[i].parameter;
+                    func(client, user, chan, event, channel_settings[i].setting, args);
+                } else {
+                    neonserv_cmd_set_setting(client, user, chan, event, i, args);
+                }
+                j = 1;
+                break;
+            }
+            i++;
+        }
+        if(j == 0) {
+            //unknown setting
+            reply(getTextBot(), user, "NS_SET_UNKNOWN_SETTING", argv[0]);
+        }
+    } else {
+        char query[MAX_QUERY_LEN], *value, *org_value, *tmp, nameBuf[64];
+        int querypos = 0;
+        MYSQL_RES *res, *defaults_res;
+        MYSQL_ROW row, defaults;
+        struct Table *table;
+        char *content[2];
+        int with_halfops = get_int_field("General.have_halfop");
+        i = 0;
+        j = 0;
+        while(channel_settings[i].setting) {
+            if((channel_settings[i].valid & NS_VALID_IF_HALFOP) && !with_halfops) {
+                j++;
+                i++;
+                continue;
+            }
+            if(channel_settings[i].chanfield)
+                querypos += sprintf(query + querypos, ", `%s`", channel_settings[i].chanfield);
+            i++;
+        }
+        table = table_init(2, i-j, 0);
+        table_set_bold(table, 0, 1);
+        printf_mysql_query("SELECT `channel_id` %s FROM `channels` WHERE `channel_name` = 'defaults'", query);
+        defaults_res = mysql_use();
+        defaults = mysql_fetch_row(defaults_res);
+        printf_mysql_query("SELECT `channel_name` %s FROM `channels` WHERE `channel_id` = '%d'", query, chan->channel_id);
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+        i = 0;
+        j = 0;
+        reply(getTextBot(), user, "NS_SET_HEADER", chan->name);
+        while(channel_settings[i].setting) {
+            if((channel_settings[i].valid & NS_VALID_IF_HALFOP) && !with_halfops) {
+                i++;
+                continue;
+            }
+            if(channel_settings[i].chanfield) {
+                j++;
+                org_value = (row[j] ? row[j] : defaults[j]);
+            } else if(channel_settings[i].valid & NS_VALID_FUNCTION) {
+                neonserv_cmd_set_function *func = channel_settings[i].parameter;
+                org_value = func(client, user, chan, event, NULL, NULL);
+            } else
+                org_value = "0";
+            value = org_value;
+            if(channel_settings[i].valid & NS_VALID_BOOLEAN) {
+                if(!strcmp(value, "0"))
+                    value = get_language_string(user, "NS_SET_OFF");
+                else
+                    value = get_language_string(user, "NS_SET_ON");
+            }
+            strcpy(query, value);
+            querypos = strlen(query);
+            if(channel_settings[i].valid & NS_HAS_OPT) {
+                sprintf(nameBuf, "NS_SET_OPTION_%s_%s", channel_settings[i].setting, org_value);
+                tmp = get_language_string(user, nameBuf);
+                if(tmp) {
+                    querypos += sprintf(query+querypos, " - %s", tmp);
+                }
+            }
+            if(argc && channel_settings[i].valid & NS_HAS_HELP) {
+                sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[i].setting);
+                tmp = get_language_string(user, nameBuf);
+                if(tmp) {
+                    querypos += sprintf(query+querypos, " - %s", tmp);
+                }
+            }
+            content[0] = (char*)channel_settings[i].setting;
+            content[1] = query;
+            table_add(table, content);
+            i++;
+        }
+        char **table_lines = table_end(table);
+        for(i = 0; i < table->entrys; i++) {
+            reply(getTextBot(), user, table_lines[i]);
+        }
+        table_free(table);
+    }
+}
+
+static void neonserv_cmd_set_setting(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, int setting, char *args) {
+    char *value;
+    char nameBuf[64];
+    //get current value
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(row[0] == NULL) {
+        printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", channel_settings[setting].chanfield);
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+    }
+    value = row[0];
+    if(args) {
+        //change the channel setting
+        //check the new argument
+        int valid = channel_settings[setting].valid;
+        if(valid & NS_VALID_STRING) {
+            if(!strcmp(args, "*")) {
+                args = "";
+            }
+        }
+        if(valid & NS_VALID_ACCESS) {
+            int caccess = atoi(args);
+            int max = ((valid & NS_VALID_NO501) ? 500 : 501);
+            if(caccess < 0 || caccess > max) {
+                reply(getTextBot(), user, "NS_INVALID_ACCESS", caccess);
+                return;
+            }
+            int uaccess = getChannelAccess(user, chan);
+            if(uaccess == 500) uaccess++;
+            if(atoi(value) > uaccess) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(getTextBot(), user, "NS_SET_CANNOT_SET");
+                    return;
+                }
+            }
+            if(caccess > uaccess) {
+                if(isGodMode(user)) {
+                    event->flags |= CMDFLAG_OPLOG;
+                } else {
+                    reply(getTextBot(), user, "NS_SET_BADLEVEL");
+                    return;
+                }
+            }
+            sprintf(nameBuf, "%d", caccess);
+            args = nameBuf;
+        }
+        if(valid & NS_VALID_OPTIONS) {
+            int options = atoi((char *) channel_settings[setting].parameter);
+            int coption = atoi(args);
+            if(coption < 0 || coption >= options) {
+                reply(getTextBot(), user, "NS_SET_INVALID_OPTION", coption);
+                int i;
+                int nameBufPos = 0;
+                if(valid & NS_HAS_OPT) {
+                    for(i = 0; i < options; i++) {
+                        sprintf(nameBuf, "NS_SET_OPTION_%s_%d", channel_settings[setting].setting, i);
+                        reply(getTextBot(), user, "\002%d\002 - %s", i, get_language_string(user, nameBuf));
+                    }
+                } else {
+                    for(i = 0; i < options; i++) {
+                        nameBufPos += sprintf(nameBuf + nameBufPos, "\002%d\002, ", i);
+                    }
+                    if(nameBufPos) {
+                        nameBuf[nameBufPos-2] = '\0';
+                        reply(getTextBot(), user, nameBuf);
+                    }
+                }
+                return;
+            }
+        }
+        if(valid & NS_VALID_NUMERIC) {
+            sprintf(nameBuf, "%d", atoi(args));
+            args = nameBuf;
+        }
+        if(valid & NS_VALID_BOOLEAN) {
+            if(!strcmp(args, "0") || !stricmp(args, "off") || !stricmp(args, get_language_string(user, "NS_SET_OFF"))) {
+                args = "0";
+            } else if(!strcmp(args, "1") || !stricmp(args, "on") || !stricmp(args, get_language_string(user, "NS_SET_ON"))) {
+                args = "1";
+            } else {
+                reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", args);
+                return;
+            }
+        }
+        //valid - set it
+        value = args;
+        printf_mysql_query("UPDATE `channels` SET `%s` = '%s' WHERE `channel_id` = '%d'", channel_settings[setting].chanfield, escape_string(value), chan->channel_id);
+        logEvent(event);
+    }
+    if(channel_settings[setting].valid & NS_HAS_OPT) {
+        sprintf(nameBuf, "NS_SET_OPTION_%s_%s", channel_settings[setting].setting, value);
+        char *tmp = get_language_string(user, nameBuf);
+        if(tmp)
+            reply(getTextBot(), user, "\002%s\002 %s - %s", channel_settings[setting].setting, value, tmp);
+        else
+            reply(getTextBot(), user, "\002%s\002 %s", channel_settings[setting].setting, value);
+    } else
+        reply(getTextBot(), user, "\002%s\002 %s", channel_settings[setting].setting, value);
+    if(channel_settings[setting].valid & NS_HAS_HELP) {
+         sprintf(nameBuf, "NS_SET_HELP_%s", channel_settings[setting].setting);
+         reply(getTextBot(), user, "  %s", get_language_string(user, nameBuf));
+    }
+}
+
+static char* neonserv_cmd_set_trigger(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
+    char *trigger;
+    //get current trigger
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    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);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    trigger = (row[0] ? row[0] : row[1]);
+    if(argument) {
+        int uaccess = getChannelAccess(user, chan);
+        if(uaccess < 500) {
+            if(isGodMode(user)) {
+                event->flags |= CMDFLAG_OPLOG;
+            } else {
+                reply(getTextBot(), user, "NS_SET_TRIGGER_OWNER", chan->name);
+                return NULL;
+            }
+        }
+        if(strlen(argument) > 15)
+            argument[15] = '\0';
+        printf_mysql_query("UPDATE `bot_channels` SET `trigger` = '%s' WHERE `chanid` = '%d' AND `botid` = '%d'", escape_string(argument), chan->channel_id, client->clientid);
+        trigger = argument;
+        changeChannelTrigger(client->botid, chan, trigger);
+        logEvent(event);
+    }
+    if(setting) {
+        reply(getTextBot(), user, "\002%s\002 %s", setting, trigger);
+    }
+    return trigger;
+}
+
+static char* neonserv_cmd_set_modes(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
+    char *value;
+    char valueBuf[MAXLEN];
+    //get current value
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(row[0] == NULL) {
+        printf_mysql_query("SELECT `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+    }
+    value = row[0];
+    if(argument) {
+        //change the channel setting
+        struct ModeNode *modenode = createModeNode(NULL);
+        parseModeString(modenode, argument);
+        getFullModeString(modenode, valueBuf);
+        value = valueBuf;
+        printf_mysql_query("UPDATE `channels` SET `channel_modes` = '%s' WHERE `channel_id` = '%d'", escape_string(value), chan->channel_id);
+        //TODO: set modelock
+        freeModeNode(modenode);
+    }
+    if(setting) {
+        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
+    }
+    return value;
+}
+
+static char* neonserv_cmd_set_dynlimit(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
+    char *value;
+    char tmp[64];
+    //get current value
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(row[0] == NULL) {
+        printf_mysql_query("SELECT `channel_dynlimit` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+    }
+    value = row[0];
+    if(argument) {
+        //change the channel setting
+        sprintf(tmp, "%d", atoi(argument));
+        argument = tmp;
+        printf_mysql_query("UPDATE `channels` SET `channel_dynlimit` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
+        if(strcmp(argument, "0"))
+            putsock(client, "MODE %s +l %d", chan->name, (chan->usercount + atoi(argument)));
+        else if(isModeSet(chan->modes, 'l'))
+            putsock(client, "MODE %s -l", chan->name);
+        value = argument;
+        logEvent(event);
+    }
+    if(setting) {
+        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
+    }
+    return value;
+}
+
+static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *argument) {
+    char *value;
+    //get current value
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+    res = mysql_use();
+    row = mysql_fetch_row(res);
+    if(row[0] == NULL) {
+        printf_mysql_query("SELECT `channel_nodelete` FROM `channels` WHERE `channel_name` = 'defaults'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+    }
+    value = row[0];
+    if(argument && isGodMode(user)) {
+        //change the channel setting
+        if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
+            argument = "0";
+        } else if(!strcmp(argument, "0") || !strcmp(argument, "off") || !strcmp(argument, get_language_string(user, "NS_SET_OFF"))) {
+            argument = "1";
+        } else {
+            reply(getTextBot(), user, "NS_SET_INVALID_BOOLEAN", argument);
+            return NULL;
+        }
+        printf_mysql_query("UPDATE `channels` SET `channel_nodelete` = '%s' WHERE `channel_id` = '%d'", escape_string(argument), chan->channel_id);
+        event->flags |= CMDFLAG_OPLOG;
+        value = argument;
+        logEvent(event);
+    }
+    if(setting) {
+        reply(getTextBot(), user, "\002%s\002 %s", setting, value);
+    }
+    return value;
+}
+
+#undef MAX_QUERY_LEN