X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fmodcmd.c;h=2c0182bbd894741afbfa3d7e7841de18c14d7828;hb=44436a96352a38631237978c9fd431cef3d85cfb;hp=931c508df83daaca0d0751e056effa8720d0c28c;hpb=41f8f0a14e2aaa05735ed3303ee0ffa260e192cd;p=NeonServV5.git diff --git a/src/modcmd.c b/src/modcmd.c index 931c508..2c0182b 100644 --- a/src/modcmd.c +++ b/src/modcmd.c @@ -1,4 +1,4 @@ -/* modcmd.c - NeonServ v5.2 +/* modcmd.c - NeonServ v5.3 * Copyright (C) 2011 Philipp Kreil (pk910) * * This program is free software: you can redistribute it and/or modify @@ -68,6 +68,9 @@ static const struct default_language_entry msgtab[] = { {"MODCMD_PRIVILEGED", "$b%s$b is a privileged command."}, /* {ARGS: "god"} */ {"MODCMD_PUBCMD", "Public commands in $b%s$b are restricted."}, /* {ARGS: "#TestChan"} */ {"MODCMD_ACCESS_DENIED", "Access denied."}, + {"MODCMD_SUBCOMMANDS", "Subcommands of %s: %s"}, /* {ARGS: "bot", "ADD, DEL, EDIT"} */ + {"MODCMD_CROSSCHAN", "You must be in %s (or on its userlist) to use this command."}, + {"MODCMD_UNKNOWN", "$b%s$b is an unknown command."}, /* {ARGS: "bla"} */ {NULL, NULL} }; @@ -78,10 +81,10 @@ static int get_binds_index(char first_char) { return 26; } -struct ClientSocket* get_prefered_bot(int botid) { +struct ClientSocket* get_botwise_prefered_bot(int botid, int clientid) { struct ClientSocket *client, *lowbot = NULL; for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) { - if(client->botid == botid) { + if(client->botid == botid && (botid || clientid == client->clientid)) { if((client->flags & SOCKET_FLAG_PREFERRED)) return client; else @@ -91,10 +94,10 @@ struct ClientSocket* get_prefered_bot(int botid) { return lowbot; } -static char* get_channel_trigger(int botid, struct ChanNode *chan) { +static char* get_channel_trigger(int botid, int clientid, struct ChanNode *chan) { struct trigger_cache *trigger; for(trigger = chan->trigger; trigger; trigger = trigger->next) { - if(trigger->botid == botid) + if(trigger->botid == botid && (botid || trigger->clientid == clientid)) return trigger->trigger; } struct trigger_callback *cb; @@ -104,15 +107,16 @@ static char* get_channel_trigger(int botid, struct ChanNode *chan) { } char triggerStr[TRIGGERLEN]; if(cb) - cb->func(chan, triggerStr); + cb->func(clientid, chan, triggerStr); else - strcpy(triggerStr, "+"); + triggerStr[0] = '\0'; trigger = malloc(sizeof(*trigger)); if (!trigger) { perror("malloc() failed"); return 0; } trigger->botid = botid; + trigger->clientid = clientid; trigger->trigger = (triggerStr[0] ? strdup(triggerStr) : NULL); trigger->next = chan->trigger; chan->trigger = trigger; @@ -132,6 +136,11 @@ static USERAUTH_CALLBACK(command_checked_auth) { free(cache); } +static CMD_BIND(modcmd_linker) { + //fake command for subcommands + //just empty +} + static void handle_command(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message) { struct ChanNode *sent_chan = chan; if(message[0] == '#') { @@ -153,8 +162,44 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s args++; } struct cmd_binding *cbind; + int found_cmd = 0; for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { - if(cbind->botid == client->botid && stricmp(cbind->cmd, message) == 0) { + if(cbind->botid == client->botid && (cbind->botid || cbind->clientid == client->clientid) && stricmp(cbind->cmd, message) == 0) { + found_cmd = 1; + //get a text bot + tmp_text_client = get_botwise_prefered_bot(client->botid, (client->botid == 0 ? client->clientid : 0)); + if(cbind->func->func == modcmd_linker) { + //links subcommands + char command[MAXLEN]; + struct cmd_binding *parent_bind = cbind; + if(args) { + char *subcmd = args; + args = strstr(args, " "); + if(args) { + *args = '\0'; + args++; + } + sprintf(command, "%s %s", parent_bind->cmd, subcmd); + for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { + if(cbind->botid == client->botid && (cbind->botid || cbind->clientid == client->clientid) && stricmp(cbind->cmd, command) == 0) + break; + } + if(!cbind) + break; + } else { + //list all sub commands + int commandlen = sprintf(command, "%s ", parent_bind->cmd); + char subcommands[MAXLEN]; + int subcompos = 0; + for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { + if(cbind->botid == client->botid && (cbind->botid || cbind->clientid == client->clientid) && stricmplen(cbind->cmd, command, commandlen) == 0) { + subcompos += sprintf(subcommands + subcompos, (subcompos ? ", %s" : "%s"), cbind->cmd + commandlen); + } + } + reply(tmp_text_client, user, "MODCMD_SUBCOMMANDS", parent_bind->cmd, (subcompos ? subcommands : "none")); + break; + } + } if(statistics_enabled) statistics_commands++; total_triggered++; @@ -164,12 +209,12 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s break; chan = sent_chan; } - //get a text bot - tmp_text_client = get_prefered_bot(client->botid); //parse the arguments... char *arga[MAXNUMPARAMS]; char **argv; int argc = 0; + int escape = 0; + int offset = 0; if(args) { while(*args) { //skip leading spaces @@ -178,8 +223,22 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s arga[argc++] = args; if (argc >= MAXNUMPARAMS) break; - while (*args != ' ' && *args) + while ((escape || *args != ' ') && *args) { + if((cbind->func->flags & CMDFLAG_ESCAPE_ARGS) && *args == '\\') { + escape = 1; + offset++; + } else if(escape) + escape = 0; + if(!escape && offset) { + args[0 - offset] = args[0]; + } args++; + + } + if(offset) { + args[0-offset] = '\0'; + offset = 0; + } } } argv = arga; @@ -197,13 +256,23 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s int args_pos = 0; char *uargs[MAXNUMPARAMS]; int uargc = 0; - char *b; + char *b, *c; int i; int allargs, argi; for(i = 0; i < cbind->paramcount; i++) { b = cbind->parameters[i]; if(b[0] == '%') { b++; + c = b; + while(*c && *c != ' ') { + if(*c == '|') break; + c++; + } + if(!*c || *c == ' ') c = NULL; + else { + *c = '\0'; + c++; + } if(b[strlen(b)-1] == '-') { allargs = strlen(b)-1; b[allargs] = '\0'; @@ -241,6 +310,9 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s } else if((cbind->func->flags & CMDFLAG_EMPTY_ARGS)) { uargs[uargc++] = args_buffer + args_pos; args_buffer[args_pos++] = '\0'; + } else if(c) { + uargs[uargc++] = args_buffer + args_pos; + args_pos += sprintf(args_buffer + args_pos, "%s", c) + 1; } } else if(!strcmp(b, "c")) { uargs[uargc++] = args_buffer + args_pos; @@ -249,6 +321,7 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s uargs[uargc++] = args_buffer + args_pos; args_pos += sprintf(args_buffer + args_pos, "%s", user->nick) + 1; } + if(c) c[-1] = '|'; //reset \0 to | } else { uargs[uargc++] = args_buffer + args_pos; args_pos += sprintf(args_buffer + args_pos, "%s", b) + 1; @@ -265,7 +338,7 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED"); break; } - if((cbind->func->flags & CMDFLAG_CHECK_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) { + if(((cbind->func->flags & CMDFLAG_CHECK_AUTH) || (chan && chan != sent_chan && !isUserOnChan(user, chan))) && !(user->flags & USERFLAG_ISAUTHED)) { //check auth... struct command_check_user_cache *data = malloc(sizeof(*data)); char **temp_argv = malloc(argc*sizeof(*temp_argv)); @@ -291,6 +364,8 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s break; } } + if(!found_cmd && !sent_chan) + reply(get_botwise_prefered_bot(client->botid, (client->botid == 0 ? client->clientid : 0)), user, "MODCMD_UNKNOWN", message); free(message); if(args_buffer) free(args_buffer); @@ -300,18 +375,41 @@ static void handle_command_async(struct ClientSocket *client, struct UserNode *u MYSQL_RES *res; MYSQL_ROW row; int uaccess; + char requested_uaccess = 0; int eventflags = (cbind->func->flags & (CMDFLAG_LOG | CMDFLAG_OPLOG)); if((cbind->func->flags & CMDFLAG_REQUIRE_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) { reply(tmp_text_client, user, "MODCMD_AUTH_REQUIRED"); return; } + if(chan && sent_chan != chan && !isUserOnChan(user, chan)) { + char user_in_chan = 0; + if((user->flags & USERFLAG_ISAUTHED)) { + //maybe there's another user authed to user->auth on the channel... + struct ChanUser *cchanuser; + for(cchanuser = getChannelUsers(chan, NULL); cchanuser; cchanuser = getChannelUsers(chan, cchanuser)) { + if((cchanuser->user->flags & USERFLAG_ISAUTHED) && !stricmp(user->auth, cchanuser->user->auth)) { + user_in_chan = 1; + break; + } + } + } + if(!user_in_chan) { + //check if we are allowed to execute commands in this channel + requested_uaccess = 1; + uaccess = getChannelAccess(user, chan); + if(!uaccess) { + reply(tmp_text_client, user, "MODCMD_CROSSCHAN", chan->name); + return; + } + } + } if(sent_chan && sent_chan != chan) { //check pubcmd of this channel printf_mysql_query("SELECT `channel_pubcmd` FROM `channels` WHERE `channel_name` = '%s'", escape_string(sent_chan->name)); res = mysql_use(); if ((row = mysql_fetch_row(res)) != NULL) { - uaccess = getChannelAccess(user, sent_chan); - if(row[0] && uaccess < atoi(row[0]) && !isGodMode(user)) { //NOTE: HARDCODED DEFAULT: pubcmd = 0 + int saccess = getChannelAccess(user, sent_chan); + if(row[0] && saccess < atoi(row[0]) && !isGodMode(user)) { //NOTE: HARDCODED DEFAULT: pubcmd = 0 reply(tmp_text_client, user, "MODCMD_PUBCMD", sent_chan->name); return; } @@ -370,7 +468,7 @@ static void handle_command_async(struct ClientSocket *client, struct UserNode *u chan->flags |= CHANFLAG_CHAN_REGISTERED; chan->channel_id = atoi(row[0]); if((sent_chan && sent_chan == chan) || access_count || minaccess) { - uaccess = getChannelAccess(user, chan); + if(!requested_uaccess) uaccess = getChannelAccess(user, chan); if(uaccess < minaccess && isGodMode(user)) { eventflags |= CMDFLAG_OPLOG; } else if(uaccess < minaccess) { @@ -428,30 +526,37 @@ static void handle_command_async(struct ClientSocket *client, struct UserNode *u reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd); return; } - struct Event *event = createEvent(client, user, chan, cbind->func->name, argv, argc, eventflags); + struct Event *event = createEvent(client, user, chan, cbind, argv, argc, eventflags); cbind->func->func(client, user, chan, argv, argc, event); } static void got_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) { - fd_set fds; + fd_set fds, fds2; char *trigger; struct ClientSocket *client; FD_ZERO(&fds); + FD_ZERO(&fds2); + got_chanmsg_loop1: for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) { - if(isUserOnChan(client->user, chan) && (client->flags & SOCKET_FLAG_PREFERRED) && !FD_ISSET(client->botid, &fds)) { - FD_SET(client->botid, &fds); - trigger = get_channel_trigger(client->botid, chan); + if(isUserOnChan(client->user, chan) && (client->flags & SOCKET_FLAG_PREFERRED) && ((client->botid == 0 && !FD_ISSET(client->clientid, &fds)) || (client->botid && !FD_ISSET(client->botid, &fds2)))) { + FD_SET(client->clientid, &fds); + FD_SET(client->botid, &fds2); + trigger = get_channel_trigger(client->botid, client->clientid, chan); if(trigger && stricmplen(message, trigger, strlen(trigger)) == 0) { handle_command(client, user, chan, message + strlen(trigger)); + goto got_chanmsg_loop1; //Thats really really bad, i know... But we can't count on the "getBots" list anymore after executing a command } } } + got_chanmsg_loop2: for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) { - if(isUserOnChan(client->user, chan) && !FD_ISSET(client->botid, &fds)) { - FD_SET(client->botid, &fds); - trigger = get_channel_trigger(client->botid, chan); + if(isUserOnChan(client->user, chan) && ((client->botid == 0 && !FD_ISSET(client->clientid, &fds)) || (client->botid && !FD_ISSET(client->botid, &fds2)))) { + FD_SET(client->clientid, &fds); + FD_SET(client->botid, &fds2); + trigger = get_channel_trigger(client->botid, client->clientid, chan); if(trigger && stricmplen(message, trigger, strlen(trigger)) == 0) { handle_command(client, user, chan, message + strlen(trigger)); + goto got_chanmsg_loop2; //Thats really really bad, i know... But we can't count on the "getBots" list anymore after executing a command } } } @@ -509,10 +614,10 @@ int set_trigger_callback(int botid, trigger_callback_t *func) { return 1; } -int changeChannelTrigger(int botid, struct ChanNode *chan, char *new_trigger) { +int changeBotwiseChannelTrigger(int botid, int clientid, struct ChanNode *chan, char *new_trigger) { struct trigger_cache *trigger; for(trigger = chan->trigger; trigger; trigger = trigger->next) { - if(trigger->botid == botid) { + if(trigger->botid == botid && (botid || trigger->clientid == clientid)) { free(trigger->trigger); trigger->trigger = strdup(new_trigger); return 1; @@ -521,11 +626,11 @@ int changeChannelTrigger(int botid, struct ChanNode *chan, char *new_trigger) { return 0; } -int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func) { +int bind_botwise_cmd_to_function(int botid, int clientid, char *cmd, struct cmd_function *func) { int bind_index = get_binds_index(cmd[0]); struct cmd_binding *cbind; for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { - if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) + if(((botid && cbind->botid == botid) || (botid == 0 && clientid == cbind->clientid)) && strcmp(cbind->cmd, cmd) == 0) return 0; } cbind = malloc(sizeof(*cbind)); @@ -534,6 +639,7 @@ int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func) { return 0; } cbind->botid = botid; + cbind->clientid = clientid; cbind->cmd = strdup(cmd); cbind->func = func; cbind->paramcount = 0; @@ -546,7 +652,7 @@ int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func) { return 1; } -int bind_cmd_to_command(int botid, char *cmd, char *func) { +int bind_botwise_cmd_to_command(int botid, int clientid, char *cmd, char *func) { struct cmd_function *cmdfunc; int fbotid = botid; char *c; @@ -570,7 +676,7 @@ int bind_cmd_to_command(int botid, char *cmd, char *func) { int bind_index = get_binds_index(cmd[0]); struct cmd_binding *cbind; for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { - if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) + if(((botid && cbind->botid == botid) || (botid == 0 && clientid == cbind->clientid)) && strcmp(cbind->cmd, cmd) == 0) return 0; } cbind = malloc(sizeof(*cbind)); @@ -579,6 +685,7 @@ int bind_cmd_to_command(int botid, char *cmd, char *func) { return 0; } cbind->botid = botid; + cbind->clientid = clientid; cbind->cmd = strdup(cmd); cbind->func = cmdfunc; cbind->next = cmd_binds[bind_index]; @@ -591,11 +698,11 @@ int bind_cmd_to_command(int botid, char *cmd, char *func) { return 1; } -int unbind_cmd(int botid, char *cmd) { +int unbind_botwise_cmd(int botid, int clientid, char *cmd) { int bind_index = get_binds_index(cmd[0]); struct cmd_binding *cbind, *last = NULL; for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { - if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) { + if(cbind->botid == botid && (botid || clientid == cbind->clientid) && strcmp(cbind->cmd, cmd) == 0) { if(last) last->next = cbind->next; else @@ -606,6 +713,8 @@ int unbind_cmd(int botid, char *cmd) { for(i = 0; i < cbind->paramcount; i++) free(cbind->parameters[i]); } + if(cbind->channel_access) + free(cbind->channel_access); free(cbind); return 1; } else @@ -614,6 +723,33 @@ int unbind_cmd(int botid, char *cmd) { return 0; } +int unbind_botwise_allcmd(int clientid) { + int i; + for(i = 0; i < 27; i++) { + struct cmd_binding *cbind, *next, *last = NULL; + for(cbind = cmd_binds[i]; cbind; cbind = next) { + next = cbind->next; + if(clientid == cbind->clientid) { + if(last) + last->next = cbind->next; + else + cmd_binds[i] = cbind->next; + free(cbind->cmd); + if(cbind->paramcount) { + int j; + for(j = 0; j < cbind->paramcount; j++) + free(cbind->parameters[j]); + } + if(cbind->channel_access) + free(cbind->channel_access); + free(cbind); + } else + last = cbind; + } + } + return 1; +} + struct cmd_function *find_cmd_function(int botid, char *name) { struct cmd_function *cmdfunc; char *c; @@ -645,6 +781,7 @@ void init_modcmd() { bind_chanmsg(got_chanmsg); bind_privmsg(got_privmsg); register_default_language_table(msgtab); + register_command(0, "linker", modcmd_linker, 0, 0, 0, 0); //fake command for subcommands } void free_modcmd() { @@ -687,11 +824,11 @@ void free_modcmd() { bot_aliases = NULL; } -void bind_set_parameters(int botid, char *cmd, char *parameters) { +void bind_botwise_set_parameters(int botid, int clientid, char *cmd, char *parameters) { int bind_index = get_binds_index(cmd[0]); struct cmd_binding *cbind; for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { - if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) { + if(cbind->botid == botid && (botid || clientid == cbind->clientid) && strcmp(cbind->cmd, cmd) == 0) { if(cbind->paramcount) { int i; for(i = 0; i < cbind->paramcount; i++) @@ -710,11 +847,11 @@ void bind_set_parameters(int botid, char *cmd, char *parameters) { } } -void bind_set_global_access(int botid, char *cmd, int gaccess) { +void bind_botwise_set_global_access(int botid, int clientid, char *cmd, int gaccess) { int bind_index = get_binds_index(cmd[0]); struct cmd_binding *cbind; for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { - if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) { + if(cbind->botid == botid && (botid || clientid == cbind->clientid) && strcmp(cbind->cmd, cmd) == 0) { if(gaccess > -1) { cbind->global_access = gaccess; cbind->flags |= CMDFLAG_OVERRIDE_GLOBAL_ACCESS; @@ -726,11 +863,11 @@ void bind_set_global_access(int botid, char *cmd, int gaccess) { } } -void bind_set_channel_access(int botid, char *cmd, char *chanaccess) { +void bind_botwise_set_channel_access(int botid, int clientid, char *cmd, char *chanaccess) { int bind_index = get_binds_index(cmd[0]); struct cmd_binding *cbind; for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { - if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) { + if(cbind->botid == botid && (botid || clientid == cbind->clientid) && strcmp(cbind->cmd, cmd) == 0) { if(cbind->channel_access) free(cbind->channel_access); if(chanaccess) { @@ -745,18 +882,18 @@ void bind_set_channel_access(int botid, char *cmd, char *chanaccess) { } } -struct cmd_binding *find_cmd_binding(int botid, char *cmd) { +struct cmd_binding *find_botwise_cmd_binding(int botid, int clientid, char *cmd) { int bind_index = get_binds_index(cmd[0]); struct cmd_binding *cbind; for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) { - if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) { + if(cbind->botid == botid && (botid || clientid == cbind->clientid) && strcmp(cbind->cmd, cmd) == 0) { return cbind; } } return NULL; } -void bind_unbound_required_functions(int botid) { +void bind_botwise_unbound_required_functions(int botid, int clientid) { struct cmd_function *cmdfunc; int i, found; struct cmd_binding *cbind; @@ -765,7 +902,7 @@ void bind_unbound_required_functions(int botid) { found = 0; for(i = 0; i < 27; i++) { for(cbind = cmd_binds[i]; cbind; cbind = cbind->next) { - if(cbind->botid == botid && cbind->func == cmdfunc) { + if(cbind->botid == botid && (botid || clientid == cbind->clientid) && cbind->func == cmdfunc) { found = 1; break; } @@ -773,8 +910,8 @@ void bind_unbound_required_functions(int botid) { if(found) break; } - if(!found && bind_cmd_to_function(botid, cmdfunc->name, cmdfunc)) { - cbind = find_cmd_binding(botid, cmdfunc->name); + if(!found && bind_botwise_cmd_to_function(botid, clientid, cmdfunc->name, cmdfunc)) { + cbind = find_botwise_cmd_binding(botid, clientid, cmdfunc->name); cbind->flags |= CMDFLAG_TEMPONARY_BIND; } }