diff --git a/Makefile b/Makefile index 9b33d77..2806cd1 100755 --- a/Makefile +++ b/Makefile @@ -30,6 +30,8 @@ mods: $(MODS_DIR) $(MODS_DIR): $(MAKE) -C $@ +all: main mods + clean: @rm -rf build $(EXEC) @rm -rf mods/*.so diff --git a/mods/lua/Makefile b/mods/lua/Makefile index f519f3a..eeef769 100755 --- a/mods/lua/Makefile +++ b/mods/lua/Makefile @@ -1,7 +1,7 @@ CC=gcc -CFLAGS=-fPIC -I../../lib -llua +CFLAGS=-g -fPIC -I../../lib -llua OBJ=../lua.so main: - $(CC) -shared -o $(OBJ) $(CFLAGS) ./lua.c + $(CC) -shared -o $(OBJ) $(CFLAGS) ./wrappers.c ./events.c ./handlers.c ./lua.c @echo "All Done!" diff --git a/mods/lua/events.c b/mods/lua/events.c new file mode 100755 index 0000000..2bf84fd --- /dev/null +++ b/mods/lua/events.c @@ -0,0 +1,261 @@ +#include "lua.h" +#include "events.h" +#include +#include +#include + +void lua_init_events() +{ + lua_register(lua.L, "add_handler", lua_add_handler); + lua_register(lua.L, "del_handler", lua_del_handler); +} + +int lua_add_handler(lua_State *L) +{ + char *event; + int lreg; + + if (lua_gettop(L) < 2) + { + printf("Error: add_handler requires 2 arguments\n"); + return 0; + } + + luaL_checktype(L, 1, LUA_TSTRING); + luaL_checktype(L, 2, LUA_TFUNCTION); + + lreg = luaL_ref(L, LUA_REGISTRYINDEX); + if (lreg == -1) + { + const char *err = lua_tostring(L, -1); + printf("Error: %s\n", err); + } + + event = (char *)lua_tostring(L, 1); + + printf("Installing handler for event: %s : %d\n", event, lreg); + + strlcpy(lua.events[lua.event_count].event, event, 25); + lua.events[lua.event_count].lreg = lreg; + + lua.event_count++; + + lua_pushinteger(L, lreg); + return 1; +} + +void lua_del_handler(lua_State *L) +{ + char *event; + int i; + int lreg; + + + if (lua_gettop(L) < 2) + { + printf("Error: del_handler requires 2 arguments\n"); + return; + } + + luaL_checktype(L, 1, LUA_TSTRING); + luaL_checktype(L, 2, LUA_TNUMBER); + + event = (char *)lua_tostring(L, 1); + lreg = (int)lua_tointeger(L, 2); + + for (i = 0; i < lua.event_count; i++) + { + if (!strcmp(lua.events[i].event, event)) + { + if (lua.events[i].lreg == lreg) + { + printf("Removing handler for event: %s : %d\n", event, lreg); + luaL_unref(L, LUA_REGISTRYINDEX, lua.events[i].lreg); + + while (i < lua.event_count) + { + lua.events[i] = lua.events[i + 1]; + i++; + } + + lua.event_count--; + } + } + } +} + +void lua_callfunc(int lreg, int argc, ...) +{ + int i; + va_list args; + + va_start(args, argc); + + lua_State *L = lua.L; + int stackSize = lua_gettop(L); + + lua_rawgeti(L, LUA_REGISTRYINDEX, lreg); + + for (i = 0; i < argc; i++) + { + lua_pushstring(lua.L, va_arg(args, char *)); + } + + if (lua_pcall(lua.L, argc, 0, 0) != LUA_OK) + { + const char *err = lua_tostring(L, -1); + printf("Error: %s\n", err); + lua_pop(L, 1); + } + + lua_settop(L, stackSize); + + va_end(args); +} + +void lua_fire_handlers(char *event, ...) +{ + int i; + va_list args; + + char *user, *host, *chan, *text; + + for (i = 0; i < lua.event_count; i++) + { + if (!lua.events[i].lreg) + continue; + + if (!strcmp(lua.events[i].event, event)) + { + if (!strcmp(event, PRIVMSG_CHAN)) + { + va_start(args, event); + + user = va_arg(args, char *); + host = va_arg(args, char *); + chan = va_arg(args, char *); + text = va_arg(args, char *); + + printf("dbug: %s %s %s %s\n", user, host, chan, text); + + lua_callfunc(lua.events[i].lreg, 4, user, host, chan, text); + } + else if (!strcmp(event, PRIVMSG_SELF)) + { + va_start(args, event); + + user = va_arg(args, char *); + host = va_arg(args, char *); + text = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 3, user, host, text); + } + else if (!strcmp(event, JOIN)) + { + va_start(args, event); + + user = va_arg(args, char *); + host = va_arg(args, char *); + chan = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 3, user, host, chan); + } + else if (!strcmp(event, JOIN_MYSELF)) + { + va_start(args, event); + + chan = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 1, chan); + } + else if (!strcmp(event, PART)) + { + va_start(args, event); + + user = va_arg(args, char *); + host = va_arg(args, char *); + chan = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 3, user, host, chan); + } + else if (!strcmp(event, PART_MYSELF)) + { + va_start(args, event); + + chan = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 1, chan); + } + else if (!strcmp(event, QUIT)) + { + va_start(args, event); + + user = va_arg(args, char *); + host = va_arg(args, char *); + text = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 3, user, host, text); + } + else if (!strcmp(event, NICK)) + { + va_start(args, event); + + user = va_arg(args, char *); + host = va_arg(args, char *); + text = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 3, user, host, text); + } + else if (!strcmp(event, NICK_MYSELF)) + { + va_start(args, event); + + text = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 1, text); + } + else if (!strcmp(event, CTCP)) + { + va_start(args, event); + + user = va_arg(args, char *); + host = va_arg(args, char *); + text = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 3, user, host, text); + } + else if (!strcmp(event, IRC_CONNECTED)) + { + lua_callfunc(lua.events[i].lreg, 0); + } + else if (!strcmp(event, IRC_NAMREPLY)) + { + va_start(args, event); + + chan = va_arg(args, char *); + text = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 2, chan, text); + } + else if (!strcmp(event, IRC_WHOREPLY)) + { + va_start(args, event); + + chan = va_arg(args, char *); + text = va_arg(args, char *); + + lua_callfunc(lua.events[i].lreg, 2, chan, text); + } + else if (!strcmp(event, NICK_INUSE)) + { + lua_callfunc(lua.events[i].lreg, 0); + } + else if (!strcmp(event, TICK)) + { + lua_callfunc(lua.events[i].lreg, 0); + } + } + } + + va_end(args); +} diff --git a/mods/lua/handlers.c b/mods/lua/handlers.c new file mode 100755 index 0000000..4f50951 --- /dev/null +++ b/mods/lua/handlers.c @@ -0,0 +1,126 @@ +#include "lua.h" +#include "events.h" + +void lua_init_handlers() +{ + // see lib/events.h + lua_setvar("PRIVMSG_CHAN", PRIVMSG_CHAN); + lua_setvar("PRIVMSG_SELF", PRIVMSG_SELF); + lua_setvar("TICK", TICK); + lua_setvar("JOIN", JOIN); + lua_setvar("JOIN_MYSELF", JOIN_MYSELF); + lua_setvar("IRC_CONNECTED", IRC_CONNECTED); + lua_setvar("NICK_MYSELF", NICK_MYSELF); + lua_setvar("NICK_INUSE", NICK_INUSE); + lua_setvar("CTCP", CTCP); + lua_setvar("IRC_NAMREPLY", IRC_NAMREPLY); + lua_setvar("IRC_WHOREPLY", IRC_WHOREPLY); + lua_setvar("PART", PART); + lua_setvar("PART_MYSELF", PART_MYSELF); + lua_setvar("QUIT", QUIT); + + add_handler(PRIVMSG_CHAN, chanprivmsg_handler); + add_handler(PRIVMSG_SELF, selfprivmsg_handler); + add_handler(TICK, tick_handler); + add_handler(JOIN, join_handler); + add_handler(JOIN_MYSELF, joinmyself_handler); + add_handler(IRC_CONNECTED, ircconnected_handler); + add_handler(NICK_MYSELF, nickmyself_handler); + add_handler(NICK_INUSE, nickinuse_handler); + add_handler(CTCP, ctcp_handler); + add_handler(IRC_NAMREPLY, ircnamreply_handler); + add_handler(IRC_WHOREPLY, ircwhoreply_handler); + add_handler(PART, part_handler); + add_handler(PART_MYSELF, partmyself_handler); + add_handler(QUIT, quit_handler); +} + +void lua_unload_handlers() +{ + del_handler(PRIVMSG_CHAN, chanprivmsg_handler); + del_handler(PRIVMSG_SELF, selfprivmsg_handler); + del_handler(TICK, tick_handler); + del_handler(JOIN, join_handler); + del_handler(JOIN_MYSELF, joinmyself_handler); + del_handler(IRC_CONNECTED, ircconnected_handler); + del_handler(NICK_MYSELF, nickmyself_handler); + del_handler(NICK_INUSE, nickinuse_handler); + del_handler(CTCP, ctcp_handler); + del_handler(IRC_NAMREPLY, ircnamreply_handler); + del_handler(IRC_WHOREPLY, ircwhoreply_handler); + del_handler(PART, part_handler); + del_handler(PART_MYSELF, partmyself_handler); + del_handler(QUIT, quit_handler); +} + + +MY_API void chanprivmsg_handler(struct irc_conn *bot, char *user, char *host, char *chan, const char *text) +{ + lua_fire_handlers(PRIVMSG_CHAN, user, host, chan, text); + lua_eval(bot, user, host, chan, text); +} + +MY_API void selfprivmsg_handler(struct irc_conn *bot, char *user, char *host, const char *text) +{ + lua_fire_handlers(PRIVMSG_SELF, user, host, text); +} + +MY_API void tick_handler(struct irc_conn *bot) +{ + lua_fire_handlers(TICK); +} + +MY_API void join_handler(struct irc_conn *bot, char *user, char *host, char *chan) +{ + lua_fire_handlers(JOIN, user, host, chan); +} + +MY_API void joinmyself_handler(struct irc_conn *bot, char *chan) +{ + lua_fire_handlers(JOIN_MYSELF, chan); +} + +MY_API void ircconnected_handler(struct irc_conn *bot) +{ + lua_fire_handlers(IRC_CONNECTED); +} + +MY_API void nickmyself_handler(struct irc_conn *bot, char *newnick) +{ + lua_fire_handlers(NICK_MYSELF, newnick); +} + +MY_API void nickinuse_handler(struct irc_conn *bot, char *newnick) +{ + lua_fire_handlers(NICK_INUSE, newnick); +} + +MY_API void ctcp_handler(struct irc_conn *bot, char *user, char *host, char *chan, const char *text) +{ + lua_fire_handlers(CTCP, user, host, chan, text); +} + +MY_API void ircnamreply_handler(struct irc_conn *bot, char *chan, char *nicks) +{ + lua_fire_handlers(IRC_NAMREPLY, chan, nicks); +} + +MY_API void ircwhoreply_handler(struct irc_conn *bot, char *chan, char *user, char *host, char *server, char *nick, char *flags, char *hops, char *realname) +{ + lua_fire_handlers(IRC_WHOREPLY, chan, user, host, server, nick, flags, hops, realname); +} + +MY_API void part_handler(struct irc_conn *bot, char *user, char *host, char *chan) +{ + lua_fire_handlers(PART, user, host, chan); +} + +MY_API void partmyself_handler(struct irc_conn *bot, char *chan) +{ + lua_fire_handlers(PART_MYSELF, chan); +} + +MY_API void quit_handler(struct irc_conn *bot, char *user, char *host, const char *text) +{ + lua_fire_handlers(QUIT, user, host, text); +} diff --git a/mods/lua/lua.c b/mods/lua/lua.c index 70af434..cbe2ea4 100755 --- a/mods/lua/lua.c +++ b/mods/lua/lua.c @@ -14,6 +14,7 @@ struct lua_interp lua; struct irc_conn *instance; + MY_API void lua_eval(struct irc_conn *bot, char *user, char *host, char *chan, const char *text) { printf("lua eval called with %s\n", text); @@ -30,6 +31,7 @@ MY_API void lua_eval(struct irc_conn *bot, char *user, char *host, char *chan, c } } + MY_API void lua_load_script(struct irc_conn *bot, char *user, char *host, char *chan, const char *text) { char *name; @@ -41,7 +43,7 @@ MY_API void lua_load_script(struct irc_conn *bot, char *user, char *host, char * text = skip((char *)text, ' '); sprintf(buf, "../scripts/%s", text); - strlcpy(lua.scripts[lua.count].fname, buf, 150); + strlcpy(lua.scripts[lua.script_count].fname, buf, 150); if (luaL_loadfile(lua.L, buf)) { @@ -50,25 +52,18 @@ MY_API void lua_load_script(struct irc_conn *bot, char *user, char *host, char * } sprintf(buf, "Loaded %s", name); + lua.script_count++; + irc_privmsg(bot, chan, buf); } free(buf); } -void raw_wrapper(lua_State *L) +void lua_setvar(char *name, char *value) { - char *text = (char *)lua_tostring(L, 1); - - irc_raw(instance, text); -} - -void privmsg_wrapper(lua_State *L) -{ - char *where = (char *)lua_tostring(L, 1); - char *text = (char *)lua_tostring(L, 2); - - irc_privmsg(instance, where, text); + lua_pushstring(lua.L, value); + lua_setglobal(lua.L, name); } MY_API void mod_init() @@ -76,16 +71,19 @@ MY_API void mod_init() instance = get_bot(); lua.scripts = calloc(512, sizeof(struct lua_script)); - lua.count = 0; + lua.events = calloc(1024, sizeof(struct lua_event)); + + lua.script_count = 0; + lua.event_count = 0; lua.L = luaL_newstate(); luaL_openlibs(lua.L); - - lua_register(lua.L, "privmsg", privmsg_wrapper); - lua_register(lua.L, "raw", raw_wrapper); + lua_init_wrappers(); + lua_init_events(); register_module("lua", "Aaron Blakely", "v0.1", "Lua module"); - add_handler(PRIVMSG_CHAN, lua_eval); + lua_init_handlers(); + printf("Lua module loaded\n"); } diff --git a/mods/lua/lua.h b/mods/lua/lua.h index ae2e568..0a4cec9 100755 --- a/mods/lua/lua.h +++ b/mods/lua/lua.h @@ -16,13 +16,59 @@ struct lua_script char fname[256]; }; -struct lua_interp +struct lua_event { - lua_State *L; - int count; - struct lua_script *scripts; + char event[25]; + int lreg; }; +struct lua_interp +{ + int script_count; + int event_count; + + lua_State *L; + + struct lua_script *scripts; + struct lua_event *events; +}; + + extern struct lua_interp lua; +extern struct irc_conn *instance; + +// events.c +void lua_init_events(); +int lua_add_handler(lua_State *L); +void lua_del_handler(lua_State *L); +void lua_fire_handlers(char *event, ...); + +// wrappers.c +void lua_init_wrappers(); +void raw_wrapper(lua_State *L); +void privmsg_wrapper(lua_State *L); + +// handlers.c +void lua_init_handlers(); +void lua_unload_handlers(); + +MY_API void chanprivmsg_handler(struct irc_conn *bot, char *user, char *host, char *chan, const char *text); +MY_API void selfprivmsg_handler(struct irc_conn *bot, char *user, char *host, const char *text); +MY_API void tick_handler(struct irc_conn *bot); +MY_API void join_handler(struct irc_conn *bot, char *user, char *host, char *chan); +MY_API void joinmyself_handler(struct irc_conn *bot, char *chan); +MY_API void ircconnected_handler(struct irc_conn *bot); +MY_API void nickmyself_handler(struct irc_conn *bot, char *newnick); +MY_API void nickinuse_handler(struct irc_conn *bot, char *newnick); +MY_API void ctcp_handler(struct irc_conn *bot, char *user, char *host, char *chan, const char *text); +MY_API void ircnamreply_handler(struct irc_conn *bot, char *chan, char *nicks); +MY_API void ircwhoreply_handler(struct irc_conn *bot, char *chan, char *user, char *host, char *server, char *nick, char *flags, char *hops, char *realname); +MY_API void part_handler(struct irc_conn *bot, char *user, char *host, char *chan); +MY_API void partmyself_handler(struct irc_conn *bot, char *chan); +MY_API void quit_handler(struct irc_conn *bot, char *user, char *host, const char *text); + +// lua.c +void lua_setvar(char *name, char *value); +MY_API void lua_eval(struct irc_conn *bot, char *user, char *host, char *chan, const char *text); #endif diff --git a/mods/lua/wrappers.c b/mods/lua/wrappers.c new file mode 100755 index 0000000..d823b0d --- /dev/null +++ b/mods/lua/wrappers.c @@ -0,0 +1,22 @@ +#include "lua.h" + +void lua_init_wrappers() +{ + lua_register(lua.L, "raw", raw_wrapper); + lua_register(lua.L, "privmsg", privmsg_wrapper); +} + +void raw_wrapper(lua_State *L) +{ + char *text = (char *)lua_tostring(L, 1); + + irc_raw(instance, text); +} + +void privmsg_wrapper(lua_State *L) +{ + char *where = (char *)lua_tostring(L, 1); + char *text = (char *)lua_tostring(L, 2); + + irc_privmsg(instance, where, text); +} diff --git a/scripts/hello.lua b/scripts/hello.lua index ea7ed44..eadba7d 100755 --- a/scripts/hello.lua +++ b/scripts/hello.lua @@ -3,15 +3,18 @@ VERSION = "v0.5" AUTHOR = "Aaron Blakely" DESCRIPTION = "A simple hello world script for xbot" +local handlers = {} function hi(nick, host, chan, text) irc_privmsg(chan, "Hello, " .. nick .. "!") end function load() - add_lua_handler("PRIVMSG_CHAN", hi) + table.insert(handlers, {PRIVMSG_CHAN, add_handler(PRIVMSG_CHAN, hi)}) end function unload() - remove_lua_handler("PRIVMSG_CHAN", hi) + for i, v in ipairs(handlers) do + del_handler(v[1], v[2]) + end end