#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"
+#include "mysqlConn.h"
+#include "DBHelper.h"
+#include "EventLogger.h"
struct trigger_callback {
int botid;
struct trigger_callback *next;
};
+struct command_check_user_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct ChanNode *chan, *sent_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 and the bot is on."},
+ {"MODCMD_AUTH_REQUIRED", "You need to be authenticated with AuthServ to use this command."},
+ {"MODCMD_CHAN_SUSPENDED", "This channel is currently suspended."},
+ {"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."},
+ {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 tolower(first_char) - 'a';
}
return 26;
}
return trigger->trigger;
}
+static void handle_command_async(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct ChanNode *sent_chan, struct cmd_binding *cbind, char **argv, int argc);
+
+static USERAUTH_CALLBACK(command_checked_auth) {
+ struct command_check_user_cache *cache = data;
+ tmp_text_client = cache->textclient;
+ handle_command_async(cache->client, user, cache->chan, cache->sent_chan, cache->cbind, cache->argv, cache->argc);
+ free(cache->message);
+ free(cache);
+}
+
static void handle_command(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message) {
+ struct ChanNode *sent_chan = chan;
if(message[0] == '#') {
char *chanName = message;
message = strstr(message, " ");
if(chan2)
chan = chan2;
}
+ message = strdup(message);
int bind_index = get_binds_index(message[0]);
char *args = strstr(message, " ");
if(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) {
+ if(cbind->botid == client->botid && stricmp(cbind->cmd, message) == 0) {
+ //get a text bot
+ tmp_text_client = get_prefered_bot(client->botid);
//parse the arguments...
char *arga[MAXNUMPARAMS];
char **argv;
}
}
argv = arga;
- if(argc != 0 && argv[0][0] == '#') {
+ if(argc != 0 && argv[0][0] == '#' && !(cbind->func->flags & CMDFLAG_CHAN_PARAM)) {
struct ChanNode *chan2 = getChanByName(argv[0]);
if(chan2) {
argv += 1;
chan = chan2;
}
}
- cbind->func->func(client, user, chan, argv, argc);
+ if(cbind->parameters) {
+ //userdefined parameters...
+ char *uargs[MAXNUMPARAMS];
+ int uargc = 0;
+ char *a,*b = cbind->parameters;
+ int allargs, argi;
+ do {
+ a = strstr(b, " ");
+ if(a) *a = '\0';
+ if(b[0] == '%') {
+ b++;
+ if(b[strlen(b)-1] == '-') {
+ allargs = 1;
+ b[strlen(b)-1] = '\0';
+ argi = atoi(b);
+ b[strlen(b)-1] = '-';
+ } else {
+ allargs = 0;
+ argi = atoi(b);
+ }
+ if(argi > 0) {
+ if(argi <= argc) {
+ uargs[uargc++] = argv[argi-1];
+ if(allargs) {
+ for(argi++; argi <= argc; argi++)
+ uargs[uargc++] = argv[argi-1];
+ }
+ }
+ } else if(!strcmp(b, "c")) {
+ uargs[uargc++] = (chan ? chan->name : NULL);
+ } else if(!strcmp(b, "n")) {
+ uargs[uargc++] = user->nick;
+ }
+ } else {
+ uargs[uargc++] = b;
+ }
+ if(a) {
+ *a = ' ';
+ b = a+1;
+ }
+ } while(a);
+ argv = uargs;
+ argc = uargc;
+ }
+ 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->sent_chan = sent_chan;
+ data->message = message;
+ data->cbind = cbind;
+ data->textclient = tmp_text_client;
+ get_userauth(user, command_checked_auth, data);
+ return;
+ } else
+ handle_command_async(client, user, chan, sent_chan, cbind, argv, argc);
+ break;
+ }
+ }
+ free(message);
+}
+
+static void handle_command_async(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct ChanNode *sent_chan, struct cmd_binding *cbind, char **argv, int argc) {
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ int uaccess;
+ 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(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, 1);
+ if(row[0] && uaccess < atoi(row[0])) { //NOTE: HARDCODED DEFAULT: pubcmd = 0
+ reply(tmp_text_client, user, "MODCMD_PUBCMD", sent_chan->name);
+ return;
+ }
+ }
+ }
+ int global_access = ((cbind->flags & CMDFLAG_OVERRIDE_GLOBAL_ACCESS) ? cbind->global_access : cbind->func->global_access);
+ if(global_access > 0) {
+ int user_global_access = 0;
+ printf_mysql_query("SELECT `user_access` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+ res = mysql_use();
+ if ((row = mysql_fetch_row(res)) != NULL) {
+ user_global_access = atoi(row[0]);
+ }
+ if(user_global_access < global_access) {
+ if(!user_global_access)
+ reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd);
+ else
+ reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
+ return;
+ }
+ }
+ if((cbind->func->flags & CMDFLAG_REGISTERED_CHAN)) {
+ MYSQL_ROW defaults = NULL;
+ char access_list[256];
+ int access_pos = 0;
+ int access_count = 0;
+ int minaccess = 0;
+ char *str_a, *str_b = cbind->func->channel_access, *str_c;
+ if(cbind->flags & CMDFLAG_OVERRIDE_CHANNEL_ACCESS)
+ str_b = cbind->channel_access;
+ access_list[0] = '\0';
+ if(str_b) {
+ str_c = strdup(str_b);
+ str_b = str_c;
+ while((str_a = str_b)) {
+ str_b = strstr(str_a, ",");
+ if(str_b) {
+ *str_b = '\0';
+ str_b++;
+ }
+ if(*str_a == '#') {
+ str_a++;
+ access_pos += sprintf(access_list+access_pos, ", `%s`", str_a);
+ access_count++;
+ } else {
+ if(atoi(str_a) > minaccess)
+ minaccess = atoi(str_a);
+ }
+ }
+ free(str_c);
+ }
+ if(!(chan->flags & CHANFLAG_REQUESTED_CHANINFO) || (sent_chan && sent_chan == chan) || access_count || minaccess) {
+ printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = '%s'", access_list, escape_string(chan->name));
+ res = mysql_use();
+ if ((row = mysql_fetch_row(res)) != NULL) {
+ chan->flags |= CHANFLAG_CHAN_REGISTERED;
+ chan->channel_id = atoi(row[0]);
+ if((sent_chan && sent_chan == chan) || access_count || minaccess) {
+ uaccess = getChannelAccess(user, chan, 0);
+ if(uaccess < minaccess && isGodMode(user)) {
+ eventflags |= CMDFLAG_OPLOG;
+ } else if(uaccess < minaccess) {
+ //ACCESS DENIED
+ reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
+ return;
+ }
+ if(!row[1] && !defaults) {
+ printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = 'defaults'", access_list);
+ defaults = mysql_fetch_row(mysql_use());
+ }
+ if(sent_chan && (sent_chan == chan) && uaccess < (row[1] ? atoi(row[1]) : atoi(defaults[1]))) {
+ if(isGodMode(user)) {
+ eventflags |= CMDFLAG_OPLOG;
+ } else {
+ //PUBCMD
+ reply(tmp_text_client, user, "MODCMD_PUBCMD", chan->name);
+ return;
+ }
+ }
+ int i;
+ for(i = 0; i < access_count; i++) {
+ if(!row[2+i] && !defaults) {
+ printf_mysql_query("SELECT `channel_id`, `channel_pubcmd` %s FROM `channels` WHERE `channel_name` = 'defaults'", access_list);
+ defaults = mysql_fetch_row(mysql_use());
+ }
+ if(uaccess < (row[2+i] ? atoi(row[2+i]) : atoi(defaults[2+i]))) {
+ if(isGodMode(user)) {
+ eventflags |= CMDFLAG_OPLOG;
+ } else {
+ reply(tmp_text_client, user, "MODCMD_ACCESS_DENIED");
+ return;
+ }
+ }
+ }
+ }
+ }
+ chan->flags |= CHANFLAG_REQUESTED_CHANINFO;
+ }
+ if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) {
+ reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
return;
}
+ printf_mysql_query("SELECT `botid`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, client->botid);
+ res = mysql_use();
+ if ((row = mysql_fetch_row(res)) == NULL) {
+ reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
+ return;
+ } else if(!strcmp(row[1], "1")) {
+ reply(tmp_text_client, user, "MODCMD_CHAN_SUSPENDED");
+ return;
+ }
+ }
+ if((cbind->func->flags & CMDFLAG_REQUIRE_GOD) && !isGodMode(user)) {
+ reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd);
+ return;
}
+ struct Event *event = createEvent(client, user, chan, cbind->func->name, argv, argc, eventflags);
+ cbind->func->func(client, user, chan, argv, argc, event);
}
static void got_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) {
}
}
-int register_command(int botid, char *name, cmd_bind_t *func) {
+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)
cmdfunc->botid = botid;
cmdfunc->name = strdup(name);
cmdfunc->func = func;
+ cmdfunc->flags = flags;
+ cmdfunc->paramcount = paramcount;
+ cmdfunc->channel_access = channel_access;
+ cmdfunc->global_access = global_access;
cmdfunc->next = cmd_functions;
cmd_functions = cmdfunc;
return 1;
cbind->botid = botid;
cbind->cmd = strdup(cmd);
cbind->func = func;
+ cbind->parameters = NULL;
+ cbind->global_access = 0;
+ cbind->channel_access = NULL;
+ cbind->flags = 0;
cbind->next = cmd_binds[bind_index];
cmd_binds[bind_index] = cbind;
return 1;
cbind->cmd = strdup(cmd);
cbind->func = cmdfunc;
cbind->next = cmd_binds[bind_index];
+ cbind->parameters = NULL;
+ cbind->global_access = 0;
+ cbind->channel_access = NULL;
+ cbind->flags = 0;
cmd_binds[bind_index] = cbind;
return 1;
}
else
cmd_binds[bind_index] = cbind->next;
free(cbind->cmd);
+ if(cbind->parameters)
+ free(cbind->parameters);
free(cbind);
return 1;
} else
return 0;
}
+struct cmd_function *find_cmd_function(int botid, char *name) {
+ struct cmd_function *cmdfunc;
+ for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
+ if(cmdfunc->botid == botid && stricmp(cmdfunc->name, name) == 0)
+ break;
+ }
+ return cmdfunc;
+}
+
+struct ClientSocket *getTextBot() {
+ return tmp_text_client;
+}
+
void init_modcmd() {
cmd_binds = calloc(27, sizeof(*cmd_binds));
bind_chanmsg(got_chanmsg);
bind_privmsg(got_privmsg);
+ register_default_language_table(msgtab);
}
void free_modcmd() {
for(cbind = cmd_binds[i]; cbind; cbind = next) {
next = cbind->next;
free(cbind->cmd);
+ if(cbind->parameters)
+ free(cbind->parameters);
+ if(cbind->channel_access)
+ free(cbind->channel_access);
free(cbind);
}
}
trigger_callbacks = NULL;
}
+void bind_set_parameters(int botid, 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->parameters)
+ free(cbind->parameters);
+ cbind->parameters = strdup(parameters);
+ return;
+ }
+ }
+}
+
+void bind_set_global_access(int botid, 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(gaccess > -1) {
+ cbind->global_access = gaccess;
+ cbind->flags |= CMDFLAG_OVERRIDE_GLOBAL_ACCESS;
+ } else {
+ cbind->flags &= ~CMDFLAG_OVERRIDE_GLOBAL_ACCESS;
+ }
+ return;
+ }
+ }
+}
+
+void bind_set_channel_access(int botid, 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->channel_access)
+ free(cbind->channel_access);
+ if(chanaccess) {
+ cbind->channel_access = strdup(chanaccess);
+ cbind->flags |= CMDFLAG_OVERRIDE_CHANNEL_ACCESS;
+ } else {
+ cbind->channel_access = NULL;
+ cbind->flags &= ~CMDFLAG_OVERRIDE_CHANNEL_ACCESS;
+ }
+ return;
+ }
+ }
+}
+
+struct cmd_binding *find_cmd_binding(int botid, 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) {
+ return cbind;
+ }
+ }
+ return NULL;
+}
+