--- a/main.c Sun Mar 22 05:49:14 2009 +0200
+++ b/main.c Sun Mar 22 18:15:58 2009 +0200
@@ -21,6 +21,7 @@
#include "hooks.h" // hk_add_handler, hk_del_handler
#include "settings.h" // settings_set, settings_del, settings_get
#include "compl.h" // compl_new_category, compl_add_category_word, compl_del_category_word
+#include "events.h" // evs_*
// global lua state object, necessary for uninitialization function
@@ -525,6 +526,105 @@
return 0;
}
+// MCABBER EVENTS
+
+/// event context
+/// Enum, indicating what exactly caused event function firing.
+/// XXX Well, I am not really understand that EVS_* constants mapping semantics,
+/// so, I just provide data, obtained by experiment.
+/// G:
+static const string2enum_t lua_event_context[] = {
+ { "timeout", EVS_CONTEXT_TIMEOUT },
+ { "cancel", EVS_CONTEXT_CANCEL },
+ { "reject", EVS_CONTEXT_USER },
+ { "accept", EVS_CONTEXT_USER + 1 },
+ { NULL, 0 },
+};
+
+typedef struct {
+ lua_State *L;
+ int reference;
+} lua_event_callback_t;
+
+static GSList *lua_events = NULL;
+
+/// event function
+/// Function to be called, when some event state change occurs
+/// A: event context
+static int lua_event_callback (eviqs *event, int context)
+{
+ lua_event_callback_t *cb = event->data;
+
+ lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
+ luaL_pushenum (cb->L, context, lua_event_context);
+ if (lua_pcall (cb->L, 1, 0, 0)) {
+ scr_LogPrint (LPRINT_LOGNORM, "lua: Event callback execution error: %s", lua_tostring (cb->L, -1));
+ lua_pop (cb->L, 1);
+ }
+
+ luaL_unref (cb->L, LUA_REGISTRYINDEX, cb->reference);
+ lua_events = g_slist_remove (lua_events, event);
+ evs_del (event->id); // XXX
+
+ return 0; // XXX
+}
+
+/// main.event
+/// Creates new event. If called without arguments, returns event id list.
+/// A: event function (optional), integer (expiration timeout, optional), string (description, optional)
+/// R: string (event id) or nothing (creation error) or table (list of event names)
+static int lua_main_event (lua_State *L)
+{
+ int top = lua_gettop (L);
+ if (top > 0) { // Create
+ eviqs *event;
+ lua_event_callback_t *cb;
+ int timeout = 0;
+ char *desc = NULL;
+ luaL_argcheck (L, lua_type (L, 1) == LUA_TFUNCTION, 1, "event function expected");
+
+ if (top > 1) {
+ timeout = luaL_checkinteger (L, 2);
+ if (top > 2) {
+ desc = g_strdup (luaL_checkstring (L, 3)); // g_freed by mcabber
+ lua_pop (L, 2);
+ } else
+ lua_pop (L, 1);
+ }
+
+ event = evs_new (EVS_TYPE_USER, timeout);
+ if (!event)
+ return 0;
+
+ lua_pushvalue (L, 1);
+ cb = g_new (lua_event_callback_t, 1); // g_freed by mcabber
+ cb->L = L;
+ cb->reference = luaL_ref (L, LUA_REGISTRYINDEX);
+
+ event->data = cb;
+ event->callback = lua_event_callback;
+ event->desc = desc;
+
+ lua_events = g_slist_prepend (lua_events, event);
+
+ lua_pushstring (L, event->id);
+ return 1;
+ } else { // List
+ GSList *events = evs_geteventslist (0);
+ GSList *event;
+
+ lua_newtable (L);
+ for (event = events; event; event = g_slist_next (event)) {
+ lua_pushstring (L, event->data);
+ luaL_ref (L, -2);
+ g_free (event->data);
+ }
+ g_slist_free (events);
+
+ return 1;
+ }
+}
+
// MCABBER COMMANDS
/// completion type
@@ -1072,6 +1172,7 @@
reg ( fileoption )
reg ( add_feature )
reg ( del_feature )
+ reg ( event )
reg ( parse_args )
reg ( add_category )
reg ( del_category )
@@ -1161,6 +1262,14 @@
return NULL;
}
+static void lua_events_destroy (eviqs *event, gpointer ignore)
+{
+ lua_event_callback_t *cb = event->data;
+ evs_callback (event->id, EVS_CONTEXT_CANCEL); // ignore
+ luaL_unref (cb->L, LUA_REGISTRYINDEX, cb->reference);
+ evs_del (event->id);
+}
+
static void lua_timers_destroy (guint source, gpointer ignore)
{
g_source_remove (source);
@@ -1202,6 +1311,10 @@
g_slist_free (lua_timers);
lua_timers = NULL;
+ g_slist_foreach (lua_events, (GFunc) lua_events_destroy, NULL);
+ g_slist_free (lua_events);
+ lua_events = NULL;
+
g_slist_foreach (lua_added_features, (GFunc) lua_features_destroy, NULL);
g_slist_free (lua_added_features);
lua_added_features = NULL;