Compare commits

...

10 Commits

Author SHA1 Message Date
Aaron Blakely
79cf4fda3d test 2024-02-29 04:54:18 -06:00
Aaron Blakely
a7345ae957 more work on lua module, now able to load/unload scripts 2024-02-29 02:51:30 -06:00
Aaron Blakely
b1a4865852 more work on lua module, now able to load/unload scripts 2024-02-29 02:51:00 -06:00
Aaron Blakely
5626a7844b lua module now loading/unloading scripts 2024-02-27 02:37:29 -06:00
Aaron Blakely
80bea46895 more work on lua module 2024-02-27 01:16:58 -06:00
Aaron Blakely
97713e6c29 working on lua module 2024-02-25 11:09:24 -06:00
Aaron Blakely
aa5cfa756f fix duplicate allocation of irc buffers 2024-02-23 20:00:26 -06:00
Aaron Blakely
4d025dde85 current 2024-02-23 19:57:59 -06:00
Aaron Blakely
c4e1ad5af7 current snap 2024-02-21 08:24:49 -06:00
Aaron Blakely
3cd8871b24 make uptime module work on win32 2024-02-17 03:50:15 -06:00
28 changed files with 1662 additions and 54 deletions

View File

@ -21,6 +21,7 @@ main:
$(CC) $(CFLAGS) $(SRC)/events.c -o $(OBJ)/events.o $(CC) $(CFLAGS) $(SRC)/events.c -o $(OBJ)/events.o
$(CC) $(CFLAGS) $(SRC)/module.c -o $(OBJ)/module.o $(CC) $(CFLAGS) $(SRC)/module.c -o $(OBJ)/module.o
$(CC) $(CFLAGS) $(SRC)/channel.c -o $(OBJ)/channel.o $(CC) $(CFLAGS) $(SRC)/channel.c -o $(OBJ)/channel.o
$(CC) $(CFLAGS) $(SRC)/timers.c -o $(OBJ)/timers.o
$(CC) -o $(EXEC) $(OBJECTS) $(BINFLAGS) $(CC) -o $(EXEC) $(OBJECTS) $(BINFLAGS)
@echo "All Done!" @echo "All Done!"
@ -29,6 +30,8 @@ mods: $(MODS_DIR)
$(MODS_DIR): $(MODS_DIR):
$(MAKE) -C $@ $(MAKE) -C $@
all: main mods
clean: clean:
@rm -rf build $(EXEC) @rm -rf build $(EXEC)
@rm -rf mods/*.so @rm -rf mods/*.so

View File

@ -50,6 +50,8 @@ struct channel
struct user *users; struct user *users;
}; };
extern struct channel *channels[60];
void add_channel(char *name); void add_channel(char *name);
void remove_channel(char *name); void remove_channel(char *name);
void add_user_to_channel(char *user, char *host, char *chan); void add_user_to_channel(char *user, char *host, char *chan);
@ -61,6 +63,10 @@ void update_server(char *nick, char *server);
void update_realname(char *nick, char *real_name); void update_realname(char *nick, char *real_name);
void user_quit(char *nick); void user_quit(char *nick);
void set_realname(char *nick, char *real_name); void set_realname(char *nick, char *real_name);
struct user *get_user(char *nick);
MY_API char *get_user_host(char *nick);
MY_API char *get_user_user(char *nick);
#ifdef _WIN32 #ifdef _WIN32
MY_API BOOL is_op(char *chan, char *nick); MY_API BOOL is_op(char *chan, char *nick);

View File

@ -19,6 +19,7 @@
#define IRC_END_MOTD "376" #define IRC_END_MOTD "376"
#define IRC_NAMREPLY "353" #define IRC_NAMREPLY "353"
#define IRC_WHOREPLY "352" #define IRC_WHOREPLY "352"
#define TICK "TICK"
struct ev_handler struct ev_handler
{ {
@ -33,6 +34,7 @@ struct handler
struct ev_handler *evhands; struct ev_handler *evhands;
}; };
extern struct handler *handlers[512];
void init_events(); void init_events();
MY_API int add_handler(char *type, void *handler); MY_API int add_handler(char *type, void *handler);

View File

@ -13,6 +13,8 @@
#include <winsock2.h> #include <winsock2.h>
#endif #endif
#define OUTBUF_SIZE 60000
#define INBUF_SIZE 60000
struct irc_conn struct irc_conn
{ {
@ -29,8 +31,8 @@ struct irc_conn
char real_name[512]; char real_name[512];
// I/O Buffers // I/O Buffers
char out[4096]; char *out;
char in[4096]; char *in;
}; };
typedef struct handler event_handler; typedef struct handler event_handler;
@ -53,7 +55,9 @@ MY_API void irc_privmsg(struct irc_conn *bot, char *to, char *fmt, ...);
MY_API void irc_raw(struct irc_conn *bot, char *fmt, ...); MY_API void irc_raw(struct irc_conn *bot, char *fmt, ...);
MY_API void irc_join(struct irc_conn *bot, char *channel); MY_API void irc_join(struct irc_conn *bot, char *channel);
MY_API void irc_part(struct irc_conn *bot, char *channel, char *reason); MY_API void irc_part(struct irc_conn *bot, char *channel, char *reason);
MY_API void irc_ban(struct irc_conn *bot, char *channel, char *nick);
MY_API void irc_kick(struct irc_conn *bot, char *channel, char *user, char *reason);
MY_API void irc_mode(struct irc_conn *bot, char *channel, char *mode);
void irc_parse_raw(struct irc_conn *bot, char *raw); void irc_parse_raw(struct irc_conn *bot, char *raw);

View File

@ -32,12 +32,16 @@ struct mods {
struct module *modules; struct module *modules;
}; };
extern struct mods *mods;
void init_mods(); void init_mods();
void load_module(struct irc_conn *bot, char *where, char *stype, char *file); void load_module(struct irc_conn *bot, char *where, char *stype, char *file);
void unload_module(struct irc_conn *bot, char *where, char *file); void unload_module(struct irc_conn *bot, char *where, char *file);
void list_modules(struct irc_conn *bot, char *where); void list_modules(struct irc_conn *bot, char *where);
void set_bot(struct irc_conn *b);
MY_API void register_module(char *name, char *author, char *version, char *description); MY_API void register_module(char *name, char *author, char *version, char *description);
MY_API void unregister_module(char *name); MY_API void unregister_module(char *name);
MY_API struct mods *get_mods(); MY_API struct mods *get_mods();
MY_API struct irc_conn *get_bot();
#endif #endif

58
lib/timers.h Executable file
View File

@ -0,0 +1,58 @@
#ifndef TIMERS_H
#define TIMERS_H
#include "irc.h"
#include "util.h"
#include <time.h>
#ifdef _WIN32
#include <windef.h>
#else
#include <stdbool.h>
#endif
struct timer
{
int id;
char name[50];
int interval;
int repeat;
int repeat_count;
#ifdef _WIN32
BOOL active;
#else
bool active;
#endif
time_t next_run;
struct irc_conn *bot;
void *handler;
void *data;
};
struct timers
{
int count;
struct timer *timers;
};
extern struct timers *timers;;
void init_timers();
MY_API int add_timer(struct irc_conn *bot, int interval, int repeat, void *handler, void *data);
MY_API void set_timer_name(int id, char *name);
MY_API int get_timer_repeat(int id);
MY_API void del_timer(int id);
#ifdef _WIN32
MY_API BOOL active_timers();
#else
MY_API bool active_timers();
#endif
void add_to_delete_queue(int id);
void fire_timers();
#endif

7
mods/chanop/Makefile Executable file
View File

@ -0,0 +1,7 @@
CC=gcc
CFLAGS=-fPIC -I../../lib
OBJ=../chanop.so
main:
$(CC) -shared -o $(OBJ) $(CFLAGS) ./chanop.c
@echo "All Done!"

108
mods/chanop/chanop.c Executable file
View File

@ -0,0 +1,108 @@
#include "channel.h"
#define MY_DLL_EXPORTS 1
#include "util.h"
#include "irc.h"
#include "events.h"
#include "module.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windef.h>
BOOL hasAccess(char *user, char *chan)
{
if (is_op(chan, user) || is_halfop(chan, user))
{
return TRUE;
}
else
{
return FALSE;
}
}
#else
#include <stdbool.h>
bool hasAccess(char *user, char *chan)
{
if (is_op(chan, user) || is_halfop(chan, user))
{
return true;
}
else
{
return false;
}
}
#endif
MY_API void chanop_privmsg_handler(struct irc_conn *bot, char *user, char *host, char *chan, const char *text)
{
char *nick;
char *buf = (char *)malloc(sizeof(char *) * 500);
int sn = 1;
if (strstr(text, "!kb") != NULL)
{
if (!hasAccess(user, chan))
goto NO_ACCESS;
nick = skip((char *)text, ' ');
sprintf(buf, "Requested by %s", user);
irc_ban(bot, chan, nick);
irc_kick(bot, chan, nick, buf);
}
else if (strstr(text, "!op") != NULL)
{
if (!hasAccess(user, chan))
goto NO_ACCESS;
nick = skip((char *)text, ' ');
irc_raw(bot, "MODE %s +o %s", chan, nick);
}
else if (strstr(text, "!deop") != NULL)
{
if (!hasAccess(user, chan))
goto NO_ACCESS;
nick = skip((char *)text, ' ');
irc_raw(bot, "MODE %s -o %s", chan, nick);
}
else if (strstr(text, "!voice") != NULL)
{
if (!hasAccess(user, chan))
goto NO_ACCESS;
nick = skip((char *)text, ' ');
irc_raw(bot, "MODE %s +v %s", chan, nick);
}
else if (strstr(text, "!devoice") != NULL)
{
if (!hasAccess(user, chan))
goto NO_ACCESS;
nick = skip((char *)text, ' ');
irc_raw(bot, "MODE %s -v %s", chan, nick);
}
sn = 0;
NO_ACCESS:
if (sn)
irc_notice(bot, user, "You do not have access to use that command in %s", chan);
free(buf);
}
MY_API void mod_init()
{
register_module("chanop", "Aaron Blakely", "v0.1", "Channel Operator module");
add_handler(PRIVMSG_CHAN, chanop_privmsg_handler);
}
MY_API void mod_unload()
{
unregister_module("chanop");
del_handler(PRIVMSG_CHAN, chanop_privmsg_handler);
}

View File

@ -1,27 +1,61 @@
#define MY_DLL_EXPORTS 1 #define MY_DLL_EXPORTS 1
#include "util.h"
#include "irc.h" #include "irc.h"
#include "events.h" #include "events.h"
#include "module.h" #include "module.h"
#include "timers.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct said_hi
{
int timer_id;
int repeat;
char user[50];
char host[150];
char chan[70];
};
MY_API void said_h(struct irc_conn *bot, void *data)
{
struct said_hi *hi = (struct said_hi *)data;
irc_privmsg(bot, hi->chan, "[timer %d] %d : %s", hi->timer_id, get_timer_repeat(hi->timer_id), hi->user);
if ((get_timer_repeat(hi->timer_id) + 1) > hi->repeat)
{
free(hi);
}
}
MY_API void hello(struct irc_conn *bot, char *user, char *host, char *chan, const char *text) MY_API void hello(struct irc_conn *bot, char *user, char *host, char *chan, const char *text)
{ {
struct said_hi *hi;
char *buf = (char *)malloc(sizeof(char *) * 500); char *buf = (char *)malloc(sizeof(char *) * 500);
sprintf(buf, "hi %s", bot->nick); sprintf(buf, "hi %s", bot->nick);
if (!strcmp(text, buf)) if (!strcmp(text, buf))
{ {
hi = calloc(1, sizeof(struct said_hi));
irc_privmsg(bot, chan, "hi %s", user); irc_privmsg(bot, chan, "hi %s", user);
printf("%s said hi to me\n", user); sprintf(hi->user, "%s", user);
sprintf(hi->host, "%s", host);
sprintf(hi->chan, "%s", chan);
hi->repeat = 3;
hi->timer_id = add_timer(bot, 10, hi->repeat, said_h, hi);
} }
free(buf); free(buf);
} }
MY_API void hello_join(struct irc_conn *bot, char *user, char *host, char *chan) MY_API void hello_join(struct irc_conn *bot, char *user, char *host, char *chan)
{ {
printf("%s!%s joined %s\n", user, host, chan); printf("%s!%s joined %s\n", user, host, chan);

7
mods/lua/Makefile Executable file
View File

@ -0,0 +1,7 @@
CC=gcc
CFLAGS=-g -fPIC -I../../lib -llua
OBJ=../lua.so
main:
$(CC) -shared -o $(OBJ) $(CFLAGS) ./wrappers.c ./events.c ./handlers.c ./lua.c
@echo "All Done!"

272
mods/lua/events.c Executable file
View File

@ -0,0 +1,272 @@
#include "lua.h"
#include "events.h"
#include <lua5.3/lua.h>
#include <string.h>
#include <stdlib.h>
int block = 0;
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 (block)
{
// return error
return !LUA_OK;
}
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;
printf("lua_fire_handlers: %s\n", event);
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);
printf("dbug: %s %d %d\n", lua.events[i].event, lua.events[i].lreg, lua.event_count);
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);
}

128
mods/lua/handlers.c Executable file
View File

@ -0,0 +1,128 @@
#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);
lua_load_script(bot, user, host, chan, text);
lua_unload_script(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);
}

38
mods/lua/init.lua Executable file
View File

@ -0,0 +1,38 @@
-- init.lua: xbot runtime script
-- Do not modify this file unless you know what you are doing.
--
-- Written by Aaron Blakely
local handlerstore = {}
function add_handler(type, func)
local ret = _add_handler(type, func)
local callfilename = debug.getinfo(2, "S").source
if ret then
table.insert(handlerstore, {type, func, ret, callfilename})
end
end
function del_handler(type, func)
local callfilename = debug.getinfo(2, "S").source
-- loop through the handlerstore and remove the handler
for i, v in ipairs(handlerstore) do
print("called with type: " .. type .. "callfilename: " .. callfilename)
print("dbug: type: " .. v[1] .. " func: " .. v[3] .. " callfilename: " .. v[4])
if v[2] == func then
print("dbug: ref found")
end
if v[1] == type and v[2] == func and v[4] == callfilename then
_del_handler(type, v[3])
table.remove(handlerstore, i)
return
end
end
print("Handler not found")
end

377
mods/lua/lua.c Executable file
View File

@ -0,0 +1,377 @@
#define MY_DLL_EXPORTS 1
#include "util.h"
#include "irc.h"
#include "events.h"
#include "module.h"
#include "timers.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include "lua.h"
struct lua_interp lua;
struct irc_conn *instance;
char *scriptsfile = "./mods/lua/scripts";
int append_script(char *fname)
{
FILE *fp;
char *buf = (char *)malloc(sizeof(char *) * 500);
// check if the file is already in the list
struct script_list list = get_scripts();
for (int i = 0; i < list.count; i++)
{
if (strcmp(list.scripts[i], fname) == 0)
{
free(buf);
return 0;
}
}
if ((fp = fopen(scriptsfile, "a")) == NULL)
{
free(buf);
return -1;
}
sprintf(buf, "%s\n", fname);
fputs(buf, fp);
fclose(fp);
free(buf);
return 0;
}
int remove_script(char *fname)
{
FILE *fp;
char *buf = (char *)malloc(sizeof(char *) * 500);
char *tmpfile = "./mods/lua/scripts.tmp";
if ((fp = fopen(scriptsfile, "r")) == NULL)
{
free(buf);
return -1;
}
FILE *tmp = fopen(tmpfile, "w");
while (fgets(buf, 500, fp) != NULL)
{
if (strcmp(buf, fname) != 0)
{
fputs(buf, tmp);
}
}
fclose(fp);
fclose(tmp);
remove(scriptsfile);
rename(tmpfile, scriptsfile);
free(buf);
return 0;
}
struct script_list get_scripts()
{
FILE *fp;
char *buf = (char *)malloc(sizeof(char *) * 500);
struct script_list list;
int i = 0;
if ((fp = fopen(scriptsfile, "r")) == NULL)
{
free(buf);
list.count = 0;
return list;
}
while (fgets(buf, 500, fp) != NULL)
{
list.scripts[i] = (char *)malloc(sizeof(char *) * 150);
strlcpy(list.scripts[i], buf, 150);
// remove newline
list.scripts[i][strlen(list.scripts[i]) - 1] = '\0';
i++;
}
list.count = i;
free(buf);
return list;
}
MY_API void lua_eval(struct irc_conn *bot, char *user, char *host, char *chan, const char *text)
{
int res;
block = 1;
printf("lua eval called with %s\n", text);
if (strstr(text, "!lua") != NULL)
{
text = skip(text, ' ');
printf("lua: %s\n", text);
res = luaL_loadstring(lua.L, text);
if (res == LUA_OK)
{
res = lua_pcall(lua.L, 0, 0, 0);
if (res != LUA_OK)
{
irc_privmsg(bot, chan, "Error: %s", lua_tostring(lua.L, -1));
lua_pop(lua.L, 1);
}
}
else
{
irc_privmsg(bot, chan, "Error: %s", lua_tostring(lua.L, -1));
lua_pop(lua.L, 1);
}
}
block = 0;
}
MY_API void lua_load_script(struct irc_conn *bot, char *user, char *host, char *chan, const char *text)
{
char *name;
char *script;
char *buf = (char *)malloc(sizeof(char *) * 500);
if (strstr(text, "!load") != NULL)
{
text = skip((char *)text, ' ');
sprintf(buf, "./scripts/%s", text);
strlcpy(lua.scripts[lua.script_count].fname, buf, 150);
if (luaL_loadfile(lua.L, buf) != LUA_OK)
{
if (!strcmp(chan, "-stdio-"))
{
printf("Error loading lua script: %s\n", lua_tostring(lua.L, -1));
}
else
{
irc_privmsg(bot, chan, "Error loading lua script: %s", lua_tostring(lua.L, -1));
}
return;
}
name = basename(buf);
append_script(text);
// execute the script
if (lua_pcall(lua.L, 0, 0, 0) != LUA_OK)
{
if (!strcmp(chan, "-stdio-"))
{
printf("Error executing lua script: %s\n", lua_tostring(lua.L, -1));
}
else
{
irc_privmsg(bot, chan, "Error executing lua script: %s", lua_tostring(lua.L, -1));
}
return;
}
// get a ref to unload function if it exists and store it with luaL_ref
lua_getglobal(lua.L, "unload");
if (lua_isfunction(lua.L, -1))
{
lua.scripts[lua.script_count].unload = luaL_ref(lua.L, LUA_REGISTRYINDEX);
printf("dbg: unload ref: %d\n", lua.scripts[lua.script_count].unload);
}
else
{
lua.scripts[lua.script_count].unload = -1;
if (!strcmp(chan, "-stdio-"))
{
printf("No unload() function in %s\n", name);
}
else
{
irc_privmsg(bot, chan, "No unload() function in %s", name);
}
}
// call the load function if it exists
lua_getglobal(lua.L, "load");
if (lua_isfunction(lua.L, -1))
{
if (lua_pcall(lua.L, 0, 0, 0) != LUA_OK)
{
if (!strcmp(chan, "-stdio-"))
{
printf("Error calling load() in %s: %s\n", buf, lua_tostring(lua.L, -1));
}
else
{
irc_privmsg(bot, chan, "Error calling load() in %s: %s", buf, lua_tostring(lua.L, -1));
}
return;
}
lua.script_count++;
if (!strcmp(chan, "-stdio-"))
{
printf("Loaded %s\n", name);
}
else
{
irc_privmsg(bot, chan, "Loaded %s", name);
}
}
else
{
if (!strcmp(chan, "-stdio-"))
{
printf("Error: No load() function in %s\n", buf);
}
else
{
irc_privmsg(bot, chan, "Error: No load() function in %s", buf);
}
}
}
free(buf);
}
MY_API void lua_unload_script(struct irc_conn *bot, char *user, char *host, char *chan, const char *text)
{
char *name;
char *script;
char *buf = (char *)malloc(sizeof(char *) * 500);
if (strstr(text, "!unload") != NULL)
{
text = skip((char *)text, ' ');
sprintf(buf, "./scripts/%s", text);
irc_privmsg(bot, chan, "Unloading %s", buf);
for (int i = 0; i < lua.script_count; i++)
{
if (strcmp(lua.scripts[i].fname, buf) == 0)
{
// call from the ref in .unload
lua_rawgeti(lua.L, LUA_REGISTRYINDEX, lua.scripts[i].unload);
if (lua_pcall(lua.L, 0, 0, 0) != LUA_OK)
{
irc_privmsg(bot, chan, "Error calling unload() in %s: %s", buf, lua_tostring(lua.L, -1));
return;
}
luaL_unref(lua.L, LUA_REGISTRYINDEX, lua.scripts[i].unload);
lua.scripts[i].unload = -1;
remove_script(text);
sprintf(buf, "Unloaded %s", text);
irc_privmsg(bot, chan, buf);
while (i < lua.script_count)
{
lua.scripts[i] = lua.scripts[i + 1];
i++;
}
lua.script_count--;
free(buf);
return;
}
}
irc_privmsg(bot, chan, "Error: %s not loaded", text);
}
free(buf);
}
void lua_setvar(char *name, char *value)
{
lua_pushstring(lua.L, value);
lua_setglobal(lua.L, name);
}
MY_API void mod_init()
{
char *buf = (char *)malloc(sizeof(char *) * 500);
struct script_list list = get_scripts();
instance = get_bot();
lua.scripts = calloc(512, sizeof(struct lua_script));
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_init_wrappers();
lua_init_events();
lua_init_handlers();
register_module("lua", "Aaron Blakely", "v0.1", "Lua module");
// load init.lua
if (luaL_loadfile(lua.L, "./mods/lua/init.lua") != LUA_OK)
{
printf("Error loading init.lua: %s\n", lua_tostring(lua.L, -1));
return;
}
if (lua_pcall(lua.L, 0, 0, 0) != LUA_OK)
{
printf("Error executing init.lua: %s\n", lua_tostring(lua.L, -1));
return;
}
for (int i = 0; i < list.count; i++)
{
printf("Loading %s\n", list.scripts[i]);
sprintf(buf, "!load %s", list.scripts[i]);
lua_load_script(instance, "lua", "localhost", "-stdio-", buf);
}
printf("Lua module loaded\n");
free(buf);
}
MY_API void mod_unload()
{
lua_close(lua.L);
free(lua.scripts);
free(lua.events);
unregister_module("lua");
del_handler(PRIVMSG_CHAN, lua_eval);
printf("Lua module unloaded\n");
}

88
mods/lua/lua.h Executable file
View File

@ -0,0 +1,88 @@
#ifndef LUA_H
#define LUA_H
#include <lua5.3/lua.h>
#include <lua5.3/lauxlib.h>
#include <lua5.3/lualib.h>
#include "irc.h"
struct lua_script
{
char name[25];
char author[50];
char version[10];
char description[256];
char fname[256];
int unload;
};
struct lua_event
{
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;
};
struct script_list
{
int count;
char *scripts[512];
};
extern int block;
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);
int append_script(char *fname);
int remove_script(char *fname);
struct script_list get_scripts();
MY_API void lua_eval(struct irc_conn *bot, char *user, char *host, char *chan, const char *text);
MY_API void lua_load_script(struct irc_conn *bot, char *user, char *host, char *chan, const char *text);
MY_API void lua_unload_script(struct irc_conn *bot, char *user, char *host, char *chan, const char *text);
#endif

22
mods/lua/wrappers.c Executable file
View 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);
}

View File

@ -1,3 +1,5 @@
#define MY_DLL_EXPORTS 1
#include "irc.h" #include "irc.h"
#include "events.h" #include "events.h"
#include "module.h" #include "module.h"
@ -5,13 +7,151 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef _WIN32
#define BUFFER_SIZE 512
#include <windows.h>
void parseUptime(const char *output, struct irc_conn *bot, const char *where) {
const char *keyword = "Statistics since ";
const char *uptime_start;
int month, day, year, hour, minute;
SYSTEMTIME uptime_systemtime, current_time;
ULONGLONG uptime_ticks, current_ticks;
ULONGLONG uptime_seconds;
char buf[BUFFER_SIZE];
int days, hours, minutes;
OSVERSIONINFOEX osInfo;
ZeroMemory(&osInfo, sizeof(OSVERSIONINFOEX));
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
uptime_start = strstr(output, keyword);
if (uptime_start == NULL) {
printf("Failed to parse uptime information.\n");
return;
}
// Skip the "Statistics since " keyword
uptime_start += strlen(keyword);
// Parse the date and time
if (sscanf(uptime_start, "%d/%d/%d %d:%d", &month, &day, &year, &hour, &minute) != 5) {
printf("Failed to parse date and time.\n");
return;
}
// Get the current time
GetLocalTime(&current_time);
// Calculate the uptime
uptime_systemtime.wYear = year;
uptime_systemtime.wMonth = month;
uptime_systemtime.wDayOfWeek = 0;
uptime_systemtime.wDay = day;
uptime_systemtime.wHour = hour;
uptime_systemtime.wMinute = minute;
uptime_systemtime.wSecond = 0;
uptime_systemtime.wMilliseconds = 0;
SystemTimeToFileTime(&uptime_systemtime, (FILETIME *)&uptime_ticks);
SystemTimeToFileTime(&current_time, (FILETIME *)&current_ticks);
uptime_seconds = (current_ticks - uptime_ticks) / 10000000UL; // Convert to seconds
uptime_seconds -= 1470;
days = uptime_seconds / (24 * 3600);
hours = (uptime_seconds % (24 * 3600)) / 3600;
minutes = (uptime_seconds % 3600) / 60;
if (GetVersionEx((OSVERSIONINFO*)&osInfo)) {
if (osInfo.dwMajorVersion == 10 && osInfo.dwMinorVersion == 0) {
sprintf(buf, "Windows 10");
} else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 3) {
sprintf(buf, "Windows 8.1");
} else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 2) {
sprintf(buf, "Windows 8");
} else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 1) {
// detect Windows 7 or Windows Server 2008 R2
if (osInfo.wProductType == VER_NT_WORKSTATION) {
sprintf(buf, "Windows 7");
} else {
sprintf(buf, "Windows Server 2008 R2");
}
} else if (osInfo.dwMajorVersion == 6 && osInfo.dwMinorVersion == 0) {
// detect Windows Vista or Windows Server 2008
if (osInfo.wProductType == VER_NT_WORKSTATION) {
sprintf(buf, "Windows Vista");
} else {
sprintf(buf, "Windows Server 2008");
}
} else if (osInfo.dwMajorVersion == 5 && osInfo.dwMinorVersion == 1) {
// detect Windows XP or Windows Server 2003
if (osInfo.wProductType == VER_NT_WORKSTATION) {
sprintf(buf, "Windows XP");
} else {
sprintf(buf, "Windows Server 2003");
}
} else if (osInfo.dwMajorVersion == 5 && osInfo.dwMinorVersion == 0) {
sprintf(buf, "Windows 2000");
} else {
sprintf(buf, "Windows");
}
}
irc_privmsg(bot, where, "%s: %d days, %d hours, and %d minutes up\n", buf, days, hours, minutes);
}
char *executeCommand(const char *command)
{
char buffer[BUFFER_SIZE];
char *old_result = NULL;
char *result = NULL;
FILE *fp;
fp = _popen(command, "r");
if (fp == NULL) {
printf("Failed to run command\n");
exit(1);
}
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
if (result == NULL) {
result = _strdup(buffer);
} else {
old_result = result;
result = malloc(strlen(old_result) + strlen(buffer) + 1);
strcpy(result, old_result);
strcat(result, buffer);
free(old_result);
}
}
_pclose(fp);
return result;
}
#endif
MY_API void up(struct irc_conn *bot, char *user, char *host, char *chan, char *text) MY_API void up(struct irc_conn *bot, char *user, char *host, char *chan, char *text)
{ {
#ifdef _WIN32
char *output;
if (!strcmp(text, "!uptime"))
{
output = executeCommand("net statistics server");
parseUptime(output, bot, chan);
free(output);
}
#else
char buf[100]; char buf[100];
FILE* file; FILE* file;
printf("dbug up called: %s!%s %s\n", user, host, text);
if (!strcmp(text, "!uptime")) if (!strcmp(text, "!uptime"))
{ {
file = popen("uptime", "r"); file = popen("uptime", "r");
@ -20,7 +160,7 @@ MY_API void up(struct irc_conn *bot, char *user, char *host, char *chan, char *t
irc_privmsg(bot, chan, "%s", buf); irc_privmsg(bot, chan, "%s", buf);
} }
#endif
} }
MY_API void mod_init() MY_API void mod_init()

20
scripts/hello.lua Executable file
View File

@ -0,0 +1,20 @@
NAME = "hello"
VERSION = "v0.5"
AUTHOR = "Aaron Blakely"
DESCRIPTION = "A simple hello world script for xbot"
function hi(nick, host, chan, text)
privmsg(chan, "Hello, " .. nick .. " from hello.lua!!!!!")
end
function load()
-- register_script(NAME, VERSION, AUTHOR, DESCRIPTION)
add_handler(PRIVMSG_CHAN, hi)
end
function unload()
-- unregister_script(NAME)
del_handler(PRIVMSG_CHAN, hi)
end

25
scripts/test.lua Executable file
View File

@ -0,0 +1,25 @@
local NAME = "hello"
local VERSION = "v0.5"
local AUTHOR = "Aaron Blakely"
local DESCRIPTION = "A simple hello world script for xbot"
function test(nick, host, chan, text)
-- check if text contains "hello"
if string.find(text, "hello") then
privmsg(chan, "Hello, " .. nick .. " from test.lua!!!")
end
end
function load()
-- register_script(NAME, VERSION, AUTHOR, DESCRIPTION)
add_handler(PRIVMSG_CHAN, test)
end
function unload()
-- unregister_script(NAME)
del_handler(PRIVMSG_CHAN, test)
end

View File

@ -49,9 +49,28 @@ void remove_channel(char *name)
} }
} }
struct user *get_user(char *nick)
{
int i, j;
for (i = 0; i < chan_count; i++)
{
for (j = 0; j < channels[i]->user_count; j++)
{
if (!strcmp(channels[i]->users[j].nick, nick))
{
return &channels[i]->users[j];
}
}
}
return NULL;
}
void add_user_to_channel(char *user, char *host, char *chan) void add_user_to_channel(char *user, char *host, char *chan)
{ {
int i; int i;
struct user *u, *uc;
#ifdef _WIN32 #ifdef _WIN32
BOOL is_op, is_voice, is_halfop, is_owner, is_admin; BOOL is_op, is_voice, is_halfop, is_owner, is_admin;
@ -107,6 +126,21 @@ void add_user_to_channel(char *user, char *host, char *chan)
{ {
if (!strcmp(channels[i]->name, chan)) if (!strcmp(channels[i]->name, chan))
{ {
if (get_user(user) != NULL)
{
u = get_user(user);
u->is_op = is_op | is_owner | is_admin;
u->is_voice = is_voice | is_halfop | is_op | is_owner | is_admin;
u->is_halfop = is_halfop;
u->is_owner = is_owner;
u->is_admin = is_admin;
channels[i]->users[channels[i]->user_count] = *u;
channels[i]->user_count++;
return;
}
strlcpy(channels[i]->users[channels[i]->user_count].nick, user, 50); strlcpy(channels[i]->users[channels[i]->user_count].nick, user, 50);
strlcpy(channels[i]->users[channels[i]->user_count].host, host, 256); strlcpy(channels[i]->users[channels[i]->user_count].host, host, 256);
@ -267,6 +301,43 @@ void set_realname(char *nick, char *real_name)
} }
} }
MY_API char *get_user_host(char *nick)
{
int i, j;
for (i = 0; i < chan_count; i++)
{
for (j = 0; j < channels[i]->user_count; j++)
{
if (!strcmp(channels[i]->users[j].nick, nick))
{
return channels[i]->users[j].host;
}
}
}
return NULL;
}
char *get_user_user(char *nick)
{
int i, j;
for (i = 0; i < chan_count; i++)
{
for (j = 0; j < channels[i]->user_count; j++)
{
if (!strcmp(channels[i]->users[j].nick, nick))
{
return channels[i]->users[j].user;
}
}
}
return NULL;
}
#ifdef _WIN32 #ifdef _WIN32
MY_API BOOL is_op(char *chan, char *nick) MY_API BOOL is_op(char *chan, char *nick)
#else #else

View File

@ -11,13 +11,8 @@
#include <ctype.h> #include <ctype.h>
#endif #endif
struct handler *privmsg_self;
struct handler *privmsg_chan;
struct handler *chan_join;
struct handler *irc_connected;
int handlers_count = 0;
struct handler *handlers[512]; struct handler *handlers[512];
int handlers_count = 0;
void init_event_type(char *type) void init_event_type(char *type)
{ {
@ -31,6 +26,7 @@ void init_event_type(char *type)
void init_events() void init_events()
{ {
init_event_type(TICK);
init_event_type(PRIVMSG_SELF); init_event_type(PRIVMSG_SELF);
init_event_type(PRIVMSG_CHAN); init_event_type(PRIVMSG_CHAN);
init_event_type(JOIN); init_event_type(JOIN);
@ -93,10 +89,10 @@ MY_API void del_handler(char *type, void *handler)
void fire_handler(struct irc_conn *bot, char *type, ...) void fire_handler(struct irc_conn *bot, char *type, ...)
{ {
va_list args; va_list args;
char *usr = calloc(1, 64); char *usr;
char *host = calloc(1, 512); char *host;
char *chan = calloc(1, 64); char *chan;
char *text = calloc(1, 512); char *text;
int i, j; int i, j;
void (*handler)(); void (*handler)();
char *cmd, *arg, *modpath; char *cmd, *arg, *modpath;
@ -136,7 +132,7 @@ void fire_handler(struct irc_conn *bot, char *type, ...)
irc_notice(bot, usr, "You are unauthorized to use this command."); irc_notice(bot, usr, "You are unauthorized to use this command.");
} }
} }
else if (!strcmp("PRINT_HANDLERS", cmd)) else if (!strcmp("HANDLERS", cmd))
{ {
if (!strcmp(bot->admin, usr)) if (!strcmp(bot->admin, usr))
{ {

View File

@ -142,9 +142,10 @@ void irc_raw(struct irc_conn *bot, char *fmt, ...)
{ {
va_list ap; va_list ap;
char outbuf[4096]; char outbuf[4096];
char *p;
va_start(ap, fmt); va_start(ap, fmt);
vsnprintf(bot->out, sizeof bot->out, fmt, ap); vsnprintf(bot->out, OUTBUF_SIZE, fmt, ap);
va_end(ap); va_end(ap);
sprintf(outbuf, "%s\r\n", bot->out); sprintf(outbuf, "%s\r\n", bot->out);
@ -175,6 +176,29 @@ void irc_part(struct irc_conn *bot, char *chan, char *reason)
irc_raw(bot, "PART %s :%s", chan, reason); irc_raw(bot, "PART %s :%s", chan, reason);
} }
void irc_ban(struct irc_conn *bot, char *channel, char *user)
{
char *host = get_user_host(user);
char *un = get_user_user(user);
irc_raw(bot, "MODE %s +b *!%s@%s", channel, un, host);
}
void irc_kick(struct irc_conn *bot, char *channel, char *user, char *reason)
{
if (!reason)
{
reason = "";
}
irc_raw(bot, "KICK %s %s :%s", channel, user, reason);
}
void irc_mode(struct irc_conn *bot, char *channel, char *mode)
{
irc_raw(bot, "MODE %s %s", channel, mode);
}
void irc_ctcp(struct irc_conn *bot, char *to, char *fmt, ...) void irc_ctcp(struct irc_conn *bot, char *to, char *fmt, ...)
{ {
char msg_[4096]; char msg_[4096];
@ -192,8 +216,6 @@ void irc_parse_raw(struct irc_conn *bot, char *raw)
char *user, *host, *par, *text, *chan, *nick, *nicks, *tmp; char *user, *host, *par, *text, *chan, *nick, *nicks, *tmp;
user = bot->host; user = bot->host;
text = calloc(1, strlen(raw) + 1);
if (!raw || !*raw) if (!raw || !*raw)
{ {
return; return;
@ -315,7 +337,7 @@ void irc_parse_raw(struct irc_conn *bot, char *raw)
#ifdef _WIN32 #ifdef _WIN32
_snprintf(bot->nick, sizeof bot->nick, "%s_", bot->nick); _snprintf(bot->nick, sizeof bot->nick, "%s_", bot->nick);
#else #else
snprintf(bot->nick, sizeof bot->nick, "%s_", bot->nick); sprintf(bot->nick, "%s_", bot->nick);
#endif #endif
irc_raw(bot, "NICK %s", bot->nick); irc_raw(bot, "NICK %s", bot->nick);
} }
@ -334,14 +356,20 @@ void irc_parse_raw(struct irc_conn *bot, char *raw)
while (nick) while (nick)
{ {
add_user_to_channel(nick, "", chan);
tmp = nick; tmp = nick;
if (nick[0] == '@' || nick[0] == '+' || nick[0] == '%' || nick[0] == '~' || nick[0] == '&') if (nick[0] == '@' || nick[0] == '+' || nick[0] == '%' || nick[0] == '~' || nick[0] == '&')
{ {
tmp++; tmp++;
} }
if (get_user(tmp))
{
nick = strtok(NULL, " ");
continue;
}
add_user_to_channel(nick, "", chan);
irc_raw(bot, "WHO %s", tmp); irc_raw(bot, "WHO %s", tmp);
nick = strtok(NULL, " "); nick = strtok(NULL, " ");
} }
@ -376,4 +404,5 @@ void irc_parse_raw(struct irc_conn *bot, char *raw)
fire_handler(bot, NICK_MYSELF, user, text); fire_handler(bot, NICK_MYSELF, user, text);
} }
} }
} }

View File

@ -15,6 +15,7 @@
#include "events.h" #include "events.h"
#include "module.h" #include "module.h"
#include "channel.h" #include "channel.h"
#include "timers.h"
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
@ -22,7 +23,6 @@
#include <sys/select.h> #include <sys/select.h>
#endif #endif
static time_t trespond; static time_t trespond;
int main() int main()
@ -31,12 +31,20 @@ int main()
fd_set rd; fd_set rd;
struct irc_conn bot; struct irc_conn bot;
struct timeval tv; struct timeval tv;
struct timeval last_ping;
char *p; char *p;
int bytesRecv; int bytesRecv;
bot.in = calloc(INBUF_SIZE, sizeof(char));
bot.out = calloc(OUTBUF_SIZE, sizeof(char));
last_ping.tv_sec = time(NULL);
set_bot(&bot);
init_events(); init_events();
init_timers();
init_mods(); init_mods();
// Read the config // Read the config
@ -46,10 +54,15 @@ int main()
printf("Connecting to %s...\n", bot.host); printf("Connecting to %s...\n", bot.host);
irc_connect(&bot); irc_connect(&bot);
trespond = time(NULL);
irc_auth(&bot); irc_auth(&bot);
for (;;) for (;;)
{ {
fire_timers();
fire_handler(&bot, TICK, NULL);
FD_ZERO(&rd); FD_ZERO(&rd);
#ifdef _WIN32 #ifdef _WIN32
@ -58,7 +71,7 @@ int main()
FD_SET(0, &rd); FD_SET(0, &rd);
FD_SET(fileno(bot.srv_fd), &rd); FD_SET(fileno(bot.srv_fd), &rd);
#endif #endif
tv.tv_sec = 120; tv.tv_sec = 1;
tv.tv_usec = 0; tv.tv_usec = 0;
#ifdef _WIN32 #ifdef _WIN32
@ -90,13 +103,18 @@ int main()
return -1; return -1;
} }
if (time(NULL) - last_ping.tv_sec >= 120)
{
last_ping.tv_sec = time(NULL);
irc_raw(&bot, "PING %s", bot.host); irc_raw(&bot, "PING %s", bot.host);
}
continue; continue;
} }
#ifdef _WIN32 #ifdef _WIN32
if (FD_ISSET(bot.srv_fd, &rd)) if (FD_ISSET(bot.srv_fd, &rd))
{ {
bytesRecv = recv(bot.srv_fd, bot.in, sizeof(bot.in), 0); bytesRecv = recv(bot.srv_fd, bot.in, INBUF_SIZE, 0);
if (bytesRecv == SOCKET_ERROR) if (bytesRecv == SOCKET_ERROR)
{ {
eprint("Error receiving data: %d\n", WSAGetLastError()); eprint("Error receiving data: %d\n", WSAGetLastError());
@ -118,7 +136,6 @@ int main()
// split bot.in into lines by \r\n and parse each one // split bot.in into lines by \r\n and parse each one
while (1) while (1)
{ {
// remove \r // remove \r
@ -131,10 +148,12 @@ int main()
irc_parse_raw(&bot, bot.in); irc_parse_raw(&bot, bot.in);
memmove(bot.in, p + 1, strlen(p + 1) + 1); memmove(bot.in, p + 1, strlen(p + 1) + 1);
} }
free(p);
#else #else
if (FD_ISSET(fileno(bot.srv_fd), &rd)) if (FD_ISSET(fileno(bot.srv_fd), &rd))
{ {
if (fgets(bot.in, sizeof bot.in, bot.srv_fd) == NULL) if (fgets(bot.in, INBUF_SIZE, bot.srv_fd) == NULL)
{ {
eprint("xbot: remote host closed connection\n"); eprint("xbot: remote host closed connection\n");
return 0; return 0;
@ -145,6 +164,7 @@ int main()
#endif #endif
trespond = time(NULL); trespond = time(NULL);
} }
} }
return 0; return 0;

View File

@ -13,6 +13,7 @@
#endif #endif
struct mods *mods; struct mods *mods;
struct irc_conn *instance;
void init_mods() void init_mods()
{ {
@ -23,14 +24,17 @@ void init_mods()
void load_module(struct irc_conn *bot, char *where, char *stype, char *file) void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
{ {
char *error = (char *)malloc(sizeof(char *)*1024);
strlcpy(mods->modules[mods->count].fname, file, 256);
#ifdef _WIN32
char *error = (char *)malloc(sizeof(char *)*1024);
#ifdef _WIN32
DWORD err;
strlcpy(mods->modules[mods->count].fname, file, 256);
mods->modules[mods->count].handle = LoadLibrary(file); mods->modules[mods->count].handle = LoadLibrary(file);
if (mods->modules[mods->count].handle == NULL) if (mods->modules[mods->count].handle == NULL)
{ {
sprintf(error, "Error loading %s\n", file); err = GetLastError();
sprintf(error, "Error loading %s: %lu", file, err);
if (strcmp("runtime", stype)) if (strcmp("runtime", stype))
{ {
@ -39,7 +43,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
} }
else if (strcmp(PRIVMSG_CHAN, stype)) else if (strcmp(PRIVMSG_CHAN, stype))
{ {
irc_privmsg(bot, where, error); irc_notice(bot, where, error);
} }
else else
{ {
@ -63,7 +67,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
} }
else if (strcmp(PRIVMSG_CHAN, stype)) else if (strcmp(PRIVMSG_CHAN, stype))
{ {
irc_privmsg(bot, where, error); irc_notice(bot, where, error);
} }
else else
{ {
@ -89,7 +93,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
} }
else if (strcmp(PRIVMSG_CHAN, stype)) else if (strcmp(PRIVMSG_CHAN, stype))
{ {
irc_privmsg(bot, where, error); irc_notice(bot, where, error);
} }
else else
{ {
@ -101,7 +105,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
if (strcmp("runtime", stype)) if (strcmp("runtime", stype))
{ {
irc_privmsg(bot, where, "Module '%s' loaded.", file); irc_notice(bot, where, "Module '%s' loaded.", file);
} }
else else
{ {
@ -111,6 +115,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
#else #else
void (*mod_init)(); void (*mod_init)();
strlcpy(mods->modules[mods->count].fname, file, 256);
mods->modules[mods->count].handle = dlopen(file, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE); mods->modules[mods->count].handle = dlopen(file, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
if (!mods->modules[mods->count].handle) if (!mods->modules[mods->count].handle)
{ {
@ -123,7 +128,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
} }
else if (strcmp(PRIVMSG_CHAN, stype)) else if (strcmp(PRIVMSG_CHAN, stype))
{ {
irc_privmsg(bot, where, error); irc_notice(bot, where, error);
} }
else else
{ {
@ -148,7 +153,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
} }
else if (strcmp(PRIVMSG_CHAN, stype)) else if (strcmp(PRIVMSG_CHAN, stype))
{ {
irc_privmsg(bot, where, error); irc_notice(bot, where, error);
} }
else else
{ {
@ -170,7 +175,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
} }
else if (strcmp(PRIVMSG_CHAN, stype)) else if (strcmp(PRIVMSG_CHAN, stype))
{ {
irc_privmsg(bot, where, error); irc_notice(bot, where, error);
} }
else else
{ {
@ -189,7 +194,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
} }
else if (strcmp(PRIVMSG_CHAN, stype)) else if (strcmp(PRIVMSG_CHAN, stype))
{ {
irc_privmsg(bot, where, error); irc_notice(bot, where, error);
} }
else else
{ {
@ -200,7 +205,7 @@ void load_module(struct irc_conn *bot, char *where, char *stype, char *file)
if (strcmp("runtime", stype)) if (strcmp("runtime", stype))
{ {
irc_privmsg(bot, where, "Module '%s' loaded.", file); irc_notice(bot, where, "Module '%s' loaded.", file);
} }
else else
{ {
@ -229,7 +234,7 @@ void unload_module(struct irc_conn *bot, char *where, char *file)
if (strcmp(PRIVMSG_CHAN, where)) if (strcmp(PRIVMSG_CHAN, where))
{ {
irc_privmsg(bot, where, "Module '%s' unloaded.", file); irc_notice(bot, where, "Module '%s' unloaded.", file);
} }
else else
{ {
@ -242,6 +247,8 @@ void unload_module(struct irc_conn *bot, char *where, char *file)
i++; i++;
} }
mods->count--;
return; return;
} }
} }
@ -298,3 +305,13 @@ MY_API struct mods *get_mods()
{ {
return mods; return mods;
} }
MY_API struct irc_conn *get_bot()
{
return instance;
}
MY_API void set_bot(struct irc_conn *b)
{
instance = b;
}

136
src/timers.c Executable file
View File

@ -0,0 +1,136 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "timers.h"
#include "util.h"
#include "irc.h"
struct timers *timers;
int delete_queue[512];
void init_timers()
{
timers = calloc(1, sizeof(struct timers));
timers->count = 1;
timers->timers = calloc(512, sizeof(struct timer));
}
MY_API int add_timer(struct irc_conn *bot, int interval, int repeat, void *handler, void *data)
{
timers->timers[timers->count].interval = interval;
timers->timers[timers->count].handler = handler;
timers->timers[timers->count].id = timers->count;
timers->timers[timers->count].bot = bot;
timers->timers[timers->count].repeat = repeat;
timers->timers[timers->count].repeat_count = 0;
timers->timers[timers->count].data = data;
timers->timers[timers->count].active = true;
timers->timers[timers->count].next_run = time(NULL) + interval;
timers->count++;
return timers->count - 1;
}
MY_API void set_timer_name(int id, char *name)
{
sprintf(timers->timers[id].name, "%s", name);
}
MY_API int get_timer_repeat(int id)
{
return timers->timers[id].repeat_count;
}
#ifdef _WIN32
MY_API BOOL active_timers()
#else
MY_API bool active_timers()
#endif
{
int i;
for (i = 0; i < timers->count; i++)
{
if (timers->timers[i].active)
{
return true;
}
}
return false;
}
void add_to_delete_queue(int id)
{
int i;
for (i = 0; i < 512; i++)
{
if (delete_queue[i] == 0)
{
delete_queue[i] = id;
break;
}
}
}
MY_API void del_timer(int id)
{
int i;
for (i = 0; i < timers->count; i++)
{
if (timers->timers[i].id == id)
{
while (i < timers->count)
{
timers->timers[i] = timers->timers[i + 1];
i++;
}
timers->count--;
}
}
}
void fire_timers()
{
int i;
void (*handler)();
for (i = 0; i < timers->count; i++)
{
if (timers->timers[i].next_run <= time(NULL))
{
timers->timers[i].next_run = time(NULL) + timers->timers[i].interval;
handler = timers->timers[i].handler;
if (timers->timers[i].active)
(*handler)(timers->timers[i].bot, timers->timers[i].data);
if (timers->timers[i].repeat > 0)
{
timers->timers[i].repeat_count++;
if (timers->timers[i].repeat_count >= timers->timers[i].repeat)
{
timers->timers[i].active = false;
add_to_delete_queue(timers->timers[i].id);
}
}
}
}
if (active_timers() == false)
{
for (i = 0; i < 512; i++)
{
if (delete_queue[i] != 0)
{
del_timer(delete_queue[i]);
delete_queue[i] = 0;
}
}
}
}

View File

@ -3,7 +3,7 @@
bot: bot:
{ {
verbose = 1; verbose = 1;
nick = "Lini"; nick = "xbot";
user = "xbot"; user = "xbot";
admin = "ab3800"; admin = "ab3800";
}; };
@ -16,7 +16,7 @@ server:
mods: mods:
{ {
autoload = ("autojoin", "hello", "uptime"); autoload = ("chanop", "lua", "autojoin", "hello", "uptime");
blacklist = (); blacklist = ();
# config option for mods/autojoin.so # config option for mods/autojoin.so

View File

@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xbot", "xbot.vcxproj", "{F9EBC08A-C550-413C-8CC6-81A232859D94}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xbot", "xbot.vcxproj", "{F9EBC08A-C550-413C-8CC6-81A232859D94}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xbot-mods", "xbot-mods\xbot-mods.vcxproj", "{BB6BFF6F-3972-4F0D-86E9-06FF4EAC5C5A}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
@ -15,10 +13,6 @@ Global
{F9EBC08A-C550-413C-8CC6-81A232859D94}.Debug|Win32.Build.0 = Debug|Win32 {F9EBC08A-C550-413C-8CC6-81A232859D94}.Debug|Win32.Build.0 = Debug|Win32
{F9EBC08A-C550-413C-8CC6-81A232859D94}.Release|Win32.ActiveCfg = Release|Win32 {F9EBC08A-C550-413C-8CC6-81A232859D94}.Release|Win32.ActiveCfg = Release|Win32
{F9EBC08A-C550-413C-8CC6-81A232859D94}.Release|Win32.Build.0 = Release|Win32 {F9EBC08A-C550-413C-8CC6-81A232859D94}.Release|Win32.Build.0 = Release|Win32
{BB6BFF6F-3972-4F0D-86E9-06FF4EAC5C5A}.Debug|Win32.ActiveCfg = Debug|Win32
{BB6BFF6F-3972-4F0D-86E9-06FF4EAC5C5A}.Debug|Win32.Build.0 = Debug|Win32
{BB6BFF6F-3972-4F0D-86E9-06FF4EAC5C5A}.Release|Win32.ActiveCfg = Release|Win32
{BB6BFF6F-3972-4F0D-86E9-06FF4EAC5C5A}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -45,7 +45,7 @@
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</OutDir> <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</IntDir> <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</OutDir> <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</IntDir> <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</LinkIncremental> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</LinkIncremental>
@ -108,6 +108,7 @@
<ClInclude Include="lib\events.h" /> <ClInclude Include="lib\events.h" />
<ClInclude Include="lib\irc.h" /> <ClInclude Include="lib\irc.h" />
<ClInclude Include="lib\module.h" /> <ClInclude Include="lib\module.h" />
<ClInclude Include="lib\timers.h" />
<ClInclude Include="lib\util.h" /> <ClInclude Include="lib\util.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -117,6 +118,7 @@
<ClCompile Include="src\irc.c" /> <ClCompile Include="src\irc.c" />
<ClCompile Include="src\main.c" /> <ClCompile Include="src\main.c" />
<ClCompile Include="src\module.c" /> <ClCompile Include="src\module.c" />
<ClCompile Include="src\timers.c" />
<ClCompile Include="src\util.c" /> <ClCompile Include="src\util.c" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />