X-Git-Url: http://git.pk910.de/?p=NeonServV5.git;a=blobdiff_plain;f=src%2Fmodules%2FNeonServ.mod%2Fcmd_neonserv_set.c;fp=src%2Fmodules%2FNeonServ.mod%2Fcmd_neonserv_set.c;h=ec21e44c6ef6113a06a08b3114be3b30793e1650;hp=0000000000000000000000000000000000000000;hb=706e48b1e666054030c491d864f740071e390038;hpb=b53d0c5f88063f075a48a0426f9d5d6b3490b9fc diff --git a/src/modules/NeonServ.mod/cmd_neonserv_set.c b/src/modules/NeonServ.mod/cmd_neonserv_set.c new file mode 100644 index 0000000..ec21e44 --- /dev/null +++ b/src/modules/NeonServ.mod/cmd_neonserv_set.c @@ -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 . + */ + +#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