#include "modcmd.h"
#include "IRCEvents.h"
+#include "IRCParser.h"
#include "ClientSocket.h"
#include "UserNode.h"
#include "ChanNode.h"
#include "ChanUser.h"
+#include "WHOHandler.h"
+#include "lang.h"
+
+struct trigger_callback {
+ int botid;
+ trigger_callback_t *func;
+
+ struct trigger_callback *next;
+};
+
+struct command_check_user_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct ChanNode *chan;
+ char **argv;
+ int argc;
+ char *message;
+ struct cmd_binding *cbind;
+};
+
+static struct cmd_binding **cmd_binds;
+static struct cmd_function *cmd_functions = NULL;
+static struct trigger_callback *trigger_callbacks = NULL;
+static struct ClientSocket *tmp_text_client;
+
+static const struct default_language_entry msgtab[] = {
+ {"MODCMD_LESS_PARAM_COUNT", "This command requires more parameters."},
+ {"MODCMD_CHAN_REQUIRED", "You must provide the name of a channel that exists."},
+ {"MODCMD_AUTH_REQUIRED", "You need to be authenticated with AuthServ to use this command."},
+ {"MODCMD_PRIVILEGED", "§b%s§b is a privileged command."},
+
+
+ {NULL, NULL}
+};
+
+static int get_binds_index(char first_char) {
+ if(tolower(first_char) >= 'a' && tolower(first_char) <= 'z') {
+ return tolower(first_char - 'a');
+ }
+ return 26;
+}
+
+struct ClientSocket* get_prefered_bot(int botid) {
+ struct ClientSocket *client;
+ for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
+ if(client->botid == botid && (client->flags & SOCKET_FLAG_PREFERRED))
+ return client;
+ }
+ return NULL;
+}
+
+static char* get_channel_trigger(int botid, struct ChanNode *chan) {
+ struct trigger_cache *trigger;
+ for(trigger = chan->trigger; trigger; trigger = trigger->next) {
+ if(trigger->botid == botid)
+ return trigger->trigger;
+ }
+ struct trigger_callback *cb;
+ for(cb = trigger_callbacks; cb; cb = cb->next) {
+ if(cb->botid == botid)
+ break;
+ }
+ char triggerStr[TRIGGERLEN];
+ if(cb)
+ cb->func(chan, triggerStr);
+ else
+ strcpy(triggerStr, "+");
+ trigger = malloc(sizeof(*trigger));
+ if (!trigger) {
+ perror("malloc() failed");
+ return 0;
+ }
+ trigger->botid = botid;
+ trigger->trigger = strdup(triggerStr);
+ trigger->next = chan->trigger;
+ chan->trigger = trigger;
+ return trigger->trigger;
+}
+
+static USERAUTH_CALLBACK(command_checked_auth) {
+ struct command_check_user_cache *cache = data;
+ int execute_cmd = 1;
+ tmp_text_client = cache->textclient;
+ if((cache->cbind->func->flags & CMDFLAG_REQUIRE_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
+ reply(tmp_text_client, user, "MODCMD_AUTH_REQUIRED");
+ execute_cmd = 0;
+ }
+ else if((cache->cbind->func->flags & CMDFLAG_REQUIRE_GOD) && !isGodMode(user)) {
+ reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cache->cbind->cmd);
+ execute_cmd = 0;
+ }
+ if(execute_cmd) {
+ cache->cbind->func->func(cache->client, user, cache->chan, cache->argv, cache->argc);
+ }
+ free(cache->message);
+ free(cache);
+}
+
+static void handle_command(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message) {
+ if(message[0] == '#') {
+ char *chanName = message;
+ message = strstr(message, " ");
+ if(!message) return;
+ *message = '\0';
+ message++;
+ struct ChanNode *chan2 = getChanByName(chanName);
+ if(chan2)
+ chan = chan2;
+ }
+ message = strdup(message);
+ int bind_index = get_binds_index(message[0]);
+ char *args = strstr(message, " ");
+ if(args) {
+ *args = '\0';
+ args++;
+ }
+ struct cmd_binding *cbind;
+ for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
+ if(cbind->botid == client->botid && strcmp(cbind->cmd, message) == 0) {
+ //get a text bot
+ tmp_text_client = get_prefered_bot(client->botid);
+ //parse the arguments...
+ char *arga[MAXNUMPARAMS];
+ char **argv;
+ int argc = 0;
+ if(args) {
+ while(*args) {
+ //skip leading spaces
+ while (*args == ' ')
+ *args++ = 0;
+ arga[argc++] = args;
+ if (argc >= MAXNUMPARAMS)
+ break;
+ while (*args != ' ' && *args)
+ args++;
+ }
+ }
+ argv = arga;
+ if(argc != 0 && argv[0][0] == '#') {
+ struct ChanNode *chan2 = getChanByName(argv[0]);
+ if(chan2) {
+ argv += 1;
+ argc -= 1;
+ chan = chan2;
+ }
+ }
+ if(cbind->parameters) {
+ //userdefined parameters...
+ char *uarga[MAXNUMPARAMS];
+ char params[strlen(cbind->parameters)+1];
+ strcpy(params, cbind->parameters);
+ int uargpos = 0, argi, allargs = 0;
+ char *ppos = params;
+ char *prev_ppos = params;
+ while((ppos = strstr(ppos, " "))) {
+ *ppos = '\0';
+ if(prev_ppos[0] == '%') {
+ prev_ppos++;
+ if(prev_ppos[strlen(prev_ppos)-1] == '-') {
+ allargs = 1;
+ prev_ppos[strlen(prev_ppos)-1] = '\0';
+ } else
+ allargs = 0;
+ argi = atoi(prev_ppos);
+ if(argi > 0) {
+ if(argi <= argc) continue;
+ uarga[uargpos++] = argv[argi-1];
+ if(allargs) {
+ for(;argi < argc; argi++)
+ uarga[uargpos++] = argv[argi-1];
+ }
+ } else if(!strcmp(prev_ppos, "c"))
+ uarga[uargpos++] = (chan ? chan->name : NULL);
+ else if(!strcmp(prev_ppos, "n"))
+ uarga[uargpos++] = user->nick;
+ } else {
+ uarga[uargpos++] = prev_ppos;
+ }
+ ppos++;
+ prev_ppos = ppos;
+ }
+ argv = uarga;
+ argc = uargpos;
+ }
+ if(argc < cbind->func->paramcount) {
+ reply(tmp_text_client, user, "MODCMD_LESS_PARAM_COUNT");
+ break;
+ }
+ if((cbind->func->flags & CMDFLAG_REQUIRE_CHAN) && !chan) {
+ reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
+ break;
+ }
+ if((cbind->func->flags & CMDFLAG_CHECK_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
+ //check auth...
+ struct command_check_user_cache *data = malloc(sizeof(*data));
+ char **temp_argv = malloc(argc*sizeof(*temp_argv));
+ if (!data || !temp_argv) {
+ perror("malloc() failed");
+ break;
+ }
+ memcpy(temp_argv, argv, argc*sizeof(*temp_argv));
+ data->argv = temp_argv;
+ data->argc = argc;
+ data->client = client;
+ data->user = user;
+ data->chan = chan;
+ data->message = message;
+ data->cbind = cbind;
+ data->textclient = tmp_text_client;
+ get_userauth(user, command_checked_auth, data);
+ return;
+ }
+ if((cbind->func->flags & CMDFLAG_REQUIRE_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
+ reply(tmp_text_client, user, "MODCMD_AUTH_REQUIRED");
+ break;
+ }
+ if((cbind->func->flags & CMDFLAG_REQUIRE_GOD) && !isGodMode(user)) {
+ reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd);
+ break;
+ }
+ cbind->func->func(client, user, chan, argv, argc);
+ break;
+ }
+ }
+ free(message);
+}
static void got_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) {
- struct ClientSocket *client = getBots(SOCKET_FLAG_READY, NULL);
- if(!strcmp(message, "users")) {
- struct ChanUser *chanuser;
- putsock(client, "PRIVMSG %s :[BOT JOIN] Users on this Channel:", chan->name);
- for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
- putsock(client, "PRIVMSG %s : %s!%s@%s [%s] rights: %d", chan->name, chanuser->user->nick, chanuser->user->ident, chanuser->user->host, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "*"), chanuser->flags);
+ fd_set fds;
+ char *trigger;
+ struct ClientSocket *client;
+ FD_ZERO(&fds);
+ 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(stricmplen(message, trigger, strlen(trigger)) == 0) {
+ handle_command(client, user, chan, message + strlen(trigger));
+ }
}
}
- if(!strcmp(message, "modes")) {
- char modeBuf[MAXLEN];
- getModeString(chan, modeBuf);
- putsock(client, "PRIVMSG %s :Modes: %s", chan->name, modeBuf);
+ 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(stricmplen(message, trigger, strlen(trigger)) == 0) {
+ handle_command(client, user, chan, message + strlen(trigger));
+ }
+ }
}
}
static void got_privmsg(struct UserNode *user, struct UserNode *target, char *message) {
-
+ struct ClientSocket *client;
+ for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
+ if(client->user == target) {
+ handle_command(client, user, NULL, message);
+ }
+ }
+}
+
+int register_command(int botid, char *name, cmd_bind_t *func, int paramcount, unsigned int flags) {
+ struct cmd_function *cmdfunc;
+ for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
+ if(cmdfunc->botid == botid && strcmp(cmdfunc->name, name) == 0)
+ return 0;
+ }
+ cmdfunc = malloc(sizeof(*cmdfunc));
+ if (!cmdfunc) {
+ perror("malloc() failed");
+ return 0;
+ }
+ cmdfunc->botid = botid;
+ cmdfunc->name = strdup(name);
+ cmdfunc->func = func;
+ cmdfunc->flags = 0;
+ cmdfunc->paramcount = paramcount;
+ cmdfunc->next = cmd_functions;
+ cmd_functions = cmdfunc;
+ return 1;
+}
+
+int set_trigger_callback(int botid, trigger_callback_t *func) {
+ static struct trigger_callback *cb = NULL;
+ for(cb = trigger_callbacks; cb; cb = cb->next) {
+ if(cb->botid == botid)
+ break;
+ }
+ if(!cb) {
+ cb = malloc(sizeof(*cb));
+ if (!cb) {
+ perror("malloc() failed");
+ return 0;
+ }
+ cb->botid = botid;
+ cb->next = trigger_callbacks;
+ trigger_callbacks = cb;
+ }
+ cb->func = func;
+ return 1;
+}
+
+int changeChannelTrigger(int botid, struct ChanNode *chan, char *new_trigger) {
+ struct trigger_cache *trigger;
+ for(trigger = chan->trigger; trigger; trigger = trigger->next) {
+ if(trigger->botid == botid) {
+ free(trigger->trigger);
+ trigger->trigger = strdup(new_trigger);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int bind_cmd_to_function(int botid, 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)
+ return 0;
+ }
+ cbind = malloc(sizeof(*cbind));
+ if (!cbind) {
+ perror("malloc() failed");
+ return 0;
+ }
+ cbind->botid = botid;
+ cbind->cmd = strdup(cmd);
+ cbind->func = func;
+ cbind->parameters = NULL;
+ cbind->gaccess = 0;
+ cbind->flags = 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) {
+ struct cmd_function *cmdfunc;
+ for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
+ if(cmdfunc->botid == botid && 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)
+ return 0;
+ }
+ cbind = malloc(sizeof(*cbind));
+ if (!cbind) {
+ perror("malloc() failed");
+ return 0;
+ }
+ cbind->botid = botid;
+ cbind->cmd = strdup(cmd);
+ cbind->func = cmdfunc;
+ cbind->next = cmd_binds[bind_index];
+ cbind->parameters = NULL;
+ cbind->gaccess = 0;
+ cbind->flags = 0;
+ cmd_binds[bind_index] = cbind;
+ return 1;
+}
+
+int unbind_cmd(int botid, 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(last)
+ last->next = cbind->next;
+ else
+ cmd_binds[bind_index] = cbind->next;
+ free(cbind->cmd);
+ if(cbind->parameters)
+ free(cbind->parameters);
+ free(cbind);
+ return 1;
+ } else
+ last = cbind;
+ }
+ return 0;
+}
+
+struct ClientSocket *getTextBot() {
+ return tmp_text_client;
}
void init_modcmd() {
- bind_chanmsg(got_chanmsg);
- bind_privmsg(got_privmsg);
+ cmd_binds = calloc(27, sizeof(*cmd_binds));
+ bind_chanmsg(got_chanmsg);
+ bind_privmsg(got_privmsg);
+ register_default_language_table(msgtab);
+}
+
+void free_modcmd() {
+ int i;
+ for(i = 0; i < 27; i++) {
+ struct cmd_binding *cbind, *next;
+ for(cbind = cmd_binds[i]; cbind; cbind = next) {
+ next = cbind->next;
+ free(cbind->cmd);
+ if(cbind->parameters)
+ free(cbind->parameters);
+ free(cbind);
+ }
+ }
+ free(cmd_binds);
+ struct cmd_function *cmdfunct, *next;
+ for(cmdfunct = cmd_functions; cmdfunct; cmdfunct = next) {
+ next = cmdfunct->next;
+ free(cmdfunct->name);
+ free(cmdfunct);
+ }
+ struct trigger_callback *cb, *next_cb;
+ for(cb = trigger_callbacks; cb; cb = next_cb) {
+ next_cb = cb->next;
+ free(next_cb);
+ }
+ cmd_functions = NULL;
+ trigger_callbacks = NULL;
+}
+
+void bind_set_parameters(int botid, char *cmd, char *parameters) {
+
+}
+
+void bind_set_gaccess(int botid, char *cmd, int gaccess) {
+
}