more work on lua module
This commit is contained in:
parent
97713e6c29
commit
80bea46895
2
Makefile
2
Makefile
@ -30,6 +30,8 @@ mods: $(MODS_DIR)
|
||||
$(MODS_DIR):
|
||||
$(MAKE) -C $@
|
||||
|
||||
all: main mods
|
||||
|
||||
clean:
|
||||
@rm -rf build $(EXEC)
|
||||
@rm -rf mods/*.so
|
||||
|
@ -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!"
|
||||
|
261
mods/lua/events.c
Executable file
261
mods/lua/events.c
Executable file
@ -0,0 +1,261 @@
|
||||
#include "lua.h"
|
||||
#include "events.h"
|
||||
#include <lua5.3/lua.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
}
|
126
mods/lua/handlers.c
Executable file
126
mods/lua/handlers.c
Executable file
@ -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);
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
22
mods/lua/wrappers.c
Executable file
22
mods/lua/wrappers.c
Executable file
@ -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);
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user