lua.c
changeset 103 2cb96eae301a
child 104 626ff4f83519
equal deleted inserted replaced
102:f3d9d9e67ee4 103:2cb96eae301a
       
     1 
       
     2 /* Copyright 2009 Myhailo Danylenko
       
     3 
       
     4 This file is part of mcabber-lua.
       
     5 
       
     6 mcabber-lua is free software: you can redistribute it and/or modify
       
     7 it under the terms of the GNU General Public License as published by
       
     8 the Free Software Foundation, either version 2 of the License, or
       
     9 (at your option) any later version.
       
    10 
       
    11 This program is distributed in the hope that it will be useful,
       
    12 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    14 GNU General Public License for more details.
       
    15 
       
    16 You should have received a copy of the GNU General Public License
       
    17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
       
    18 
       
    19 #include <glib.h>
       
    20 #include <gmodule.h>   // g_module_*
       
    21 #include <lua.h>
       
    22 #include <lauxlib.h>
       
    23 #include <lualib.h>
       
    24 #include <stdio.h>
       
    25 #include <stdlib.h>    // getenv
       
    26 #include <string.h>    // strcmp
       
    27 
       
    28 #include <mcabber/logprint.h>    // scr_log_print
       
    29 #include <mcabber/screen.h>      // scr_Beep, scr_WriteIncomingMessage
       
    30 #include <mcabber/hbuf.h>        // HBB_PREFIX_INFO
       
    31 #include <mcabber/commands.h>    // process_command, cmd_add, cmd_del
       
    32 #include <mcabber/xmpp.h>        // xmpp_getstatus, xmpp_getstatusmsg, lconnection
       
    33 #include <mcabber/xmpp_helper.h> // xmpp_add_feature, xmpp_del_feature
       
    34 #include <mcabber/roster.h>      // imstatus2char, foreach_buddy, buddy_*, current_buddy, BUDDATA, ROSTER_TYPE_*
       
    35 #include <mcabber/utils.h>       // from_utf8, jidtodisp
       
    36 #include <mcabber/hooks.h>       // hk_add_handler, hk_del_handler
       
    37 #include <mcabber/settings.h>    // settings_set, settings_del, settings_get
       
    38 #include <mcabber/compl.h>       // compl_new_category, compl_add_category_word, compl_del_category_word
       
    39 #include <mcabber/events.h>      // evs_*
       
    40 #include <mcabber/modules.h>     // module_info_t
       
    41 
       
    42 #include "config.h"
       
    43 #include "util.h"
       
    44 
       
    45 // module description
       
    46 static void mlua_init   (void);
       
    47 static void mlua_uninit (void);
       
    48 
       
    49 #ifdef LLM_LOG_HANDLER
       
    50 #define DESCRIPTION ( \
       
    51 	"Lua scripting interface\n" \
       
    52 	"Recognizes options lua_init_file, lua_hook_function and lua_lm_debug\n" \
       
    53 	"Provides command /lua" )
       
    54 #else
       
    55 #define DESCRIPTION ( \
       
    56 	"Lua scripting interface\n" \
       
    57 	"Recognizes options lua_init_file and lua_hook_function\n" \
       
    58 	"Provides command /lua" )
       
    59 #endif
       
    60 
       
    61 static module_info_t info_lua_experimental = {
       
    62 	.branch      = "experimental",
       
    63 	.api         = 12,
       
    64 	.version     = PROJECT_VERSION,
       
    65 	.description = DESCRIPTION,
       
    66 	.requires    = NULL,
       
    67 	.init        = mlua_init,
       
    68 	.uninit      = mlua_uninit,
       
    69 	.next        = NULL,
       
    70 };
       
    71 
       
    72 module_info_t info_lua = {
       
    73 	.branch      = "dev",
       
    74 	.api         = 11,
       
    75 	.version     = PROJECT_VERSION,
       
    76 	.description = DESCRIPTION,
       
    77 	.requires    = NULL,
       
    78 	.init        = mlua_init,
       
    79 	.uninit      = mlua_uninit,
       
    80 	.next        = &info_lua_experimental,
       
    81 };
       
    82 
       
    83 // global lua state object, necessary for uninitialization function
       
    84 static lua_State *lua = NULL;
       
    85 
       
    86 // caller sould g_free result
       
    87 static char *mcabber_config_filename (const char *file)
       
    88 {
       
    89 	const char *home = getenv ("HOME");
       
    90 	if (!home)
       
    91 		return NULL;
       
    92 	return g_strconcat (home, "/.mcabber/", file ? file : "", NULL);
       
    93 }
       
    94 
       
    95 /// print
       
    96 /// Prints its arguments to log with default priority.
       
    97 /// A: something, ...
       
    98 static int lua_global_print (lua_State *L)
       
    99 {
       
   100 	int         top = lua_gettop (L);
       
   101 	int         i;
       
   102 	luaL_Buffer B;
       
   103 	luaL_buffinit (L, &B);
       
   104 	for (i = 1; i <= top; i++) {
       
   105 		int type = lua_type (L, i);
       
   106 		if (i > 1)
       
   107 			luaL_addchar (&B, '\t');
       
   108 		if (type == LUA_TSTRING) {
       
   109 			size_t len;
       
   110 			const char *str = lua_tolstring (L, i, &len);
       
   111 			luaL_addlstring (&B, str, len);
       
   112 		} else if (type == LUA_TNUMBER)
       
   113 			luaL_addstring (&B, lua_tostring (L, i)); // XXX: modifies
       
   114 		else if (type == LUA_TBOOLEAN) {
       
   115 			if (lua_toboolean (L, i))
       
   116 				 luaL_addstring (&B, "true");
       
   117 			else
       
   118 				luaL_addstring (&B, "false");
       
   119 		} else if (type == LUA_TNIL)
       
   120 			luaL_addstring (&B, "nil");
       
   121 		else {
       
   122 			char xbuf[9];
       
   123 			luaL_addstring (&B, luaL_typename (L, i));
       
   124 			luaL_addstring (&B, ": 0x");
       
   125 			snprintf (&xbuf[0], 9, "%08x", (int) lua_topointer (L, i));
       
   126 			luaL_addlstring (&B, xbuf, 8); // XXX
       
   127 		}
       
   128 	}
       
   129 	luaL_pushresult (&B);
       
   130 
       
   131 	scr_log_print (LPRINT_LOGNORM | LPRINT_NOTUTF8, lua_tostring (L, -1));
       
   132 	return 0;
       
   133 }
       
   134 
       
   135 /// dopath
       
   136 /// Loads lua file from default location.
       
   137 /// XXX: g_filename_from_utf8?
       
   138 /// A: string (filename, without ".lua")
       
   139 /// R: string (error message, optional)
       
   140 static int lua_global_dopath (lua_State *L)
       
   141 {
       
   142 	const char *name = luaL_checkstring (L, 1);
       
   143 	size_t      size = lua_objlen (L, 1);
       
   144 	char       *path;
       
   145 	int         ret = 0;
       
   146 	if (size > 4 && !strncmp (name + size - 4, ".lua", 4))
       
   147 		path = mcabber_config_filename (name);
       
   148 	else {
       
   149 		char *fname = g_strconcat (name, ".lua", NULL);
       
   150 		path = mcabber_config_filename (fname);
       
   151 		g_free (fname);
       
   152 	}
       
   153 
       
   154 	if ((ret = luaL_loadfile (L, path)))
       
   155 		scr_log_print (LPRINT_LOGNORM, "lua: Unable to compile file %s: %s", path, lua_tostring (L, -1));
       
   156 	else if ((ret = lua_pcall (L, 0, LUA_MULTRET, 0)))
       
   157 		scr_log_print (LPRINT_LOGNORM, "lua: Runtime error in file %s: %s", path, lua_tostring (L, -1));
       
   158 	g_free (path);
       
   159 
       
   160 	if (ret)
       
   161 		return 1;
       
   162 	else
       
   163 		return 0;
       
   164 }
       
   165 
       
   166 /// yes or no ansvers
       
   167 /// G:
       
   168 static const string2enum_t lua_yesno[] = {
       
   169 	{ "1",       1 },
       
   170 	{ "0",       0 },
       
   171 	{ "enable",  1 },
       
   172 	{ "disable", 0 },
       
   173 	{ "true",    1 },
       
   174 	{ "false",   0 },
       
   175 	{ "on",      1 },
       
   176 	{ "off",     0 },
       
   177 	{ "yes",     1 },
       
   178 	{ "no",      0 },
       
   179 	{ NULL,     -1 },
       
   180 };
       
   181 
       
   182 /// main.yesno
       
   183 /// According to yes or no ansvers returns true or false.
       
   184 /// If ansver is not recognized, returns nil.
       
   185 /// A: anything (string expected)
       
   186 /// R: boolean or nil
       
   187 static int lua_main_yesno (lua_State *L)
       
   188 {
       
   189 	int type = lua_type (L, 1);
       
   190 	if (type == LUA_TSTRING) {
       
   191 		int ret = luaL_checkenum (L, 1, lua_yesno);
       
   192 		if (ret == -1)
       
   193 			lua_pushnil (L);
       
   194 		else
       
   195 			lua_pushboolean (L, ret);
       
   196 	} else if (type == LUA_TNUMBER)
       
   197 		lua_pushboolean (L, lua_tointeger (L, 1));
       
   198 	else if (type != LUA_TBOOLEAN)
       
   199 		lua_pushnil (L);
       
   200 	return 1;
       
   201 }
       
   202 
       
   203 /// log print type
       
   204 /// G:
       
   205 static const string2enum_t lua_lprint[] = {
       
   206 	{ "normal",  LPRINT_NORMAL  },
       
   207 	{ "log",     LPRINT_LOG     },
       
   208 	{ "debug",   LPRINT_DEBUG   },
       
   209 	{ "notutf0", LPRINT_NOTUTF8 },
       
   210 	{ NULL,      0              },
       
   211 };
       
   212 
       
   213 /// roster type
       
   214 /// G:
       
   215 static const string2enum_t lua_roster_type[] = {
       
   216 	{ "user",    ROSTER_TYPE_USER    },
       
   217 	{ "group",   ROSTER_TYPE_GROUP   },
       
   218 	{ "agent",   ROSTER_TYPE_AGENT   },
       
   219 	{ "room",    ROSTER_TYPE_ROOM    },
       
   220 	{ "special", ROSTER_TYPE_SPECIAL },
       
   221 	{ NULL,      0                   },
       
   222 };
       
   223 
       
   224 /// main.log
       
   225 /// Prints message to log.
       
   226 /// Note: most likely you need notutf8 flag enabled.
       
   227 /// A: log print type, message, message...
       
   228 static int lua_main_log (lua_State *L)
       
   229 {
       
   230 	int type = luaL_checkenum_multi (L, 1, lua_lprint);
       
   231 	lua_concat (L, lua_gettop (L) - 1);
       
   232 	scr_log_print (type, lua_tostring (L, -1));
       
   233 	return 0;
       
   234 }
       
   235 
       
   236 // expects table on top
       
   237 static void lua_options_callback (char *key, char *value, lua_State *L)
       
   238 {
       
   239 	char *loc = from_utf8 (key);
       
   240 	lua_pushstring (L, loc);
       
   241 	g_free (loc);
       
   242 	loc = from_utf8 (value);
       
   243 	lua_pushstring (L, loc);
       
   244 	g_free (loc);
       
   245 	lua_settable (L, -3);
       
   246 }
       
   247 
       
   248 /// main.option
       
   249 /// Sets or gets value of mcabber option.
       
   250 /// You can specify nil as a value to delete option.
       
   251 /// If you omit option name, it returns hash table of all options.
       
   252 /// A: string (option name, optional), string (value, optional)
       
   253 /// R: string (value, optional)
       
   254 static int lua_main_option (lua_State *L)
       
   255 {
       
   256 	int top = lua_gettop (L);
       
   257 	if (top > 0) {
       
   258 		char *name = to_utf8 (luaL_checkstring (L, 1));
       
   259 		if (top > 1) { // Set
       
   260 			if (lua_type (L, 2) == LUA_TNIL) // Unset
       
   261 				settings_del (SETTINGS_TYPE_OPTION, name);
       
   262 			else { // Set
       
   263 				char *value = to_utf8 (luaL_checkstring (L, 2));
       
   264 				settings_set (SETTINGS_TYPE_OPTION, name, value);
       
   265 				g_free (value);
       
   266 			}
       
   267 			g_free (name);
       
   268 			return 0;
       
   269 		} else { // Get
       
   270 			char *value = from_utf8 (settings_get (SETTINGS_TYPE_OPTION, name));
       
   271 			if (value) {
       
   272 				lua_pushstring (L, value);
       
   273 				g_free (value);
       
   274 			} else
       
   275 				lua_pushnil (L);
       
   276 			g_free (name);
       
   277 			return 1;
       
   278 		}
       
   279 	} else { // List
       
   280 		lua_newtable (L);
       
   281 		settings_foreach (SETTINGS_TYPE_OPTION, (void (*)(char *key, char *val, void *ud)) lua_options_callback, L);
       
   282 		return 1;
       
   283 	}
       
   284 }
       
   285 
       
   286 /// main.alias
       
   287 /// Sets or gets alias.
       
   288 /// You can specify nil as a command to delete alias.
       
   289 /// If you omit alias name, it will return hash table of all aliases.
       
   290 /// A: string (alias name, optional), string (command, optional)
       
   291 /// R: string (command, optional)
       
   292 static int lua_main_alias (lua_State *L)
       
   293 {
       
   294 	int top = lua_gettop (L);
       
   295 	if (top > 0) {
       
   296 		char *name = to_utf8 (luaL_checkstring (L, 1));
       
   297 		if (top > 1) { // Set
       
   298 			if (lua_type (L, 2) == LUA_TNIL) { // Unset
       
   299 				settings_del (SETTINGS_TYPE_ALIAS, name);
       
   300 				compl_del_category_word (COMPL_CMD, name);
       
   301 			} else { // Set
       
   302 				char *value = to_utf8 (luaL_checkstring (L, 2));
       
   303 				if (!settings_get (SETTINGS_TYPE_ALIAS, name))
       
   304 					compl_add_category_word (COMPL_CMD, name);
       
   305 				settings_set (SETTINGS_TYPE_ALIAS, name, value);
       
   306 				g_free (value);
       
   307 			}
       
   308 			g_free (name);
       
   309 			return 0;
       
   310 		} else { // Get
       
   311 			char *value = from_utf8 (settings_get (SETTINGS_TYPE_ALIAS, name));
       
   312 			if (value) {
       
   313 				lua_pushstring (L, value);
       
   314 				g_free (value);
       
   315 			} else
       
   316 				lua_pushnil (L);
       
   317 			g_free (name);
       
   318 			return 1;
       
   319 		}
       
   320 	} else { // List
       
   321 		lua_newtable (L);
       
   322 		settings_foreach (SETTINGS_TYPE_ALIAS, (void (*)(char *key, char *val, void *ud)) lua_options_callback, L);
       
   323 		return 1;
       
   324 	}
       
   325 }
       
   326 
       
   327 /// main.bind
       
   328 /// Sets or gets binding.
       
   329 /// You can specify nil as a command to unbind key.
       
   330 /// If you omit keycode, it will return hash table of all bindings.
       
   331 /// A: string (keycode, optional), string (command, optional)
       
   332 /// R: string (command, optional)
       
   333 static int lua_main_binding (lua_State *L)
       
   334 {
       
   335 	int top = lua_gettop (L);
       
   336 	if (top > 0) {
       
   337 		// just to be sure...
       
   338 		char *name = to_utf8 (luaL_checkstring (L, 1));
       
   339 		if (top > 1) { // Set
       
   340 			if (lua_type (L, 2) == LUA_TNIL) // Unset
       
   341 				settings_del (SETTINGS_TYPE_BINDING, name);
       
   342 			else { // Set
       
   343 				char *value = to_utf8 (luaL_checkstring (L, 2));
       
   344 				settings_set (SETTINGS_TYPE_BINDING, name, value);
       
   345 				g_free (value);
       
   346 			}
       
   347 			g_free (name);
       
   348 			return 0;
       
   349 		} else { // Get
       
   350 			char *value = from_utf8 (settings_get (SETTINGS_TYPE_BINDING, name));
       
   351 			if (value) {
       
   352 				lua_pushstring (L, value);
       
   353 				g_free (value);
       
   354 			} else
       
   355 				lua_pushnil (L);
       
   356 			g_free (name);
       
   357 			return 1;
       
   358 		}
       
   359 	} else { // List
       
   360 		lua_newtable (L);
       
   361 		settings_foreach (SETTINGS_TYPE_BINDING, (void (*)(char *key, char *val, void *ud)) lua_options_callback, L);
       
   362 		return 1;
       
   363 	}
       
   364 }
       
   365 
       
   366 /// main.fileoption
       
   367 /// Gets option, expanding it as filename.
       
   368 /// A: string (option name)
       
   369 /// R: string (expanded option value) or nil
       
   370 static int lua_main_fileoption (lua_State *L)
       
   371 {
       
   372 	char *fname = expand_filename (settings_opt_get (luaL_checkstring (L, 1)));
       
   373 	if (fname) {
       
   374 		lua_pushstring (L, fname);
       
   375 		g_free (fname);
       
   376 	} else
       
   377 		lua_pushnil (L);
       
   378 	return 1;
       
   379 }
       
   380 
       
   381 #ifdef LLM_CONNECTION_ENABLE
       
   382 /// main.connection
       
   383 /// Returns lightuserdata of mcabber's loudmouth connection.
       
   384 /// This can be very useful with lua-loudmouth, and not much otherwise.
       
   385 /// R: lightuserdata or nil
       
   386 static int lua_main_connection (lua_State *L)
       
   387 {
       
   388 	if (xmpp_is_online ())
       
   389 		lua_pushlightuserdata (L, lconnection);
       
   390 	else
       
   391 		lua_pushnil (L);
       
   392 	return 1;
       
   393 }
       
   394 #endif
       
   395 
       
   396 /// main.print_info
       
   397 /// Prints a system message to buddy's window.
       
   398 /// A: string (jid), string (message)
       
   399 static int lua_main_print_info (lua_State *L)
       
   400 {
       
   401 	char *jid  = to_utf8 (luaL_checkstring (L, 1));
       
   402 	char *to   = jidtodisp (jid);
       
   403 	char *mesg = to_utf8 (luaL_checkstring (L, 2));
       
   404 	scr_write_incoming_message (to, mesg, 0, HBB_PREFIX_INFO, 0);
       
   405 	g_free (mesg);
       
   406 	g_free (to);
       
   407 	g_free (jid);
       
   408 	return 0;
       
   409 }
       
   410 
       
   411 /// main.beep
       
   412 /// Beeps with system speaker.
       
   413 static int lua_main_beep (lua_State *L)
       
   414 {
       
   415 	scr_beep ();
       
   416 	return 0;
       
   417 }
       
   418 
       
   419 /// main.run
       
   420 /// Runs specified mcabber command.
       
   421 /// A: string
       
   422 static int lua_main_run (lua_State *L)
       
   423 {
       
   424 	process_command (luaL_checkstring (L, 1), TRUE);
       
   425 	return 0;
       
   426 }
       
   427 
       
   428 /// main.status
       
   429 /// Returns your current status.
       
   430 /// R: string (status letter), string (status message)
       
   431 static int lua_main_status (lua_State *L)
       
   432 {
       
   433 	char *sm = from_utf8 (xmpp_getstatusmsg ());
       
   434 	lua_pushlstring (L, &imstatus2char[xmpp_getstatus ()], 1);
       
   435 	lua_pushstring (L, sm);
       
   436 	g_free (sm);
       
   437 	return 2;
       
   438 }
       
   439 
       
   440 // expects table on top
       
   441 static void lua_rosterlist_callback (gpointer buddy, lua_State *L)
       
   442 {
       
   443 	char *jid = from_utf8 (buddy_getjid (buddy));
       
   444 	lua_pushnumber (L, lua_objlen (L, -1) + 1);
       
   445 	lua_pushstring (L, jid);
       
   446 	lua_settable (L, -3);
       
   447 	g_free (jid);
       
   448 }
       
   449 
       
   450 /// main.roster
       
   451 /// Returns array of jids of buddies in roster.
       
   452 /// R: table
       
   453 static int lua_main_roster (lua_State *L)
       
   454 {
       
   455 	lua_newtable (L);
       
   456 	foreach_buddy (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM, (void (*) (gpointer buddy, void *data)) lua_rosterlist_callback, L);
       
   457 	return 1;
       
   458 }
       
   459 
       
   460 /// main.current_buddy
       
   461 /// Returns jid of current selected buddy or sets current buddy to buddy with specified jid.
       
   462 /// A: string (optional)
       
   463 /// R: string (optional)
       
   464 static int lua_main_current_buddy (lua_State *L)
       
   465 {
       
   466 	if (lua_gettop (L) > 0) { // Set
       
   467 		// XXX: we need not convert to utf, RS works on jids/names in locale charset,
       
   468 		// but will jidtodisp always correctly work on such tings?
       
   469 		char *jid = jidtodisp (luaL_checkstring (L, 1));
       
   470 		scr_roster_search (jid);
       
   471 		g_free (jid);
       
   472 		return 0;
       
   473 	} else { // Get
       
   474 		char *jid = from_utf8 (buddy_getjid (BUDDATA (current_buddy)));
       
   475 		lua_pushstring (L, jid);
       
   476 		g_free (jid);
       
   477 		return 1;
       
   478 	}
       
   479 }
       
   480 
       
   481 /// main.full_jid
       
   482 /// Returns full jid (with current resource) of specified buddy (or current, if not specified).
       
   483 /// Note, that if there are no resources online, it will return just what it got.
       
   484 /// A: string (jid, optional)
       
   485 /// R: string (jid)
       
   486 static int lua_main_full_jid (lua_State *L)
       
   487 {
       
   488 	GList  *buddy;
       
   489 	GSList *resources;
       
   490 	GSList *resource;
       
   491 	if (lua_gettop (L) > 0) {
       
   492 		char *jid = from_utf8 (luaL_checkstring (L, 1));
       
   493 		buddy = buddy_search_jid (jid);
       
   494 		g_free (jid);
       
   495 	} else
       
   496 		buddy = current_buddy;
       
   497 	if (!buddy)
       
   498 		return 0;
       
   499 	resources = buddy_getresources (BUDDATA (buddy));
       
   500 	if (!resources) {
       
   501 		char *loc = from_utf8 (buddy_getjid (BUDDATA (buddy)));
       
   502 		lua_pushstring (L, loc);
       
   503 		g_free (loc);
       
   504 	} else {
       
   505 		char *jid = from_utf8 (buddy_getjid (BUDDATA (buddy)));
       
   506 		char *res = from_utf8 (g_slist_last (resources)->data);
       
   507 		lua_pushfstring (L, "%s%c%s", jid, JID_RESOURCE_SEPARATOR, res);
       
   508 		for (resource = resources; resource; resource = g_slist_next (resource))
       
   509 			g_free (resource->data);
       
   510 		g_slist_free (resources);
       
   511 		g_free (jid);
       
   512 		g_free (res);
       
   513 	}
       
   514 	return 1;
       
   515 }
       
   516 
       
   517 typedef struct {
       
   518 	lua_State *L;
       
   519 	gpointer   buddy;
       
   520 } lua_state_and_buddy_t; // :)
       
   521 
       
   522 /// resources table
       
   523 /// Hash table with resource name as keys and another hash tables as values.
       
   524 /// Inner tables contain resource-specific information: priority, status and message.
       
   525 static void lua_buddy_resources_callback (gpointer resource, lua_state_and_buddy_t *d)
       
   526 {
       
   527 	char *loc = from_utf8 (resource);
       
   528 	lua_pushstring (d->L, loc);
       
   529 	g_free (loc);
       
   530 	lua_createtable (d->L, 0, 3);
       
   531 	lua_pushstring (d->L, "priority");
       
   532 	lua_pushnumber (d->L, buddy_getresourceprio (d->buddy, resource));
       
   533 	lua_settable   (d->L, -3);
       
   534 	lua_pushstring  (d->L, "status");
       
   535 	lua_pushlstring (d->L, &imstatus2char[buddy_getstatus (d->buddy, resource)], 1);
       
   536 	lua_settable    (d->L, -3);
       
   537 	lua_pushstring (d->L, "message");
       
   538 	loc = from_utf8 (buddy_getstatusmsg (d->buddy, resource));
       
   539 	lua_pushstring (d->L, loc);
       
   540 	g_free (loc);
       
   541 	lua_settable   (d->L, -3);
       
   542 	lua_settable (d->L, -3);
       
   543 	g_free (resource);
       
   544 }
       
   545 
       
   546 /// main.buddy_info
       
   547 /// Returns a hash table with information on specified buddy.
       
   548 /// Table contains fields type, name, onserver and resources (which points to resources table).
       
   549 /// A: string (jid)
       
   550 /// R: table
       
   551 static int lua_main_buddy_info (lua_State *L)
       
   552 {
       
   553 	char                  *loc   = to_utf8 (luaL_checkstring (L, 1));
       
   554 	char                  *jid   = jidtodisp (loc);
       
   555 	GSList                *buddy = roster_find (jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM);
       
   556 	GSList                *resources;
       
   557 	lua_state_and_buddy_t  snb;
       
   558 	g_free (jid);
       
   559 	g_free (loc);
       
   560 
       
   561 	if (!buddy) {
       
   562 		lua_pushnil (L);
       
   563 		return 1;
       
   564 	}
       
   565 
       
   566 	lua_createtable (L, 0, 3);
       
   567 	lua_pushstring (L, "type");
       
   568 	luaL_pushenum  (L, buddy_gettype (BUDDATA (buddy)), lua_roster_type);
       
   569 	lua_settable   (L, -3);
       
   570 	lua_pushstring (L, "name");
       
   571 	loc = from_utf8 (buddy_getname (BUDDATA (buddy)));
       
   572 	lua_pushstring (L, loc);
       
   573 	g_free (loc);
       
   574 	lua_settable   (L, -3);
       
   575 	lua_pushstring  (L, "onserver");
       
   576 	lua_pushboolean (L, buddy_getonserverflag (BUDDATA (buddy)));
       
   577 	lua_settable    (L, -3);
       
   578 	lua_pushstring  (L, "resources");
       
   579 	lua_createtable (L, 0, 0);
       
   580 	snb.L     = L;
       
   581 	snb.buddy = BUDDATA (buddy);
       
   582 	resources = buddy_getresources (BUDDATA (buddy));
       
   583 	g_slist_foreach (buddy_getresources (BUDDATA (buddy)), (GFunc) lua_buddy_resources_callback, &snb);
       
   584 	g_slist_free (resources);
       
   585 	lua_settable (L, -3);
       
   586 	
       
   587 	return 1;
       
   588 }
       
   589 
       
   590 // XMPP DISCO FEATURES
       
   591 
       
   592 GSList *lua_added_features = NULL;
       
   593 
       
   594 /// main.add_feature
       
   595 /// Adds xmlns to disco#info features list.
       
   596 /// A: string (xmlns)
       
   597 static int lua_main_add_feature (lua_State *L)
       
   598 {
       
   599 	char *xmlns = to_utf8 (luaL_checkstring (L, 1));
       
   600 	xmpp_add_feature (xmlns);
       
   601 	lua_added_features = g_slist_prepend (lua_added_features, xmlns);
       
   602 	return 0;
       
   603 }
       
   604 
       
   605 /// main.del_feature
       
   606 /// Removes xmlns from disco#info features list.
       
   607 /// A: stirng (xmlns)
       
   608 static int lua_main_del_feature (lua_State *L)
       
   609 {
       
   610 	char   *xmlns = to_utf8 (luaL_checkstring (L, 1));
       
   611 	GSList *el    = g_slist_find_custom (lua_added_features, xmlns, (GCompareFunc) strcmp);
       
   612 	xmpp_del_feature (xmlns);
       
   613 	if (el) {
       
   614 		g_free (el->data);
       
   615 		lua_added_features = g_slist_delete_link (lua_added_features, el);
       
   616 	}
       
   617 	return 0;
       
   618 }
       
   619 
       
   620 // MCABBER EVENTS
       
   621 
       
   622 /// event context
       
   623 /// Enum, indicating what exactly caused event function firing.
       
   624 /// G:
       
   625 static const string2enum_t lua_event_context[] = {
       
   626 	{ "timeout", EVS_CONTEXT_TIMEOUT  },
       
   627 	{ "cancel",  EVS_CONTEXT_CANCEL   },
       
   628 	{ "reject",  EVS_CONTEXT_REJECT   },
       
   629 	{ "accept",  EVS_CONTEXT_ACCEPT   },
       
   630 	{ NULL,      0                    },
       
   631 };
       
   632 
       
   633 typedef struct {
       
   634 	lua_State *L;
       
   635 	int        reference;
       
   636 	int        evid;
       
   637 } lua_event_callback_t;
       
   638 
       
   639 static GSList *lua_events = NULL;
       
   640 
       
   641 static void lua_event_callback_destroy_notify (gpointer udata)
       
   642 {
       
   643 	lua_event_callback_t *cb = udata;
       
   644 
       
   645 	luaL_unref (cb -> L, LUA_REGISTRYINDEX, cb->reference);
       
   646 	luaL_unref (cb -> L, LUA_REGISTRYINDEX, cb->evid);
       
   647 	luaL_free  (cb -> L, cb);
       
   648 }
       
   649 
       
   650 /// event function
       
   651 /// Function to be called, when some event state change occurs
       
   652 /// A: event context, string (event args)
       
   653 /// R: boolean (if event shoud be preserved)
       
   654 static gboolean lua_event_callback (guint context, const gchar *arg, gpointer userdata)
       
   655 {
       
   656 	lua_event_callback_t *cb = userdata;
       
   657 
       
   658 	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
   659 	luaL_pushenum (cb->L, context, lua_event_context);
       
   660 	lua_pushstring (cb -> L, arg);
       
   661 	if (lua_pcall (cb->L, 2, 1, 0)) {
       
   662 		scr_log_print (LPRINT_LOGNORM, "lua: Event callback execution error: %s", lua_tostring (cb->L, -1));
       
   663 		lua_pop (cb->L, 1);
       
   664 	}
       
   665 
       
   666 	if (lua_toboolean (cb -> L, -1))
       
   667 		return TRUE;
       
   668 	else {
       
   669 		lua_events = g_slist_remove (lua_events, cb); // XXX
       
   670 		return FALSE;
       
   671 	}
       
   672 }
       
   673 
       
   674 /// main.event
       
   675 /// Creates new event. If called without arguments, returns event id list.
       
   676 /// A: event function (optional), string (event id), string (description, optional), integer (expiration timeout, optional)
       
   677 /// R: string (event id) or nothing (creation error) or table (list of event names)
       
   678 static int lua_main_event (lua_State *L)
       
   679 {
       
   680 	int top = lua_gettop (L);
       
   681 	if (top > 0) { // Create
       
   682 		lua_event_callback_t *cb;
       
   683 		const char           *evid    = NULL;
       
   684 		int                   timeout = 0;
       
   685 		const char           *desc    = NULL;
       
   686 		luaL_argcheck (L, lua_type (L, 1) == LUA_TFUNCTION, 1, "event function expected");
       
   687 
       
   688 		if (top > 1) {
       
   689 			evid = luaL_checkstring (L, 2);
       
   690 			if (top > 2) {
       
   691 				timeout = luaL_checkinteger (L, 3);
       
   692 				if (top > 2) {
       
   693 					desc = luaL_checkstring (L, 4);
       
   694 					lua_pop (L, 3);
       
   695 				} else
       
   696 					lua_pop (L, 2);
       
   697 			} else
       
   698 				lua_pop (L, 1);
       
   699 		}
       
   700 
       
   701 		lua_pushvalue (L, 1); // XXX
       
   702 		cb              = luaL_malloc (L, sizeof (lua_event_callback_t));
       
   703 		cb -> L         = L;
       
   704 		cb -> reference = luaL_ref (L, LUA_REGISTRYINDEX);
       
   705 		cb -> evid      = LUA_NOREF;
       
   706 		lua_events      = g_slist_prepend (lua_events, cb);
       
   707 
       
   708 		evid = evs_new (desc, evid, timeout, lua_event_callback, cb, lua_event_callback_destroy_notify);
       
   709 		if (!evid) {
       
   710 			lua_events = g_slist_remove (lua_events, cb); // XXX
       
   711 			return 0;
       
   712 		}
       
   713 
       
   714 		lua_pushstring (L, evid);
       
   715 		lua_pushvalue (L, -1);
       
   716 		cb -> evid = luaL_ref (L, LUA_REGISTRYINDEX); // XXX
       
   717 		return 1;
       
   718 
       
   719 	} else { // List
       
   720 		GSList *events = evs_geteventslist ();
       
   721 		GSList *event;
       
   722 
       
   723 		lua_newtable (L);
       
   724 		for (event = events; event; event = g_slist_next (event)) {
       
   725 			lua_pushstring (L, event->data);
       
   726 			luaL_ref (L, -2);
       
   727 		}
       
   728 		g_slist_free (events);
       
   729 
       
   730 		return 1;
       
   731 	}
       
   732 }
       
   733 
       
   734 // MCABBER COMMANDS
       
   735 
       
   736 /// completion type
       
   737 /// Built-it completion types can be specified as string, instead of id.
       
   738 /// G:
       
   739 static string2enum_t lua_completion_type[] = { // not const,  we need to modify yesno
       
   740 	{ "cmd",       COMPL_CMD       },
       
   741 	{ "jid",       COMPL_JID       },
       
   742 	{ "urljid",    COMPL_URLJID    },
       
   743 	{ "name",      COMPL_NAME      },
       
   744 	{ "status",    COMPL_STATUS    },
       
   745 	{ "filename",  COMPL_FILENAME  },
       
   746 	{ "roster",    COMPL_ROSTER    },
       
   747 	{ "buffer",    COMPL_BUFFER    },
       
   748 	{ "group",     COMPL_GROUP     },
       
   749 	{ "groupname", COMPL_GROUPNAME },
       
   750 	{ "multiline", COMPL_MULTILINE },
       
   751 	{ "room",      COMPL_ROOM      },
       
   752 	{ "resource",  COMPL_RESOURCE  },
       
   753 	{ "auth",      COMPL_AUTH      },
       
   754 	{ "request",   COMPL_REQUEST   },
       
   755 	{ "events",    COMPL_EVENTS    },
       
   756 	{ "eventsid",  COMPL_EVENTSID  },
       
   757 	{ "pgp",       COMPL_PGP       },
       
   758 	{ "color",     COMPL_COLOR     },
       
   759 	{ "otr",       COMPL_OTR       },
       
   760 	{ "ortpolicy", COMPL_OTRPOLICY },
       
   761 	{ "yesno",     0               },
       
   762 	{ NULL,        0               },
       
   763 };
       
   764 #define MLUA_YESNO_POS ( 21 )
       
   765 
       
   766 typedef struct {
       
   767 	int        reference;
       
   768 	int        parse_args;
       
   769 	lua_State *L;
       
   770 } lua_command_callback_t;
       
   771 
       
   772 static GSList *lua_added_commands = NULL;
       
   773 
       
   774 static GSList *lua_added_categories = NULL;
       
   775 
       
   776 // returns true if string contains errors - unclosed quotes or unvalued option
       
   777 /// command arguments table
       
   778 /// It can parse barewords (with escapes), double-quoted strings (with escapes), single-quoted strings (without escapes), options and arguments.
       
   779 /// Arguments are separated only by whitespace, so, consequential quoted strings or barewords are one argument.
       
   780 /// This strings are equal:
       
   781 /// * ab\ cd\'e\\f\"
       
   782 /// * "ab cd'e\\f\""
       
   783 /// * 'ab cd'\''e\f"'
       
   784 /// * ab" cd'"'e\f"'
       
   785 /// Returned table have option names as keys, option values as values, and arguments as sequential members. -- option is supported.
       
   786 /// Example: "-t jid -m 9 -- -aa bb cc" will result in { t = 'jid', m = 9, '-aa', 'bb', 'cc' }
       
   787 /// Implementation notes:
       
   788 /// * All options should be before any arguments. First non-option argument disables options recognizing.
       
   789 /// * EOL is a cutting edge, that can cut much earlier, than you expect. Non-closed quoted strings lose leading quote and option without value loses its leading minus.
       
   790 /// * Escape character just before EOL is preserved.
       
   791 static int luaL_pushargs (lua_State *L, const char *args)
       
   792 {
       
   793 	const char  *p       = args;
       
   794 	luaL_Buffer  buf;
       
   795 	int          option  = 0;
       
   796 	int          options = 1;
       
   797 
       
   798 	lua_newtable (L);
       
   799 	luaL_buffinit (L, &buf);
       
   800 	while (*p) {
       
   801 		if (*p == ' ') {
       
   802 			++p;
       
   803 			continue;
       
   804 		}
       
   805 		if (*p == '"') { // soft quote
       
   806 			const char *start = ++p;
       
   807 			while (*p) {
       
   808 				if (*p == '\\') { // escape symbol
       
   809 					luaL_addlstring (&buf, start, p - start);
       
   810 					start = ++p;
       
   811 					if (*p) // skip symbol
       
   812 						++p;
       
   813 					else // add last \ in line
       
   814 						luaL_addchar (&buf, '\\');
       
   815 				} else if (*p == '"') // quotation end
       
   816 					break;
       
   817 				else
       
   818 					++p;
       
   819 			}
       
   820 			luaL_addlstring (&buf, start, p - start); // XXX: eats quote on eol
       
   821 			if (*p)
       
   822 				++p;
       
   823 			else
       
   824 				return 1;
       
   825 		} else if (*p == '\'') { // no-escape quote
       
   826 			const char *start = ++p;
       
   827 			while (*p && *p != '\'')
       
   828 				p++;
       
   829 			luaL_addlstring (&buf, start, p - start); // XXX: eats quote on eol
       
   830 			if (*p)
       
   831 				++p;
       
   832 			else
       
   833 				return 1;
       
   834 		} else { // bareword
       
   835 			const char *start = p;
       
   836 			while (*p) {
       
   837 				if (*p == '\\') {
       
   838 					luaL_addlstring (&buf, start, p - start);
       
   839 					start = ++p;
       
   840 					if (*p) // skip symbol
       
   841 						++p;
       
   842 					else // add last \ in line
       
   843 						luaL_addchar (&buf, '\\');
       
   844 				} else if (*p == ' ' || *p == '\'' || *p == '"')
       
   845 					break;
       
   846 				else
       
   847 					++p;
       
   848 			}
       
   849 			luaL_addlstring (&buf, start, p - start);
       
   850 		}
       
   851 
       
   852 		if ((!*p) || *p == ' ') {
       
   853 			const char *result;
       
   854 			luaL_pushresult (&buf);
       
   855 
       
   856 			result = lua_tostring (L, -1);
       
   857 			if (options && !option && *result == '-') { // option
       
   858 				if (*(result+1) == '-' && !*(result+2)) { // end of options
       
   859 					lua_pop (L, 1);
       
   860 					options = 0;
       
   861 				} else { // option name
       
   862 					lua_pushstring (L, result + 1);
       
   863 					lua_remove (L, -2);
       
   864 					option = 1;
       
   865 				}
       
   866 			} else if (option) { // opion value
       
   867 				lua_settable (L, -3);
       
   868 				option = 0;
       
   869 			} else { // argument
       
   870 				options = 0;
       
   871 				luaL_ref (L, -2);
       
   872 			}
       
   873 
       
   874 			luaL_buffinit (L, &buf);
       
   875 		}
       
   876 	}
       
   877 
       
   878 	if (option) {
       
   879 		luaL_ref (L, -2); // XXX: eats minus on eol
       
   880 		return 1;
       
   881 	}
       
   882 
       
   883 	return 0;
       
   884 }
       
   885 
       
   886 /// command function
       
   887 /// Function to handle newly registered command.
       
   888 /// Argument type passed depends on how command is registered.
       
   889 /// A: string (arguments) or command arguments table
       
   890 static void lua_main_command_handler (char *args, lua_command_callback_t *cb)
       
   891 {
       
   892 	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
   893 
       
   894 	if (cb->parse_args)
       
   895 		luaL_pushargs (cb->L, args);
       
   896 	else
       
   897 		lua_pushstring (cb->L, args);
       
   898 
       
   899 	if (lua_pcall (cb->L, 1, 0, 0)) {
       
   900 		scr_log_print (LPRINT_LOGNORM, "lua: Command execution error: %s", lua_tostring (cb->L, -1));
       
   901 		lua_pop (cb->L, 1);
       
   902 	}
       
   903 }
       
   904 
       
   905 /// main.parse_args
       
   906 /// Function to parse command argument string to command arguments table.
       
   907 /// A: string
       
   908 /// R: table
       
   909 static int lua_main_parse_args (lua_State *L)
       
   910 {
       
   911 	luaL_pushargs (L, luaL_checkstring (L, 1));
       
   912 	return 1;
       
   913 }
       
   914 
       
   915 /// main.add_category
       
   916 /// Adds completion category.
       
   917 /// A: table (values are used as words for completion, optional)
       
   918 /// R: integer (category id, in fact completion type) or nil
       
   919 static int lua_main_add_category (lua_State *L)
       
   920 {
       
   921 	guint cid;
       
   922 
       
   923 	if (lua_gettop (L) > 0) {
       
   924 		luaL_argcheck (L, lua_type (L, 1) == LUA_TTABLE, 1, "table expected");
       
   925 		cid = compl_new_category ();
       
   926 		if (cid) {
       
   927 			lua_pushnil (L);
       
   928 			while (lua_next (L, 1)) {
       
   929 				char *word = to_utf8 (luaL_checkstring (L, -1));
       
   930 				if (word) {
       
   931 					compl_add_category_word (cid, word);
       
   932 					g_free (word);
       
   933 				}
       
   934 				lua_pop (L, 1);
       
   935 			}
       
   936 		}
       
   937 	} else
       
   938 		cid = compl_new_category ();
       
   939 
       
   940 	if (cid) {
       
   941 		lua_added_categories = g_slist_prepend (lua_added_categories, (gpointer) cid);
       
   942 		lua_pushinteger (L, cid);
       
   943 	} else
       
   944 		lua_pushnil (L);
       
   945 
       
   946 	return 1;
       
   947 }
       
   948 
       
   949 /// main.del_category
       
   950 /// Removes completion category.
       
   951 /// A: integer (category id)
       
   952 static int lua_main_del_category (lua_State *L)
       
   953 {
       
   954 	guint cid = luaL_checkinteger (L, 1);
       
   955 	compl_del_category (cid);
       
   956 	lua_added_categories = g_slist_remove (lua_added_categories, (gpointer) cid);
       
   957 	return 0;
       
   958 }
       
   959 
       
   960 /// main.add_completion
       
   961 /// Adds word to a completion list.
       
   962 /// A: integer (completion group id), string (word)
       
   963 static int lua_main_add_completion (lua_State *L)
       
   964 {
       
   965 	guint  cid  = luaL_checkinteger (L, 1);
       
   966 	char  *word = to_utf8 (luaL_checkstring (L, 2)); // XXX
       
   967 	compl_add_category_word (cid, word);
       
   968 	g_free (word);
       
   969 	return 0;
       
   970 }
       
   971 
       
   972 /// main.del_completion
       
   973 /// Removes word from a completion list.
       
   974 /// A: integer (completion group id), string (word)
       
   975 static int lua_main_del_completion (lua_State *L)
       
   976 {
       
   977 	guint  cid  = luaL_checkinteger (L, 1);
       
   978 	char  *word = to_utf8 (luaL_checkstring (L, 2)); // XXX
       
   979 	compl_del_category_word (cid, word);
       
   980 	g_free (word);
       
   981 	return 0;
       
   982 }
       
   983 
       
   984 /// main.command
       
   985 /// Associates or breaks association between mcabber command name and lua function.
       
   986 /// To unregister command omit function argument.
       
   987 /// If you specify a third argument, table (even empty), function will return completion group id or nothing.
       
   988 /// You can also specify a string name (see completion type) instead of table, for non-builtin, you can just pass integer id.
       
   989 /// Note, that for now there are no way to unregister completion group, so, resources can be exausted easily.
       
   990 /// Also note, that it ignores keys in a completion table.
       
   991 /// A: string (command name), command function (optional), boolean (parse args flag, optional), table (completions, optional)/completion type (or integer comletion group id, optional)
       
   992 /// R: completion type (integer completion group id or string for builtin types, optional)
       
   993 static int lua_main_command (lua_State *L)
       
   994 {
       
   995 	const char             *name = luaL_checkstring (L, 1); // XXX: to_utf8? looks like no :/
       
   996 	lua_command_callback_t *cb;
       
   997 	int                     top  = lua_gettop (L);
       
   998 	if (top > 1) { // Register
       
   999 		guint cid = 0;
       
  1000 		int parse = 0;
       
  1001 		luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
       
  1002 
       
  1003 		if (top > 2) { // parse flag provided
       
  1004 			parse = lua_toboolean (L, 3);
       
  1005 
       
  1006 			if (top > 3) { // Completions provided
       
  1007 				if (lua_type (L, 4) == LUA_TTABLE) {
       
  1008 					cid = compl_new_category ();
       
  1009 					if (cid) {
       
  1010 						lua_added_categories = g_slist_prepend (lua_added_categories, (gpointer) cid);
       
  1011 						lua_pushnil (L);
       
  1012 						while (lua_next (L, 4)) {
       
  1013 							char *word = to_utf8 (luaL_checkstring (L, -1));
       
  1014 							compl_add_category_word (cid, word);
       
  1015 							lua_pop (L, 1);
       
  1016 							g_free (word);
       
  1017 						}
       
  1018 					}
       
  1019 				} else
       
  1020 					cid = luaL_checkenum (L, 4, lua_completion_type);
       
  1021 			}
       
  1022 		}
       
  1023 
       
  1024 		cb = luaL_malloc (L, sizeof (lua_command_callback_t));
       
  1025 		lua_pushvalue (L, 2);
       
  1026 		cb->reference  = luaL_ref (L, LUA_REGISTRYINDEX);
       
  1027 		cb->parse_args = parse;
       
  1028 		cb->L          = L;
       
  1029 		cmd_add (name, "", cid, 0, (void (*) (char *p)) lua_main_command_handler, cb);
       
  1030 
       
  1031 		lua_added_commands = g_slist_prepend (lua_added_commands, g_strdup (name));
       
  1032 
       
  1033 		if (cid) {
       
  1034 			luaL_pushenum (L, cid, lua_completion_type);
       
  1035 			return 1;
       
  1036 		}
       
  1037 	} else { // Unregister
       
  1038 		GSList *el = g_slist_find_custom (lua_added_commands, name, (GCompareFunc) g_strcmp0);
       
  1039 
       
  1040 		cb = cmd_del (name);
       
  1041 		if (cb) {
       
  1042 			luaL_unref (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
  1043 			luaL_free (cb->L, cb);
       
  1044 		}
       
  1045 
       
  1046 		if (el) {
       
  1047 			g_free (el->data);
       
  1048 			lua_added_commands = g_slist_delete_link (lua_added_commands, el);
       
  1049 		}
       
  1050 	}
       
  1051 	return 0;
       
  1052 }
       
  1053 
       
  1054 // TIMER
       
  1055 
       
  1056 typedef struct {
       
  1057 	int        reference;
       
  1058 	guint      source;
       
  1059 	lua_State *L;
       
  1060 } lua_timer_callback_t;
       
  1061 
       
  1062 static GSList *lua_timers = NULL;
       
  1063 
       
  1064 static void lua_timer_callback_destroy (lua_timer_callback_t *cb)
       
  1065 {
       
  1066 	luaL_unref (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
  1067 	lua_timers = g_slist_remove (lua_timers, (gpointer) cb->source);
       
  1068 	luaL_free (cb->L, cb);
       
  1069 }
       
  1070 
       
  1071 /// timer function
       
  1072 /// Function, that will be called periodically until it returns false.
       
  1073 /// R: boolean
       
  1074 static gboolean lua_timer_callback (lua_timer_callback_t *cb)
       
  1075 {
       
  1076 	int ret;
       
  1077 	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
  1078 	if (lua_pcall (cb->L, 0, 1, 0)) {
       
  1079 		scr_log_print (LPRINT_LOGNORM, "lua: Timer callback execution error: %s", lua_tostring (cb->L, -1));
       
  1080 		lua_pop (cb->L, 1);
       
  1081 		return FALSE;
       
  1082 	}
       
  1083 	ret = lua_toboolean (cb->L, -1);
       
  1084 	lua_pop (cb->L, 1);
       
  1085 	return ret;
       
  1086 }
       
  1087 
       
  1088 /// main.timer
       
  1089 /// Creates new timer function, that will be called periodically.
       
  1090 /// A: integer (interval, seconds), timer function
       
  1091 static int lua_main_timer (lua_State *L)
       
  1092 {
       
  1093 	int                   interval = luaL_checkint (L, 1);
       
  1094 	guint                 source;
       
  1095 	lua_timer_callback_t *cb;
       
  1096 	luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
       
  1097 
       
  1098 	cb = luaL_malloc (L, sizeof (lua_timer_callback_t));
       
  1099 	cb->reference = luaL_ref (L, LUA_REGISTRYINDEX);
       
  1100 	cb->L         = L;
       
  1101 
       
  1102 	source = g_timeout_add_seconds_full (MLUA_SOURCE_PRIORITY, interval, (GSourceFunc) lua_timer_callback, cb, (GDestroyNotify) lua_timer_callback_destroy);
       
  1103 	cb->source = source;
       
  1104 	lua_timers = g_slist_prepend (lua_timers, (gpointer) source);
       
  1105 
       
  1106 	return 0;
       
  1107 }
       
  1108 
       
  1109 // BACKGROUND PIPE READING
       
  1110 
       
  1111 typedef struct {
       
  1112 	lua_State *L;
       
  1113 	guint      source;
       
  1114 	FILE      *fd;
       
  1115 	int        reference;
       
  1116 } lua_bgread_callback_t;
       
  1117 
       
  1118 static GSList *lua_bgreads = NULL;
       
  1119 
       
  1120 static gchar lua_bgread_buffer[MLUA_BGREAD_BUFFER];
       
  1121 
       
  1122 static void lua_bgread_callback_destroy (lua_bgread_callback_t *cb)
       
  1123 {
       
  1124 	luaL_unref (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
  1125 	pclose (cb->fd); // Not necessary?
       
  1126 	lua_bgreads = g_slist_remove (lua_bgreads, (gpointer) cb->source);
       
  1127 	luaL_free (cb->L, cb);
       
  1128 }
       
  1129 
       
  1130 /// background reading function
       
  1131 /// Function, that processes output from pipe in asynchroneous way.
       
  1132 /// A: string (data) or nil (eof)
       
  1133 /// R: boolean (false if reading should be terminated)
       
  1134 static gboolean lua_bgread_callback (GIOChannel *source, GIOCondition condition, lua_bgread_callback_t *cb)
       
  1135 {
       
  1136 	int ret = TRUE;
       
  1137 
       
  1138 	if (condition | G_IO_IN) { // data
       
  1139 		while (TRUE) {
       
  1140 			gsize read = 0;
       
  1141 			g_io_channel_read_chars (source, lua_bgread_buffer, MLUA_BGREAD_BUFFER, &read, NULL);
       
  1142 			if (!read) // exhausted
       
  1143 				break;
       
  1144 
       
  1145 			lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
  1146 			lua_pushlstring (cb->L, lua_bgread_buffer, read);
       
  1147 			if (lua_pcall (cb->L, 1, 1, 0)) {
       
  1148 				scr_log_print (LPRINT_LOGNORM, "lua: Bgread callback execution error: %s", lua_tostring (cb->L, -1));
       
  1149 				lua_pop (cb->L, 1);
       
  1150 				return FALSE;
       
  1151 			}
       
  1152 			ret = lua_toboolean (cb->L, -1);
       
  1153 			lua_pop (cb->L, 1);
       
  1154 			if (!ret) // enough
       
  1155 				return FALSE;
       
  1156 		}
       
  1157 	}
       
  1158 
       
  1159 	if (condition & ~G_IO_IN) { // err or hup
       
  1160 		lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
  1161 		lua_pushnil (cb->L);
       
  1162 		if (lua_pcall (cb->L, 1, 1, 0)) {
       
  1163 			scr_log_print (LPRINT_LOGNORM, "lua: Bgread callback execution error: %s", lua_tostring (cb->L, -1));
       
  1164 			lua_pop (cb->L, 1);
       
  1165 			return FALSE;
       
  1166 		}
       
  1167 		ret = lua_toboolean (cb->L, -1);
       
  1168 		lua_pop (cb->L, 1);
       
  1169 	}
       
  1170 
       
  1171 	return ret;
       
  1172 }
       
  1173 
       
  1174 /// main.bgread
       
  1175 /// Runs specified command and passes its output to a given function.
       
  1176 /// A: string (command), background reading function
       
  1177 static int lua_main_bgread (lua_State *L)
       
  1178 {
       
  1179 	const char            *command = luaL_checkstring (L, 1);
       
  1180 	lua_bgread_callback_t *cb;
       
  1181 	FILE                  *fd;
       
  1182 	GIOChannel            *channel;
       
  1183 	const char            *charset = NULL;
       
  1184 	guint                  source;
       
  1185 	luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
       
  1186 
       
  1187 	fd = popen (command, "r");
       
  1188 	if (!fd) {
       
  1189 		lua_pushstring (L, "Error opening pipe");
       
  1190 		lua_error (L);
       
  1191 	}
       
  1192 
       
  1193 	channel = g_io_channel_unix_new (fileno (fd));
       
  1194 	// We, most likely, need this,
       
  1195 	// But we cannot use this,
       
  1196 	// It will block.
       
  1197 	//if (!g_get_charset (&charset))
       
  1198 	g_io_channel_set_encoding (channel, charset, NULL);
       
  1199 	g_io_channel_set_buffered (channel, FALSE);
       
  1200 	g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
       
  1201 	g_io_channel_set_close_on_unref (channel, TRUE);
       
  1202 
       
  1203 	cb = luaL_malloc (L, sizeof (lua_bgread_callback_t));
       
  1204 	cb->reference = luaL_ref (L, LUA_REGISTRYINDEX);
       
  1205 	cb->L         = L;
       
  1206 	cb->fd        = fd;
       
  1207 
       
  1208 	source = g_io_add_watch_full (channel, MLUA_SOURCE_PRIORITY, G_IO_IN|G_IO_HUP|G_IO_ERR, (GIOFunc) lua_bgread_callback, cb, (GDestroyNotify) lua_bgread_callback_destroy);
       
  1209 	cb->source = source;
       
  1210 	lua_bgreads = g_slist_prepend (lua_bgreads, (gpointer) source);
       
  1211 
       
  1212 	// unref?
       
  1213 
       
  1214 	return 0;
       
  1215 }
       
  1216 
       
  1217 // HOOK HANDLING
       
  1218 
       
  1219 typedef struct {
       
  1220 	lua_State *L;       // lua environment for handler use
       
  1221 	int        nameref; // reference to hook name string
       
  1222 	int        cbref;   // reference to hook handler function
       
  1223 	int        selfref; // self-reference to object
       
  1224 	guint      hid;     // hook id for object destruction
       
  1225 } lua_hook_t;
       
  1226 
       
  1227 /// hook handler result
       
  1228 /// What to do with hook processing afterwards
       
  1229 /// G:
       
  1230 static const string2enum_t lua_hook_handler_result[] = {
       
  1231 	{ "proceed", HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS       },
       
  1232 	{ "stop",    HOOK_HANDLER_RESULT_NO_MORE_HANDLER           },
       
  1233 	{ "drop",    HOOK_HANDLER_RESULT_NO_MORE_HANDLER_DROP_DATA },
       
  1234 	{ NULL,      HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS       },
       
  1235 };
       
  1236 
       
  1237 /// hook handler priority
       
  1238 /// Feel free to specify just a number instead of some preset value.
       
  1239 /// G:
       
  1240 static const string2enum_t lua_hook_handler_priority[] = {
       
  1241 	{ "high",      G_PRIORITY_HIGH         },
       
  1242 	{ "default",   G_PRIORITY_DEFAULT      },
       
  1243 	{ "idle-high", G_PRIORITY_HIGH_IDLE    },
       
  1244 	{ "idle",      G_PRIORITY_DEFAULT_IDLE },
       
  1245 	{ "low",       G_PRIORITY_LOW          },
       
  1246 	{ NULL,        G_PRIORITY_DEFAULT      },
       
  1247 };
       
  1248 
       
  1249 /// hook function
       
  1250 /// Function to be called, when hook will be processsed.
       
  1251 /// XXX: we can provide object as argument, but is this necessary?
       
  1252 /// A: table (arguments hash)
       
  1253 /// R: hook handler result
       
  1254 static guint lua_hook_cb (const gchar *hookid, hk_arg_t *args, gpointer data)
       
  1255 {
       
  1256 	lua_hook_t *cb  = data;
       
  1257 	hk_arg_t   *arg = args;
       
  1258 	guint       ret = HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  1259 	lua_State  *L   = cb -> L;
       
  1260 
       
  1261 	if (cb -> cbref == LUA_NOREF)
       
  1262 		return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  1263 
       
  1264 	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> cbref);
       
  1265 	if (!lua_isfunction (L, -1)) {
       
  1266 		lua_pop (L, 1);
       
  1267 		return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  1268 	}
       
  1269 
       
  1270 	lua_newtable (L);
       
  1271 	lua_pushliteral (L, "hook");
       
  1272 	lua_pushstring  (L, hookid);
       
  1273 	lua_settable (L, -3);
       
  1274 	while (arg->name != NULL) {
       
  1275 		char *name  = from_utf8 (arg->name);
       
  1276 		char *value = from_utf8 (arg->value);
       
  1277 		lua_pushstring (L, name);
       
  1278 		lua_pushstring (L, value);
       
  1279 		lua_settable (L, -3);
       
  1280 		g_free (name);
       
  1281 		g_free (value);
       
  1282 		arg++;
       
  1283 	}
       
  1284 
       
  1285 	if (lua_pcall (L, 1, 1, 0)) {
       
  1286 		scr_log_print (LPRINT_NORMAL, "lua: Error in hook handler: %s", lua_tostring (L, -1));
       
  1287 		lua_pop (L, 1);
       
  1288 	} else {
       
  1289 		switch (lua_type (L, -1)) {
       
  1290 		case LUA_TSTRING:
       
  1291 		case LUA_TNUMBER:
       
  1292 			ret = luaL_checkenum (L, -1, lua_hook_handler_result);
       
  1293 			break;
       
  1294 		default:
       
  1295 			ret = HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  1296 			break;
       
  1297 		}
       
  1298 		lua_pop (L, 1);
       
  1299 	}
       
  1300 
       
  1301 	return ret;
       
  1302 }
       
  1303 
       
  1304 /// main.hook
       
  1305 /// Installs hook handler, returns an object, that you need to keep until
       
  1306 /// hook handling is no more needed.
       
  1307 /// A: string (hook name), hook function, integer (priority, optional)
       
  1308 /// R: userdata (hook object)
       
  1309 static int lua_main_hook (lua_State *L)
       
  1310 {
       
  1311 	const char   *hook_name = luaL_checkstring (L, 1);
       
  1312 	int           priority  = G_PRIORITY_DEFAULT;
       
  1313 	lua_hook_t   *cb;
       
  1314 
       
  1315 	luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
       
  1316 
       
  1317 	if (lua_gettop (L) > 2)
       
  1318 		priority = luaL_checkenum (L, 3, lua_hook_handler_priority);
       
  1319 
       
  1320 	cb = lua_newuserdata (L, sizeof (lua_hook_t));
       
  1321 	luaL_getmetatable (L, "mcabber.hook");
       
  1322 	lua_setmetatable (L, -2);
       
  1323 
       
  1324 	lua_pushvalue (L, -1);
       
  1325 	cb -> selfref = luaL_ref (L, LUA_REGISTRYINDEX);
       
  1326 	lua_pushvalue (L, 1);
       
  1327 	cb -> nameref = luaL_ref (L, LUA_REGISTRYINDEX);
       
  1328 	lua_pushvalue (L, 2);
       
  1329 	cb -> cbref   = luaL_ref (L, LUA_REGISTRYINDEX);
       
  1330 	cb -> L       = L;
       
  1331 	cb -> hid     = hk_add_handler (lua_hook_cb, hook_name, priority, cb);
       
  1332 
       
  1333 	return 1;
       
  1334 }
       
  1335 
       
  1336 static void lua_mcabber_unregister_hook (lua_State *L, lua_hook_t *cb)
       
  1337 {
       
  1338 	const char *name;
       
  1339 
       
  1340 	if (!cb -> hid || cb -> nameref == LUA_NOREF)
       
  1341 		return;
       
  1342 
       
  1343 	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> nameref);
       
  1344 	name = lua_tostring (L, -1);
       
  1345 	if (name) {
       
  1346 		hk_del_handler (name, cb -> hid);
       
  1347 		cb -> hid = 0;
       
  1348 	}
       
  1349 
       
  1350 	lua_pop (L, 1);
       
  1351 }
       
  1352 
       
  1353 /// hook:del
       
  1354 /// Unregisters given hook handler from mcabber. Object will be destroyed later.
       
  1355 static int lua_mcabber_hook_del (lua_State *L)
       
  1356 {
       
  1357 	lua_hook_t *cb = luaL_checkudata (L, 1, "mcabber.hook");
       
  1358 	luaL_argcheck (L, cb != NULL, 1, "mcabber hook object expected");
       
  1359 	lua_mcabber_unregister_hook (L, cb);
       
  1360 	if (cb -> selfref != LUA_NOREF) {
       
  1361 		luaL_unref (L, LUA_REGISTRYINDEX, cb -> selfref);
       
  1362 		cb -> selfref = LUA_NOREF;
       
  1363 	}
       
  1364 	return 0;
       
  1365 }
       
  1366 
       
  1367 static int lua_mcabber_hook_gc (lua_State *L)
       
  1368 {
       
  1369 	lua_hook_t *cb = luaL_checkudata (L, 1, "mcabber.hook");
       
  1370 	luaL_argcheck (L, cb != NULL, 1, "mcabber hook object expected");
       
  1371 	lua_mcabber_unregister_hook (L, cb);
       
  1372 	if (cb -> nameref != LUA_NOREF)
       
  1373 		luaL_unref (L, LUA_REGISTRYINDEX, cb -> nameref);
       
  1374 	if (cb -> cbref != LUA_NOREF)
       
  1375 		luaL_unref (L, LUA_REGISTRYINDEX, cb -> cbref);
       
  1376 	return 0;
       
  1377 }
       
  1378 
       
  1379 static const luaL_Reg lua_mcabber_hook_reg_m[] = {
       
  1380 	{ "del",  lua_mcabber_hook_del },
       
  1381 	{ "__gc", lua_mcabber_hook_gc  },
       
  1382 	{ NULL,   NULL                 },
       
  1383 };
       
  1384 
       
  1385 static void lua_hook_init (lua_State *L)
       
  1386 {
       
  1387 	luaL_newmetatable (L, "mcabber.hook");
       
  1388 	lua_pushvalue (L, -1);
       
  1389 	lua_setfield (L, -2, "__index");
       
  1390 	luaL_register (L, NULL, lua_mcabber_hook_reg_m);
       
  1391 	lua_pop (L, 1);
       
  1392 }
       
  1393 
       
  1394 #if 0
       
  1395 // OPTION GUARDS
       
  1396 
       
  1397 GSList *lua_installed_guards = NULL;
       
  1398 
       
  1399 typedef struct {
       
  1400 	lua_State *L;       // lua environment for handler use
       
  1401 	int        nameref; // reference to key name string
       
  1402 	int        cbref;   // reference to guard function
       
  1403 //	int        objref;  // self_reference to object
       
  1404 	guint      hid;     // hook id for object destruction
       
  1405 } lua_guard_t;
       
  1406 
       
  1407 /// guard function
       
  1408 /// Function to be called, when option changes it's value.
       
  1409 /// Old option value is still accessible through main.option.
       
  1410 /// A: string (key), string (new value)
       
  1411 /// R: string (value to save in hash table)
       
  1412 static gchar *lua_guard_cb (const gchar *key, const gchar *value)
       
  1413 {
       
  1414 	lua_guard_t *cb = ;// FIXME
       
  1415 	lua_State   *L  = cb -> L;
       
  1416 
       
  1417 	if (cb -> cbref == LUA_NOREF)
       
  1418 		return g_strdup (value);
       
  1419 
       
  1420 	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> cbref);
       
  1421 	if (!lua_isfunction (L, -1)) {
       
  1422 		lua_pop (L, 1);
       
  1423 		return g_strdup (value);
       
  1424 	}
       
  1425 
       
  1426 	lua_pushstring (L, key);
       
  1427 	lua_psuhstring (L, value);
       
  1428 
       
  1429 	if (lua_pcall (L, 2, 1, 0)) {
       
  1430 		scr_log_print (LPRINT_NORMAL, "lua: Error in hook handler: %s", lua_tostring (L, -1));
       
  1431 		lua_pop (L, 1);
       
  1432 		return g_strdup (value);
       
  1433 	}
       
  1434 
       
  1435 	return g_strdup (lua_tostring (L, -1));
       
  1436 }
       
  1437 
       
  1438 /// main.guard
       
  1439 /// Installs option guard for given option. Returns guard object, that
       
  1440 /// should be kept around as long, as guard is needed.
       
  1441 /// A: string (option name), guard function
       
  1442 /// R: userdata (guard object)
       
  1443 static int lua_main_guard (lua_State *L)
       
  1444 {
       
  1445 	const char   *name      = luaL_checkstring (L, 1);
       
  1446 	int           priority  = G_PRIORITY_DEFAULT;
       
  1447 	lua_guard_t   *cb;
       
  1448 
       
  1449 	luaL_argcheck (L, lua_isfunction (L, 2), 2, "function expected");
       
  1450 
       
  1451 	cb = lua_newuserdata (L, sizeof (lua_guard_t));
       
  1452 	luaL_getmetatable (L, "mcabber.guard");
       
  1453 	lua_setmetatable (L, -2);
       
  1454 
       
  1455 	lua_pushvalue (L, 1);
       
  1456 	cb -> nameref = luaL_ref (L, LUA_REGISTRYINDEX);
       
  1457 	lua_pushvalue (L, 2);
       
  1458 	cb -> cbref   = luaL_ref (L, LUA_REGISTRYINDEX);
       
  1459 	cb -> L       = L;
       
  1460 
       
  1461 	settings_set_guard (name, lua_guard_cb)
       
  1462 
       
  1463 	return 1;
       
  1464 }
       
  1465 
       
  1466 static void lua_mcabber_unregister_guard (lua_State *L, lua_guard_t *cb)
       
  1467 {
       
  1468 	const char *name;
       
  1469 
       
  1470 	if (cb -> nameref == LUA_NOREF)
       
  1471 		return;
       
  1472 
       
  1473 	lua_rawgeti (L, LUA_REGISTRYINDEX, cb -> nameref);
       
  1474 	name = lua_tostring (L, -1);
       
  1475 	if (name) {
       
  1476 		settings_del_guard (name);
       
  1477 		luaL_unref (L, LUA_REGISTRYINDEX, cb -> nameref);
       
  1478 		cb -> nameref = LUA_NOREF;
       
  1479 	}
       
  1480 
       
  1481 	lua_pop (L, 1);
       
  1482 }
       
  1483 
       
  1484 /// guard:del
       
  1485 /// Unregisters given option guard from mcabber. Object will be destroyed later.
       
  1486 static int lua_mcabber_guard_del (lua_State *L)
       
  1487 {
       
  1488 	lua_guard_t *cb = luaL_checkudata (L, 1, "mcabber.guard");
       
  1489 	luaL_argcheck (L, cb != NULL, 1, "mcabber guard object expected");
       
  1490 	lua_mcabber_unregister_guard (L, cb);
       
  1491 	return 0;
       
  1492 }
       
  1493 
       
  1494 static int lua_mcabber_guard_gc (lua_State *L)
       
  1495 {
       
  1496 	lua_hook_t *cb = luaL_checkudata (L, 1, "mcabber.guard");
       
  1497 	luaL_argcheck (L, cb != NULL, 1, "mcabber guard object expected");
       
  1498 	lua_mcabber_unregister_guard (L, cb);
       
  1499 	if (cb -> cbref != LUA_NOREF)
       
  1500 		luaL_unref (L, LUA_REGISTRYINDEX, cb -> cbref);
       
  1501 	return 0;
       
  1502 }
       
  1503 
       
  1504 static const luaL_Reg lua_mcabber_hook_reg_m[] = {
       
  1505 	{ "del",  lua_mcabber_guard_del },
       
  1506 	{ "__gc", lua_mcabber_guard_gc  },
       
  1507 	{ NULL,   NULL                 },
       
  1508 };
       
  1509 
       
  1510 static void lua_guard_init (lua_State *L)
       
  1511 {
       
  1512 	luaL_newmetatable (L, "mcabber.guard");
       
  1513 	lua_pushvalue (L, -1);
       
  1514 	lua_setfield (L, -2, "__index");
       
  1515 	luaL_register (L, NULL, lua_mcabber_guard_reg_m);
       
  1516 	lua_pop (L, 1);
       
  1517 }
       
  1518 
       
  1519 static void lua_guard_uninit (lua_State *L)
       
  1520 {
       
  1521 }
       
  1522 #endif
       
  1523 
       
  1524 // MAIN INITIALIZATION CODE
       
  1525 
       
  1526 #ifdef LLM_LOG_HANDLER
       
  1527 // FIXME: this should not be here
       
  1528 guint lua_lm_log_handler_id;
       
  1529 
       
  1530 void lua_lm_log_handler (const gchar *domain, GLogLevelFlags log_level, const gchar *message, gpointer ignore)
       
  1531 {
       
  1532 	if (settings_opt_get_int ("lua_lm_debug"))
       
  1533 		scr_log_print (LPRINT_LOGNORM, "%s: %s", domain, message);
       
  1534 }
       
  1535 #endif
       
  1536 
       
  1537 static void do_lua(char *arg, lua_State *L)
       
  1538 {
       
  1539 	if (luaL_loadbuffer (L, arg, strlen (arg), "line")) {
       
  1540 		scr_log_print (LPRINT_LOGNORM, "lua: Compilation error: %s", lua_tostring (L, -1));
       
  1541 		lua_pop (L, 1);
       
  1542 		return;
       
  1543 	}
       
  1544  
       
  1545 	if (lua_pcall (L, 0, 0, 0)) {
       
  1546 		scr_log_print (LPRINT_NORMAL, "lua: Runtime error: %s", lua_tostring(L, -1));
       
  1547 		lua_pop (L, 1);
       
  1548 		return;
       
  1549 	}
       
  1550 }
       
  1551 
       
  1552 static void *lua_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
       
  1553 	if (nsize == 0) {
       
  1554 		g_free (ptr);
       
  1555 		return NULL;
       
  1556 	} else
       
  1557 		return g_realloc (ptr, nsize);
       
  1558 }
       
  1559 
       
  1560 #define reg(NAME)                   \
       
  1561 	{ #NAME, lua_main_##NAME },
       
  1562 static const luaL_Reg lua_reg_main[] = {
       
  1563 	reg ( yesno          ) 
       
  1564 #ifdef LLM_CONNECTION_ENABLE
       
  1565 	reg ( connection     ) 
       
  1566 #endif
       
  1567 	reg ( log            ) 
       
  1568 	reg ( option         ) 
       
  1569 	reg ( alias          ) 
       
  1570 	reg ( binding        ) 
       
  1571 	reg ( fileoption     ) 
       
  1572 	reg ( add_feature    ) 
       
  1573 	reg ( del_feature    ) 
       
  1574 	reg ( event          )
       
  1575 	reg ( parse_args     ) 
       
  1576 	reg ( add_category   ) 
       
  1577 	reg ( del_category   ) 
       
  1578 	reg ( add_completion ) 
       
  1579 	reg ( del_completion ) 
       
  1580 	reg ( command        ) 
       
  1581 	reg ( print_info     ) 
       
  1582 	reg ( beep           ) 
       
  1583 	reg ( run            ) 
       
  1584 	reg ( status         ) 
       
  1585 	reg ( roster         ) 
       
  1586 	reg ( current_buddy  ) 
       
  1587 	reg ( full_jid       ) 
       
  1588 	reg ( buddy_info     ) 
       
  1589 	reg ( timer          ) 
       
  1590 	reg ( alias          ) 
       
  1591 	reg ( binding        ) 
       
  1592 	reg ( fileoption     ) 
       
  1593 	reg ( add_feature    ) 
       
  1594 	reg ( del_feature    ) 
       
  1595 	reg ( event          )
       
  1596 	reg ( parse_args     ) 
       
  1597 	reg ( add_category   ) 
       
  1598 	reg ( del_category   ) 
       
  1599 	reg ( add_completion ) 
       
  1600 	reg ( del_completion ) 
       
  1601 	reg ( command        ) 
       
  1602 	reg ( print_info     ) 
       
  1603 	reg ( beep           ) 
       
  1604 	reg ( run            ) 
       
  1605 	reg ( status         ) 
       
  1606 	reg ( roster         ) 
       
  1607 	reg ( current_buddy  ) 
       
  1608 	reg ( full_jid       ) 
       
  1609 	reg ( buddy_info     ) 
       
  1610 	reg ( timer          ) 
       
  1611 	reg ( bgread         ) 
       
  1612 	reg ( hook           )
       
  1613 	{ NULL, NULL },
       
  1614 };
       
  1615 #undef reg
       
  1616 
       
  1617 const gchar *g_module_check_init (GModule *module)
       
  1618 {
       
  1619 	lua = lua_newstate (lua_alloc, NULL);
       
  1620 	if (!lua)
       
  1621 		return "Lua initialization error";
       
  1622 	else
       
  1623 		return NULL;
       
  1624 }
       
  1625 
       
  1626 void g_module_unload (GModule *module)
       
  1627 {
       
  1628 	if (lua) {
       
  1629 		lua_close (lua);
       
  1630 		lua = NULL;
       
  1631 	}
       
  1632 }
       
  1633 
       
  1634 static void mlua_init (void)
       
  1635 {
       
  1636 	luaL_openlibs (lua);
       
  1637 
       
  1638 	luaL_register (lua, "main", lua_reg_main);
       
  1639 	lua_pop (lua, 1); // XXX
       
  1640 	lua_register (lua, "dopath", lua_global_dopath);
       
  1641 	lua_register (lua, "print",  lua_global_print );
       
  1642 
       
  1643 	{
       
  1644 		int cid = compl_new_category ();
       
  1645 
       
  1646 		if (cid) {
       
  1647 			const string2enum_t *word = lua_yesno;
       
  1648 			lua_completion_type[MLUA_YESNO_POS].value = cid;
       
  1649 			lua_added_categories = g_slist_prepend (lua_added_categories, (gpointer) cid);
       
  1650 			while (word->string) {
       
  1651 				compl_add_category_word (cid, word->string);
       
  1652 				++word;
       
  1653 			}
       
  1654 		}
       
  1655 	}
       
  1656 
       
  1657 	cmd_add ("lua", "Evaluate lua string", 0, 0, (void (*) (char *p)) do_lua, lua);
       
  1658 
       
  1659 #ifdef LLM_LOG_HANDLER
       
  1660 	// FIXME: this should not be here.
       
  1661 	lua_lm_log_handler_id = g_log_set_handler ("lua-lm", G_LOG_LEVEL_MASK, (GLogFunc) lua_lm_log_handler, NULL);
       
  1662 #endif
       
  1663 
       
  1664 	lua_hook_init (lua);
       
  1665 
       
  1666 	{
       
  1667 		char *initfile = expand_filename (settings_opt_get ("lua_init_filename"));
       
  1668 		
       
  1669 		if (!initfile)
       
  1670 			scr_log_print (LPRINT_LOGNORM, "lua: Cannot determine config file name");
       
  1671 		else {
       
  1672 			if (luaL_loadfile(lua, initfile)) {
       
  1673 				scr_log_print (LPRINT_LOGNORM, "lua: Unable to compile rc file: %s", lua_tostring (lua, -1));
       
  1674 				lua_pop (lua, 1);
       
  1675 			} else if (lua_pcall (lua, 0, LUA_MULTRET, 0)) {
       
  1676 				scr_log_print (LPRINT_LOGNORM, "lua: Runtime error in rc file: %s", lua_tostring(lua, -1));
       
  1677 				lua_pop (lua, 1);
       
  1678 			} else
       
  1679 				scr_log_print (LPRINT_LOGNORM, "lua: Loaded %s", initfile);
       
  1680 			g_free (initfile);
       
  1681 		}
       
  1682 	}
       
  1683 
       
  1684 	{
       
  1685 		hk_arg_t args[] = {
       
  1686 			{ NULL, NULL },
       
  1687 		};
       
  1688 		hk_run_handlers("hook-lua-start", args);
       
  1689 	}
       
  1690 }
       
  1691 
       
  1692 static void lua_events_cancel (gpointer data, gpointer ignore)
       
  1693 {
       
  1694 	lua_event_callback_t *cb = data;
       
  1695 	const char *evid;
       
  1696 	if (cb->evid == LUA_NOREF)
       
  1697 		return;
       
  1698 	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->evid);
       
  1699 	evid = lua_tostring (cb ->L, -1);
       
  1700 	evs_callback (evid, EVS_CONTEXT_CANCEL, "Module unloading");
       
  1701 }
       
  1702 
       
  1703 static void lua_events_destroy (gpointer data, gpointer ignore)
       
  1704 {
       
  1705 	lua_event_callback_t *cb = data;
       
  1706 	const char *evid;
       
  1707 	if (cb->evid == LUA_NOREF)
       
  1708 		return;
       
  1709 	lua_rawgeti (cb->L, LUA_REGISTRYINDEX, cb->evid);
       
  1710 	evid = lua_tostring (cb ->L, -1);
       
  1711 	evs_del (evid);
       
  1712 }
       
  1713 
       
  1714 static void lua_bgreads_destroy (guint source, gpointer ignore)
       
  1715 {
       
  1716 	g_source_remove (source);
       
  1717 }
       
  1718 
       
  1719 static void lua_timers_destroy (guint source, gpointer ignore)
       
  1720 {
       
  1721 	g_source_remove (source);
       
  1722 }
       
  1723 
       
  1724 static void lua_features_destroy (char *xmlns, gpointer ignore)
       
  1725 {
       
  1726 	xmpp_del_feature (xmlns);
       
  1727 	g_free (xmlns);
       
  1728 }
       
  1729 
       
  1730 static void lua_commands_destroy (char *name, gpointer ignore)
       
  1731 {
       
  1732 	lua_command_callback_t *cb = cmd_del (name);
       
  1733 	if (cb) {
       
  1734 		luaL_unref (cb->L, LUA_REGISTRYINDEX, cb->reference);
       
  1735 		luaL_free (cb->L, cb);
       
  1736 	}
       
  1737 	g_free (name);
       
  1738 }
       
  1739 
       
  1740 static void lua_categories_destroy (guint id, gpointer ignore)
       
  1741 {
       
  1742 	compl_del_category (id);
       
  1743 }
       
  1744 
       
  1745 static void mlua_uninit (void)
       
  1746 {
       
  1747 	if (lua) {
       
  1748 		hk_arg_t args[] = {
       
  1749 			{ NULL, NULL },
       
  1750 		};
       
  1751 		hk_run_handlers ("hook-lua-quit", args);
       
  1752 
       
  1753 		// hook handlers will be unregistered upon objects destruction
       
  1754 
       
  1755 		g_slist_foreach (lua_bgreads, (GFunc) lua_bgreads_destroy, NULL);
       
  1756 		g_slist_free (lua_bgreads);
       
  1757 		lua_bgreads = NULL;
       
  1758 
       
  1759 		g_slist_foreach (lua_timers, (GFunc) lua_timers_destroy, NULL);
       
  1760 		g_slist_free (lua_timers);
       
  1761 		lua_timers = NULL;
       
  1762 
       
  1763 		g_slist_foreach (lua_events, (GFunc) lua_events_cancel, NULL);
       
  1764 		g_slist_foreach (lua_events, (GFunc) lua_events_destroy, NULL);
       
  1765 		g_slist_free (lua_events);
       
  1766 		lua_events = NULL;
       
  1767 
       
  1768 		g_slist_foreach (lua_added_features, (GFunc) lua_features_destroy, NULL);
       
  1769 		g_slist_free (lua_added_features);
       
  1770 		lua_added_features = NULL;
       
  1771 
       
  1772 		g_slist_foreach (lua_added_commands, (GFunc) lua_commands_destroy, NULL);
       
  1773 		g_slist_free (lua_added_commands);
       
  1774 		lua_added_commands = NULL;
       
  1775 
       
  1776 		g_slist_foreach (lua_added_categories, (GFunc) lua_categories_destroy, NULL);
       
  1777 		g_slist_free (lua_added_categories);
       
  1778 		lua_added_categories = NULL;
       
  1779 
       
  1780 		cmd_del ("lua");
       
  1781 
       
  1782 		lua_close (lua);
       
  1783 		lua = NULL;
       
  1784 
       
  1785 #ifdef LLM_LOG_HANDLER
       
  1786 		// FIXME: shouldn't be here
       
  1787 		g_log_remove_handler ("lua-lm", lua_lm_log_handler_id);
       
  1788 #endif
       
  1789 	}
       
  1790 }
       
  1791