From 2127820ae0b2203b67f48137265c78ef79db1dcc Mon Sep 17 00:00:00 2001 From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:47:08 -0700 Subject: [PATCH 1/3] Enhance README with build badges and links Updated README to include build badges and documentation link. --- readme.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index f8b058b8..8acd51e3 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,6 @@ -# ZoiteChat - +
+ + [![Debian Build](https://github.com/ZoiteChat/zoitechat/actions/workflows/debian-build.yml/badge.svg)](https://github.com/ZoiteChat/zoitechat/actions/workflows/debian-build.yml) [![Flatpak Build](https://github.com/ZoiteChat/zoitechat/actions/workflows/flatpak-build.yml/badge.svg)](https://github.com/ZoiteChat/zoitechat/actions/workflows/flatpak-build.yml) [![AppImage Build](https://github.com/ZoiteChat/zoitechat/actions/workflows/appimage-build.yml/badge.svg)](https://github.com/ZoiteChat/zoitechat/actions/workflows/appimage-build.yml) @@ -7,6 +8,13 @@ [![MSYS2 Build](https://github.com/ZoiteChat/zoitechat/actions/workflows/msys-build.yml/badge.svg)](https://github.com/ZoiteChat/zoitechat/actions/workflows/msys-build.yml) [![OpenBSD Build](https://github.com/ZoiteChat/zoitechat/actions/workflows/openbsd-build.yml/badge.svg)](https://github.com/ZoiteChat/zoitechat/actions/workflows/openbsd-build.yml) +[![Version][github-version-img]][github-version-uri] [![Downloads][github-downloads-img]][github-downloads-uri] [![Size][github-size-img]][github-size-img] [![Last Commit][github-commit-img]][github-commit-img] [![Contributors][contribs-all-img]](#contributors-) + +[![View Official Documentation](https://img.shields.io/badge/View_Official_Documentation-526CFE?style=for-the-badge&logo=MaterialForMkDocs&logoColor=white)](https://zoitechat.zoite.net/docs/) + +
+ + ZoiteChat is an HexChat based IRC client for Windows and UNIX-like operating systems. See [IRCHelp.org](http://irchelp.org) for information about IRC in general. For more information on ZoiteChat please read our [documentation](https://zoitechat.zoite.net/docs/): From 4e01192979c482e7caed296ef1d47c212b269e93 Mon Sep 17 00:00:00 2001 From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:52:49 -0700 Subject: [PATCH 2/3] Add badge references to README Added badge references for GitHub version, downloads, size, last commit, and contributors. --- readme.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/readme.md b/readme.md index 8acd51e3..3fbc845e 100644 --- a/readme.md +++ b/readme.md @@ -14,6 +14,24 @@ + +[github-version-img]: https://img.shields.io/github/v/release/ZoiteChat/zoitechat?display_name=tag&sort=semver +[github-version-uri]: https://github.com/ZoiteChat/zoitechat/releases/latest + +[github-downloads-img]: https://img.shields.io/github/downloads/ZoiteChat/zoitechat/total +[github-downloads-uri]: https://github.com/ZoiteChat/zoitechat/releases + +[github-size-img]: https://img.shields.io/github/repo-size/ZoiteChat/zoitechat +[github-size-uri]: https://github.com/ZoiteChat/zoitechat + +[github-commit-img]: https://img.shields.io/github/last-commit/ZoiteChat/zoitechat +[github-commit-uri]: https://github.com/ZoiteChat/zoitechat/commits + +[contribs-all-img]: https://img.shields.io/github/contributors/ZoiteChat/zoitechat + +
+
+ ZoiteChat is an HexChat based IRC client for Windows and UNIX-like operating systems. See [IRCHelp.org](http://irchelp.org) for information about IRC in general. From 4ed7032fd51ff645cb770011d4578bd7d3978e73 Mon Sep 17 00:00:00 2001 From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com> Date: Sun, 25 Jan 2026 16:02:58 -0700 Subject: [PATCH 3/3] Update lua.c Allowed Lua scripts to be located by basename (script name only) when resolving /lua unload and related operations, while keeping path-based matching for explicit paths. Ensured /lua load reports failures when script creation fails and added explicit failure feedback to the user. Added unload feedback that distinguishes immediate unloads from deferred unloads, so users see confirmation right away. --- plugins/lua/lua.c | 2590 +++++++++++++++++++++++---------------------- 1 file changed, 1309 insertions(+), 1281 deletions(-) diff --git a/plugins/lua/lua.c b/plugins/lua/lua.c index 0f9adbd7..bcab4729 100644 --- a/plugins/lua/lua.c +++ b/plugins/lua/lua.c @@ -43,14 +43,14 @@ static char plugin_version[16] = "1.3"; static char console_tab[] = ">>lua<<"; static char command_help[] = - "Usage: /lua load \n" - " unload \n" - " reload \n" - " exec \n" - " inject \n" - " reset\n" - " list\n" - " console"; + "Usage: /lua load \n" + " unload \n" + " reload \n" + " exec \n" + " inject \n" + " reset\n" + " list\n" + " console"; static char registry_field[] = "plugin"; @@ -63,24 +63,24 @@ static zoitechat_plugin *ph; typedef struct { - zoitechat_hook *hook; - lua_State *state; - int ref; + zoitechat_hook *hook; + lua_State *state; + int ref; } hook_info; typedef struct { - char *name; - char *description; - char *version; - zoitechat_plugin *handle; - char *filename; - lua_State *state; - GPtrArray *hooks; - GPtrArray *unload_hooks; - int traceback; - int status; + char *name; + char *description; + char *version; + zoitechat_plugin *handle; + char *filename; + lua_State *state; + GPtrArray *hooks; + GPtrArray *unload_hooks; + int traceback; + int status; } script_info; @@ -92,1113 +92,1113 @@ static void check_deferred(script_info *info); static inline script_info *get_info(lua_State *L) { - script_info *info; + script_info *info; - lua_getfield(L, LUA_REGISTRYINDEX, registry_field); - info = lua_touserdata(L, -1); - lua_pop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, registry_field); + info = lua_touserdata(L, -1); + lua_pop(L, 1); - return info; + return info; } static int api_zoitechat_register(lua_State *L) { - char const *name, *version, *description; - script_info *info = get_info(L); - if(info->name) - return luaL_error(L, "script is already registered as '%s'", info->name); + char const *name, *version, *description; + script_info *info = get_info(L); + if(info->name) + return luaL_error(L, "script is already registered as '%s'", info->name); - name = luaL_checkstring(L, 1); - version = luaL_checkstring(L, 2); - description = luaL_checkstring(L, 3); + name = luaL_checkstring(L, 1); + version = luaL_checkstring(L, 2); + description = luaL_checkstring(L, 3); - info->name = g_strdup(name); - info->description = g_strdup(description); - info->version = g_strdup(version); - info->handle = zoitechat_plugingui_add(ph, info->filename, info->name, info->description, info->version, NULL); + info->name = g_strdup(name); + info->description = g_strdup(description); + info->version = g_strdup(version); + info->handle = zoitechat_plugingui_add(ph, info->filename, info->name, info->description, info->version, NULL); - return 0; + return 0; } static int api_zoitechat_command(lua_State *L) { - zoitechat_command(ph, luaL_checkstring(L, 1)); - return 0; + zoitechat_command(ph, luaL_checkstring(L, 1)); + return 0; } static int tostring(lua_State *L, int n) { - luaL_checkany(L, n); - switch (lua_type(L, n)) - { - case LUA_TNUMBER: - lua_pushstring(L, lua_tostring(L, n)); - break; - case LUA_TSTRING: - lua_pushvalue(L, n); - break; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, n) ? "true" : "false")); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - default: - lua_pushfstring(L, "%s: %p", luaL_typename(L, n), lua_topointer(L, n)); - break; - } - return 1; + luaL_checkany(L, n); + switch (lua_type(L, n)) + { + case LUA_TNUMBER: + lua_pushstring(L, lua_tostring(L, n)); + break; + case LUA_TSTRING: + lua_pushvalue(L, n); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, n) ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, n), lua_topointer(L, n)); + break; + } + return 1; } static int api_zoitechat_print(lua_State *L) { - int i, args = lua_gettop(L); - luaL_Buffer b; - luaL_buffinit(L, &b); - for(i = 1; i <= args; i++) - { - if(i != 1) - luaL_addstring(&b, " "); - tostring(L, i); - luaL_addvalue(&b); - } - luaL_pushresult(&b); - zoitechat_print(ph, lua_tostring(L, -1)); - return 0; + int i, args = lua_gettop(L); + luaL_Buffer b; + luaL_buffinit(L, &b); + for(i = 1; i <= args; i++) + { + if(i != 1) + luaL_addstring(&b, " "); + tostring(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + zoitechat_print(ph, lua_tostring(L, -1)); + return 0; } static int api_zoitechat_emit_print(lua_State *L) { - zoitechat_emit_print(ph, luaL_checkstring(L, 1), luaL_optstring(L, 2, NULL), luaL_optstring(L, 3, NULL), luaL_optstring(L, 4, NULL), luaL_optstring(L, 5, NULL), luaL_optstring(L, 6, NULL), NULL); - return 0; + zoitechat_emit_print(ph, luaL_checkstring(L, 1), luaL_optstring(L, 2, NULL), luaL_optstring(L, 3, NULL), luaL_optstring(L, 4, NULL), luaL_optstring(L, 5, NULL), luaL_optstring(L, 6, NULL), NULL); + return 0; } static int api_zoitechat_emit_print_attrs(lua_State *L) { - zoitechat_event_attrs *attrs = *(zoitechat_event_attrs **)luaL_checkudata(L, 1, "attrs"); - zoitechat_emit_print_attrs(ph, attrs, luaL_checkstring(L, 2), luaL_optstring(L, 3, NULL), luaL_optstring(L, 4, NULL), luaL_optstring(L, 5, NULL), luaL_optstring(L, 6, NULL), luaL_optstring(L, 7, NULL), NULL); - return 0; + zoitechat_event_attrs *attrs = *(zoitechat_event_attrs **)luaL_checkudata(L, 1, "attrs"); + zoitechat_emit_print_attrs(ph, attrs, luaL_checkstring(L, 2), luaL_optstring(L, 3, NULL), luaL_optstring(L, 4, NULL), luaL_optstring(L, 5, NULL), luaL_optstring(L, 6, NULL), luaL_optstring(L, 7, NULL), NULL); + return 0; } static int api_zoitechat_send_modes(lua_State *L) { - size_t i, n; - int modes; - char const *mode; - char const **targets; + size_t i, n; + int modes; + char const *mode; + char const **targets; - luaL_checktype(L, 1, LUA_TTABLE); - n = lua_rawlen(L, 1); - mode = luaL_checkstring(L, 2); - if(strlen(mode) != 2) - return luaL_argerror(L, 2, "expected sign followed by a mode letter"); - modes = luaL_optinteger(L, 3, 0); - targets = g_new(char const *, n); + luaL_checktype(L, 1, LUA_TTABLE); + n = lua_rawlen(L, 1); + mode = luaL_checkstring(L, 2); + if(strlen(mode) != 2) + return luaL_argerror(L, 2, "expected sign followed by a mode letter"); + modes = luaL_optinteger(L, 3, 0); + targets = g_new(char const *, n); - for(i = 0; i < n; i++) - { - lua_rawgeti(L, 1, i + 1); - if(lua_type(L, -1) != LUA_TSTRING) - { - g_free(targets); - return luaL_argerror(L, 1, "expected an array of strings"); - } - targets[i] = lua_tostring(L, -1); - lua_pop(L, 1); - } - zoitechat_send_modes(ph, targets, n, modes, mode[0], mode[1]); - g_free(targets); - return 0; + for(i = 0; i < n; i++) + { + lua_rawgeti(L, 1, i + 1); + if(lua_type(L, -1) != LUA_TSTRING) + { + g_free(targets); + return luaL_argerror(L, 1, "expected an array of strings"); + } + targets[i] = lua_tostring(L, -1); + lua_pop(L, 1); + } + zoitechat_send_modes(ph, targets, n, modes, mode[0], mode[1]); + g_free(targets); + return 0; } static int api_zoitechat_nickcmp(lua_State *L) { - lua_pushinteger(L, zoitechat_nickcmp(ph, luaL_checkstring(L, 1), luaL_checkstring(L, 2))); - return 1; + lua_pushinteger(L, zoitechat_nickcmp(ph, luaL_checkstring(L, 1), luaL_checkstring(L, 2))); + return 1; } static int api_zoitechat_strip(lua_State *L) { - size_t len; - char const *text; - gboolean leave_colors, leave_attrs; - char *result; + size_t len; + char const *text; + gboolean leave_colors, leave_attrs; + char *result; - luaL_checktype(L, 1, LUA_TSTRING); - text = lua_tolstring(L, 1, &len); - leave_colors = lua_toboolean(L, 2); - leave_attrs = lua_toboolean(L, 3); - result = zoitechat_strip(ph, text, len, (leave_colors ? 0 : 1) | (leave_attrs ? 0 : 2)); - if(result) - { - lua_pushstring(L, result); - zoitechat_free(ph, result); - return 1; - } - return 0; + luaL_checktype(L, 1, LUA_TSTRING); + text = lua_tolstring(L, 1, &len); + leave_colors = lua_toboolean(L, 2); + leave_attrs = lua_toboolean(L, 3); + result = zoitechat_strip(ph, text, len, (leave_colors ? 0 : 1) | (leave_attrs ? 0 : 2)); + if(result) + { + lua_pushstring(L, result); + zoitechat_free(ph, result); + return 1; + } + return 0; } static void register_hook(hook_info *hook) { - script_info *info = get_info(hook->state); - g_ptr_array_add(info->hooks, hook); + script_info *info = get_info(hook->state); + g_ptr_array_add(info->hooks, hook); } static void free_hook(hook_info *hook) { - if(hook->state) - luaL_unref(hook->state, LUA_REGISTRYINDEX, hook->ref); - if(hook->hook) - zoitechat_unhook(ph, hook->hook); - g_free(hook); + if(hook->state) + luaL_unref(hook->state, LUA_REGISTRYINDEX, hook->ref); + if(hook->hook) + zoitechat_unhook(ph, hook->hook); + g_free(hook); } static int unregister_hook(hook_info *hook) { - script_info *info = get_info(hook->state); + script_info *info = get_info(hook->state); - if(g_ptr_array_remove_fast(info->hooks, hook)) - return 1; + if(g_ptr_array_remove_fast(info->hooks, hook)) + return 1; - if(g_ptr_array_remove_fast(info->unload_hooks, hook)) - return 1; + if(g_ptr_array_remove_fast(info->unload_hooks, hook)) + return 1; - return 0; + return 0; } static int api_command_closure(char *word[], char *word_eol[], void *udata) { - int base, i, ret; - hook_info *info = udata; - lua_State *L = info->state; - script_info *script = get_info(L); + int base, i, ret; + hook_info *info = udata; + lua_State *L = info->state; + script_info *script = get_info(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); - base = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); - lua_newtable(L); - for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) - { - lua_pushstring(L, word[i]); - lua_rawseti(L, -2, i); - } - lua_newtable(L); - for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) - { - lua_pushstring(L, word_eol[i]); - lua_rawseti(L, -2, i); - } - script->status |= STATUS_ACTIVE; - if(lua_pcall(L, 2, 1, base)) - { - char const *error = lua_tostring(L, -1); - lua_pop(L, 2); - zoitechat_printf(ph, "Lua error in command hook: %s", error ? error : "(non-string error)"); - check_deferred(script); - return HEXCHAT_EAT_NONE; - } - ret = lua_tointeger(L, -1); - lua_pop(L, 2); - check_deferred(script); - return ret; + lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); + base = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); + lua_newtable(L); + for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) + { + lua_pushstring(L, word[i]); + lua_rawseti(L, -2, i); + } + lua_newtable(L); + for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) + { + lua_pushstring(L, word_eol[i]); + lua_rawseti(L, -2, i); + } + script->status |= STATUS_ACTIVE; + if(lua_pcall(L, 2, 1, base)) + { + char const *error = lua_tostring(L, -1); + lua_pop(L, 2); + zoitechat_printf(ph, "Lua error in command hook: %s", error ? error : "(non-string error)"); + check_deferred(script); + return HEXCHAT_EAT_NONE; + } + ret = lua_tointeger(L, -1); + lua_pop(L, 2); + check_deferred(script); + return ret; } static int api_zoitechat_hook_command(lua_State *L) { - hook_info *info, **u; - char const *command, *help; - int ref, pri; + hook_info *info, **u; + char const *command, *help; + int ref, pri; - command = luaL_optstring(L, 1, ""); - lua_pushvalue(L, 2); - ref = luaL_ref(L, LUA_REGISTRYINDEX); - help = luaL_optstring(L, 3, NULL); - pri = luaL_optinteger(L, 4, HEXCHAT_PRI_NORM); - info = g_new(hook_info, 1); - info->state = L; - info->ref = ref; - info->hook = zoitechat_hook_command(ph, command, pri, api_command_closure, help, info); - u = lua_newuserdata(L, sizeof(hook_info *)); - *u = info; - luaL_newmetatable(L, "hook"); - lua_setmetatable(L, -2); - register_hook(info); - return 1; + command = luaL_optstring(L, 1, ""); + lua_pushvalue(L, 2); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + help = luaL_optstring(L, 3, NULL); + pri = luaL_optinteger(L, 4, HEXCHAT_PRI_NORM); + info = g_new(hook_info, 1); + info->state = L; + info->ref = ref; + info->hook = zoitechat_hook_command(ph, command, pri, api_command_closure, help, info); + u = lua_newuserdata(L, sizeof(hook_info *)); + *u = info; + luaL_newmetatable(L, "hook"); + lua_setmetatable(L, -2); + register_hook(info); + return 1; } static int api_print_closure(char *word[], void *udata) { - hook_info *info = udata; - lua_State *L = info->state; - script_info *script = get_info(L); - int i, j, base, ret; + hook_info *info = udata; + lua_State *L = info->state; + script_info *script = get_info(L); + int i, j, base, ret; - lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); - base = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); + base = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); - for(j = 31; j >= 1; j--) - { - if(*word[j]) - break; - } - lua_newtable(L); - for(i = 1; i <= j; i++) - { - lua_pushstring(L, word[i]); - lua_rawseti(L, -2, i); - } - script->status |= STATUS_ACTIVE; - if(lua_pcall(L, 1, 1, base)) - { - char const *error = lua_tostring(L, -1); - lua_pop(L, 2); - zoitechat_printf(ph, "Lua error in print hook: %s", error ? error : "(non-string error)"); - check_deferred(script); - return HEXCHAT_EAT_NONE; - } - ret = lua_tointeger(L, -1); - lua_pop(L, 2); - check_deferred(script); - return ret; + for(j = 31; j >= 1; j--) + { + if(*word[j]) + break; + } + lua_newtable(L); + for(i = 1; i <= j; i++) + { + lua_pushstring(L, word[i]); + lua_rawseti(L, -2, i); + } + script->status |= STATUS_ACTIVE; + if(lua_pcall(L, 1, 1, base)) + { + char const *error = lua_tostring(L, -1); + lua_pop(L, 2); + zoitechat_printf(ph, "Lua error in print hook: %s", error ? error : "(non-string error)"); + check_deferred(script); + return HEXCHAT_EAT_NONE; + } + ret = lua_tointeger(L, -1); + lua_pop(L, 2); + check_deferred(script); + return ret; } static int api_zoitechat_hook_print(lua_State *L) { - char const *event = luaL_checkstring(L, 1); - hook_info *info, **u; - int ref, pri; + char const *event = luaL_checkstring(L, 1); + hook_info *info, **u; + int ref, pri; - lua_pushvalue(L, 2); - ref = luaL_ref(L, LUA_REGISTRYINDEX); - pri = luaL_optinteger(L, 3, HEXCHAT_PRI_NORM); - info = g_new(hook_info, 1); - info->state = L; - info->ref = ref; - info->hook = zoitechat_hook_print(ph, event, pri, api_print_closure, info); - u = lua_newuserdata(L, sizeof(hook_info *)); - *u = info; - luaL_newmetatable(L, "hook"); - lua_setmetatable(L, -2); - register_hook(info); - return 1; + lua_pushvalue(L, 2); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + pri = luaL_optinteger(L, 3, HEXCHAT_PRI_NORM); + info = g_new(hook_info, 1); + info->state = L; + info->ref = ref; + info->hook = zoitechat_hook_print(ph, event, pri, api_print_closure, info); + u = lua_newuserdata(L, sizeof(hook_info *)); + *u = info; + luaL_newmetatable(L, "hook"); + lua_setmetatable(L, -2); + register_hook(info); + return 1; } static zoitechat_event_attrs *event_attrs_copy(const zoitechat_event_attrs *attrs) { - zoitechat_event_attrs *copy = zoitechat_event_attrs_create(ph); - copy->server_time_utc = attrs->server_time_utc; - return copy; + zoitechat_event_attrs *copy = zoitechat_event_attrs_create(ph); + copy->server_time_utc = attrs->server_time_utc; + return copy; } static int api_print_attrs_closure(char *word[], zoitechat_event_attrs *attrs, void *udata) { - hook_info *info = udata; - lua_State *L = info->state; - script_info *script = get_info(L); - int base, i, j, ret; - zoitechat_event_attrs **u; + hook_info *info = udata; + lua_State *L = info->state; + script_info *script = get_info(L); + int base, i, j, ret; + zoitechat_event_attrs **u; - lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); - base = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); - for(j = 31; j >= 1; j--) - { - if(*word[j]) - break; - } - lua_newtable(L); - for(i = 1; i <= j; i++) - { - lua_pushstring(L, word[i]); - lua_rawseti(L, -2, i); - } - u = lua_newuserdata(L, sizeof(zoitechat_event_attrs *)); - *u = event_attrs_copy(attrs); - luaL_newmetatable(L, "attrs"); - lua_setmetatable(L, -2); - script->status |= STATUS_ACTIVE; - if(lua_pcall(L, 2, 1, base)) - { - char const *error = lua_tostring(L, -1); - lua_pop(L, 2); - zoitechat_printf(ph, "Lua error in print_attrs hook: %s", error ? error : "(non-string error)"); - check_deferred(script); - return HEXCHAT_EAT_NONE; - } - ret = lua_tointeger(L, -1); - lua_pop(L, 2); - check_deferred(script); - return ret; + lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); + base = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); + for(j = 31; j >= 1; j--) + { + if(*word[j]) + break; + } + lua_newtable(L); + for(i = 1; i <= j; i++) + { + lua_pushstring(L, word[i]); + lua_rawseti(L, -2, i); + } + u = lua_newuserdata(L, sizeof(zoitechat_event_attrs *)); + *u = event_attrs_copy(attrs); + luaL_newmetatable(L, "attrs"); + lua_setmetatable(L, -2); + script->status |= STATUS_ACTIVE; + if(lua_pcall(L, 2, 1, base)) + { + char const *error = lua_tostring(L, -1); + lua_pop(L, 2); + zoitechat_printf(ph, "Lua error in print_attrs hook: %s", error ? error : "(non-string error)"); + check_deferred(script); + return HEXCHAT_EAT_NONE; + } + ret = lua_tointeger(L, -1); + lua_pop(L, 2); + check_deferred(script); + return ret; } static int api_zoitechat_hook_print_attrs(lua_State *L) { - hook_info *info, **u; - int ref, pri; - char const *event = luaL_checkstring(L, 1); + hook_info *info, **u; + int ref, pri; + char const *event = luaL_checkstring(L, 1); - lua_pushvalue(L, 2); - ref = luaL_ref(L, LUA_REGISTRYINDEX); - pri = luaL_optinteger(L, 3, HEXCHAT_PRI_NORM); - info = g_new(hook_info, 1); - info->state = L; - info->ref = ref; - info->hook = zoitechat_hook_print_attrs(ph, event, pri, api_print_attrs_closure, info); - u = lua_newuserdata(L, sizeof(hook_info *)); - *u = info; - luaL_newmetatable(L, "hook"); - lua_setmetatable(L, -2); - register_hook(info); - return 1; + lua_pushvalue(L, 2); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + pri = luaL_optinteger(L, 3, HEXCHAT_PRI_NORM); + info = g_new(hook_info, 1); + info->state = L; + info->ref = ref; + info->hook = zoitechat_hook_print_attrs(ph, event, pri, api_print_attrs_closure, info); + u = lua_newuserdata(L, sizeof(hook_info *)); + *u = info; + luaL_newmetatable(L, "hook"); + lua_setmetatable(L, -2); + register_hook(info); + return 1; } static int api_server_closure(char *word[], char *word_eol[], void *udata) { - hook_info *info = udata; - lua_State *L = info->state; - script_info *script = get_info(L); - int base, i, ret; + hook_info *info = udata; + lua_State *L = info->state; + script_info *script = get_info(L); + int base, i, ret; - lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); - base = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); - lua_newtable(L); - for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) - { - lua_pushstring(L, word[i]); - lua_rawseti(L, -2, i); - } - lua_newtable(L); - for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) - { - lua_pushstring(L, word_eol[i]); - lua_rawseti(L, -2, i); - } - script->status |= STATUS_ACTIVE; - if(lua_pcall(L, 2, 1, base)) - { - char const *error = lua_tostring(L, -1); - lua_pop(L, 2); - zoitechat_printf(ph, "Lua error in server hook: %s", error ? error : "(non-string error)"); - check_deferred(script); - return HEXCHAT_EAT_NONE; - } - ret = lua_tointeger(L, -1); - lua_pop(L, 2); - check_deferred(script); - return ret; + lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); + base = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); + lua_newtable(L); + for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) + { + lua_pushstring(L, word[i]); + lua_rawseti(L, -2, i); + } + lua_newtable(L); + for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) + { + lua_pushstring(L, word_eol[i]); + lua_rawseti(L, -2, i); + } + script->status |= STATUS_ACTIVE; + if(lua_pcall(L, 2, 1, base)) + { + char const *error = lua_tostring(L, -1); + lua_pop(L, 2); + zoitechat_printf(ph, "Lua error in server hook: %s", error ? error : "(non-string error)"); + check_deferred(script); + return HEXCHAT_EAT_NONE; + } + ret = lua_tointeger(L, -1); + lua_pop(L, 2); + check_deferred(script); + return ret; } static int api_zoitechat_hook_server(lua_State *L) { - char const *command = luaL_optstring(L, 1, "RAW LINE"); - hook_info *info, **u; - int ref, pri; + char const *command = luaL_optstring(L, 1, "RAW LINE"); + hook_info *info, **u; + int ref, pri; - lua_pushvalue(L, 2); - ref = luaL_ref(L, LUA_REGISTRYINDEX); - pri = luaL_optinteger(L, 3, HEXCHAT_PRI_NORM); - info = g_new(hook_info, 1); - info->state = L; - info->ref = ref; - info->hook = zoitechat_hook_server(ph, command, pri, api_server_closure, info); - u = lua_newuserdata(L, sizeof(hook_info *)); - *u = info; - luaL_newmetatable(L, "hook"); - lua_setmetatable(L, -2); - register_hook(info); - return 1; + lua_pushvalue(L, 2); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + pri = luaL_optinteger(L, 3, HEXCHAT_PRI_NORM); + info = g_new(hook_info, 1); + info->state = L; + info->ref = ref; + info->hook = zoitechat_hook_server(ph, command, pri, api_server_closure, info); + u = lua_newuserdata(L, sizeof(hook_info *)); + *u = info; + luaL_newmetatable(L, "hook"); + lua_setmetatable(L, -2); + register_hook(info); + return 1; } static int api_server_attrs_closure(char *word[], char *word_eol[], zoitechat_event_attrs *attrs, void *udata) { - hook_info *info = udata; - lua_State *L = info->state; - script_info *script = get_info(L); - int base, i, ret; - zoitechat_event_attrs **u; + hook_info *info = udata; + lua_State *L = info->state; + script_info *script = get_info(L); + int base, i, ret; + zoitechat_event_attrs **u; - lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); - base = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); - lua_newtable(L); - for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) - { - lua_pushstring(L, word[i]); - lua_rawseti(L, -2, i); - } - lua_newtable(L); - for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) - { - lua_pushstring(L, word_eol[i]); - lua_rawseti(L, -2, i); - } + lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); + base = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); + lua_newtable(L); + for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) + { + lua_pushstring(L, word[i]); + lua_rawseti(L, -2, i); + } + lua_newtable(L); + for(i = 1; i < WORD_ARRAY_LEN && *word_eol[i]; i++) + { + lua_pushstring(L, word_eol[i]); + lua_rawseti(L, -2, i); + } - u = lua_newuserdata(L, sizeof(zoitechat_event_attrs *)); - *u = event_attrs_copy(attrs); - luaL_newmetatable(L, "attrs"); - lua_setmetatable(L, -2); - script->status |= STATUS_ACTIVE; - if(lua_pcall(L, 3, 1, base)) - { - char const *error = lua_tostring(L, -1); - lua_pop(L, 2); - zoitechat_printf(ph, "Lua error in server_attrs hook: %s", error ? error : "(non-string error)"); - check_deferred(script); - return HEXCHAT_EAT_NONE; - } - ret = lua_tointeger(L, -1); - lua_pop(L, 2); - check_deferred(script); - return ret; + u = lua_newuserdata(L, sizeof(zoitechat_event_attrs *)); + *u = event_attrs_copy(attrs); + luaL_newmetatable(L, "attrs"); + lua_setmetatable(L, -2); + script->status |= STATUS_ACTIVE; + if(lua_pcall(L, 3, 1, base)) + { + char const *error = lua_tostring(L, -1); + lua_pop(L, 2); + zoitechat_printf(ph, "Lua error in server_attrs hook: %s", error ? error : "(non-string error)"); + check_deferred(script); + return HEXCHAT_EAT_NONE; + } + ret = lua_tointeger(L, -1); + lua_pop(L, 2); + check_deferred(script); + return ret; } static int api_zoitechat_hook_server_attrs(lua_State *L) { - char const *command = luaL_optstring(L, 1, "RAW LINE"); - int ref, pri; - hook_info *info, **u; + char const *command = luaL_optstring(L, 1, "RAW LINE"); + int ref, pri; + hook_info *info, **u; - lua_pushvalue(L, 2); - ref = luaL_ref(L, LUA_REGISTRYINDEX); - pri = luaL_optinteger(L, 3, HEXCHAT_PRI_NORM); - info = g_new(hook_info, 1); - info->state = L; - info->ref = ref; - info->hook = zoitechat_hook_server_attrs(ph, command, pri, api_server_attrs_closure, info); - u = lua_newuserdata(L, sizeof(hook_info *)); - *u = info; - luaL_newmetatable(L, "hook"); - lua_setmetatable(L, -2); - register_hook(info); - return 1; + lua_pushvalue(L, 2); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + pri = luaL_optinteger(L, 3, HEXCHAT_PRI_NORM); + info = g_new(hook_info, 1); + info->state = L; + info->ref = ref; + info->hook = zoitechat_hook_server_attrs(ph, command, pri, api_server_attrs_closure, info); + u = lua_newuserdata(L, sizeof(hook_info *)); + *u = info; + luaL_newmetatable(L, "hook"); + lua_setmetatable(L, -2); + register_hook(info); + return 1; } static int api_timer_closure(void *udata) { - hook_info *info = udata; - lua_State *L = info->state; - script_info *script = get_info(L); - int base, ret; + hook_info *info = udata; + lua_State *L = info->state; + script_info *script = get_info(L); + int base, ret; - lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); - base = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); - script->status |= STATUS_ACTIVE; - if(lua_pcall(L, 0, 1, base)) - { - char const *error = lua_tostring(L, -1); - lua_pop(L, 2); - zoitechat_printf(ph, "Lua error in timer hook: %s", error ? error : "(non-string error)"); - check_deferred(script); - return 0; - } - ret = lua_toboolean(L, -1); - lua_pop(L, 2); - check_deferred(script); - return ret; + lua_rawgeti(L, LUA_REGISTRYINDEX, script->traceback); + base = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, info->ref); + script->status |= STATUS_ACTIVE; + if(lua_pcall(L, 0, 1, base)) + { + char const *error = lua_tostring(L, -1); + lua_pop(L, 2); + zoitechat_printf(ph, "Lua error in timer hook: %s", error ? error : "(non-string error)"); + check_deferred(script); + return 0; + } + ret = lua_toboolean(L, -1); + lua_pop(L, 2); + check_deferred(script); + return ret; } static int api_zoitechat_hook_timer(lua_State *L) { - int ref, timeout = luaL_checkinteger (L, 1); - hook_info *info, **u; + int ref, timeout = luaL_checkinteger (L, 1); + hook_info *info, **u; - lua_pushvalue(L, 2); - ref = luaL_ref(L, LUA_REGISTRYINDEX); - info = g_new(hook_info, 1); - info->state = L; - info->ref = ref; - info->hook = zoitechat_hook_timer(ph, timeout, api_timer_closure, info); - u = lua_newuserdata(L, sizeof(hook_info *)); - *u = info; - luaL_newmetatable(L, "hook"); - lua_setmetatable(L, -2); - register_hook(info); - return 1; + lua_pushvalue(L, 2); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + info = g_new(hook_info, 1); + info->state = L; + info->ref = ref; + info->hook = zoitechat_hook_timer(ph, timeout, api_timer_closure, info); + u = lua_newuserdata(L, sizeof(hook_info *)); + *u = info; + luaL_newmetatable(L, "hook"); + lua_setmetatable(L, -2); + register_hook(info); + return 1; } static int api_zoitechat_hook_unload(lua_State *L) { - script_info *script; - hook_info *info, **u; - int ref; + script_info *script; + hook_info *info, **u; + int ref; - lua_pushvalue(L, 1); - ref = luaL_ref(L, LUA_REGISTRYINDEX); - info = g_new(hook_info, 1); - info->state = L; - info->ref = ref; - info->hook = NULL; - u = lua_newuserdata(L, sizeof(hook_info *)); - *u = info; - luaL_newmetatable(L, "hook"); - lua_setmetatable(L, -2); - script = get_info(info->state); + lua_pushvalue(L, 1); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + info = g_new(hook_info, 1); + info->state = L; + info->ref = ref; + info->hook = NULL; + u = lua_newuserdata(L, sizeof(hook_info *)); + *u = info; + luaL_newmetatable(L, "hook"); + lua_setmetatable(L, -2); + script = get_info(info->state); - g_ptr_array_add(script->unload_hooks, info); - return 1; + g_ptr_array_add(script->unload_hooks, info); + return 1; } static int api_zoitechat_unhook(lua_State *L) { - hook_info **info = (hook_info **)luaL_checkudata(L, 1, "hook"); - if(*info) - { - unregister_hook(*info); - *info = 0; - return 0; - } - else - { - tostring(L, 1); - return luaL_error(L, "hook %s is already unhooked", lua_tostring(L, -1)); - } + hook_info **info = (hook_info **)luaL_checkudata(L, 1, "hook"); + if(*info) + { + unregister_hook(*info); + *info = 0; + return 0; + } + else + { + tostring(L, 1); + return luaL_error(L, "hook %s is already unhooked", lua_tostring(L, -1)); + } } static int api_zoitechat_find_context(lua_State *L) { - char const *server = luaL_optstring(L, 1, NULL); - char const *channel = luaL_optstring(L, 2, NULL); - zoitechat_context *context = zoitechat_find_context(ph, server, channel); - if(context) - { - zoitechat_context **u = lua_newuserdata(L, sizeof(zoitechat_context *)); - *u = context; - luaL_newmetatable(L, "context"); - lua_setmetatable(L, -2); - return 1; - } - else - { - lua_pushnil(L); - return 1; - } + char const *server = luaL_optstring(L, 1, NULL); + char const *channel = luaL_optstring(L, 2, NULL); + zoitechat_context *context = zoitechat_find_context(ph, server, channel); + if(context) + { + zoitechat_context **u = lua_newuserdata(L, sizeof(zoitechat_context *)); + *u = context; + luaL_newmetatable(L, "context"); + lua_setmetatable(L, -2); + return 1; + } + else + { + lua_pushnil(L); + return 1; + } } static int api_zoitechat_get_context(lua_State *L) { - zoitechat_context *context = zoitechat_get_context(ph); - zoitechat_context **u = lua_newuserdata(L, sizeof(zoitechat_context *)); - *u = context; - luaL_newmetatable(L, "context"); - lua_setmetatable(L, -2); - return 1; + zoitechat_context *context = zoitechat_get_context(ph); + zoitechat_context **u = lua_newuserdata(L, sizeof(zoitechat_context *)); + *u = context; + luaL_newmetatable(L, "context"); + lua_setmetatable(L, -2); + return 1; } static int api_zoitechat_set_context(lua_State *L) { - zoitechat_context *context = *(zoitechat_context **)luaL_checkudata(L, 1, "context"); - int success = zoitechat_set_context(ph, context); - lua_pushboolean(L, success); - return 1; + zoitechat_context *context = *(zoitechat_context **)luaL_checkudata(L, 1, "context"); + int success = zoitechat_set_context(ph, context); + lua_pushboolean(L, success); + return 1; } static int wrap_context_closure(lua_State *L) { - zoitechat_context *old, *context = *(zoitechat_context **)luaL_checkudata(L, 1, "context"); - lua_pushvalue(L, lua_upvalueindex(1)); - lua_replace(L, 1); - old = zoitechat_get_context(ph); - if(!zoitechat_set_context(ph, context)) - return luaL_error(L, "could not switch into context"); - lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); - zoitechat_set_context(ph, old); - return lua_gettop(L); + zoitechat_context *old, *context = *(zoitechat_context **)luaL_checkudata(L, 1, "context"); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_replace(L, 1); + old = zoitechat_get_context(ph); + if(!zoitechat_set_context(ph, context)) + return luaL_error(L, "could not switch into context"); + lua_call(L, lua_gettop(L) - 1, LUA_MULTRET); + zoitechat_set_context(ph, old); + return lua_gettop(L); } static inline void wrap_context(lua_State *L, char const *field, lua_CFunction func) { - lua_pushcfunction(L, func); - lua_pushcclosure(L, wrap_context_closure, 1); - lua_setfield(L, -2, field); + lua_pushcfunction(L, func); + lua_pushcclosure(L, wrap_context_closure, 1); + lua_setfield(L, -2, field); } static int api_zoitechat_context_meta_eq(lua_State *L) { - zoitechat_context *this = *(zoitechat_context **)luaL_checkudata(L, 1, "context"); - zoitechat_context *that = *(zoitechat_context **)luaL_checkudata(L, 2, "context"); - lua_pushboolean(L, this == that); - return 1; + zoitechat_context *this = *(zoitechat_context **)luaL_checkudata(L, 1, "context"); + zoitechat_context *that = *(zoitechat_context **)luaL_checkudata(L, 2, "context"); + lua_pushboolean(L, this == that); + return 1; } static int api_zoitechat_get_info(lua_State *L) { - char const *key = luaL_checkstring(L, 1); - char const *data = zoitechat_get_info(ph, key); - if(data) - { - if(!strcmp(key, "gtkwin_ptr") || !strcmp(key, "win_ptr")) - lua_pushlightuserdata(L, (void *)data); - else - lua_pushstring(L, data); - return 1; - } - lua_pushnil(L); - return 1; + char const *key = luaL_checkstring(L, 1); + char const *data = zoitechat_get_info(ph, key); + if(data) + { + if(!strcmp(key, "gtkwin_ptr") || !strcmp(key, "win_ptr")) + lua_pushlightuserdata(L, (void *)data); + else + lua_pushstring(L, data); + return 1; + } + lua_pushnil(L); + return 1; } static int api_zoitechat_attrs(lua_State *L) { - zoitechat_event_attrs *attrs = zoitechat_event_attrs_create(ph); - zoitechat_event_attrs **u = lua_newuserdata(L, sizeof(zoitechat_event_attrs *)); - *u = attrs; - luaL_newmetatable(L, "attrs"); - lua_setmetatable(L, -2); - return 1; + zoitechat_event_attrs *attrs = zoitechat_event_attrs_create(ph); + zoitechat_event_attrs **u = lua_newuserdata(L, sizeof(zoitechat_event_attrs *)); + *u = attrs; + luaL_newmetatable(L, "attrs"); + lua_setmetatable(L, -2); + return 1; } static int api_iterate_closure(lua_State *L) { - zoitechat_list *list = *(zoitechat_list **)luaL_checkudata(L, lua_upvalueindex(1), "list"); - if(zoitechat_list_next(ph, list)) - { - lua_pushvalue(L, lua_upvalueindex(1)); - return 1; - } - else - return 0; + zoitechat_list *list = *(zoitechat_list **)luaL_checkudata(L, lua_upvalueindex(1), "list"); + if(zoitechat_list_next(ph, list)) + { + lua_pushvalue(L, lua_upvalueindex(1)); + return 1; + } + else + return 0; } static int api_zoitechat_iterate(lua_State *L) { - char const *name = luaL_checkstring(L, 1); - zoitechat_list *list = zoitechat_list_get(ph, name); - if(list) - { - zoitechat_list **u = lua_newuserdata(L, sizeof(zoitechat_list *)); - *u = list; - luaL_newmetatable(L, "list"); - lua_setmetatable(L, -2); - lua_pushcclosure(L, api_iterate_closure, 1); - return 1; - } - else - return luaL_argerror(L, 1, "invalid list name"); + char const *name = luaL_checkstring(L, 1); + zoitechat_list *list = zoitechat_list_get(ph, name); + if(list) + { + zoitechat_list **u = lua_newuserdata(L, sizeof(zoitechat_list *)); + *u = list; + luaL_newmetatable(L, "list"); + lua_setmetatable(L, -2); + lua_pushcclosure(L, api_iterate_closure, 1); + return 1; + } + else + return luaL_argerror(L, 1, "invalid list name"); } static int api_zoitechat_prefs_meta_index(lua_State *L) { - char const *key = luaL_checkstring(L, 2); - char const *string; - int number; - int ret = zoitechat_get_prefs(ph, key, &string, &number); - switch(ret) - { - case 0: - lua_pushnil(L); - return 1; - case 1: - lua_pushstring(L, string); - return 1; - case 2: - lua_pushnumber(L, number); - return 1; - case 3: - lua_pushboolean(L, number); - return 1; - default: - return 0; - } + char const *key = luaL_checkstring(L, 2); + char const *string; + int number; + int ret = zoitechat_get_prefs(ph, key, &string, &number); + switch(ret) + { + case 0: + lua_pushnil(L); + return 1; + case 1: + lua_pushstring(L, string); + return 1; + case 2: + lua_pushnumber(L, number); + return 1; + case 3: + lua_pushboolean(L, number); + return 1; + default: + return 0; + } } static int api_zoitechat_prefs_meta_newindex(lua_State *L) { - return luaL_error(L, "zoitechat.prefs is read-only"); + return luaL_error(L, "zoitechat.prefs is read-only"); } static inline int list_marshal(lua_State *L, const char *key, zoitechat_list *list) { - char const *str = zoitechat_list_str(ph, list, key); - int number; - if(str) - { - if(!strcmp(key, "context")) - { - zoitechat_context **u = lua_newuserdata(L, sizeof(zoitechat_context *)); - *u = (zoitechat_context *)str; - luaL_newmetatable(L, "context"); - lua_setmetatable(L, -2); - return 1; - } - lua_pushstring(L, str); - return 1; - } - number = zoitechat_list_int(ph, list, key); - if(number != -1) - { - lua_pushinteger(L, number); - return 1; - } - if (list != NULL) - { - time_t tm = zoitechat_list_time(ph, list, key); - if(tm != -1) - { - lua_pushinteger(L, tm); - return 1; - } - } + char const *str = zoitechat_list_str(ph, list, key); + int number; + if(str) + { + if(!strcmp(key, "context")) + { + zoitechat_context **u = lua_newuserdata(L, sizeof(zoitechat_context *)); + *u = (zoitechat_context *)str; + luaL_newmetatable(L, "context"); + lua_setmetatable(L, -2); + return 1; + } + lua_pushstring(L, str); + return 1; + } + number = zoitechat_list_int(ph, list, key); + if(number != -1) + { + lua_pushinteger(L, number); + return 1; + } + if (list != NULL) + { + time_t tm = zoitechat_list_time(ph, list, key); + if(tm != -1) + { + lua_pushinteger(L, tm); + return 1; + } + } - lua_pushnil(L); - return 1; + lua_pushnil(L); + return 1; } static int api_zoitechat_props_meta_index(lua_State *L) { - char const *key = luaL_checkstring(L, 2); - return list_marshal(L, key, NULL); + char const *key = luaL_checkstring(L, 2); + return list_marshal(L, key, NULL); } static int api_zoitechat_props_meta_newindex(lua_State *L) { - return luaL_error(L, "zoitechat.props is read-only"); + return luaL_error(L, "zoitechat.props is read-only"); } static int api_zoitechat_pluginprefs_meta_index(lua_State *L) { - script_info *script = get_info(L); - const char *key; - zoitechat_plugin *h; - char str[512]; - int r; + script_info *script = get_info(L); + const char *key; + zoitechat_plugin *h; + char str[512]; + int r; - if(!script->name) - return luaL_error(L, "cannot use zoitechat.pluginprefs before registering with zoitechat.register"); + if(!script->name) + return luaL_error(L, "cannot use zoitechat.pluginprefs before registering with zoitechat.register"); - key = luaL_checkstring(L, 2); - h = script->handle; - r = zoitechat_pluginpref_get_int(h, key); - if(r != -1) - { - lua_pushinteger(L, r); - return 1; - } - if(zoitechat_pluginpref_get_str(h, key, str)) - { - /* Wasn't actually a failure */ - if (!strcmp(str, "-1")) - lua_pushinteger(L, r); - else - lua_pushstring(L, str); - return 1; - } - lua_pushnil(L); - return 1; + key = luaL_checkstring(L, 2); + h = script->handle; + r = zoitechat_pluginpref_get_int(h, key); + if(r != -1) + { + lua_pushinteger(L, r); + return 1; + } + if(zoitechat_pluginpref_get_str(h, key, str)) + { + /* Wasn't actually a failure */ + if (!strcmp(str, "-1")) + lua_pushinteger(L, r); + else + lua_pushstring(L, str); + return 1; + } + lua_pushnil(L); + return 1; } static int api_zoitechat_pluginprefs_meta_newindex(lua_State *L) { - script_info *script = get_info(L); - const char *key; - zoitechat_plugin *h; + script_info *script = get_info(L); + const char *key; + zoitechat_plugin *h; - if(!script->name) - return luaL_error(L, "cannot use zoitechat.pluginprefs before registering with zoitechat.register"); + if(!script->name) + return luaL_error(L, "cannot use zoitechat.pluginprefs before registering with zoitechat.register"); - key = luaL_checkstring(L, 2); - h = script->handle; - switch(lua_type(L, 3)) - { - case LUA_TSTRING: - zoitechat_pluginpref_set_str(h, key, lua_tostring(L, 3)); - return 0; - case LUA_TNUMBER: - zoitechat_pluginpref_set_int(h, key, lua_tointeger(L, 3)); - return 0; - case LUA_TNIL: case LUA_TNONE: - zoitechat_pluginpref_delete(h, key); - return 0; - default: - return luaL_argerror(L, 3, "expected string, number, or nil"); - } + key = luaL_checkstring(L, 2); + h = script->handle; + switch(lua_type(L, 3)) + { + case LUA_TSTRING: + zoitechat_pluginpref_set_str(h, key, lua_tostring(L, 3)); + return 0; + case LUA_TNUMBER: + zoitechat_pluginpref_set_int(h, key, lua_tointeger(L, 3)); + return 0; + case LUA_TNIL: case LUA_TNONE: + zoitechat_pluginpref_delete(h, key); + return 0; + default: + return luaL_argerror(L, 3, "expected string, number, or nil"); + } } static int api_zoitechat_pluginprefs_meta_pairs_closure(lua_State *L) { - char *dest = lua_touserdata(L, lua_upvalueindex(1)); - zoitechat_plugin *h = get_info(L)->handle; + char *dest = lua_touserdata(L, lua_upvalueindex(1)); + zoitechat_plugin *h = get_info(L)->handle; - if(dest && *dest) - { - int r; - char str[512]; - char *key = dest; + if(dest && *dest) + { + int r; + char str[512]; + char *key = dest; - dest = strchr(dest, ','); - if(dest) - *(dest++) = 0; - lua_pushlightuserdata(L, dest); - lua_replace(L, lua_upvalueindex(1)); - lua_pushstring(L, key); - r = zoitechat_pluginpref_get_int(h, key); - if(r != -1) - { - lua_pushinteger(L, r); - return 2; - } - if(zoitechat_pluginpref_get_str(h, key, str)) - { - lua_pushstring(L, str); - return 2; - } - lua_pushnil(L); - return 2; - } - else - return 0; + dest = strchr(dest, ','); + if(dest) + *(dest++) = 0; + lua_pushlightuserdata(L, dest); + lua_replace(L, lua_upvalueindex(1)); + lua_pushstring(L, key); + r = zoitechat_pluginpref_get_int(h, key); + if(r != -1) + { + lua_pushinteger(L, r); + return 2; + } + if(zoitechat_pluginpref_get_str(h, key, str)) + { + lua_pushstring(L, str); + return 2; + } + lua_pushnil(L); + return 2; + } + else + return 0; } static int api_zoitechat_pluginprefs_meta_pairs(lua_State *L) { - script_info *script = get_info(L); - char *dest; - zoitechat_plugin *h; + script_info *script = get_info(L); + char *dest; + zoitechat_plugin *h; - if(!script->name) + if(!script->name) - return luaL_error(L, "cannot use zoitechat.pluginprefs before registering with zoitechat.register"); + return luaL_error(L, "cannot use zoitechat.pluginprefs before registering with zoitechat.register"); - dest = lua_newuserdata(L, 4096); + dest = lua_newuserdata(L, 4096); - h = script->handle; - if(!zoitechat_pluginpref_list(h, dest)) - strcpy(dest, ""); - lua_pushlightuserdata(L, dest); - lua_pushlightuserdata(L, dest); - lua_pushcclosure(L, api_zoitechat_pluginprefs_meta_pairs_closure, 2); - lua_insert(L, -2); // Return the userdata (second return value from pairs), - // even though it's not used by the closure (first return - // value from pairs), so that Lua knows not to GC it. - return 2; + h = script->handle; + if(!zoitechat_pluginpref_list(h, dest)) + strcpy(dest, ""); + lua_pushlightuserdata(L, dest); + lua_pushlightuserdata(L, dest); + lua_pushcclosure(L, api_zoitechat_pluginprefs_meta_pairs_closure, 2); + lua_insert(L, -2); // Return the userdata (second return value from pairs), + // even though it's not used by the closure (first return + // value from pairs), so that Lua knows not to GC it. + return 2; } static int api_attrs_meta_index(lua_State *L) { - zoitechat_event_attrs *attrs = *(zoitechat_event_attrs **)luaL_checkudata(L, 1, "attrs"); - char const *key = luaL_checkstring(L, 2); - if(!strcmp(key, "server_time_utc")) - { - lua_pushinteger(L, attrs->server_time_utc); - return 1; - } - else - { - lua_pushnil(L); - return 1; - } + zoitechat_event_attrs *attrs = *(zoitechat_event_attrs **)luaL_checkudata(L, 1, "attrs"); + char const *key = luaL_checkstring(L, 2); + if(!strcmp(key, "server_time_utc")) + { + lua_pushinteger(L, attrs->server_time_utc); + return 1; + } + else + { + lua_pushnil(L); + return 1; + } } static int api_attrs_meta_newindex(lua_State *L) { - zoitechat_event_attrs *attrs = *(zoitechat_event_attrs **)luaL_checkudata(L, 1, "attrs"); - char const *key = luaL_checkstring(L, 2); - if(!strcmp(key, "server_time_utc")) - { - attrs->server_time_utc = luaL_checkinteger(L, 3); - return 0; - } - else - return 0; + zoitechat_event_attrs *attrs = *(zoitechat_event_attrs **)luaL_checkudata(L, 1, "attrs"); + char const *key = luaL_checkstring(L, 2); + if(!strcmp(key, "server_time_utc")) + { + attrs->server_time_utc = luaL_checkinteger(L, 3); + return 0; + } + else + return 0; } static int api_attrs_meta_gc(lua_State *L) { - zoitechat_event_attrs *attrs = *(zoitechat_event_attrs **)luaL_checkudata(L, 1, "attrs"); - zoitechat_event_attrs_free(ph, attrs); - return 0; + zoitechat_event_attrs *attrs = *(zoitechat_event_attrs **)luaL_checkudata(L, 1, "attrs"); + zoitechat_event_attrs_free(ph, attrs); + return 0; } static int api_list_meta_index(lua_State *L) { - zoitechat_list *list = *(zoitechat_list **)luaL_checkudata(L, 1, "list"); - char const *key = luaL_checkstring(L, 2); - return list_marshal(L, key, list); + zoitechat_list *list = *(zoitechat_list **)luaL_checkudata(L, 1, "list"); + char const *key = luaL_checkstring(L, 2); + return list_marshal(L, key, list); } static int api_list_meta_newindex(lua_State *L) { - return luaL_error(L, "zoitechat.iterate list is read-only"); + return luaL_error(L, "zoitechat.iterate list is read-only"); } static int api_list_meta_gc(lua_State *L) { - zoitechat_list *list = *(zoitechat_list **)luaL_checkudata(L, 1, "list"); - zoitechat_list_free(ph, list); - return 0; + zoitechat_list *list = *(zoitechat_list **)luaL_checkudata(L, 1, "list"); + zoitechat_list_free(ph, list); + return 0; } static luaL_Reg api_zoitechat[] = { - {"register", api_zoitechat_register}, - {"command", api_zoitechat_command}, - {"print", api_zoitechat_print}, - {"emit_print", api_zoitechat_emit_print}, - {"emit_print_attrs", api_zoitechat_emit_print_attrs}, - {"send_modes", api_zoitechat_send_modes}, - {"nickcmp", api_zoitechat_nickcmp}, - {"strip", api_zoitechat_strip}, - {"get_info", api_zoitechat_get_info}, - {"hook_command", api_zoitechat_hook_command}, - {"hook_print", api_zoitechat_hook_print}, - {"hook_print_attrs", api_zoitechat_hook_print_attrs}, - {"hook_server", api_zoitechat_hook_server}, - {"hook_server_attrs", api_zoitechat_hook_server_attrs}, - {"hook_timer", api_zoitechat_hook_timer}, - {"hook_unload", api_zoitechat_hook_unload}, - {"unhook", api_zoitechat_unhook}, - {"get_context", api_zoitechat_get_context}, - {"find_context", api_zoitechat_find_context}, - {"set_context", api_zoitechat_set_context}, - {"attrs", api_zoitechat_attrs}, - {"iterate", api_zoitechat_iterate}, - {NULL, NULL} + {"register", api_zoitechat_register}, + {"command", api_zoitechat_command}, + {"print", api_zoitechat_print}, + {"emit_print", api_zoitechat_emit_print}, + {"emit_print_attrs", api_zoitechat_emit_print_attrs}, + {"send_modes", api_zoitechat_send_modes}, + {"nickcmp", api_zoitechat_nickcmp}, + {"strip", api_zoitechat_strip}, + {"get_info", api_zoitechat_get_info}, + {"hook_command", api_zoitechat_hook_command}, + {"hook_print", api_zoitechat_hook_print}, + {"hook_print_attrs", api_zoitechat_hook_print_attrs}, + {"hook_server", api_zoitechat_hook_server}, + {"hook_server_attrs", api_zoitechat_hook_server_attrs}, + {"hook_timer", api_zoitechat_hook_timer}, + {"hook_unload", api_zoitechat_hook_unload}, + {"unhook", api_zoitechat_unhook}, + {"get_context", api_zoitechat_get_context}, + {"find_context", api_zoitechat_find_context}, + {"set_context", api_zoitechat_set_context}, + {"attrs", api_zoitechat_attrs}, + {"iterate", api_zoitechat_iterate}, + {NULL, NULL} }; static luaL_Reg api_zoitechat_props_meta[] = { - {"__index", api_zoitechat_props_meta_index}, - {"__newindex", api_zoitechat_props_meta_newindex}, - {NULL, NULL} + {"__index", api_zoitechat_props_meta_index}, + {"__newindex", api_zoitechat_props_meta_newindex}, + {NULL, NULL} }; static luaL_Reg api_zoitechat_prefs_meta[] = { - {"__index", api_zoitechat_prefs_meta_index}, - {"__newindex", api_zoitechat_prefs_meta_newindex}, - {NULL, NULL} + {"__index", api_zoitechat_prefs_meta_index}, + {"__newindex", api_zoitechat_prefs_meta_newindex}, + {NULL, NULL} }; static luaL_Reg api_zoitechat_pluginprefs_meta[] = { - {"__index", api_zoitechat_pluginprefs_meta_index}, - {"__newindex", api_zoitechat_pluginprefs_meta_newindex}, - {"__pairs", api_zoitechat_pluginprefs_meta_pairs}, - {NULL, NULL} + {"__index", api_zoitechat_pluginprefs_meta_index}, + {"__newindex", api_zoitechat_pluginprefs_meta_newindex}, + {"__pairs", api_zoitechat_pluginprefs_meta_pairs}, + {NULL, NULL} }; static luaL_Reg api_hook_meta_index[] = { - {"unhook", api_zoitechat_unhook}, - {NULL, NULL} + {"unhook", api_zoitechat_unhook}, + {NULL, NULL} }; static luaL_Reg api_attrs_meta[] = { - {"__index", api_attrs_meta_index}, - {"__newindex", api_attrs_meta_newindex}, - {"__gc", api_attrs_meta_gc}, - {NULL, NULL} + {"__index", api_attrs_meta_index}, + {"__newindex", api_attrs_meta_newindex}, + {"__gc", api_attrs_meta_gc}, + {NULL, NULL} }; static luaL_Reg api_list_meta[] = { - {"__index", api_list_meta_index}, - {"__newindex", api_list_meta_newindex}, - {"__gc", api_list_meta_gc}, - {NULL, NULL} + {"__index", api_list_meta_index}, + {"__newindex", api_list_meta_newindex}, + {"__gc", api_list_meta_gc}, + {NULL, NULL} }; static int luaopen_zoitechat(lua_State *L) { - lua_newtable(L); - luaL_setfuncs(L, api_zoitechat, 0); + lua_newtable(L); + luaL_setfuncs(L, api_zoitechat, 0); - lua_pushinteger(L, HEXCHAT_PRI_HIGHEST); lua_setfield(L, -2, "PRI_HIGHEST"); - lua_pushinteger(L, HEXCHAT_PRI_HIGH); lua_setfield(L, -2, "PRI_HIGH"); - lua_pushinteger(L, HEXCHAT_PRI_NORM); lua_setfield(L, -2, "PRI_NORM"); - lua_pushinteger(L, HEXCHAT_PRI_LOW); lua_setfield(L, -2, "PRI_LOW"); - lua_pushinteger(L, HEXCHAT_PRI_LOWEST); lua_setfield(L, -2, "PRI_LOWEST"); - lua_pushinteger(L, HEXCHAT_EAT_NONE); lua_setfield(L, -2, "EAT_NONE"); - lua_pushinteger(L, HEXCHAT_EAT_HEXCHAT); lua_setfield(L, -2, "EAT_HEXCHAT"); - lua_pushinteger(L, HEXCHAT_EAT_PLUGIN); lua_setfield(L, -2, "EAT_PLUGIN"); - lua_pushinteger(L, HEXCHAT_EAT_ALL); lua_setfield(L, -2, "EAT_ALL"); + lua_pushinteger(L, HEXCHAT_PRI_HIGHEST); lua_setfield(L, -2, "PRI_HIGHEST"); + lua_pushinteger(L, HEXCHAT_PRI_HIGH); lua_setfield(L, -2, "PRI_HIGH"); + lua_pushinteger(L, HEXCHAT_PRI_NORM); lua_setfield(L, -2, "PRI_NORM"); + lua_pushinteger(L, HEXCHAT_PRI_LOW); lua_setfield(L, -2, "PRI_LOW"); + lua_pushinteger(L, HEXCHAT_PRI_LOWEST); lua_setfield(L, -2, "PRI_LOWEST"); + lua_pushinteger(L, HEXCHAT_EAT_NONE); lua_setfield(L, -2, "EAT_NONE"); + lua_pushinteger(L, HEXCHAT_EAT_HEXCHAT); lua_setfield(L, -2, "EAT_HEXCHAT"); + lua_pushinteger(L, HEXCHAT_EAT_PLUGIN); lua_setfield(L, -2, "EAT_PLUGIN"); + lua_pushinteger(L, HEXCHAT_EAT_ALL); lua_setfield(L, -2, "EAT_ALL"); - lua_newtable(L); - lua_newtable(L); - luaL_setfuncs(L, api_zoitechat_prefs_meta, 0); - lua_setmetatable(L, -2); - lua_setfield(L, -2, "prefs"); + lua_newtable(L); + lua_newtable(L); + luaL_setfuncs(L, api_zoitechat_prefs_meta, 0); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "prefs"); - lua_newtable(L); - lua_newtable(L); - luaL_setfuncs(L, api_zoitechat_props_meta, 0); - lua_setmetatable(L, -2); - lua_setfield(L, -2, "props"); + lua_newtable(L); + lua_newtable(L); + luaL_setfuncs(L, api_zoitechat_props_meta, 0); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "props"); - lua_newtable(L); - lua_newtable(L); - luaL_setfuncs(L, api_zoitechat_pluginprefs_meta, 0); - lua_setmetatable(L, -2); - lua_setfield(L, -2, "pluginprefs"); + lua_newtable(L); + lua_newtable(L); + luaL_setfuncs(L, api_zoitechat_pluginprefs_meta, 0); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "pluginprefs"); - luaL_newmetatable(L, "hook"); - lua_newtable(L); - luaL_setfuncs(L, api_hook_meta_index, 0); - lua_setfield(L, -2, "__index"); - lua_pop(L, 1); + luaL_newmetatable(L, "hook"); + lua_newtable(L); + luaL_setfuncs(L, api_hook_meta_index, 0); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); - luaL_newmetatable(L, "context"); - lua_newtable(L); - lua_pushcfunction(L, api_zoitechat_set_context); - lua_setfield(L, -2, "set"); - wrap_context(L, "find_context", api_zoitechat_find_context); - wrap_context(L, "print", api_zoitechat_print); - wrap_context(L, "emit_print", api_zoitechat_emit_print); - wrap_context(L, "emit_print_attrs", api_zoitechat_emit_print_attrs); - wrap_context(L, "command", api_zoitechat_command); - wrap_context(L, "nickcmp", api_zoitechat_nickcmp); - wrap_context(L, "get_info", api_zoitechat_get_info); - wrap_context(L, "iterate", api_zoitechat_iterate); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, api_zoitechat_context_meta_eq); - lua_setfield(L, -2, "__eq"); - lua_pop(L, 1); + luaL_newmetatable(L, "context"); + lua_newtable(L); + lua_pushcfunction(L, api_zoitechat_set_context); + lua_setfield(L, -2, "set"); + wrap_context(L, "find_context", api_zoitechat_find_context); + wrap_context(L, "print", api_zoitechat_print); + wrap_context(L, "emit_print", api_zoitechat_emit_print); + wrap_context(L, "emit_print_attrs", api_zoitechat_emit_print_attrs); + wrap_context(L, "command", api_zoitechat_command); + wrap_context(L, "nickcmp", api_zoitechat_nickcmp); + wrap_context(L, "get_info", api_zoitechat_get_info); + wrap_context(L, "iterate", api_zoitechat_iterate); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, api_zoitechat_context_meta_eq); + lua_setfield(L, -2, "__eq"); + lua_pop(L, 1); - luaL_newmetatable(L, "attrs"); - luaL_setfuncs(L, api_attrs_meta, 0); - lua_pop(L, 1); + luaL_newmetatable(L, "attrs"); + luaL_setfuncs(L, api_attrs_meta, 0); + lua_pop(L, 1); - luaL_newmetatable(L, "list"); - luaL_setfuncs(L, api_list_meta, 0); - lua_pop(L, 1); + luaL_newmetatable(L, "list"); + luaL_setfuncs(L, api_list_meta, 0); + lua_pop(L, 1); - return 1; + return 1; } static int pairs_closure(lua_State *L) { - lua_settop(L, 1); - if(luaL_getmetafield(L, 1, "__pairs")) - { - lua_insert(L, 1); - lua_call(L, 1, LUA_MULTRET); - return lua_gettop(L); - } - else - { - lua_pushvalue(L, lua_upvalueindex(1)); - lua_insert(L, 1); - lua_call(L, 1, LUA_MULTRET); - return lua_gettop(L); - } + lua_settop(L, 1); + if(luaL_getmetafield(L, 1, "__pairs")) + { + lua_insert(L, 1); + lua_call(L, 1, LUA_MULTRET); + return lua_gettop(L); + } + else + { + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, 1); + lua_call(L, 1, LUA_MULTRET); + return lua_gettop(L); + } } static void patch_pairs(lua_State *L) { - lua_getglobal(L, "pairs"); - lua_pushcclosure(L, pairs_closure, 1); - lua_setglobal(L, "pairs"); + lua_getglobal(L, "pairs"); + lua_pushcclosure(L, pairs_closure, 1); + lua_setglobal(L, "pairs"); } static void patch_clibs(lua_State *L) { - lua_pushnil(L); - while(lua_next(L, LUA_REGISTRYINDEX)) - { - if(lua_type(L, -2) == LUA_TLIGHTUSERDATA && lua_type(L, -1) == LUA_TTABLE) - { - lua_setfield(L, LUA_REGISTRYINDEX, "_CLIBS"); - lua_pop(L, 1); - break; - } - lua_pop(L, 1); - } + lua_pushnil(L); + while(lua_next(L, LUA_REGISTRYINDEX)) + { + if(lua_type(L, -2) == LUA_TLIGHTUSERDATA && lua_type(L, -1) == LUA_TTABLE) + { + lua_setfield(L, LUA_REGISTRYINDEX, "_CLIBS"); + lua_pop(L, 1); + break; + } + lua_pop(L, 1); + } } static GPtrArray *scripts; @@ -1206,500 +1206,528 @@ static GPtrArray *scripts; static char *expand_buffer = NULL; static char const *expand_path(char const *path) { - if(g_path_is_absolute(path)) - return path; + if(g_path_is_absolute(path)) + return path; #ifndef G_OS_WIN32 - if(path[0] == '~') - { - if(!path[1] || path[1] == '/') - { - g_free(expand_buffer); - expand_buffer = g_build_filename(g_get_home_dir(), path + 1, NULL); - return expand_buffer; - } - else - { - char *user = g_strdup(path + 1); - char *slash_pos = strchr(user, '/'); - struct passwd *pw; - if(slash_pos) - *slash_pos = 0; - pw = getpwnam(user); - g_free(user); - if(pw) - { - slash_pos = strchr(path, '/'); - if(!slash_pos) - return pw->pw_dir; + if(path[0] == '~') + { + if(!path[1] || path[1] == '/') + { + g_free(expand_buffer); + expand_buffer = g_build_filename(g_get_home_dir(), path + 1, NULL); + return expand_buffer; + } + else + { + char *user = g_strdup(path + 1); + char *slash_pos = strchr(user, '/'); + struct passwd *pw; + if(slash_pos) + *slash_pos = 0; + pw = getpwnam(user); + g_free(user); + if(pw) + { + slash_pos = strchr(path, '/'); + if(!slash_pos) + return pw->pw_dir; - g_free(expand_buffer); - expand_buffer = g_strconcat(pw->pw_dir, slash_pos, NULL); - return expand_buffer; - } - else - { - return path; - } - } - } - else + g_free(expand_buffer); + expand_buffer = g_strconcat(pw->pw_dir, slash_pos, NULL); + return expand_buffer; + } + else + { + return path; + } + } + } + else #endif - { - g_free(expand_buffer); - expand_buffer = g_build_filename(zoitechat_get_info(ph, "configdir"), "addons", path, NULL); - return expand_buffer; - } + { + g_free(expand_buffer); + expand_buffer = g_build_filename(zoitechat_get_info(ph, "configdir"), "addons", path, NULL); + return expand_buffer; + } } static inline int is_lua_file(char const *file) { - return g_str_has_suffix(file, ".lua") || g_str_has_suffix(file, ".luac"); + return g_str_has_suffix(file, ".lua") || g_str_has_suffix(file, ".luac"); } static void prepare_state(lua_State *L, script_info *info) { - luaL_openlibs(L); - if(LUA_VERSION_NUM < 502) - patch_pairs(L); - if(LUA_VERSION_NUM > 502) - patch_clibs(L); - lua_getglobal(L, "debug"); - lua_getfield(L, -1, "traceback"); - info->traceback = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pop(L, 1); - lua_pushlightuserdata(L, info); - lua_setfield(L, LUA_REGISTRYINDEX, registry_field); - luaopen_zoitechat(L); - lua_setglobal(L, "zoitechat"); - lua_getglobal(L, "zoitechat"); - lua_getfield(L, -1, "print"); - lua_setglobal(L, "print"); - lua_pop(L, 1); + luaL_openlibs(L); + if(LUA_VERSION_NUM < 502) + patch_pairs(L); + if(LUA_VERSION_NUM > 502) + patch_clibs(L); + lua_getglobal(L, "debug"); + lua_getfield(L, -1, "traceback"); + info->traceback = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pop(L, 1); + lua_pushlightuserdata(L, info); + lua_setfield(L, LUA_REGISTRYINDEX, registry_field); + luaopen_zoitechat(L); + lua_setglobal(L, "zoitechat"); + lua_getglobal(L, "zoitechat"); + lua_getfield(L, -1, "print"); + lua_setglobal(L, "print"); + lua_pop(L, 1); } static void run_unload_hook(hook_info *hook, lua_State *L) { - int base = lua_gettop(L); + int base = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, hook->ref); - if(lua_pcall(L, 0, 0, base)) - { - char const *error = lua_tostring(L, -1); - zoitechat_printf(ph, "Lua error in unload hook: %s", error ? error : "(non-string error)"); - } - lua_settop(L, base); + lua_rawgeti(L, LUA_REGISTRYINDEX, hook->ref); + if(lua_pcall(L, 0, 0, base)) + { + char const *error = lua_tostring(L, -1); + zoitechat_printf(ph, "Lua error in unload hook: %s", error ? error : "(non-string error)"); + } + lua_settop(L, base); } static void run_unload_hooks(script_info *info, void *unused) { - lua_State *L = info->state; - lua_rawgeti(L, LUA_REGISTRYINDEX, info->traceback); - g_ptr_array_foreach(info->unload_hooks, (GFunc)run_unload_hook, L); - lua_pop(L, 1); + lua_State *L = info->state; + lua_rawgeti(L, LUA_REGISTRYINDEX, info->traceback); + g_ptr_array_foreach(info->unload_hooks, (GFunc)run_unload_hook, L); + lua_pop(L, 1); } static void destroy_script(script_info *info) { - if (info) - { - g_clear_pointer(&info->hooks, g_ptr_array_unref); - g_clear_pointer(&info->unload_hooks, g_ptr_array_unref); - g_clear_pointer(&info->state, lua_close); - if (info->handle) - zoitechat_plugingui_remove(ph, info->handle); - g_free(info->filename); - g_free(info->name); - g_free(info->description); - g_free(info->version); - g_free(info); - } + if (info) + { + g_clear_pointer(&info->hooks, g_ptr_array_unref); + g_clear_pointer(&info->unload_hooks, g_ptr_array_unref); + g_clear_pointer(&info->state, lua_close); + if (info->handle) + zoitechat_plugingui_remove(ph, info->handle); + g_free(info->filename); + g_free(info->name); + g_free(info->description); + g_free(info->version); + g_free(info); + } } static script_info *create_script(char const *file) { - int base; - char *filename_fs; - lua_State *L; - script_info *info = g_new0(script_info, 1); - info->hooks = g_ptr_array_new_with_free_func((GDestroyNotify)free_hook); - info->unload_hooks = g_ptr_array_new_with_free_func((GDestroyNotify)free_hook); - info->filename = g_strdup(expand_path(file)); - L = luaL_newstate(); - info->state = L; - if(!L) - { - zoitechat_print(ph, "\00304Could not allocate memory for the script"); - destroy_script(info); - return NULL; - } - prepare_state(L, info); - lua_rawgeti(L, LUA_REGISTRYINDEX, info->traceback); - base = lua_gettop(L); - filename_fs = g_filename_from_utf8(info->filename, -1, NULL, NULL, NULL); - if(!filename_fs) - { - zoitechat_printf(ph, "Invalid filename: %s", info->filename); - destroy_script(info); - return NULL; - } - if(luaL_loadfile(L, filename_fs)) - { - g_free(filename_fs); - zoitechat_printf(ph, "Lua syntax error: %s", luaL_optstring(L, -1, "")); - destroy_script(info); - return NULL; - } - g_free(filename_fs); - info->status |= STATUS_ACTIVE; - if(lua_pcall(L, 0, 0, base)) - { - char const *error = lua_tostring(L, -1); - zoitechat_printf(ph, "Lua error: %s", error ? error : "(non-string error)"); - destroy_script(info); - return NULL; - } - lua_pop(L, 1); - if(!info->name) - { - zoitechat_printf(ph, "Lua script didn't register with zoitechat.register"); - destroy_script(info); - return NULL; - } - return info; + int base; + char *filename_fs; + lua_State *L; + script_info *info = g_new0(script_info, 1); + info->hooks = g_ptr_array_new_with_free_func((GDestroyNotify)free_hook); + info->unload_hooks = g_ptr_array_new_with_free_func((GDestroyNotify)free_hook); + info->filename = g_strdup(expand_path(file)); + L = luaL_newstate(); + info->state = L; + if(!L) + { + zoitechat_print(ph, "\00304Could not allocate memory for the script"); + destroy_script(info); + return NULL; + } + prepare_state(L, info); + lua_rawgeti(L, LUA_REGISTRYINDEX, info->traceback); + base = lua_gettop(L); + filename_fs = g_filename_from_utf8(info->filename, -1, NULL, NULL, NULL); + if(!filename_fs) + { + zoitechat_printf(ph, "Invalid filename: %s", info->filename); + destroy_script(info); + return NULL; + } + if(luaL_loadfile(L, filename_fs)) + { + g_free(filename_fs); + zoitechat_printf(ph, "Lua syntax error: %s", luaL_optstring(L, -1, "")); + destroy_script(info); + return NULL; + } + g_free(filename_fs); + info->status |= STATUS_ACTIVE; + if(lua_pcall(L, 0, 0, base)) + { + char const *error = lua_tostring(L, -1); + zoitechat_printf(ph, "Lua error: %s", error ? error : "(non-string error)"); + destroy_script(info); + return NULL; + } + lua_pop(L, 1); + if(!info->name) + { + zoitechat_printf(ph, "Lua script didn't register with zoitechat.register"); + destroy_script(info); + return NULL; + } + return info; } static script_info *get_script_by_file(char const *filename) { - char const *expanded = expand_path(filename); - guint i; - for(i = 0; i < scripts->len; i++) - { - script_info *script = scripts->pdata[i]; - if(!strcmp(script->filename, expanded)) - { - return script; - } - } + guint i; + for(i = 0; i < scripts->len; i++) + { + script_info *script = scripts->pdata[i]; + if(!strcmp(script->filename, filename)) + { + return script; + } + if(g_path_is_absolute(filename) || strchr(filename, '/')) + { + char const *expanded = expand_path(filename); + if(!strcmp(script->filename, expanded)) + return script; + } + else + { + char *basename = g_path_get_basename(script->filename); + gboolean match = !strcmp(basename, filename); + g_free(basename); + if(match) + return script; + } + } - return NULL; + return NULL; } static int load_script(char const *file) { - script_info *info = get_script_by_file(file); + script_info *info = get_script_by_file(file); - if (info != NULL) - { - zoitechat_print(ph, "Lua script is already loaded"); - return 0; - } + if (info != NULL) + { + zoitechat_print(ph, "Lua script is already loaded"); + return 0; + } - info = create_script(file); - if (info) - { - g_ptr_array_add(scripts, info); - check_deferred(info); - } + info = create_script(file); + if (!info) + { + return 0; + } - return 1; + g_ptr_array_add(scripts, info); + check_deferred(info); + + return 1; } static int unload_script(char const *filename) { - script_info *script = get_script_by_file(filename); + script_info *script = get_script_by_file(filename); - if (!script) - return 0; + if (!script) + return 0; - if(script->status & STATUS_ACTIVE) - script->status |= STATUS_DEFERRED_UNLOAD; - else - { - run_unload_hooks(script, NULL); - g_ptr_array_remove_fast(scripts, script); - } + if(script->status & STATUS_ACTIVE) + script->status |= STATUS_DEFERRED_UNLOAD; + else + { + run_unload_hooks(script, NULL); + g_ptr_array_remove_fast(scripts, script); + } - return 1; + return 1; } static int reload_script(char const *filename) { - script_info *script = get_script_by_file(filename); + script_info *script = get_script_by_file(filename); - if (!script) - return 0; + if (!script) + return 0; - if(script->status & STATUS_ACTIVE) - { - script->status |= STATUS_DEFERRED_RELOAD; - } - else - { - char *filename = g_strdup(script->filename); - run_unload_hooks(script, NULL); - g_ptr_array_remove_fast(scripts, script); - load_script(filename); - g_free(filename); - } + if(script->status & STATUS_ACTIVE) + { + script->status |= STATUS_DEFERRED_RELOAD; + } + else + { + char *filename = g_strdup(script->filename); + run_unload_hooks(script, NULL); + g_ptr_array_remove_fast(scripts, script); + load_script(filename); + g_free(filename); + } - return 1; + return 1; } static void autoload_scripts(void) { - char *path = g_build_filename(zoitechat_get_info(ph, "configdir"), "addons", NULL); - GDir *dir = g_dir_open(path, 0, NULL); - if(dir) - { - char const *filename; - while((filename = g_dir_read_name(dir))) - { - if(is_lua_file(filename)) - load_script(filename); - } - g_dir_close(dir); - } - g_free(path); + char *path = g_build_filename(zoitechat_get_info(ph, "configdir"), "addons", NULL); + GDir *dir = g_dir_open(path, 0, NULL); + if(dir) + { + char const *filename; + while((filename = g_dir_read_name(dir))) + { + if(is_lua_file(filename)) + load_script(filename); + } + g_dir_close(dir); + } + g_free(path); } static script_info *interp = NULL; static void create_interpreter(void) { - lua_State *L; - interp = g_new0(script_info, 1); - interp->hooks = g_ptr_array_new_with_free_func((GDestroyNotify)free_hook); - interp->unload_hooks = g_ptr_array_new_with_free_func((GDestroyNotify)free_hook); - interp->name = "lua interpreter"; - interp->description = ""; - interp->version = ""; - interp->handle = ph; - interp->filename = ""; - L = luaL_newstate(); - interp->state = L; - if(!L) - { - zoitechat_print(ph, "\00304Could not allocate memory for the interpreter"); - g_free(interp); - interp = NULL; - return; - } - prepare_state(L, interp); + lua_State *L; + interp = g_new0(script_info, 1); + interp->hooks = g_ptr_array_new_with_free_func((GDestroyNotify)free_hook); + interp->unload_hooks = g_ptr_array_new_with_free_func((GDestroyNotify)free_hook); + interp->name = "lua interpreter"; + interp->description = ""; + interp->version = ""; + interp->handle = ph; + interp->filename = ""; + L = luaL_newstate(); + interp->state = L; + if(!L) + { + zoitechat_print(ph, "\00304Could not allocate memory for the interpreter"); + g_free(interp); + interp = NULL; + return; + } + prepare_state(L, interp); } static void destroy_interpreter(void) { - if(interp) - { - g_clear_pointer(&interp->hooks, g_ptr_array_unref); - g_clear_pointer(&interp->unload_hooks, g_ptr_array_unref); - g_clear_pointer(&interp->state, lua_close); - g_clear_pointer(&interp, g_free); - } + if(interp) + { + g_clear_pointer(&interp->hooks, g_ptr_array_unref); + g_clear_pointer(&interp->unload_hooks, g_ptr_array_unref); + g_clear_pointer(&interp->state, lua_close); + g_clear_pointer(&interp, g_free); + } } static void inject_string(script_info *info, char const *line) { - lua_State *L = info->state; - int base, top; - char *ret_line; - gboolean force_ret = FALSE; + lua_State *L = info->state; + int base, top; + char *ret_line; + gboolean force_ret = FALSE; - if(line[0] == '=') - { - line++; - force_ret = TRUE; - } - ret_line = g_strconcat("return ", line, NULL); + if(line[0] == '=') + { + line++; + force_ret = TRUE; + } + ret_line = g_strconcat("return ", line, NULL); - lua_rawgeti(L, LUA_REGISTRYINDEX, info->traceback); - base = lua_gettop(L); - if(luaL_loadbuffer(L, ret_line, strlen(ret_line), "@interpreter")) - { - if(!force_ret) - lua_pop(L, 1); - if(force_ret || luaL_loadbuffer(L, line, strlen(line), "@interpreter")) - { - zoitechat_printf(ph, "Lua syntax error: %s", luaL_optstring(L, -1, "")); - lua_pop(L, 2); - g_free(ret_line); - return; - } - } - g_free(ret_line); - info->status |= STATUS_ACTIVE; - if(lua_pcall(L, 0, LUA_MULTRET, base)) - { - char const *error = lua_tostring(L, -1); - lua_pop(L, 2); - zoitechat_printf(ph, "Lua error: %s", error ? error : "(non-string error)"); - return; - } - top = lua_gettop(L); - if(top > base) - { - int i; - luaL_Buffer b; - luaL_buffinit(L, &b); - for(i = base + 1; i <= top; i++) - { - if(i != base + 1) - luaL_addstring(&b, " "); - tostring(L, i); - luaL_addvalue(&b); - } - luaL_pushresult(&b); - zoitechat_print(ph, lua_tostring(L, -1)); - lua_pop(L, top - base + 1); - } - lua_pop(L, 1); - check_deferred(info); + lua_rawgeti(L, LUA_REGISTRYINDEX, info->traceback); + base = lua_gettop(L); + if(luaL_loadbuffer(L, ret_line, strlen(ret_line), "@interpreter")) + { + if(!force_ret) + lua_pop(L, 1); + if(force_ret || luaL_loadbuffer(L, line, strlen(line), "@interpreter")) + { + zoitechat_printf(ph, "Lua syntax error: %s", luaL_optstring(L, -1, "")); + lua_pop(L, 2); + g_free(ret_line); + return; + } + } + g_free(ret_line); + info->status |= STATUS_ACTIVE; + if(lua_pcall(L, 0, LUA_MULTRET, base)) + { + char const *error = lua_tostring(L, -1); + lua_pop(L, 2); + zoitechat_printf(ph, "Lua error: %s", error ? error : "(non-string error)"); + return; + } + top = lua_gettop(L); + if(top > base) + { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for(i = base + 1; i <= top; i++) + { + if(i != base + 1) + luaL_addstring(&b, " "); + tostring(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + zoitechat_print(ph, lua_tostring(L, -1)); + lua_pop(L, top - base + 1); + } + lua_pop(L, 1); + check_deferred(info); } static int command_load(char *word[], char *word_eol[], void *userdata) { - if(is_lua_file(word[2])) - { - load_script(word[2]); - return HEXCHAT_EAT_ALL; - } - else - return HEXCHAT_EAT_NONE; + if(is_lua_file(word[2])) + { + load_script(word[2]); + return HEXCHAT_EAT_ALL; + } + else + return HEXCHAT_EAT_NONE; } static int command_unload(char *word[], char *word_eol[], void *userdata) { - if(unload_script(word[2])) - return HEXCHAT_EAT_ALL; - else - return HEXCHAT_EAT_NONE; + if(unload_script(word[2])) + return HEXCHAT_EAT_ALL; + else + return HEXCHAT_EAT_NONE; } static int command_reload(char *word[], char *word_eol[], void *userdata) { - if(reload_script(word[2])) - return HEXCHAT_EAT_ALL; - else - return HEXCHAT_EAT_NONE; + if(reload_script(word[2])) + return HEXCHAT_EAT_ALL; + else + return HEXCHAT_EAT_NONE; } static int command_console_exec(char *word[], char *word_eol[], void *userdata) { - char const *channel = zoitechat_get_info(ph, "channel"); - if(channel && !strcmp(channel, console_tab)) - { - if(interp) - { - zoitechat_printf(ph, "> %s", word_eol[1]); - inject_string(interp, word_eol[1]); - } - return HEXCHAT_EAT_ALL; - } - return HEXCHAT_EAT_NONE; + char const *channel = zoitechat_get_info(ph, "channel"); + if(channel && !strcmp(channel, console_tab)) + { + if(interp) + { + zoitechat_printf(ph, "> %s", word_eol[1]); + inject_string(interp, word_eol[1]); + } + return HEXCHAT_EAT_ALL; + } + return HEXCHAT_EAT_NONE; } static void check_deferred(script_info *info) { - info->status &= ~STATUS_ACTIVE; - if(info->status & STATUS_DEFERRED_UNLOAD) - { - run_unload_hooks(info, NULL); - g_ptr_array_remove_fast(scripts, info); - } - else if(info->status & STATUS_DEFERRED_RELOAD) - { - if(info == interp) - { - run_unload_hooks(interp, NULL); - destroy_interpreter(); - create_interpreter(); - } - else - { - char *filename = g_strdup(info->filename); - run_unload_hooks(info, NULL); - g_ptr_array_remove_fast(scripts, info); - load_script(filename); - g_free(filename); - } - } + info->status &= ~STATUS_ACTIVE; + if(info->status & STATUS_DEFERRED_UNLOAD) + { + run_unload_hooks(info, NULL); + g_ptr_array_remove_fast(scripts, info); + } + else if(info->status & STATUS_DEFERRED_RELOAD) + { + if(info == interp) + { + run_unload_hooks(interp, NULL); + destroy_interpreter(); + create_interpreter(); + } + else + { + char *filename = g_strdup(info->filename); + run_unload_hooks(info, NULL); + g_ptr_array_remove_fast(scripts, info); + load_script(filename); + g_free(filename); + } + } } static int command_lua(char *word[], char *word_eol[], void *userdata) { - if(!strcmp(word[2], "load")) - { - load_script(word[3]); - } - else if(!strcmp(word[2], "unload")) - { - if(!unload_script(word[3])) - zoitechat_printf(ph, "Could not find a script by the name '%s'", word[3]); - } - else if(!strcmp(word[2], "reload")) - { - if(!reload_script(word[3])) - zoitechat_printf(ph, "Could not find a script by the name '%s'", word[3]); - } - else if(!strcmp(word[2], "exec")) - { - if(interp) - inject_string(interp, word_eol[3]); - } - else if(!strcmp(word[2], "inject")) - { - script_info *script = get_script_by_file(word[3]); - if (script) - { - inject_string(script, word_eol[4]); - } - else - { - zoitechat_printf(ph, "Could not find a script by the name '%s'", word[3]); - } - } - else if(!strcmp(word[2], "reset")) - { - if(interp) - { - if(interp->status & STATUS_ACTIVE) - { - interp->status |= STATUS_DEFERRED_RELOAD; - } - else - { - run_unload_hooks(interp, NULL); - destroy_interpreter(); - create_interpreter(); - } - } - } - else if(!strcmp(word[2], "list")) - { - guint i; - zoitechat_print(ph, - "Name Version Filename Description\n" - "---- ------- -------- -----------\n"); - for(i = 0; i < scripts->len; i++) - { - script_info *info = scripts->pdata[i]; - char *basename = g_path_get_basename(info->filename); - zoitechat_printf(ph, "%-16s %-8s %-20s %-10s\n", info->name, info->version, - basename, info->description); - g_free(basename); - } - if(interp) - zoitechat_printf(ph, "%-16s %-8s", interp->name, plugin_version); - } - else if(!strcmp(word[2], "console")) - { - zoitechat_commandf(ph, "query %s", console_tab); - } - else - { - zoitechat_command(ph, "help lua"); - } - return HEXCHAT_EAT_ALL; + if(!strcmp(word[2], "load")) + { + if(load_script(word[3])) + zoitechat_printf(ph, "Loaded Lua script '%s'", word[3]); + else + zoitechat_printf(ph, "Failed to load Lua script '%s'", word[3]); + } + else if(!strcmp(word[2], "unload")) + { + script_info *script = get_script_by_file(word[3]); + if(script) + { + gboolean deferred = script->status & STATUS_ACTIVE; + unload_script(word[3]); + if(deferred) + zoitechat_printf(ph, "Unload scheduled for Lua script '%s'", word[3]); + else + zoitechat_printf(ph, "Unloaded Lua script '%s'", word[3]); + } + else + zoitechat_printf(ph, "Could not find a script by the name '%s'", word[3]); + } + else if(!strcmp(word[2], "reload")) + { + if(!reload_script(word[3])) + zoitechat_printf(ph, "Could not find a script by the name '%s'", word[3]); + } + else if(!strcmp(word[2], "exec")) + { + if(interp) + inject_string(interp, word_eol[3]); + } + else if(!strcmp(word[2], "inject")) + { + script_info *script = get_script_by_file(word[3]); + if (script) + { + inject_string(script, word_eol[4]); + } + else + { + zoitechat_printf(ph, "Could not find a script by the name '%s'", word[3]); + } + } + else if(!strcmp(word[2], "reset")) + { + if(interp) + { + if(interp->status & STATUS_ACTIVE) + { + interp->status |= STATUS_DEFERRED_RELOAD; + } + else + { + run_unload_hooks(interp, NULL); + destroy_interpreter(); + create_interpreter(); + } + } + } + else if(!strcmp(word[2], "list")) + { + guint i; + zoitechat_print(ph, + "Name Version Filename Description\n" + "---- ------- -------- -----------\n"); + for(i = 0; i < scripts->len; i++) + { + script_info *info = scripts->pdata[i]; + char *basename = g_path_get_basename(info->filename); + zoitechat_printf(ph, "%-16s %-8s %-20s %-10s\n", info->name, info->version, + basename, info->description); + g_free(basename); + } + if(interp) + zoitechat_printf(ph, "%-16s %-8s %-20s %-10s", interp->name, plugin_version, "", ""); + } + else if(!strcmp(word[2], "console")) + { + zoitechat_commandf(ph, "query %s", console_tab); + } + else + { + zoitechat_command(ph, "help lua"); + } + return HEXCHAT_EAT_ALL; } /* Reinitialization safegaurd */ @@ -1707,65 +1735,65 @@ static int initialized = 0; G_MODULE_EXPORT int zoitechat_plugin_init(zoitechat_plugin *plugin_handle, char **name, char **description, char **version, char *arg) { - if(initialized != 0) - { - zoitechat_print(plugin_handle, "Lua interface already loaded\n"); - return 0; - } + if(initialized != 0) + { + zoitechat_print(plugin_handle, "Lua interface already loaded\n"); + return 0; + } - if (g_str_has_prefix(LUA_VERSION, "Lua ")) - { - strcat(plugin_version, "/"); - g_strlcat(plugin_version, LUA_VERSION + 4, sizeof(plugin_version)); - } + if (g_str_has_prefix(LUA_VERSION, "Lua ")) + { + strcat(plugin_version, "/"); + g_strlcat(plugin_version, LUA_VERSION + 4, sizeof(plugin_version)); + } - *name = plugin_name; - *description = plugin_description; - *version = plugin_version; + *name = plugin_name; + *description = plugin_description; + *version = plugin_version; - ph = plugin_handle; - initialized = 1; + ph = plugin_handle; + initialized = 1; - zoitechat_hook_command(ph, "", HEXCHAT_PRI_NORM, command_console_exec, NULL, NULL); - zoitechat_hook_command(ph, "LOAD", HEXCHAT_PRI_NORM, command_load, NULL, NULL); - zoitechat_hook_command(ph, "UNLOAD", HEXCHAT_PRI_NORM, command_unload, NULL, NULL); - zoitechat_hook_command(ph, "RELOAD", HEXCHAT_PRI_NORM, command_reload, NULL, NULL); - zoitechat_hook_command(ph, "lua", HEXCHAT_PRI_NORM, command_lua, command_help, NULL); + zoitechat_hook_command(ph, "", HEXCHAT_PRI_NORM, command_console_exec, NULL, NULL); + zoitechat_hook_command(ph, "LOAD", HEXCHAT_PRI_NORM, command_load, NULL, NULL); + zoitechat_hook_command(ph, "UNLOAD", HEXCHAT_PRI_NORM, command_unload, NULL, NULL); + zoitechat_hook_command(ph, "RELOAD", HEXCHAT_PRI_NORM, command_reload, NULL, NULL); + zoitechat_hook_command(ph, "lua", HEXCHAT_PRI_NORM, command_lua, command_help, NULL); - zoitechat_printf(ph, "%s version %s loaded.\n", plugin_name, plugin_version); + zoitechat_printf(ph, "%s version %s loaded.\n", plugin_name, plugin_version); - scripts = g_ptr_array_new_with_free_func((GDestroyNotify)destroy_script); - create_interpreter(); + scripts = g_ptr_array_new_with_free_func((GDestroyNotify)destroy_script); + create_interpreter(); - if(!arg) - autoload_scripts(); - return 1; + if(!arg) + autoload_scripts(); + return 1; } G_MODULE_EXPORT int zoitechat_plugin_deinit(zoitechat_plugin *plugin_handle) { - guint i; - gboolean active = FALSE; - for(i = 0; i < scripts->len; i++) - { - if(((script_info*)scripts->pdata[i])->status & STATUS_ACTIVE) - { - active = TRUE; - break; - } - } - if(interp && interp->status & STATUS_ACTIVE) - active = TRUE; - if(active) - { - zoitechat_print(ph, "\00304Cannot unload the lua plugin while there are active states"); - return 0; - } - if(interp) - run_unload_hooks(interp, NULL); - destroy_interpreter(); - g_ptr_array_foreach(scripts, (GFunc)run_unload_hooks, NULL); - g_clear_pointer(&scripts, g_ptr_array_unref); - g_clear_pointer(&expand_buffer, g_free); - return 1; + guint i; + gboolean active = FALSE; + for(i = 0; i < scripts->len; i++) + { + if(((script_info*)scripts->pdata[i])->status & STATUS_ACTIVE) + { + active = TRUE; + break; + } + } + if(interp && interp->status & STATUS_ACTIVE) + active = TRUE; + if(active) + { + zoitechat_print(ph, "\00304Cannot unload the lua plugin while there are active states"); + return 0; + } + if(interp) + run_unload_hooks(interp, NULL); + destroy_interpreter(); + g_ptr_array_foreach(scripts, (GFunc)run_unload_hooks, NULL); + g_clear_pointer(&scripts, g_ptr_array_unref); + g_clear_pointer(&expand_buffer, g_free); + return 1; }