Compare commits
10 Commits
f91fac4d1e
...
13bcd3d20e
Author | SHA1 | Date | |
---|---|---|---|
|
13bcd3d20e | ||
|
8ebf060f48 | ||
|
c3281dc946 | ||
|
24e535dbaf | ||
|
3ff13e35b1 | ||
|
b61a71e6ae | ||
|
1ef5bdf07b | ||
|
f275caf11f | ||
|
387ce7338f | ||
|
d7b82df673 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@ mods/test
|
||||
.cache
|
||||
UpgradeLog*.XML
|
||||
|
||||
xbot.db
|
||||
*.so
|
||||
*.dll
|
||||
*.lib
|
||||
|
2
Makefile
2
Makefile
@ -22,6 +22,8 @@ main:
|
||||
$(CC) $(CFLAGS) $(SRC)/module.c -o $(OBJ)/module.o
|
||||
$(CC) $(CFLAGS) $(SRC)/channel.c -o $(OBJ)/channel.o
|
||||
$(CC) $(CFLAGS) $(SRC)/timers.c -o $(OBJ)/timers.o
|
||||
$(CC) $(CFLAGS) $(SRC)/db.c -o $(OBJ)/db.o
|
||||
|
||||
$(CC) -o $(EXEC) $(OBJECTS) $(BINFLAGS)
|
||||
@echo "All Done!"
|
||||
|
||||
|
@ -4,5 +4,6 @@
|
||||
#include "irc.h"
|
||||
|
||||
struct irc_conn read_config(struct irc_conn bot, char *file);
|
||||
void run_autoload(struct irc_conn *bot);
|
||||
|
||||
#endif
|
52
lib/db.h
Executable file
52
lib/db.h
Executable file
@ -0,0 +1,52 @@
|
||||
#ifndef DB_H
|
||||
#define DB_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define DB_MAGIC 0xdeadbeef
|
||||
#define DB_VER 0x10
|
||||
|
||||
enum db_type
|
||||
{
|
||||
DB_TYPE_CHAR,
|
||||
DB_TYPE_INT,
|
||||
DB_TYPE_FLOAT
|
||||
};
|
||||
|
||||
struct db_hash
|
||||
{
|
||||
int key_len;
|
||||
int value_len;
|
||||
int type;
|
||||
|
||||
char *key;
|
||||
void *value;
|
||||
};
|
||||
|
||||
struct db_table
|
||||
{
|
||||
int db_magic;
|
||||
int db_ver;
|
||||
int count;
|
||||
|
||||
struct db_hash *hashes;
|
||||
};
|
||||
|
||||
MY_API int db_write(struct db_table *db, char *fname);
|
||||
MY_API struct db_table *db_read(char *fname);
|
||||
|
||||
MY_API int db_set_hash(struct db_table *db, char *key, void *value);
|
||||
MY_API int db_set_hash_char(struct db_table *db, char *key, char *value);
|
||||
MY_API int db_set_hash_int(struct db_table *db, char *key, int value);
|
||||
MY_API int db_set_hash_float(struct db_table *db, char *key, float value);
|
||||
|
||||
MY_API int db_del_hash(struct db_table *db, char *key);
|
||||
|
||||
MY_API void *db_get_hash(struct db_table *db, char *key);
|
||||
MY_API int db_get_hash_type(struct db_table *db, char *key);
|
||||
|
||||
MY_API char *db_get_hash_char(struct db_table *db, char *key);
|
||||
MY_API int db_get_hash_int(struct db_table *db, char *key);
|
||||
MY_API float db_get_hash_float(struct db_table *db, char *key);
|
||||
|
||||
#endif
|
17
lib/irc.h
17
lib/irc.h
@ -9,6 +9,9 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "db.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
@ -30,6 +33,9 @@ struct irc_conn
|
||||
char port[5];
|
||||
char real_name[512];
|
||||
|
||||
char db_file[256];
|
||||
struct db_table *db;
|
||||
|
||||
// I/O Buffers
|
||||
char *out;
|
||||
char *in;
|
||||
@ -37,16 +43,6 @@ struct irc_conn
|
||||
|
||||
typedef struct handler event_handler;
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef MY_DLL_EXPORTS
|
||||
#define MY_API __declspec(dllexport)
|
||||
#else
|
||||
#define MY_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define MY_API
|
||||
#endif
|
||||
|
||||
void irc_connect(struct irc_conn *bot);
|
||||
void irc_auth(struct irc_conn *bot);
|
||||
|
||||
@ -58,6 +54,7 @@ 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);
|
||||
MY_API void irc_ctcp(struct irc_conn *bot, char *to, char *fmt, ...);
|
||||
|
||||
void irc_parse_raw(struct irc_conn *bot, char *raw);
|
||||
|
||||
|
@ -39,9 +39,12 @@ 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 list_modules(struct irc_conn *bot, char *where);
|
||||
void set_bot(struct irc_conn *b);
|
||||
void set_bot_db(struct db_table *db);
|
||||
MY_API void register_module(char *name, char *author, char *version, char *description);
|
||||
MY_API void unregister_module(char *name);
|
||||
MY_API struct mods *get_mods();
|
||||
MY_API struct irc_conn *get_bot();
|
||||
MY_API struct db_table *get_bot_db();
|
||||
|
||||
|
||||
#endif
|
||||
|
18
lib/util.h
18
lib/util.h
@ -12,17 +12,27 @@
|
||||
#define false FALSE
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef MY_DLL_EXPORTS
|
||||
#define MY_API __declspec(dllexport)
|
||||
#else
|
||||
#define MY_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define MY_API
|
||||
#endif
|
||||
|
||||
void eprint(char *fmt, ...);
|
||||
|
||||
#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 38)) || defined(_WIN32)
|
||||
void strlcpy(char *to, const char *from, int len);
|
||||
MY_API void strlcpy(char *to, const char *from, int len);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
char *basename(char *path);
|
||||
MY_API char *basename(char *path);
|
||||
#endif
|
||||
|
||||
char *skip(char *s, char c);
|
||||
void trim(char *s);
|
||||
MY_API char *skip(char *s, char c);
|
||||
MY_API void trim(char *s);
|
||||
|
||||
#endif
|
||||
|
78
mods/lua/README.md
Executable file
78
mods/lua/README.md
Executable file
@ -0,0 +1,78 @@
|
||||
# API
|
||||
|
||||
## Events
|
||||
|
||||
### Event Types
|
||||
|
||||
- `PRIVMSG_SELF - user, host, message`
|
||||
- `PRIVMSG_CHAN - user, host, channel, message`
|
||||
- `JOIN - user, host, channel`
|
||||
- `JOIN_MYSELF - channel`
|
||||
- `PART - user, host, channel, reason`
|
||||
- `PART_MYSELF - channel, reason`
|
||||
- `QUIT - user, host, reason`
|
||||
- `NICK - user, host, newnick`
|
||||
- `NICK_MYSELF - newnick`
|
||||
- `NICK_INUSE - newnick`
|
||||
- `CTCP - user, host, to, message`
|
||||
- `IRC_CONNECTED`
|
||||
- `TICK`
|
||||
|
||||
### `add_handler(event, handler)`
|
||||
|
||||
Adds a handler for an event.
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
function msg(user, host, channel, message)
|
||||
print(user .. " said: " .. message)
|
||||
end
|
||||
|
||||
add_handler(PRIVMSG_CHAN, msg)
|
||||
```
|
||||
|
||||
### `del_handler(event, handler)`
|
||||
|
||||
Removes a handler for an event.
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
del_handler(PRIVMSG_CHAN, msg)
|
||||
```
|
||||
|
||||
## IRC Commands
|
||||
|
||||
### `raw(message)`
|
||||
|
||||
Sends a raw message to the server.
|
||||
|
||||
### `privmsg(to, message)`
|
||||
|
||||
Sends a message to a channel or user.
|
||||
|
||||
### `notice(to, message)`
|
||||
|
||||
Sends a notice to a channel or user.
|
||||
|
||||
### `join(channel)`
|
||||
|
||||
Joins a channel.
|
||||
|
||||
### `part(channel, reason)`
|
||||
|
||||
Leaves a channel.
|
||||
|
||||
### `kick(channel, user, reason)`
|
||||
|
||||
Kicks a user from a channel. Reason is optional.
|
||||
|
||||
### `mode(channel, mode, target)`
|
||||
|
||||
Sets a mode on a channel.
|
||||
|
||||
### `ctcp(to, message)`
|
||||
|
||||
Sends a CTCP message to a channel or user.
|
||||
|
163
mods/lua/lua.c
163
mods/lua/lua.c
@ -17,102 +17,102 @@
|
||||
struct lua_interp lua;
|
||||
struct irc_conn *instance;
|
||||
|
||||
char *scriptsfile = "./mods/lua/scripts";
|
||||
|
||||
int append_script(char *fname)
|
||||
{
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *buf = (char *)malloc(sizeof(char *) * 500);
|
||||
char *scriptlist = db_get_hash_char(get_bot_db(), "lua.scripts");
|
||||
char *newlist = (char *)malloc(sizeof(char) * 500);
|
||||
char *p = scriptlist;
|
||||
|
||||
// check if the file is already in the list
|
||||
struct script_list list = get_scripts();
|
||||
|
||||
for (i = 0; i < list.count; i++)
|
||||
if (scriptlist == NULL)
|
||||
{
|
||||
if (strcmp(list.scripts[i], fname) == 0)
|
||||
{
|
||||
free(buf);
|
||||
db_set_hash_char(get_bot_db(), "lua.scripts", fname);
|
||||
db_write(get_bot_db(), instance->db_file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((fp = fopen(scriptsfile, "a")) == NULL)
|
||||
{
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
sprintf(newlist, "%s,%s", scriptlist, fname);
|
||||
printf("newlist: %s\n", newlist);
|
||||
|
||||
sprintf(buf, "%s\n", fname);
|
||||
fputs(buf, fp);
|
||||
fclose(fp);
|
||||
db_set_hash_char(get_bot_db(), "lua.scripts", newlist);
|
||||
|
||||
db_write(get_bot_db(), instance->db_file);
|
||||
|
||||
free(newlist);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remove_script(char *fname)
|
||||
{
|
||||
FILE *fp, *tmp;
|
||||
char *buf = (char *)malloc(sizeof(char *) * 500);
|
||||
char *tmpfile = "./mods/lua/scripts.tmp";
|
||||
char *scriptlist = db_get_hash_char(get_bot_db(), "lua.scripts");
|
||||
char *newlist = (char *)malloc(sizeof(char) * 500);
|
||||
char *p = scriptlist;
|
||||
char *q = newlist;
|
||||
int len = strlen(fname);
|
||||
int found = 0;
|
||||
|
||||
if ((fp = fopen(scriptsfile, "r")) == NULL)
|
||||
if (scriptlist == NULL)
|
||||
{
|
||||
free(buf);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = fopen(tmpfile, "w");
|
||||
|
||||
while (fgets(buf, 500, fp) != NULL)
|
||||
while (*p != '\0')
|
||||
{
|
||||
if (strcmp(buf, fname) != 0)
|
||||
if (strncmp(p, fname, len) == 0)
|
||||
{
|
||||
fputs(buf, tmp);
|
||||
}
|
||||
p = skip(p, ',');
|
||||
found = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fclose(tmp);
|
||||
*q = *p;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
|
||||
remove(scriptsfile);
|
||||
rename(tmpfile, scriptsfile);
|
||||
if (found == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*q = '\0';
|
||||
|
||||
// remove trailing , if it exists
|
||||
|
||||
if (newlist[strlen(newlist) - 1] == ',')
|
||||
{
|
||||
newlist[strlen(newlist) - 1] = '\0';
|
||||
}
|
||||
|
||||
db_set_hash_char(get_bot_db(), "lua.scripts", newlist);
|
||||
db_write(get_bot_db(), instance->db_file);
|
||||
|
||||
free(newlist);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct script_list get_scripts()
|
||||
{
|
||||
FILE *fp;
|
||||
char *buf = (char *)malloc(sizeof(char *) * 500);
|
||||
struct script_list list;
|
||||
char *scriptlist = db_get_hash_char(get_bot_db(), "lua.scripts");
|
||||
struct script_list list = {0};
|
||||
char *p = scriptlist;
|
||||
int i = 0;
|
||||
|
||||
if ((fp = fopen(scriptsfile, "r")) == NULL)
|
||||
if (scriptlist == NULL)
|
||||
{
|
||||
free(buf);
|
||||
|
||||
list.count = 0;
|
||||
return list;
|
||||
}
|
||||
|
||||
while (fgets(buf, 500, fp) != NULL)
|
||||
while (*p != '\0')
|
||||
{
|
||||
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';
|
||||
|
||||
|
||||
list.scripts[i] = p;
|
||||
p = skip(p, ',');
|
||||
i++;
|
||||
}
|
||||
|
||||
list.count = i;
|
||||
|
||||
free(buf);
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -326,8 +326,10 @@ void mod_init()
|
||||
{
|
||||
int i;
|
||||
char *buf = (char *)malloc(sizeof(char *) * 500);
|
||||
struct script_list list = get_scripts();
|
||||
struct script_list list = {0};
|
||||
|
||||
instance = get_bot();
|
||||
list = get_scripts();
|
||||
|
||||
lua.scripts = calloc(512, sizeof(struct lua_script));
|
||||
lua.events = calloc(1024, sizeof(struct lua_event));
|
||||
@ -360,9 +362,54 @@ void mod_init()
|
||||
{
|
||||
printf("Loading %s\n", list.scripts[i]);
|
||||
|
||||
sprintf(buf, "!load %s", list.scripts[i]);
|
||||
sprintf(buf, "./scripts/%s", list.scripts[i]);
|
||||
strlcpy(lua.scripts[lua.script_count].fname, buf, 150);
|
||||
|
||||
lua_load_script(instance, "lua", "localhost", "-stdio-", buf);
|
||||
if (luaL_loadfile(lua.L, buf) != LUA_OK)
|
||||
{
|
||||
printf("Error loading lua script: %s\n", lua_tostring(lua.L, -1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// execute the script
|
||||
if (lua_pcall(lua.L, 0, 0, 0) != LUA_OK)
|
||||
{
|
||||
printf("Error executing lua script: %s\n", lua_tostring(lua.L, -1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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;
|
||||
printf("No unload() function in %s\n", list.scripts[i]);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
printf("Error calling load() in %s: %s\n", buf, lua_tostring(lua.L, -1));
|
||||
continue;
|
||||
}
|
||||
|
||||
lua.script_count++;
|
||||
printf("Loaded %s\n", list.scripts[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: No load() function in %s\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Lua module loaded\n");
|
||||
|
@ -63,6 +63,13 @@ void lua_fire_handlers(char *event, ...);
|
||||
void lua_init_wrappers();
|
||||
void raw_wrapper(lua_State *L);
|
||||
void privmsg_wrapper(lua_State *L);
|
||||
void notice_wrapper(lua_State *L);
|
||||
void join_wrapper(lua_State *L);
|
||||
void part_wrapper(lua_State *L);
|
||||
void ban_wrapper(lua_State *L);
|
||||
void kick_wrapper(lua_State *L);
|
||||
void mode_wrapper(lua_State *L);
|
||||
void ctcp_wrapper(lua_State *L);
|
||||
|
||||
// handlers.c
|
||||
void lua_init_handlers();
|
||||
|
@ -3,3 +3,5 @@ cl /I "..\..\lib" /I "..\..\include\libconfig-1.7.3\lib" /I "..\..\include\lua5.
|
||||
cl /I "..\..\lib" /I "..\..\include\libconfig-1.7.3\lib" /I "..\..\include\lua5.3\include" /c wrappers.c
|
||||
cl /I "..\..\lib" /I "..\..\include\libconfig-1.7.3\lib" /I "..\..\include\lua5.3\include" /c lua.c
|
||||
link /DLL /out:..\lua.dll events.obj handlers.obj wrappers.obj lua.obj ..\..\Debug\xbot.lib ..\..\include\libconfig.lib ..\..\include\lua5.3\lua53.lib
|
||||
del *.obj
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
hello.lua
|
||||
test.lua
|
||||
hello.lua
|
@ -4,6 +4,13 @@ void lua_init_wrappers()
|
||||
{
|
||||
lua_register(lua.L, "raw", raw_wrapper);
|
||||
lua_register(lua.L, "privmsg", privmsg_wrapper);
|
||||
lua_register(lua.L, "notice", notice_wrapper);
|
||||
lua_register(lua.L, "join", join_wrapper);
|
||||
lua_register(lua.L, "part", part_wrapper);
|
||||
lua_register(lua.L, "ban", ban_wrapper);
|
||||
lua_register(lua.L, "kick", kick_wrapper);
|
||||
lua_register(lua.L, "mode", mode_wrapper);
|
||||
lua_register(lua.L, "ctcp", ctcp_wrapper);
|
||||
}
|
||||
|
||||
void raw_wrapper(lua_State *L)
|
||||
@ -20,3 +27,70 @@ void privmsg_wrapper(lua_State *L)
|
||||
|
||||
irc_privmsg(instance, where, text);
|
||||
}
|
||||
|
||||
void notice_wrapper(lua_State *L)
|
||||
{
|
||||
char *where = (char *)lua_tostring(L, 1);
|
||||
char *text = (char *)lua_tostring(L, 2);
|
||||
|
||||
irc_notice(instance, where, text);
|
||||
}
|
||||
|
||||
void join_wrapper(lua_State *L)
|
||||
{
|
||||
char *chan = (char *)lua_tostring(L, 1);
|
||||
|
||||
irc_join(instance, chan);
|
||||
}
|
||||
|
||||
void part_wrapper(lua_State *L)
|
||||
{
|
||||
char *chan = (char *)lua_tostring(L, 1);
|
||||
char *reason = (char *)lua_tostring(L, 2);
|
||||
|
||||
if (!reason)
|
||||
{
|
||||
reason = "";
|
||||
}
|
||||
|
||||
irc_part(instance, chan, reason);
|
||||
}
|
||||
|
||||
void ban_wrapper(lua_State *L)
|
||||
{
|
||||
char *chan = (char *)lua_tostring(L, 1);
|
||||
char *user = (char *)lua_tostring(L, 2);
|
||||
|
||||
irc_ban(instance, chan, user);
|
||||
}
|
||||
|
||||
void kick_wrapper(lua_State *L)
|
||||
{
|
||||
char *chan = (char *)lua_tostring(L, 1);
|
||||
char *user = (char *)lua_tostring(L, 2);
|
||||
char *reason = (char *)lua_tostring(L, 3);
|
||||
|
||||
if (!reason)
|
||||
{
|
||||
reason = "";
|
||||
}
|
||||
|
||||
irc_kick(instance, chan, user, reason);
|
||||
}
|
||||
|
||||
void mode_wrapper(lua_State *L)
|
||||
{
|
||||
char *chan = (char *)lua_tostring(L, 1);
|
||||
char *mode = (char *)lua_tostring(L, 2);
|
||||
|
||||
irc_mode(instance, chan, mode);
|
||||
}
|
||||
|
||||
void ctcp_wrapper(lua_State *L)
|
||||
{
|
||||
char *to = (char *)lua_tostring(L, 1);
|
||||
char *msg = (char *)lua_tostring(L, 2);
|
||||
va_list ap;
|
||||
|
||||
irc_ctcp(instance, to, msg);
|
||||
}
|
||||
|
35
src/config.c
35
src/config.c
@ -41,6 +41,37 @@ struct irc_conn read_config(struct irc_conn bot, char *file)
|
||||
if (config_lookup_string(cf, "bot.admin", &base))
|
||||
strlcpy(bot.admin, base, sizeof bot.admin);
|
||||
|
||||
if (config_lookup_string(cf, "bot.db", &base))
|
||||
strlcpy(bot.db_file, base, sizeof bot.db_file);
|
||||
|
||||
config_destroy(cf);
|
||||
|
||||
return bot;
|
||||
}
|
||||
|
||||
void run_autoload(struct irc_conn *bot)
|
||||
{
|
||||
int count, n;
|
||||
config_t cfg, *cf;
|
||||
const config_setting_t *autoload;
|
||||
const char *base = (const char*)malloc(sizeof(char) * 1024);
|
||||
const char *mod = NULL;
|
||||
char *modpath = (char *)malloc(sizeof(char) * 500);
|
||||
|
||||
cf = &cfg;
|
||||
config_init(cf);
|
||||
|
||||
if (!config_read_file(cf, "xbot.cfg"))
|
||||
{
|
||||
printf("[xbot.cfg:%d] Configuration error: %s\n",
|
||||
config_error_line(cf),
|
||||
config_error_text(cf)
|
||||
);
|
||||
|
||||
config_destroy(cf);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
autoload = config_lookup(cf, "mods.autoload");
|
||||
count = config_setting_length(autoload);
|
||||
|
||||
@ -52,10 +83,8 @@ struct irc_conn read_config(struct irc_conn bot, char *file)
|
||||
#else
|
||||
sprintf(modpath, "./mods/%s.so", mod);
|
||||
#endif
|
||||
load_module(&bot, "main", "runtime", modpath);
|
||||
load_module(bot, "main", "runtime", modpath);
|
||||
}
|
||||
|
||||
config_destroy(cf);
|
||||
|
||||
return bot;
|
||||
}
|
||||
|
283
src/db.c
Executable file
283
src/db.c
Executable file
@ -0,0 +1,283 @@
|
||||
#include "util.h"
|
||||
#include "irc.h"
|
||||
#include "db.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int db_write(struct db_table *db, char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
int i;
|
||||
char *fullpath;
|
||||
|
||||
if ((fp = fopen(fname, "wb")) == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
db->db_magic = DB_MAGIC;
|
||||
db->db_ver = DB_VER;
|
||||
|
||||
// get the full path to the db file
|
||||
#ifdef _WIN32
|
||||
fullpath = _fullpath(NULL, fname, 0);
|
||||
#else
|
||||
fullpath = realpath(fname, NULL);
|
||||
#endif
|
||||
|
||||
printf("Writing db to file: %s\n", fullpath);
|
||||
|
||||
// write the header
|
||||
fwrite(db, sizeof(struct db_table), 1, fp);
|
||||
|
||||
// write the hashes
|
||||
fwrite(db->hashes, sizeof(struct db_hash), db->count, fp);
|
||||
|
||||
// write the keys and values
|
||||
for (i = 0; i < db->count; i++)
|
||||
{
|
||||
fwrite(db->hashes[i].key, sizeof(char), db->hashes[i].key_len, fp);
|
||||
fwrite(db->hashes[i].value, sizeof(char), db->hashes[i].value_len, fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct db_table *db_read(char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
struct db_table *db;
|
||||
int tmp;
|
||||
|
||||
if ((fp = fopen(fname, "rb")) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
db = (struct db_table *)malloc(sizeof(struct db_table));
|
||||
|
||||
fread(db, sizeof(struct db_table), 1, fp);
|
||||
|
||||
// check the magic value
|
||||
if (db->db_magic != DB_MAGIC)
|
||||
{
|
||||
printf("Error: %s incompatible or unknown db file format: Bad Magic\n", fname);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// check the version
|
||||
if (db->db_ver != DB_VER)
|
||||
{
|
||||
printf("Error: %s incompatible or unknown db file format: Incompatible Version\n", fname);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmp = db->count != 0 ? db->count : sizeof(struct db_hash);
|
||||
db->hashes = (struct db_hash *)malloc(sizeof(struct db_hash) * tmp);
|
||||
|
||||
fread(db->hashes, sizeof(struct db_hash), db->count, fp);
|
||||
|
||||
// read the keys and values
|
||||
for (tmp = 0; tmp < db->count; tmp++)
|
||||
{
|
||||
db->hashes[tmp].key = (char *)malloc(sizeof(char) * db->hashes[tmp].key_len);
|
||||
db->hashes[tmp].value = (char *)malloc(sizeof(char) * db->hashes[tmp].value_len);
|
||||
|
||||
fread(db->hashes[tmp].key, sizeof(char), db->hashes[tmp].key_len, fp);
|
||||
fread(db->hashes[tmp].value, sizeof(char), db->hashes[tmp].value_len, fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
int db_set_hash(struct db_table *db, char *key, void *value)
|
||||
{
|
||||
int i;
|
||||
|
||||
// check if the key already exists and update it
|
||||
for (i = 0; i < db->count; i++)
|
||||
{
|
||||
if (strcmp(db->hashes[i].key, key) == 0)
|
||||
{
|
||||
if (db->hashes[i].type == DB_TYPE_CHAR)
|
||||
{
|
||||
free(db->hashes[i].value);
|
||||
}
|
||||
|
||||
db->hashes[i].value = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
db->hashes[db->count].key_len = strlen(key) + 1;
|
||||
db->hashes[db->count].key = (char *)malloc(sizeof(char) * db->hashes[db->count].key_len);
|
||||
|
||||
memset(db->hashes[db->count].key, 0, sizeof(char) * db->hashes[db->count].key_len);
|
||||
|
||||
strlcpy(db->hashes[db->count].key, key, sizeof(char) * db->hashes[db->count].key_len);
|
||||
|
||||
db->hashes[db->count].value = value;
|
||||
|
||||
db->count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int db_set_hash_char(struct db_table *db, char *key, char *value)
|
||||
{
|
||||
// check if the key already exists and update it
|
||||
int i;
|
||||
|
||||
for (i = 0; i < db->count; i++)
|
||||
{
|
||||
if (strcmp(db->hashes[i].key, key) == 0)
|
||||
{
|
||||
if (db->hashes[i].type == DB_TYPE_CHAR)
|
||||
{
|
||||
free(db->hashes[i].value);
|
||||
}
|
||||
|
||||
db->hashes[i].type = DB_TYPE_CHAR;
|
||||
db->hashes[i].value_len = strlen(value) + 1;
|
||||
db->hashes[i].value = (char *)malloc(sizeof(char) * db->hashes[i].value_len);
|
||||
|
||||
memset(db->hashes[i].value, 0, sizeof(char) * db->hashes[i].value_len);
|
||||
|
||||
strlcpy(db->hashes[i].value, value, sizeof(char) * db->hashes[i].value_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
db->hashes = (struct db_hash *)realloc(db->hashes, sizeof(struct db_hash) * (db->count + 1));
|
||||
|
||||
// zero out reallocated memory
|
||||
memset(&db->hashes[db->count], 0, sizeof(struct db_hash));
|
||||
|
||||
db->hashes[db->count].type = DB_TYPE_CHAR;
|
||||
db->hashes[db->count].value_len = strlen(value) + 1;
|
||||
db->hashes[db->count].value = (char *)malloc(sizeof(char) * db->hashes[db->count].value_len);
|
||||
|
||||
memset(db->hashes[db->count].value, 0, sizeof(char) * db->hashes[db->count].value_len);
|
||||
|
||||
strlcpy(db->hashes[db->count].value, value, sizeof(char) * db->hashes[db->count].value_len);
|
||||
|
||||
return db_set_hash(db, key, db->hashes[db->count].value);
|
||||
}
|
||||
|
||||
int db_set_hash_int(struct db_table *db, char *key, int value)
|
||||
{
|
||||
db->hashes = (struct db_hash *)realloc(db->hashes, sizeof(struct db_hash) * (db->count + 1));
|
||||
|
||||
// zero out reallocated memory
|
||||
memset(&db->hashes[db->count], 0, sizeof(struct db_hash));
|
||||
|
||||
db->hashes[db->count].type = DB_TYPE_INT;
|
||||
db->hashes[db->count].value_len = sizeof(int);
|
||||
db->hashes[db->count].value = (int *)malloc(sizeof(int));
|
||||
|
||||
memcpy(db->hashes[db->count].value, &value, sizeof(int));
|
||||
|
||||
return db_set_hash(db, key, db->hashes[db->count].value);
|
||||
}
|
||||
|
||||
int db_set_hash_float(struct db_table *db, char *key, float value)
|
||||
{
|
||||
db->hashes = (struct db_hash *)realloc(db->hashes, sizeof(struct db_hash) * (db->count + 1));
|
||||
|
||||
// zero out reallocated memory
|
||||
memset(&db->hashes[db->count], 0, sizeof(struct db_hash));
|
||||
|
||||
db->hashes[db->count].type = DB_TYPE_FLOAT;
|
||||
db->hashes[db->count].value_len = sizeof(float);
|
||||
db->hashes[db->count].value = (float *)malloc(sizeof(float));
|
||||
|
||||
memcpy(db->hashes[db->count].value, &value, sizeof(float));
|
||||
|
||||
return db_set_hash(db, key, db->hashes[db->count].value);
|
||||
}
|
||||
|
||||
int db_del_hash(struct db_table *db, char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < db->count; i++)
|
||||
{
|
||||
if (strcmp(db->hashes[i].key, key) == 0)
|
||||
{
|
||||
free(db->hashes[i].key);
|
||||
free(db->hashes[i].value);
|
||||
memmove(&db->hashes[i], &db->hashes[i + 1], sizeof(struct db_hash) * (db->count - i));
|
||||
db->count--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *db_get_hash(struct db_table *db, char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < db->count; i++)
|
||||
{
|
||||
if (strcmp(db->hashes[i].key, key) == 0)
|
||||
{
|
||||
return db->hashes[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int db_get_hash_type(struct db_table *db, char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < db->count; i++)
|
||||
{
|
||||
if (strcmp(db->hashes[i].key, key) == 0)
|
||||
{
|
||||
return db->hashes[i].type;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *db_get_hash_char(struct db_table *db, char *key)
|
||||
{
|
||||
return (char *)db_get_hash(db, key);
|
||||
}
|
||||
|
||||
int db_get_hash_int(struct db_table *db, char *key)
|
||||
{
|
||||
int value;
|
||||
|
||||
memcpy(&value, db_get_hash(db, key), sizeof(int));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float db_get_hash_float(struct db_table *db, char *key)
|
||||
{
|
||||
float value;
|
||||
|
||||
memcpy(&value, db_get_hash(db, key), sizeof(float));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
32
src/main.c
32
src/main.c
@ -9,8 +9,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "irc.h"
|
||||
#include "db.h"
|
||||
#include "util.h"
|
||||
#include "events.h"
|
||||
#include "module.h"
|
||||
@ -21,6 +23,7 @@
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
static time_t trespond;
|
||||
@ -43,13 +46,40 @@ int main()
|
||||
last_ping.tv_sec = time(NULL);
|
||||
|
||||
set_bot(&bot);
|
||||
|
||||
init_events();
|
||||
init_timers();
|
||||
init_mods();
|
||||
|
||||
// Read the config
|
||||
bot = read_config(bot, "xbot.cfg");
|
||||
|
||||
// check if the db exists, if not, create it
|
||||
#ifdef _WIN32
|
||||
if (access(bot.db_file, 0) == -1)
|
||||
#else
|
||||
if (access(bot.db_file, F_OK) == -1)
|
||||
#endif
|
||||
{
|
||||
printf("Creating database file: %s\n", bot.db_file);
|
||||
bot.db = (struct db_table *)malloc(sizeof(struct db_table));
|
||||
memset(bot.db, 0, sizeof(struct db_table));
|
||||
set_bot_db(bot.db);
|
||||
|
||||
bot.db->count = 0;
|
||||
bot.db->hashes = NULL;
|
||||
|
||||
db_write(bot.db, bot.db_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Reading database file: %s\n", bot.db_file);
|
||||
bot.db = db_read(bot.db_file);
|
||||
set_bot_db(bot.db);
|
||||
}
|
||||
|
||||
// run autoload
|
||||
run_autoload(&bot);
|
||||
|
||||
// Connect to the server
|
||||
printf("Connecting to %s...\n", bot.host);
|
||||
|
||||
|
11
src/module.c
11
src/module.c
@ -14,6 +14,7 @@
|
||||
|
||||
struct mods *mods;
|
||||
struct irc_conn *instance;
|
||||
struct db_table *dbinstance;
|
||||
|
||||
void init_mods()
|
||||
{
|
||||
@ -315,3 +316,13 @@ void set_bot(struct irc_conn *b)
|
||||
{
|
||||
instance = b;
|
||||
}
|
||||
|
||||
void set_bot_db(struct db_table *db)
|
||||
{
|
||||
dbinstance = db;
|
||||
}
|
||||
|
||||
MY_API struct db_table *get_bot_db()
|
||||
{
|
||||
return dbinstance;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "irc.h"
|
||||
#include "util.h"
|
||||
|
||||
void eprint(char *fmt, ...)
|
||||
{
|
||||
@ -30,7 +30,7 @@ void eprint(char *fmt, ...)
|
||||
}
|
||||
|
||||
#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 38)) || defined(_WIN32)
|
||||
MY_API void strlcpy(char *to, const char *from, int len)
|
||||
void strlcpy(char *to, const char *from, int len)
|
||||
{
|
||||
memccpy(to, from, '\0', len);
|
||||
to[len-1] = '\0';
|
||||
@ -38,14 +38,14 @@ MY_API void strlcpy(char *to, const char *from, int len)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
MY_API char *basename(char *path)
|
||||
char *basename(char *path)
|
||||
{
|
||||
char *p = strrchr(path, '\\');
|
||||
return p ? p + 1 : path;
|
||||
}
|
||||
#endif
|
||||
|
||||
MY_API char *skip(char *s, char c)
|
||||
char *skip(char *s, char c)
|
||||
{
|
||||
while (*s != c && *s != '\0')
|
||||
{
|
||||
|
2
xbot.cfg
2
xbot.cfg
@ -6,6 +6,8 @@ bot:
|
||||
nick = "xbot";
|
||||
user = "xbot";
|
||||
admin = "ab3800";
|
||||
|
||||
db = "xbot.db";
|
||||
};
|
||||
|
||||
server:
|
||||
|
@ -105,6 +105,7 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="lib\channel.h" />
|
||||
<ClInclude Include="lib\config.h" />
|
||||
<ClInclude Include="lib\db.h" />
|
||||
<ClInclude Include="lib\events.h" />
|
||||
<ClInclude Include="lib\irc.h" />
|
||||
<ClInclude Include="lib\module.h" />
|
||||
@ -114,6 +115,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\channel.c" />
|
||||
<ClCompile Include="src\config.c" />
|
||||
<ClCompile Include="src\db.c" />
|
||||
<ClCompile Include="src\events.c" />
|
||||
<ClCompile Include="src\irc.c" />
|
||||
<ClCompile Include="src\main.c" />
|
||||
|
Loading…
Reference in New Issue
Block a user