From: Egor Date: Fri, 27 Oct 2023 15:43:57 +0000 (+0300) Subject: add lua scripting X-Git-Url: https://git.patchysicp.xyz/?a=commitdiff_plain;h=bc06cb1bce0a0e091590ad64e3bcf19890543dc9;p=patchyircd.git add lua scripting --- diff --git a/Makefile b/Makefile index ad27027..bc88915 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,13 @@ HEADERS := \ -include config.mk +ifdef USE_LUA +SOURCES += src/admin.c +HEADERS += src/admin.h +CFLAGS += -DHAS_LUA $(shell pkg-config --cflags lua5.4) +LDLIBS += $(shell pkg-config --libs lua5.4) +endif + ifndef USE_MAP_DYNARR SOURCES += src/map_trie.c else diff --git a/config.example.mk b/config.example.mk index a19c626..5c2efc8 100644 --- a/config.example.mk +++ b/config.example.mk @@ -6,3 +6,4 @@ CC.w32=i686-w64-mingw32-gcc CFLAGS.w32=-Wall -Wextra -DNETPOLL_USE_SELECT LDLIBS.w32=-lws2_32 USE_MAP_DYNARR=1 +USE_LUA=1 diff --git a/lua/channeldump.lua b/lua/channeldump.lua new file mode 100644 index 0000000..2aa0d4f --- /dev/null +++ b/lua/channeldump.lua @@ -0,0 +1,49 @@ +local function showlist(name, ls) + local x + for k,v in pairs(ls) do + if not x then print(name) x = 1 end + print("\t\t"..k) + end +end +for k,v in pairs(ircd.channel_map) do + print("Channel "..k) + if k ~= v.name then + print("\tName: "..tostring(v.name)) + end + if v.topic then + print("\tTopic: "..v.topic) + if v.topic_who then + print("\t\tSet by: "..v.topic_who) + end + if v.topic_when ~= 0 then + print("\t\tSet on: "..tostring(v.topic_when)) + end + end + if v.creation ~= 0 then + print("\tCreated on: "..tostring(v.creation)) + end + showlist("\tCurrent members ("..v.member_count.."):", v.members) + showlist("\tCurrent ops:", v.o) + showlist("\tCurrent voices:", v.v) + local mode = "" + if v.dmode & 1 ~= 0 then mode = mode .. "P" end + if v.dmode & 2 ~= 0 then mode = mode .. "i" end + if v.dmode & 4 ~= 0 then mode = mode .. "m" end + if v.dmode & 8 ~= 0 then mode = mode .. "n" end + if v.dmode & 16 ~= 0 then mode = mode .. "s" end + if v.dmode & 32 ~= 0 then mode = mode .. "t" end + print("\tMode: +"..mode) + showlist("\tBans:", v.listb) + showlist("\tBan exceptions:", v.liste) + showlist("\tInvite exceptions:", v.listI) + showlist("\tQuiets:", v.listq) + showlist("\tAuto-ops:", v.listwo) + showlist("\tAuto-voices:", v.listwv) + showlist("\tCurrent invitees:", v.invitees) + if v.chankey then + print("\tKey: "..v.chankey) + end + if v.member_limit ~= -1 then + print("\tMember limit: "..tostring(v.member_limit)) + end +end diff --git a/lua/init.lua b/lua/init.lua new file mode 100644 index 0000000..64b41c8 --- /dev/null +++ b/lua/init.lua @@ -0,0 +1,111 @@ +function commands.reload(client, source, command, args) + client_notice(client, "reloading...") + dofile "lua/init.lua" + client_notice(client, "done") +end +if not managed_hooks then + managed_hooks = {} +end +function hook_setfold(name, fn) + if not managed_hooks[name] then + managed_hooks[name] = {n=0,fns={}} + end + managed_hooks[name].fold = fn +end +function hook_add(name, id, fn) + if not managed_hooks[name] then error("unknown hook "..tostring(name)) end + local oldn = managed_hooks[name].n + local newn = oldn + (fn and 1 or 0)-(managed_hooks[name].fns[id] and 1 or 0) + managed_hooks[name].fns[id] = fn or nil + if oldn ~= newn and (oldn == 0 or newn == 0) then + if newn ~= 0 then + hooks[name] = function(...) + local r, exit + r = 0 + for k, v in pairs(managed_hooks[name].fns) do + r, exit = managed_hooks[name].fold(r, v(...)) + if exit then break end + end + return r + end + else + hooks[name] = nil + end + end +end +local function fold_sendtox(a, b) + b = b or 0 + if b == -1 then + return -1, true + end + return a > b and a or b +end +hook_setfold("sendtochannel", fold_sendtox) +hook_setfold("sendtoclient", fold_sendtox) + +function commands.echo(client, source, command, args) + client_notice(client, "client = "..tostring(client)) + client_notice(client, "source = "..tostring(source)) + client_notice(client, "command = "..tostring(command)) + client_notice(client, "args.n = "..tostring(args.n)) + for i = 1, args.n do + client_notice(client, "args["..i.."] = "..tostring(args[i])) + end +end +function commands.joinall(client, source, command, args) + for k, v in pairs(ircd.channel_map) do + channel_join(client, k, true) + end +end + +if not spamlevel then + spamlevel = 0 +end +function setspamlevel(newlevel) + spamlevel = newlevel + hook_add("sendtochannel", "supernets_filter", spamlevel >= 10 and function(hook, cl1, cl2, chan, txt) + if cl1.umode & 2 ~= 0 then -- UMODE_OPER + return 0 + end + if not chan.v[cl1.key] and not chan.o[cl1.key] and + (txt:find("irc.supernets.org", 1, true) or txt:find("IRC.SUPERNETS.ORG", 1, true)) then + return -1 + end + end) + hook_add("sendtoclient", "no_unsolicited_pm", spamlevel >= 20 and function(hook, cl1, cl2, chan, txt) + if cl1.umode & 2 ~= 0 then -- UMODE_OPER + return 0 + end + if cl1.umode & 8 ~= 0 then -- UMODE_REGISTERED + return 0 + end + -- allow is cl1 has perms in any of the channels cl2 is in + for k, v in pairs(cl2.channels) do + if v.v[cl1.key] or v.o[cl1.key] then + return 0 + end + end + return -1 + end) + hook_add("sendtochannel", "globally_moderated", spamlevel >= 30 and function(hook, cl1, cl2, chan, txt) + if cl1.umode & 2 ~= 0 then -- UMODE_OPER + return 0 + end + if cl1.umode & 8 ~= 0 then -- UMODE_REGISTERED + return 0 + end + if not chan.v[cl1.key] and not chan.o[cl1.key] then + return 1 + end + end) +end +setspamlevel(spamlevel) + +function commands.spam(client, source, command, args) + if args.n == 0 then + client_notice(client, "current spam protection level: "..tostring(spamlevel)) + else + setspamlevel(tonumber(args[1])) + client_notice(client, "new spam protection level: "..tostring(spamlevel)) + end +end diff --git a/src/admin.c b/src/admin.c new file mode 100644 index 0000000..568e048 --- /dev/null +++ b/src/admin.c @@ -0,0 +1,397 @@ +#include "admin.h" +#include "irc.h" +#include "ircfmt.h" +#include +#include +static lua_State *GL = 0; + +#define MAPTYPE_STRINGSET 0 +#define MAPTYPE_CLIENT 1 +#define MAPTYPE_CHANNEL 2 +static int map_index(lua_State *L) +{ + map_t *m = *(map_t **)luaL_checkudata(L, 1, "map"); + const char *key = luaL_checkstring(L, 2); + void *value = map_get(m, key); + if (!value) + return 0; + lua_getiuservalue(L, 1, 1); + switch (lua_tointeger(L, -1)) { + case MAPTYPE_STRINGSET: + lua_pushvalue(L, 2); + return 1; + case MAPTYPE_CLIENT: + *(struct client_data **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = value; + luaL_setmetatable(L, "client"); + return 1; + case MAPTYPE_CHANNEL: + *(struct channel **)lua_newuserdatauv(L, sizeof(struct channel *), 0) = value; + luaL_setmetatable(L, "channel"); + return 1; + } + return 0; +} + +static int map_newindex(lua_State *L) +{ + map_t *m = *(map_t **)luaL_checkudata(L, 1, "map"); + const char *key = luaL_checkstring(L, 2); + luaL_checkany(L, 3); + if (lua_isnil(L, 3)) { + (void)map_set(m, key, 0, 0); + return 0; + } + lua_getiuservalue(L, 1, 1); + switch (lua_tointeger(L, -1)) { + case MAPTYPE_STRINGSET: + (void)map_set(m, key, key, 0); + break; + case MAPTYPE_CLIENT: { + void **p = luaL_checkudata(L, 3, "client"); + (void)map_set(m, key, *p, 0); + break; + } + case MAPTYPE_CHANNEL: { + void **p = luaL_checkudata(L, 3, "channel"); + (void)map_set(m, key, *p, 0); + break; + } + } + return 0; +} +static int map_iter_next(lua_State *L) +{ + map_iter_t *it = luaL_checkudata(L, 1, "map_iter"); + lua_getiuservalue(L, 1, 2); + const char *key = lua_touserdata(L, -1); + lua_pop(L, 1); + void *value; + if (!map_foriter(it, &key, &value)) + return 0; + lua_pushlightuserdata(L, (void *)key); + lua_setiuservalue(L, 1, 2); + lua_getiuservalue(L, 1, 1); + switch (lua_tointeger(L, -1)) { + case MAPTYPE_STRINGSET: + lua_pushstring(L, key); + lua_pushstring(L, key); + return 2; + case MAPTYPE_CLIENT: + lua_pushstring(L, key); + *(struct client_data **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = value; + luaL_setmetatable(L, "client"); + return 2; + case MAPTYPE_CHANNEL: + lua_pushstring(L, key); + *(struct channel **)lua_newuserdatauv(L, sizeof(struct channel *), 0) = value; + luaL_setmetatable(L, "channel"); + return 2; + } + return 0; +} +static int map_pairs(lua_State *L) +{ + map_t *m = *(map_t **)luaL_checkudata(L, 1, "map"); + lua_pushcfunction(L, map_iter_next); + map_iter_t *it = lua_newuserdatauv(L, sizeof(map_iter_t), 2); + memset(it, 0, sizeof(*it)); + it->root = m; + luaL_setmetatable(L, "map_iter"); + lua_getiuservalue(L, 1, 1); + lua_setiuservalue(L, -2, 1); + lua_pushlightuserdata(L, 0); + lua_setiuservalue(L, -2, 2); + lua_pushnil(L); + return 3; +} +static void map_push(lua_State *L, map_t *map, int type) +{ + *(map_t **)lua_newuserdatauv(L, sizeof(map_t *), 1) = map; + luaL_setmetatable(L, "map"); + lua_pushinteger(L, type); + lua_setiuservalue(L, -2, 1); +} +static int client_index(lua_State *L) +{ + struct client_data *cl = *(struct client_data **)luaL_checkudata(L, 1, "client"); + const char *key = luaL_checkstring(L, 2); + if (!cl) + return 0; +#define string_getter(c, s) if (!strcmp(key, #s)) return lua_pushstring(L, c->s), 1 +#define integer_getter(c, s) if (!strcmp(key, #s)) return lua_pushinteger(L, c->s), 1 +#define map_getter(c, s, t) if (!strcmp(key, #s)) return map_push(L, &c->s, t), 1 + integer_getter(cl, FD); + /* cctx */ + integer_getter(cl, type); + if (!strcmp(key, "next")) { + if (!cl->next) + return 0; + *(struct client_data **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = cl->next; + luaL_setmetatable(L, "client"); + return 1; + } + string_getter(cl, nick); + string_getter(cl, key); + string_getter(cl, username); + string_getter(cl, realname); + string_getter(cl, hostname); + string_getter(cl, nuh); + string_getter(cl, away); + string_getter(cl, nick_reg); + /* string_getter(cl, pass_reg); */ + string_getter(cl, peername); + integer_getter(cl, peerport); + /* buf/bufLen/wbuf/wbufLen */ + integer_getter(cl, umode); + integer_getter(cl, regstate); + map_getter(cl, channels, MAPTYPE_CHANNEL); + map_getter(cl, invites, MAPTYPE_CHANNEL); + integer_getter(cl, cookie); + integer_getter(cl, signon); + integer_getter(cl, lastactivity); + integer_getter(cl, caps); + integer_getter(cl, want_write_for_read); + integer_getter(cl, want_read_for_write); + integer_getter(cl, want_write_for_write); + integer_getter(cl, want_read_for_close); + integer_getter(cl, want_write_for_close); + integer_getter(cl, dying); + integer_getter(cl, write_error); + integer_getter(cl, poll_reg); + return 0; +} +static int channel_index(lua_State *L) +{ + struct channel *chan = *(struct channel **)luaL_checkudata(L, 1, "channel"); + const char *key = luaL_checkstring(L, 2); + if (!chan) + return 0; + string_getter(chan, key); + string_getter(chan, name); + string_getter(chan, topic); + string_getter(chan, topic_who); + integer_getter(chan, topic_when); + integer_getter(chan, creation); + map_getter(chan, members, MAPTYPE_CLIENT); + map_getter(chan, o, MAPTYPE_CLIENT); + map_getter(chan, v, MAPTYPE_CLIENT); + integer_getter(chan, member_count); + integer_getter(chan, dmode); + map_getter(chan, listb, MAPTYPE_STRINGSET); + map_getter(chan, liste, MAPTYPE_STRINGSET); + map_getter(chan, listI, MAPTYPE_STRINGSET); + map_getter(chan, listq, MAPTYPE_STRINGSET); + map_getter(chan, listwo, MAPTYPE_STRINGSET); + map_getter(chan, listwv, MAPTYPE_STRINGSET); + map_getter(chan, invitees, MAPTYPE_CLIENT); + string_getter(chan, chankey); + integer_getter(chan, member_limit); + return 0; +} +static int globals_index(lua_State *L) +{ + const char *key = luaL_checkstring(L, 2); + if (!strcmp(key, "client_map")) + return map_push(L, &client_map, MAPTYPE_CLIENT), 1; + if (!strcmp(key, "channel_map")) + return map_push(L, &channel_map, MAPTYPE_CHANNEL), 1; + if (!strcmp(key, "autojoin")) + return map_push(L, &autojoin, MAPTYPE_STRINGSET), 1; + if (!strcmp(key, "clients")) { + *(struct client_data **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = clients; + luaL_setmetatable(L, "client"); + return 1; + } + if (!strcmp(key, "dyingclients")) { + *(struct client_data **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = dyingclients; + luaL_setmetatable(L, "client"); + return 1; + } + return 0; +} +static int command_eval(lua_State *L) +{ + luaL_checktype(L, 4, LUA_TTABLE); + lua_geti(L, 4, 1); + if (LUA_OK != luaL_dostring(L, lua_tostring(L, -1))) { + fprintf(stderr, "%s\n", lua_tostring(L, -1)); + } + return 0; +} +static int fn_client_notice(lua_State *L) +{ + extern const char *hostname; + struct client_data *cl = *(struct client_data **)luaL_checkudata(L, 1, "client"); + const char *msg = luaL_checkstring(L, 2); + msg_notice_server(hostname, cl->nick, msg), sendbuf(cl); + return 0; +} +static int fn_channel_join(lua_State *L) +{ + struct client_data *cl = *(struct client_data **)luaL_checkudata(L, 1, "client"); + const char *channel = 0; + struct channel *chan = 0; + if (lua_isuserdata(L, 2)) { + chan = *(struct channel **)luaL_checkudata(L, 2, "channel"); + channel = chan->key; + } else { + channel = luaL_checkstring(L, 2); + } + const char *chankey = lua_isboolean(L, 3) && lua_toboolean(L, 3) ? (chan ? chan->chankey : 0) : luaL_optstring(L, 3, 0); + channel_join(cl, channel, chankey); + return 0; +} +static int fn_channel_part(lua_State *L) +{ + struct client_data *cl = *(struct client_data **)luaL_checkudata(L, 1, "client"); + struct channel *chan = *(struct channel **)luaL_checkudata(L, 2, "channel"); + const char *reason = luaL_optstring(L, 3, 0); + struct client_data *kicker = 0; + if (lua_isuserdata(L, 4)) + kicker = *(struct client_data **)luaL_checkudata(L, 4, "client"); + channel_part(cl, chan, reason, kicker); + return 0; +} +void admin_init(void) +{ + lua_State *L = luaL_newstate(); + GL = L; + luaL_openlibs(L); + if (luaL_newmetatable(L, "map")) { + luaL_Reg funcs[] = { + {"__index", map_index}, + {"__newindex", map_newindex}, + {"__pairs", map_pairs}, + {0, 0}, + }; + luaL_setfuncs(L, funcs, 0); + } + lua_pop(L, 1); + luaL_newmetatable(L, "map_iter"); + lua_pop(L, 1); + if (luaL_newmetatable(L, "client")) { + luaL_Reg funcs[] = { + {"__index", client_index}, + {0, 0}, + }; + luaL_setfuncs(L, funcs, 0); + } + lua_pop(L, 1); + if (luaL_newmetatable(L, "channel")) { + luaL_Reg funcs[] = { + {"__index", channel_index}, + {0, 0}, + }; + luaL_setfuncs(L, funcs, 0); + } + lua_pop(L, 1); + if (luaL_newmetatable(L, "globals")) { + luaL_Reg funcs[] = { + {"__index", globals_index}, + {0, 0}, + }; + luaL_setfuncs(L, funcs, 0); + } + lua_pop(L, 1); + lua_newuserdatauv(L, 0, 0); + luaL_setmetatable(L, "globals"); + lua_setglobal(L, "ircd"); + lua_newtable(L); + lua_pushcfunction(L, command_eval); + lua_setfield(L, -2, "eval"); + lua_setglobal(L, "commands"); + lua_newtable(L); + lua_setglobal(L, "hooks"); + lua_pushcfunction(L, fn_client_notice); + lua_setglobal(L, "client_notice"); + lua_pushcfunction(L, fn_channel_join); + lua_setglobal(L, "channel_join"); + lua_pushcfunction(L, fn_channel_part); + lua_setglobal(L, "channel_part"); +} +void admin_fini(void) +{ + if (GL) { + lua_close(GL); + GL = 0; + } +} +int admin_command(struct client_data *client, char *source, char *command, int argc, char *args[]) +{ + if (!is_registered(client)) + return err_notregistered(client), sendbuf(client), 0; + if (!(client->umode & UMODE_OPER)) + return err_noprivileges(client), sendbuf(client), 0; + lua_State *L = GL; + + if (lua_getglobal(L, "commands") != LUA_TTABLE) { + fprintf(stderr, "no command table\n"); + lua_pop(L, 1); + return 0; + } + lua_getfield(L, -1, command); + lua_remove(L, -2); + if (!lua_isfunction(L, -1)) { + fprintf(stderr, "command not found: %s\n", command); + lua_pop(L, 1); + return 0; + } + *(struct client_data **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = client; + luaL_setmetatable(L, "client"); + lua_pushstring(L, source); + lua_pushstring(L, command); + lua_createtable(L, argc, 1); + for (int i = 0; i < argc; i++) { + lua_pushstring(L, args[i]); + lua_seti(L, -2, i+1); + } + lua_pushinteger(L, argc); + lua_setfield(L, -2, "n"); + if (LUA_OK != lua_pcall(L, 4, 0, 0)) { + fprintf(stderr, "%s\n", lua_tostring(L, -1)); + lua_pop(L, 1); + } + return 0; +} +int admin_hook(const char *hook, struct client_data *cl1, struct client_data *cl2, struct channel *chan, char *txt) +{ + lua_State *L = GL; + if (lua_getglobal(L, "hooks") != LUA_TTABLE) { + lua_pop(L, 1); + return 0; + } + lua_getfield(L, -1, hook); + lua_remove(L, -2); + if (!lua_isfunction(L, -1)) { + lua_pop(L, 1); + return 0; + } + lua_pushstring(L, hook); + if (cl1) { + *(struct client_data **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = cl1; + luaL_setmetatable(L, "client"); + } else { + lua_pushnil(L); + } + if (cl2) { + *(struct client_data **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = cl2; + luaL_setmetatable(L, "client"); + } else { + lua_pushnil(L); + } + if (chan) { + *(struct channel **)lua_newuserdatauv(L, sizeof(struct client_data *), 0) = chan; + luaL_setmetatable(L, "channel"); + } else { + lua_pushnil(L); + } + txt ? lua_pushstring(L, txt) : lua_pushnil(L); + if (LUA_OK != lua_pcall(L, 5, 1, 0)) { + fprintf(stderr, "%s\n", lua_tostring(L, -1)); + lua_pop(L, 1); + return 0; + } + int rv = lua_tointeger(L, 1); + lua_pop(L, 1); + return rv; +} diff --git a/src/admin.h b/src/admin.h new file mode 100644 index 0000000..57cd93d --- /dev/null +++ b/src/admin.h @@ -0,0 +1,8 @@ +#ifndef ADMIN_H_ +#define ADMIN_H_ +#include "common.h" +void admin_init(void); +void admin_fini(void); +int admin_command(struct client_data *client, char *source, char *command, int argc, char *args[]); +int admin_hook(const char *hook, struct client_data *cl1, struct client_data *cl2, struct channel *chan, char *txt); +#endif diff --git a/src/common.h b/src/common.h index 7062f1d..0b8e1fc 100644 --- a/src/common.h +++ b/src/common.h @@ -99,4 +99,7 @@ extern map_t autojoin; extern struct client_data *clients; extern struct client_data *dyingclients; +#ifdef HAS_LUA +#include "admin.h" +#endif #endif diff --git a/src/irc.c b/src/irc.c index 8fa0ecb..c02c367 100644 --- a/src/irc.c +++ b/src/irc.c @@ -9,7 +9,6 @@ map_t channel_map = {0}; map_t autojoin = {0}; const char *hostname = IRCDHOSTNAME; -#define is_registered(cl) ((cl)->regstate == REG_REGISTERED) void sendbuf(struct client_data *client) { sendClient(client, databuf.buf, databuf.len); } @@ -542,14 +541,17 @@ int processPacket(struct client_data *client, char *source, char *command, int a return err_cannotsendtochan(client, chan->name), sendbuf(client), 0; if (chan->dmode & DMODE_MODERATED && !map_get(&chan->v, client->key) && !map_get(&chan->o, client->key)) return err_cannotsendtochan(client, chan->name), sendbuf(client), 0; - if (!map_get(&chan->v, client->key) && !map_get(&chan->o, client->key) && - (strstr(args[1], "irc.supernets.org") || strstr(args[1], "IRC.SUPERNETS.ORG"))) { +#ifdef HAS_LUA + switch (admin_hook("sendtochannel", client, 0, chan, args[1])) { + case -1: msg_quit(client, "Quit: eel bearing atlantean", ""); sendbuf_visible(client); killConnection(client, 1); return 1; + case 1: + return err_cannotsendtochan(client, chan->name), sendbuf(client), 0; } - +#endif if (!is_modmsg) { sendbuf_list_sans_self(client, &chan->members, 0); } else if (memchr(args[0], '+', is_modmsg)) { @@ -560,20 +562,23 @@ int processPacket(struct client_data *client, char *source, char *command, int a sendbuf_list_sans_self(client, &chan->o, 0); } } else { - if (!(client->umode & UMODE_REGISTERED)) { + struct client_data *cl = findClient(args[0]); +#ifdef HAS_LUA + if (!cl) + return err_nosuchnick(client, args[0]), sendbuf(client), 0; + switch (admin_hook("sendtoclient", client, cl, 0, args[1])) { + case -1: msg_quit(client, "Quit: eel bearing atlantean", ""); sendbuf_visible(client); killConnection(client, 1); return 1; + case 1: + return err_cantsendtouser(client, cl), sendbuf(client), 0; } - struct client_data *cl = findClient(args[0]); - if (!cl) { - return err_nosuchnick(client, args[0]), sendbuf(client), 0; - } else { - sendbuf(cl); - if (cl->away) - rpl_away(client, cl), sendbuf(client); - } +#endif + sendbuf(cl); + if (cl->away) + rpl_away(client, cl), sendbuf(client); } } else if(strcmp(command, "QUIT") == 0) { msg_quit(client, "Quit: ", args[0] ? args[0] : ""); @@ -1039,6 +1044,12 @@ int processPacket(struct client_data *client, char *source, char *command, int a } msg_away(client); sendbuf_visible_caps(client, CAP_AWAYNOTIFY, 0); +#ifdef HAS_LUA + } else if(strcmp(command, "LUA") == 0) { + if (argc < 1) + return err_needmoreparams(client, command), sendbuf(client), 0; + return admin_command(client, source, args[0], argc-1, args+1); +#endif } else { unknown: err_unknowncommand(client, command), sendbuf(client); diff --git a/src/irc.h b/src/irc.h index 9272c82..29bd8c0 100644 --- a/src/irc.h +++ b/src/irc.h @@ -5,6 +5,7 @@ #include "net.h" #include "util.h" +#define is_registered(cl) ((cl)->regstate == REG_REGISTERED) int parsePacket(struct client_data *client); int processPacket(struct client_data *client, char *source, char *command, int argc, char *args[]); void newUser(struct client_data *client); diff --git a/src/ircfmt.c b/src/ircfmt.c index ef84f3a..d2b519f 100644 --- a/src/ircfmt.c +++ b/src/ircfmt.c @@ -597,6 +597,10 @@ void err_invalidkey(struct client_data *client, struct channel *chan) // 525 { copy_strf(&databuf, ":%s 525 %s %s :Key is not well-formed\r\n", hostname, client->nick, chan->name); } +void err_cantsendtouser(struct client_data *client, struct client_data *cl) // 531 +{ + copy_strf(&databuf, ":%s 531 %s %s :You are not permitted to send private messages to this user\r\n", hostname, client->nick, cl->nick); +} // 670 RPL_STARTTLS // 671 RPL_WHOISSECURE // 691 ERR_STARTTLS diff --git a/src/ircfmt.h b/src/ircfmt.h index 6a5dffc..ad22826 100644 --- a/src/ircfmt.h +++ b/src/ircfmt.h @@ -126,6 +126,7 @@ void err_umodeunknownflag(struct client_data *client); // 501 void err_usersdontmatch(struct client_data *client, const char *what); // 502 void err_helpnotfound(struct client_data *client); // 524 void err_invalidkey(struct client_data *client, struct channel *chan); // 525 +void err_cantsendtouser(struct client_data *client, struct client_data *cl); // 531 // 670 RPL_STARTTLS // 671 RPL_WHOISSECURE // 691 ERR_STARTTLS diff --git a/src/main.c b/src/main.c index 2703a58..efda7b0 100644 --- a/src/main.c +++ b/src/main.c @@ -203,6 +203,9 @@ int main(int argc, char *argv[]) net_init(); net_poll_init(); +#ifdef HAS_LUA + admin_init(); +#endif set_handler(); databuf.buf = malloc(sizeof(char) * 512); databuf.cap = 512; @@ -411,6 +414,9 @@ int main(int argc, char *argv[]) net_poll_del(self_sock); closesocket(self_sock); } +#endif +#ifdef HAS_LUA + admin_fini(); #endif net_poll_fini(); net_cleanup();