X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fmodcmd.c;h=058612a2b353cd09887d543c67d5ddf000389947;hb=391260f64a1dfb35bf0a55e7044fe1b8d83f2561;hp=3f480cda6b8fcac491f15397f4e84f0d632a206a;hpb=4a4f9e7a00aa6b8e4e5966dacd46b987a49bd532;p=NeonServV5.git diff --git a/src/modcmd.c b/src/modcmd.c index 3f480cd..058612a 100644 --- a/src/modcmd.c +++ b/src/modcmd.c @@ -35,6 +35,13 @@ struct trigger_callback { struct trigger_callback *next; }; +struct cmd_bot_alias { + int botid; + char *alias; + + struct cmd_bot_alias *next; +}; + struct command_check_user_cache { struct ClientSocket *client, *textclient; struct UserNode *user; @@ -48,7 +55,10 @@ struct command_check_user_cache { static struct cmd_binding **cmd_binds; static struct cmd_function *cmd_functions = NULL; static struct trigger_callback *trigger_callbacks = NULL; +static struct cmd_bot_alias *bot_aliases = NULL; static struct ClientSocket *tmp_text_client; +static int total_triggered = 0; +int statistics_commands = 0; static const struct default_language_entry msgtab[] = { {"MODCMD_LESS_PARAM_COUNT", "This command requires more parameters."}, @@ -58,6 +68,8 @@ 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."}, {NULL, NULL} }; @@ -68,10 +80,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 @@ -81,10 +93,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; @@ -94,15 +106,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; @@ -122,6 +135,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] == '#') { @@ -144,13 +162,56 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s } struct cmd_binding *cbind; 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) { + 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, subcommands); + break; + } + } + if(statistics_enabled) + statistics_commands++; + total_triggered++; + cbind->triggered++; + if((cbind->func->flags & CMDFLAG_FUNCMD)) { + if(!sent_chan) + break; + chan = sent_chan; + } //get a text bot - tmp_text_client = get_prefered_bot(client->botid); + tmp_text_client = get_botwise_prefered_bot(client->botid, (client->botid == 0 ? client->clientid : 0)); //parse the arguments... char *arga[MAXNUMPARAMS]; char **argv; int argc = 0; + int escape = 0; + int offset = 0; if(args) { while(*args) { //skip leading spaces @@ -159,8 +220,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; @@ -178,13 +253,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'; @@ -222,6 +307,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; @@ -230,6 +318,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; @@ -246,7 +335,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)); @@ -281,18 +370,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; } @@ -351,7 +463,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) { @@ -409,28 +521,31 @@ 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); 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)); } } } for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) { - if(isUserOnChan(client->user, chan) && !FD_ISSET(client->botid, &fds)) { + if(isUserOnChan(client->user, chan) && ((client->botid == 0 && !FD_ISSET(client->clientid, &fds)) || (client->botid && !FD_ISSET(client->botid, &fds2)))) { FD_SET(client->botid, &fds); - trigger = get_channel_trigger(client->botid, chan); + 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)); } @@ -450,7 +565,7 @@ static void got_privmsg(struct UserNode *user, struct UserNode *target, char *me int register_command(int botid, char *name, cmd_bind_t *func, int paramcount, char *channel_access, int global_access, unsigned int flags) { struct cmd_function *cmdfunc; for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) { - if(cmdfunc->botid == botid && strcmp(cmdfunc->name, name) == 0) + if((cmdfunc->botid == botid || cmdfunc->botid == 0) && strcmp(cmdfunc->name, name) == 0) return 0; } cmdfunc = malloc(sizeof(*cmdfunc)); @@ -490,10 +605,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; @@ -502,11 +617,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)); @@ -515,28 +630,44 @@ 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; cbind->global_access = 0; cbind->channel_access = NULL; cbind->flags = 0; + cbind->triggered = 0; cbind->next = cmd_binds[bind_index]; cmd_binds[bind_index] = cbind; 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; + if((c = strstr(func, "."))) { + *c = '\0'; + struct cmd_bot_alias *botalias; + for(botalias = bot_aliases; botalias; botalias = botalias->next) { + if(!stricmp(botalias->alias, func)) { + fbotid = botalias->botid; + break; + } + } + *c = '.'; + func = c+1; + } for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) { - if(cmdfunc->botid == botid && strcmp(cmdfunc->name, func) == 0) + if((cmdfunc->botid == fbotid || cmdfunc->botid == 0) && strcmp(cmdfunc->name, func) == 0) break; } if(!cmdfunc) return 0; 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)); @@ -545,6 +676,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]; @@ -552,15 +684,16 @@ int bind_cmd_to_command(int botid, char *cmd, char *func) { cbind->global_access = 0; cbind->channel_access = NULL; cbind->flags = 0; + cbind->triggered = 0; cmd_binds[bind_index] = cbind; 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 @@ -571,6 +704,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 @@ -579,10 +714,50 @@ 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; + if((c = strstr(name, "."))) { + *c = '\0'; + struct cmd_bot_alias *botalias; + for(botalias = bot_aliases; botalias; botalias = botalias->next) { + if(!stricmp(botalias->alias, name)) { + botid = botalias->botid; + break; + } + } + *c = '.'; + name = c+1; + } for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) { - if(cmdfunc->botid == botid && stricmp(cmdfunc->name, name) == 0) + if((cmdfunc->botid == botid || cmdfunc->botid == 0) && stricmp(cmdfunc->name, name) == 0) break; } return cmdfunc; @@ -597,6 +772,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() { @@ -628,15 +804,22 @@ void free_modcmd() { next_cb = cb->next; free(next_cb); } + struct cmd_bot_alias *botalias, *next_botalias; + for(botalias = bot_aliases; botalias; botalias = next_botalias) { + next_botalias = botalias->next; + free(botalias->alias); + free(botalias); + } cmd_functions = NULL; trigger_callbacks = NULL; + 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++) @@ -655,11 +838,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; @@ -671,11 +854,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) { @@ -690,27 +873,27 @@ 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; for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) { - if(cmdfunc->botid == botid && (cmdfunc->flags & CMDFLAG_REQUIRED)) { + if((cmdfunc->flags & CMDFLAG_REQUIRED)) { 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; } @@ -718,11 +901,45 @@ 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; } } } } +void register_command_alias(int botid, char *alias) { + struct cmd_bot_alias *botalias; + for(botalias = bot_aliases; botalias; botalias = botalias->next) { + if(!stricmp(botalias->alias, alias)) + return; + } + botalias = malloc(sizeof(*botalias)); + if (!botalias) { + perror("malloc() failed"); + return; + } + botalias->botid = botid; + botalias->alias = strdup(alias); + botalias->next = bot_aliases; + bot_aliases = botalias; +} + +struct cmd_binding *getAllBinds(struct cmd_binding *last) { + int bind_index; + if(last) { + if(last->next) + return last->next; + bind_index = get_binds_index(last->cmd[0]) + 1; + if(bind_index > 26) + return NULL; + } else + bind_index = 0; + do { + if(cmd_binds[bind_index]) + return cmd_binds[bind_index]; + bind_index++; + } while(bind_index < 27); + return NULL; +}