Included sample configuration into package
authorMyhailo Danylenko <isbear@ukrpost.net>
Mon, 23 Feb 2009 23:23:42 +0200
changeset 5 cba039bd6f13
parent 4 bca17e4a9851
child 6 90dceae3ed1f
Included sample configuration into package
CMakeLists.txt
examples/marking.lua
examples/mcabberrc.lua
examples/mpd.lua
examples/xep0004.lua
examples/xep0030.lua
examples/xep0047.lua
examples/xep0077.lua
examples/xep0146.lua
scripts/marking.lua
scripts/mcabberrc.lua
scripts/mpd.lua
scripts/xep0004.lua
scripts/xep0030.lua
scripts/xep0047.lua
scripts/xep0077.lua
scripts/xep0146.lua
--- a/CMakeLists.txt	Mon Feb 23 23:16:46 2009 +0200
+++ b/CMakeLists.txt	Mon Feb 23 23:23:42 2009 +0200
@@ -58,6 +58,7 @@
 if(PERL_FOUND)
 	install(FILES ${mcabber-lua_BINARY_DIR}/mcabber-lua.html DESTINATION share/doc/${CPACK_PACKAGE_NAME})
 endif()
+install(DIRECTORY examples DESTINATION share/doc/${CPACK_PACKAGE_NAME})
 install(FILES README DESTINATION share/doc/${CPACK_PACKAGE_NAME})
 install(FILES TODO DESTINATION share/doc/${CPACK_PACKAGE_NAME})
 install(FILES COPYING DESTINATION share/doc/${CPACK_PACKAGE_NAME})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/marking.lua	Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,67 @@
+
+marked_jids = {}
+
+function mark ()
+	local jid = main.current_buddy ()
+	marked_jids[jid] = true
+	main.print_info ( jid, "Marked" )
+end
+
+function unmark ()
+	local jid = main.current_buddy ()
+	marked_jids[jid] = nil
+	main.print_info ( jid, "Unmarked" )
+end
+
+function mark_toggle ()
+	local jid = main.current_buddy ()
+	if marked_jids[jid] then
+		return unmark ()
+	else
+		return mark ()
+	end
+end
+
+function marked ()
+	local ret = {}
+	for jid, v in pairs ( marked_jids ) do
+		table.insert ( ret, jid )
+	end
+	return ret
+end
+
+function foreach_marked ( callback )
+	for jid, v in pairs ( marked_jids ) do
+		if v then
+			callback ( jid )
+		end
+	end
+end
+
+function marked_clear ()
+	marked_jids = {}
+end
+
+main.add_command ( 'marked',
+	function ( args )
+		local cmd = args:match ( "^%s*(%w+)" )
+		if cmd == 'clear' then
+			marked_clear ()
+		elseif cmd == 'do' then
+			local command = args:match ( "^%s*%w+%s+(.+)" )
+			foreach_marked (
+				function ( jid )
+					main.run ( string.format ( command, jid ) )
+				end )
+		else
+			print ( "Marked jids:" )
+			foreach_marked (
+				function ( jid )
+					print ( ' - ' .. jid )
+				end )
+		end
+	end )
+
+commands_help['marked'] = "[clear | do mcabber_command]\n\nOperates on marked buddies. Without arguments prints list of marked jids.\nCommand should contain %s in place, where jid should be inserted."
+
+-- vim: se ts=4: --
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mcabberrc.lua	Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,456 @@
+
+
+--[[
+
+DESCRIPTION
+
+This is a demo config file to show, what you can do with lua.
+
+Feature list:
+XEP-0004 Forms parsing and filling
+XEP-0030 Info/items discovery requests (mcabber already can do replies)
+XEP-0047 In-Bound Byte Streams (sending, receiving, saving with specified name, rejecting)
+XEP-0077 In-Band Registration (only registration, but with data forms too)
+XEP-0146 Remote commands requests
+Jobs (actions, fired when some event occurs, now in one file, updated on exit)
+MPD status polling (can be turned off)
+Beep on all messages, even on chatroom ones
+Url saving to file (for urlview)
+Transported buddies availability indication
+Actions on multiple marked buddies
+Fallback commands (localized also! :) )
+Help for fallback commands (well, I know, that it can be done with mcabber's help system, but it requires access to system files...)
+All features have native mcabber interface
+
+REQUIREMENTS
+
+liblua-loudmouth (lm.lua and loudmouth.so)
+liblua-socket - mpd
+
+NOTES
+
+Most hooks get one incoming parameter - hash table with some fields in it.
+This allows further extending and adding arguments without breaking
+previous implementations.
+
+Ibb uses own iq handler. This is the laziest way to implement this.
+
+BUILTINS
+
+print (global) - prints to log
+dofile (global) - loads lua file from default mcabber location
+
+main methods:
+- run           - run literal mcabber command
+- beep          - beep
+- log           - print to log w/specified priority
+- print_info    - print info into specified buffer
+- config_file   - format full file name from relative to mcabber's config dir
+- status        - get current user status and message
+- roster        - get list of roster jids (rooms, buddies and agents)
+- current_buddy - get jid of current buddy
+- buddy_info    - get table with info about jid and its resources
+- connection    - get lightuserdata for mcabber's lm connection
+- timer         - run function periodically
+- bgread        - run command and read it's output in background
+- add_feature   - add string to feature list (for disco#info)
+- del_feature   - delete string from feature list
+- add_command   - adds mcabber command
+- del_command   - remove mcabber command
+
+--]]
+
+-- This is a hack to allow loading of lm.lua and loudmouth.so from ~/.mcabber
+-- instead of installing them system-wide
+package.path = main.config_file ( '?.lua' ) .. ';' .. package.path
+package.cpath = main.config_file ( '?.so' ) .. ';' .. package.cpath
+
+require 'lm'
+
+-- OPTIONS, COMMON SUPPORT ROUTINES
+
+url_file      = main.config_file ( 'urls.log' )
+transport_jid = 'icq.jabber.kiev.ua' -- TODO: allow multiple transports
+beep_enable   = false
+
+-- XXX: to C?
+char2status = {
+	f = 'free',
+	o = 'online',
+	a = 'away',
+	d = 'dnd',
+	n = 'notavail',
+	i = 'invisible',
+	['_'] = 'offline',
+	['?'] = 'message',
+}
+
+function shell_escape ( str )
+	if str then
+		return "'" .. str:gsub ( "'", "'\\''" ) .. "'"
+	else
+		return "''"
+	end
+end
+
+-- This is for debugging purposes, for real reloading need to quote and bracket keys.
+function table_to_string ( tab, pre )
+	local prefix = pre or ""
+	local tbls, jk = "", ""
+
+	for key, val in pairs ( tab ) do
+		if type ( val ) == 'table' then
+			tbls = string.format ( "%s  %s%s = %s,\n", tbls, prefix, tostring(key), table_to_string ( val, "  " .. prefix ) )
+		else
+			jk = string.format ( "%s %s = %q,", jk, tostring(key), tostring(val) )
+		end
+	end
+
+	if tbls == "" then
+		return string.format ( "{%s }", jk:sub ( 1, -2 ) )
+	else
+		return string.format ( "{%s\n%s%s}", jk, tbls, prefix )
+	end
+end
+
+-- XXX to C?
+function full_current_jid ()
+	local jid = main.current_buddy ()
+	if jid then
+		local info = main.buddy_info ( jid )
+		local prio, resource = 0
+		for res, par in pairs ( info.resources ) do
+			if prio <= par.priority then
+				resource = res
+				prio = par.priority
+			end
+		end
+		if resource then
+			return jid .. '/' .. resource
+		else
+			return jid
+		end
+	else
+		return nil
+	end
+end
+
+-- COMMANDS
+
+function yesno ( value )
+	if value == 'enable' or value == 'yes' or value == 'true' or value == 'on' or value == true then
+		return true
+	elseif value == 'disable' or value == 'no' or value == 'false' or value == 'off' or value == false then
+		return false
+	else
+		return nil
+	end
+end
+
+-- FIXME: eats spaces
+function parse_args ( args )
+	local ret = {}
+	local still_opts = true
+	local optname
+	local option = false
+	for word in args:gmatch ( "%S+" ) do
+		if still_opts and not option and word:sub ( 1, 1 ) == '-' then
+			option = true
+			optname = word:sub ( 2 )
+		elseif option then
+			ret[optname] = word
+			option = false
+		else
+			still_opts = false
+			table.insert ( ret, word )
+		end
+	end
+	return ret
+end
+
+-- Help strings should not contain command, only arguments. This is necessary to support soft aliases.
+commands_help = {
+	file      = "filename\n\nSends file as a message. Just shorthand.",
+	s         = "status [message]\n\nSets your status, but takes into account mpd (if enabled).",
+	beep      = "[enable|disable|on|off|yes|no|true|false]\n\nEnables or disables beeping on all messages.\nIf state is omitted, prints current state.",
+	cmd       = "shell_command\n\nRuns shell command in background and sends output to current buddy.\nWorks asynchroneously, and may break long output in the middle of line",
+	exthelp   = "[command]\n\nPrints help for a given command, or list of available help topics.",
+	reload    = "\n\nJust a shorthand to reload lua config file. Note, that for now this discards all changes to configuration, open forms, transferred files.",
+	['join!'] = "\n\nForcibly joins to current buddy. Just saves you typing of full room name (that can be quite long) in a case of a non-bookmarked rooms.",
+	count     = "\n\nPrints number of resources of current buddy. Useful to determine member count of large room."
+}
+
+main.add_command ( "lua",
+	function ( args )
+		assert ( loadstring ( args ) ) ()
+	end )
+main.add_command ( 'file',
+	function ( args )
+		main.run ( 'say_to -f ' .. args .. ' .' )
+	end )
+main.add_command ( 's',
+	function ( args )
+		main.run ( ('status %s %s'):format ( args, mpd_getstatus () ) )
+	end )
+main.add_command ( 'beep',
+	function ( args )
+		local enable = yesno ( args )
+		if enable == nil then
+			if beep_enable then
+				print ( "Beep on message is enabled" )
+			else
+				print ( "Beep on message is disabled" )
+			end
+		else
+			beep_enable = enable
+		end
+	end )
+main.add_command ( 'cmd',
+	function ( args )
+		local to = main.current_buddy ()
+		main.run ( ('send_to -q %q $ %s'):format ( to, args ) )
+		main.bgread ( args,
+			function ( data )
+				if data then
+					main.run ( ('send_to -q %q %s'):format ( to, data ) )
+					return true
+				else
+					return false
+				end
+			end )
+	end )
+main.add_command ( 'exthelp',
+	function ( args )
+		if commands_help[args] then
+			print ( "\n /" .. args .. ' ' .. commands_help[args] )
+		else
+			print ( "No help for this command." )
+			list = "Help available for commands: "
+			for k in pairs (commands_help) do
+				list = list .. k .. ', '
+			end
+			print ( list:sub ( 1, -3 ) )
+			print ( "For built-in mcabber commands see /help" )
+		end
+	end )
+main.add_command ( 'reload',
+	function ( args )
+		dofile ( main.config_file ( 'mcabberrc.lua' ) )
+	end )
+main.add_command ( 'join!',
+	function ( args )
+		main.run ( 'room join ' .. main.current_buddy () )
+	end )
+main.add_command ( 'count',
+	function ( args )
+		local count = 0
+		for resource in pairs ( main.buddy_info ( main.current_buddy () ).resources ) do
+			count = count + 1
+		end
+		print ( "Resource count: " .. count )
+	end )
+
+for k, arg in ipairs ( { ')', '/', '(', 'D', '-/', 'S', '1', ']', '[' } ) do
+	main.add_command ( arg,
+		function ( args )
+			main.run ( 'say :' .. arg .. ' ' .. args )
+		end )
+end
+
+-- MARKING
+
+dopath 'marking'
+
+-- MPD
+
+dopath 'mpd'
+
+-- FORMS (XEP-0004)
+
+dopath 'xep0004'
+
+-- DISCO (XEP-0030)
+
+dopath 'xep0030'
+
+-- IBB (XEP-0047)
+
+dopath 'xep0047'
+
+-- IN-BAND REGISTRATION (XEP-0077)
+
+dopath 'xep0077'
+
+-- REMOTE CONTROLLING CLIENTS (XEP-0146)
+
+dopath 'xep0146'
+
+-- JOBS
+
+delayed_jobs = {}
+
+-- FIXME: do only if it exists
+dopath 'jobs.lua'
+
+function save_jobs ()
+	local h = io.open ( main.config_file ( 'jobs.lua' ), "w" )
+	if not h then
+		print ( 'Cannot open jobs file for writing!' )
+		return
+	end
+	h:write ( "-- This is autogenerated file, do not edit it manually\n\ndelayed_jobs = {\n" );
+	for jid, more in pairs ( delayed_jobs ) do
+		h:write ( string.format ( "\t[%q] = {\n", jid ) )
+		for status, action in pairs ( more ) do
+			if action then -- remove fired jobs
+				h:write ( string.format ( "\t\t[%q] = %q,\n", status, action ) )
+			end
+		end
+		h:write ( "\t},\n" )
+	end
+	h:write ( "}\n" )
+	h:close ()
+end
+
+main.add_command ( 'delay',
+	function ( args )
+		args = parse_args ( args )
+		local who
+		if args.t then
+			who = args.t
+			args.t = nil
+		else
+			who = main.current_buddy ()
+		end
+		local stat = args[1]
+		args[1] = nil
+		delayed_jobs[who] = { }
+		delayed_jobs[who][stat] =
+			function ()
+				main.run ( 'say_to -q ' .. who .. ' ' .. rebuild_args_string ( args ) )
+			end
+	end )
+
+main.add_command ( 'job',
+	function ( args )
+		local action, jid, stat = args:match ( "(%w+)%s+(%w+)%s+(%w)" )
+		if action == 'del' then
+			delayed_jobs[jid][stat] = nil
+		else
+			print ( 'List of jobs:' )
+			for jid, jobs in pairs ( delayed_jobs ) do
+				for status in pairs ( jobs ) do
+					print ( ' - ' .. jid .. ' -> ' .. status )
+				end
+			end
+		end
+	end )
+
+commands_help['delay'] = "[-t target_jid] status_letter message\n\nDelays sending a message to target jid (or current buddy) until it switches to specified status."
+commands_help['job'] = "[del jid status_letter]\n\nLists available jobs or deletes specified one."
+
+-- HOOKS
+
+ibb_handler_registered = false
+
+-- Soft hooks, implemented through mcabber options
+function hook_post_connect ()
+	main.run ( 'group fold テフノ' )
+	main.run ( 'group fold にゃ' )
+	main.run ( 'group fold にゃ - Друзі' )
+
+	main.run ( 'color muc * on' )
+
+	main.run ( ("color roster * *@%s red"):format ( transport_jid ) )
+	main.run ( ("color roster dn_? *@%s red"):format ( transport_jid ) )
+
+	if mpd_enabled then
+		mpd_callback ()
+	end
+
+	-- FIXME
+	if not ibb_handler_registered then
+		lm.connection.bless( main.connection () ):handler ( ibb_incoming_iq_handler, 'iq', 'normal' )
+		main.add_feature ( 'http://jabber.org/protocol/ibb' )
+		ibb_handler_registered = true
+	end
+end
+
+function hook_pre_disconnect ()
+	main.run ( ("color roster * *@%s white"):format ( transport_jid ) )
+	main.run ( ("color roster dn_? *@%s brightblack"):format ( transport_jid ) )
+end
+
+-- Hard hooks, implemented in C
+
+-- hook
+-- - message_in
+--   jid
+--   groupchat
+--   message
+-- - message_out
+--   jid
+--   message
+-- - status_change
+--   jid
+--   resource
+--   new_status
+--   old_status
+--   message
+-- - my_status_change
+--   new_status
+--   message
+function hook_handler ( args )
+	if args.hook == 'message_in' then
+
+		-- beep on ALL messages, no matter, is it chat or something else.
+		if beep_enable then
+			main.beep ()
+		end
+	
+		-- save urls to file from where urlview can get them...
+		for url in args.message:gmatch ( "https?://[%w%p]+" ) do
+			fd = io.open ( url_file, "a" )
+			if fd then
+				fd:write ( url .. "\n" )
+				fd:close ()
+			else
+				print 'Cannot open urls log file'
+			end
+		end
+
+	elseif args.hook == 'status_change' then
+
+		-- delayed actions
+		if delayed_jobs[args.jid] and delayed_jobs[args.jid][args.new_status] then
+			delayed_jobs[args.jid][args.new_status] ()
+			delayed_jobs[args.jid][args.new_status] = nil
+		end
+		
+		-- transported buddies availability indication
+		if args.jid == transport_jid then
+			if args.new_status == '_' then
+				main.run ( ("color roster * *@%s red"):format ( transport_jid ) )
+				main.run ( ("color roster dn_? *@%s red"):format ( transport_jid ) )
+			else
+				main.run ( ("color roster * *@%s white"):format ( transport_jid ) )
+				main.run ( ("color roster dn_? *@%s brightblack"):format ( transport_jid ) )
+			end
+		end
+
+	end
+end
+
+-- (hook_start)
+
+function hook_quit ()
+	save_jobs ()
+
+	-- FIXME
+	if ibb_handler_registered then
+		lm.connection.bless( main.connection () ):handler ( ibb_incoming_iq_handler, 'iq' )
+	end
+end
+
+
+-- The End -- vim: se ts=4: --
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mpd.lua	Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,195 @@
+
+-- Requires libsocket
+
+-- TODO:
+-- do pubsub tunes+notify instead of status hacking
+
+require 'socket'
+
+local settings = {
+	hostname     = "localhost",
+	password     = nil,
+	port         = 6600,
+}
+
+mpd = {}
+
+-- separator allows split output into records, that are started by any of present in separator keys
+-- returns table of field (lowercase) - value records
+-- command status is returned in STATUS field
+-- on unexpected errors returns just false, dropping any available data
+function mpd.receive_message ( tcp, separator )
+	local ret  = {}
+	local line = tcp:receive ( '*l' )
+	while line and not ( line:find ( '^OK' ) or line:find ( '^ACK' ) ) do
+		local key, val = line:match ( '^(.-):%s*(.*)$' )
+		if key then
+			if separator then
+				key = key:lower ()
+				if separator[key] then
+					table.insert ( ret, {} )
+				end
+				ret[#ret][key]   = val
+			else
+				ret[key:lower()] = val
+			end
+		end
+		line = tcp:receive ( '*l' )
+	end
+	if not line then
+		return false -- an error occured, ret, most likely, does not contains exact and complete info...
+	else
+		ret.STATUS = line:match ( '^%S+' )
+		return ret
+	end
+end
+
+-- use: mpd.call_command { 'status' }
+--      mpd.call_command { 'lsinfo misc', list = { file = true, directory = true } }
+--      mpd.call_command { 'next', noret = true }
+--      mpd.call_command { 'status', 'currentsong' }
+-- on one command returns just results of that command, on multi - array of results
+-- on errors returns nil
+-- noret can terminate socket too early, thus, do not use it with lists of commands
+function mpd.call_command ( opts )
+	local tcp = socket.tcp ()
+	if not tcp then
+		print ( 'mpd: cannot get master tcp object' )
+		return nil
+	elseif not tcp:connect ( settings.hostname, settings.port ) then
+		tcp:close ()
+		print ( 'mpd: cannot connect to server' )
+		return nil
+	end
+
+	local ret = {}
+	if not opts.noret then
+		ret = mpd.receive_message ( tcp )
+		if not ret then
+			tcp:close ()
+			print ( 'mpd: error getting greeting from server' )
+			return nil
+		elseif ret.STATUS ~= 'OK' then
+			print ( 'mpd: server ack\'s in greeting' )
+		end
+	end
+
+	for num, command in ipairs ( opts ) do
+		if not tcp:send ( command .. "\n" ) then
+			tcp:close ()
+			print ( 'mpd: error sending command ' .. command )
+			return nil
+		end
+		if not opts.noret then
+			ret[num] = mpd.receive_message ( tcp, opts.list )
+			if not ret[num] then
+				print ( 'mpd: error getting result' )
+			end
+			if ret[num]['STATUS'] ~= 'OK' then
+				print ( 'mpd: server acks our command ' .. command )
+			end
+		end
+	end
+
+	tcp:close ()
+	if #ret > 1 then
+		return ret
+	else
+		return ret[1]
+	end
+end
+
+-- MCABBER PART --
+
+mpd_enabled = false
+
+function mpd_getstatus ()
+	if not mpd_enabled then
+		return ''
+	end
+	
+	local stats = mpd.call_command { 'status', 'currentsong' }
+	if stats[1].state ~= 'play' and stats[1].state ~= 'pause' then
+		return ''
+	end
+
+	local title = stats[2].title
+	if not title then
+		if stats[2].file then
+			title = stats[2].file
+		else
+			title = ''
+		end
+	elseif not stats[2].artist then
+		title = string.format ( "%s (%s)", title, stats[2].file )
+	else
+		title = string.format ( "%s - %s", stats[2].artist, title )
+	end
+
+	if stats[1].state == 'pause' then
+		return string.format ( "[mpd: <зупинено> %s]", title )
+	else
+		return string.format ( "[mpd: %s]", title )
+	end
+end
+
+function parse_status ()
+	local stletter, stmessage = main.status ()
+	local cmd = char2status[stletter]
+	local message, mpd_string = stmessage:match ( "^(.-)%s+(%[mpd:%s+.+%s*%])" )
+	if message then
+		return cmd, message, mpd_string
+	else
+		return cmd, stmessage, ''
+	end
+end
+
+function mpd_callback ()
+	local new_mpd_string = mpd_getstatus ()
+	local status, message, mpd_string = parse_status ()
+	if new_mpd_string ~= mpd_string then
+		main.run ( string.format ( 'status %s %s %s', status, message, new_mpd_string ) )
+	end
+	if mpd_enabled then
+		return true
+	else
+		return false
+	end
+end
+
+-- do not call it too fast, or you end up with many daemons at once
+function enable_mpd ( yn )
+	if yn == nil then
+		yn = true
+	end
+	if yn then
+		if not mpd_enabled then
+			main.timer ( 15, mpd_callback )
+			mpd_enabled = true
+			-- update status
+		end
+	else
+		if mpd_enabled then
+			mpd_enabled = false
+			-- update status
+		end
+	end
+end
+
+main.add_command ( 'mpd',
+	function ( args )
+		local enable = yesno ( args )
+		if enable == nil then
+			if mpd_enabled then
+				print ( "MPD status string is enabled" )
+			else
+				print ( "MPD status string is disabled" )
+			end
+		else
+			enable_mpd ( enable )
+		end
+	end )
+
+commands_help['mpd'] = "[enable|disable|on|off|yes|no|true|false]\n\nSets state of mpd string in your status.\nIf state is omitted, prints current state."
+
+-- vim: se ts=4: --
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/xep0004.lua	Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,151 @@
+
+forms = { }
+
+-- expects lm node   x = { xmlns = 'jabber:x:data', type = 'form', ... }
+-- returns form index in forms table, you can do whatever you want to upper level table, except exp and val fields.
+function parse_form ( node )
+	local form = { title = 'unknown', exp = '', val = { } }
+	if node:child ( 'title' ) then
+		form.title = node:child( 'title' ):value ()
+	end
+	if node:child ( 'instructions' ) then
+		form.exp = form.exp .. 'Instructions: ' .. node:child( 'instructions' ):value () .. '\n'
+	end
+	form.exp = form.exp .. 'Fields:\n'
+	local field = node:children ()
+	while field do
+		if field:name () == 'field' then
+			local field_type  = field:attribute ( 'type' ) or 'text-single'
+			local field_var   = field:attribute ( 'var' ) or ''
+			form.exp = form.exp .. ' - ' .. field_var .. '\n   Type: ' .. field_type .. '\n'
+			if field:attribute ( 'label' ) then
+				form.exp = form.exp .. '   Label: ' .. ( field:attribute ( 'label' ) or '' ) .. '\n'
+			end
+			if field:child ( 'desc' ) then
+				form.exp = form.exp .. '   Description: ' .. field:child( 'desc' ):value () .. '\n'
+			end
+			if field:child ( 'required' ) then
+				form.exp = form.exp .. '   Required: yes\n'
+			end
+
+			local field_value
+			if field_type == 'jid-multi' or field_type == 'list-multi' or field_type == 'text-multi' then
+				field_value = { }
+				local value = field:children ()
+				form.exp = form.exp .. '   Default values:\n'
+				while value do
+					if value:name () == 'value' then
+						table.insert ( field_value, { value:value () } )
+						form.exp = form.exp .. '    - ' .. value:value () .. '\n'
+					end
+					value = value:next ()
+				end
+			else
+				if field:child ( 'value' ) then
+					field_value = field:child( 'value' ):value ()
+					form.exp = form.exp .. '   Default value: ' .. field_value .. '\n'
+				end
+			end
+
+			if field_type == 'list-single' or field_type == 'list-multi' then
+				form.exp = form.exp .. '   List options:\n'
+				local option = field:children ()
+				while option do
+					if option:name () == 'option' then
+						form.exp = form.exp .. '    - ' .. ( option:child( 'value' ):value () or '' ) .. ': ' .. ( option:attribute ( 'label' ) or '' ) .. '\n'
+					end
+					option = option:next ()
+				end
+			end
+
+			if field_type == 'boolean' then
+				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '0' } } )
+			elseif field_type == 'fixed' then
+			elseif field_type == 'hidden' then
+				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '' } } )
+			elseif field_type == 'list-single' then
+				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '' } } )
+			elseif field_type == 'list-multi' then
+				table.insert ( form.val, { type = field_type, var = field_var, value = field_value or { } } )
+			elseif field_type == 'jid-multi' or field_type == 'text-multi' then
+				table.insert ( form.val, { type = field_type, var = field_var, value = field_value or { } } )
+			elseif field_type == 'jid-single' or field_type == 'text-single' then
+				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '' } } )
+			elseif field_type == 'text-private' then
+				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '' } } )
+			end
+		end
+		field = field:next ()
+	end
+	table.insert ( forms, form )
+	return #forms
+end
+
+function form_set ( id, name, value )
+	if forms[id] then
+		for index, field in ipairs ( forms[id].val ) do
+			if field.var == name then
+				if value == nil then
+					field.value = { }
+				else
+					if field.type == 'jid-multi' or field.type == 'list-multi' or field.type == 'text-multi' then
+						table.insert ( field.value, { value } )
+					else
+						field.value = { value }
+					end
+				end
+			end
+		end
+	end
+end
+
+main.add_command ( 'form',
+	function ( args )
+		args = parse_args ( args )
+		local action = args[1]
+		local id = tonumber (args[1])
+		if forms[id] then
+			if args[2] then
+				local field = args[2]
+				if args[3] == 'clear' then
+					form_set ( id, field, nil )
+				else
+					args[1] = nil
+					args[2] = nil
+					if args[3] == 'set' then
+						args[3] = nil
+					end
+					form_set ( id, field, rebuild_args_string ( args ) )
+				end
+			else
+				print ( 'Form: ' .. ( forms[id].title or '' ) .. '\n' .. forms[id].exp )
+				print ( 'Fields:' )
+				for index, field in ipairs ( forms[id].val ) do -- this should not be here, but setting up callback just for this...
+					if field.type == 'jid-multi' or field.type == 'list-multi' or field.type == 'text-multi' then
+						print ( ' - ' .. field.var .. ' [' .. field.type .. ']:' )
+						for vin, value in ipairs ( field.value ) do
+							print ( '    * ' .. value[1] )
+						end
+					else
+						print ( ' - ' .. field.var .. ' [' .. field.type .. ']: ' .. field.value[1] )
+					end
+				end
+			end
+		elseif action == 'del' then
+			forms[tonumber(args[2])] = nil
+		elseif action == 'send' then
+			local form = forms[tonumber(args[2])]
+			if form then
+				form.send ( form )
+			end
+		else
+			print ( 'Forms list:' )
+			for id, form in ipairs ( forms ) do
+				print ( ' - ' .. tostring(id) .. ' ' .. form.title .. ' [' .. ( form.status or 'unknown' ) .. ']' )
+			end
+		end
+	end )
+
+commands_help['form'] = "[del form_id | send form_id | form_id [field_name {clear | [set] value}]\n\nWith bare form id prints info on that form.\nWith field name sets or clears field value. Set subcommand is optional, just to allow values, starting with 'clear'.\nWithout arguments prints form list."
+
+-- vim: se ts=4: --
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/xep0030.lua	Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,105 @@
+
+function disco_items ( callback, what, node )
+	local request =
+		lm.message.create { to = what, mtype = 'iq-get',
+			query = { xmlns = 'http://jabber.org/protocol/disco#items' }
+		}
+	if node then
+		request:child( 'query' ):attribute ( 'node', node )
+	end
+	return lm.connection.bless( main.connection () ):send ( request,
+		function ( conn, message )
+			if message:child ( 'error' ) then
+				callback ( message:child( 'error' ):children():name () )
+			else
+				local item = message:child( 'query' ):children ()
+				local items = { }
+				while item do
+					if item:name () == 'item' then
+						table.insert ( items, { jid = item:attribute ( 'jid' ), node = item:attribute ( 'node' ), name = item:attribute ( 'name' ) } )
+					end
+					item = item:next ()
+				end
+				callback ( items )
+			end
+			return true
+		end )
+end
+
+function disco_info ( callback, what )
+	return lm.connection.bless( main.connection () ):send (
+		lm.message.create { to = what, mtype = 'iq-get',
+			query = { xmlns='http://jabber.org/protocol/disco#info' }
+		},
+		function ( conn, message )
+			local items_supported = false
+			if message:child ( 'error' ) then
+				callback ( message:child( 'error' ):children():name () )
+			else
+				local item = message:child( 'query' ):children ()
+				local identities = { }
+				local features   = { }
+				while item do
+					if item:name () == 'identity' then
+						table.insert ( identities, { category = item:attribute ( 'category' ), type = item:attribute ( 'type' ), name = item:attribute ( 'name' ) } )
+					elseif item:name () == 'feature' then
+						table.insert ( features, item:attribute ( 'var' ) )
+					end
+					item = item:next ()
+				end
+				callback ( identities, features )
+			end
+			return true
+		end )
+end
+
+main.add_command ( 'disco',
+	function ( args )
+		args = parse_args ( args )
+		local who
+		if args.t then
+			who = args.t
+			args.t = nil
+		else
+			who = full_current_jid ()
+		end
+		if args[1] == 'items' then
+			local node = nil
+			if args[2] then
+				args[1] = nil
+				node = rebuild_args_string ( args )
+			end
+			disco_items (
+				function ( items )
+					if type ( items ) == 'string' then
+						main.print_info ( who, string.format ( "Service items discovery for %s (%s) failed: %s", who, node or '', items ) )
+					else
+						main.print_info ( who, string.format ( "Service items discovery result for %s (%s):", who, node or '' ) )
+						for index, item in ipairs ( items ) do
+							main.print_info ( who, string.format ( "    [%s (%s)] %s", item.jid or '', item.node or '', item.name or '' ) )
+						end
+					end
+				end, who, node )
+		else
+			disco_info (
+				function ( identities, features )
+					if type ( identities ) == 'string' then
+						main.print_info ( who, string.format ( "Service info discovery for %s failed: %s", who, identities ) )
+					else
+						main.print_info ( who, string.format ( "Service info discovery result for %s:", who ) )
+						main.print_info ( who, "  Identities:" )
+						for index, identity in ipairs ( identities ) do
+							main.print_info ( who, string.format ( "    [%s (%s)] %s", identity.category or '', identity.type or '', identity.name or '' ) )
+						end
+						main.print_info ( who, "  Features:" )
+						for index, feature in ipairs ( features ) do
+							main.print_info ( who, string.format ( "    [%s]", feature or '' ) )
+						end
+					end
+				end, who )
+		end
+	end )
+
+commands_help['disco'] = "[-t target_jid] [info | items] [node]\n\nService discovery request.\nInfo is sent if omitted.\nIf info reveals, that buddy can do items, items request also will be sent."
+
+-- vim: se ts=4: --
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/xep0047.lua	Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,202 @@
+
+receiving_files = {}
+ibb_block_size  = 4096
+current_sid_number = 0
+
+-- FIXME: read from /dev/urandom?
+function gen_unique_sid ()
+	current_sid_number = current_sid_number + 1
+	return 'mc-' .. tostring ( current_sid_number )
+end
+
+ibb_incoming_iq_handler = lm.message_handler.new ( 
+	function ( conn, mess )
+		local id   = mess:attribute ( 'id' )
+		local from = mess:attribute ( 'from' )
+		if mess:child ( 'open' ) and mess:child( 'open' ):attribute ( 'xmlns' ) == 'http://jabber.org/protocol/ibb' then
+			local sid  = mess:child( 'open' ):attribute ( 'sid' )
+			if not receiving_files[sid] then
+				local buffer = ''
+				receiving_files[sid] = { from = from, status = 'pending' }
+				receiving_files[sid].accept =
+					function ( name )
+						main.print_info ( from, string.format ( "Receiving stream from %s, id %s", from, sid ) )
+						conn:send ( lm.message.create { to = from, mtype = 'iq-result', id = id } )
+						receiving_files[sid].name = name
+						receiving_files[sid].status = 'accepted'
+					end
+				receiving_files[sid].reject =
+					function ()
+						conn:send (
+							lm.message.create { to = from, mtype = 'iq-error', id = id,
+								error = { code = '405', type = 'cancel',
+									['not-allowed'] = { xmlns = 'urn:ietf:params:xml:ns:xmpp-stanzas' }
+								}
+							} )
+						receiving_files[sid].status = 'rejected'
+					end
+				print ( 'You have a new bytestream to receive. To save it use /ibb accept ' .. sid .. ' filename' )
+			else
+				conn:send (
+					lm.message.create { to = from, mtype = 'iq-error', id = id,
+						error = { code = '409', type = 'cancel',
+							conflict = { xmlns = 'urn:ietf:params:xml:ns:xmpp-stanzas' }
+						}
+					} )
+			end
+		elseif mess:child ( 'data' ) and mess:child( 'data' ):attribute ( 'xmlns' ) == 'http://jabber.org/protocol/ibb' then
+			local sid  = mess:child( 'data' ):attribute ( 'sid' )
+			local seq  = mess:child( 'data' ):attribute ( 'seq' )
+			if receiving_files[sid] and from == receiving_files[sid].from and not receiving_files[sid][tonumber(seq)+1] then
+				local data = mess:child( 'data' ):value ()
+				main.print_info ( from, string.format ( " - stream part %s, id %s, %d bytes", seq, sid, data:len() ) )
+				conn:send ( lm.message.create { to = from, mtype = 'iq-result', id = id } )
+				receiving_files[sid][tonumber(seq)+1] = data
+			else
+				receiving_files[sid] = nil -- invalidate session
+				conn:send (
+					lm.message.create { to = from, mtype = 'iq-error', id = id,
+						error = { code = '409', type = 'cancel',
+							conflict = { xmlns = 'urn:ietf:params:xml:ns:xmpp-stanzas' }
+						}
+					} )
+			end
+		elseif mess:child ( 'close' ) and mess:child( 'close' ):attribute ( 'xmlns' ) == 'http://jabber.org/protocol/ibb' then
+			local sid  = mess:child( 'close' ):attribute ( 'sid' )
+			if receiving_files[sid] and from == receiving_files[sid].from then
+				main.print_info ( from, "Done with stream id " .. sid )
+				conn:send ( lm.message.create { to = from, mtype = 'iq-result', id = id } )
+				local decoder = io.popen ( string.format ( "base64 -d -i >%q", receiving_files[sid].name ), "w" )
+				if not decoder then
+					main.print_info ( from, "Error opening decoder" )
+				else
+					for i, v in ipairs ( receiving_files[sid] ) do
+						decoder:write ( v )
+					end
+					decoder:close ()
+				end
+			else
+				receiving_files[sid] = nil -- invalidate session
+				conn:send (
+					lm.message.create { to = from, mtype = 'iq-error', id = id,
+						error = { code = '409', type = 'cancel',
+							conflict = { xmlns = 'urn:ietf:params:xml:ns:xmpp-stanzas' }
+						}
+					} )
+			end
+		else
+			return false
+		end
+		return true
+	end )
+
+-- You must specify a full jid with resource!
+function send_file ( to, name )
+	local sid = gen_unique_sid ()
+	local conn = lm.connection.bless ( main.connection () )
+	conn:send (
+		lm.message.create { to = to, mtype = 'iq-set',
+			open = { sid = sid, ['block-size'] = ibb_block_size, xmlns = 'http://jabber.org/protocol/ibb' }
+		},
+		function ( conn, message )
+			if message:child ( 'error' ) then
+				main.print_info ( to, "Stream request refused: " .. message:child( 'error' ):children():name () )
+			else
+				main.print_info ( to, "Stream accepted, starting sequence" )
+				local buffer = ''
+				main.bgread ( string.format ( 'base64 -w 0 %q', name ),
+					function ( data )
+						if data then
+							buffer = buffer .. data
+							return true
+						else
+							local seq = 0
+							local msgbuf = buffer:sub ( 1, ibb_block_size )
+							buffer = buffer:sub ( ibb_block_size + 1 )
+							local function handler ( conn, message )
+								if message:child ( 'error' ) then
+									main.print_info ( to, "Stream error, transfer ceased at seq = " .. seq .. ": " .. message:child( 'error' ):children():name () )
+								else
+									main.print_info ( to, " - acquired seq = " .. seq )
+									seq = seq + 1
+									if buffer:len () == 0 then
+										conn:send (
+											lm.message.create { to = to, mtype = 'iq-set',
+												close = { sid = sid, xmlns = 'http://jabber.org/protocol/ibb' }
+											},
+											function ( conn, message )
+												if message:child ( 'error' ) then
+													main.print_info ( to, "Error at closing stream: " .. message:child( 'error' ):children():name () )
+												else
+													main.print_info ( to, "File successfully transferred" )
+												end
+												return true
+											end )
+									else
+										local msgbuf = buffer:sub ( 1, ibb_block_size )
+										buffer = buffer:sub ( ibb_block_size )
+										conn:send (
+											lm.message.create { to = to, mtype = 'iq-set',
+												data = { sid = sid, xmlns = 'http://jabber.org/protocol/ibb', seq = seq,
+													msgbuf
+												}
+											},
+											handler )
+									end
+								end
+								return true
+							end
+							conn:send (
+								lm.message.create { to = to, mtype = 'iq-set',
+									data = { sid = sid, xmlns = 'http://jabber.org/protocol/ibb', seq = seq,
+										msgbuf
+									}
+								},
+								handler )
+							return false
+						end
+					end )
+			end
+			return true
+		end )
+end
+
+main.add_command ( 'ibb',
+	function ( args )
+		args = parse_args ( args )
+		if args[1] == 'send' then
+			local who
+			if args.t then
+				who = args.t
+				args.t = nil
+			else
+				who = full_current_jid ()
+			end
+			args[1] = nil
+			send_file ( who, rebuild_args_string ( args ) )
+		elseif args[1] == 'accept' then
+			local id = args[2]
+			args[1] = nil
+			args[2] = nil
+			if receiving_files[id] then
+				receiving_files[id].accept ( rebuild_args_string ( args ) )
+			end
+		elseif args[1] == 'reject' then
+			local id = args[2]
+			if receiving_files[id] then
+				receiving_files[id].reject ()
+			end
+		elseif args[1] == 'del' then
+			local id = args[2]
+			receiving_files[id] = nil
+		else
+			print ( 'List of incoming streams:' )
+			for sid, data in pairs ( receiving_files ) do
+				print ( sid .. ': ' .. ( data.name or '(not set)' ) .. ' [' .. data.status .. ']' )
+			end
+		end
+	end )
+
+commands_help['ibb'] = "[[-t target_jid] send filename | accept sid filename | reject sid filename | del sid]\n\nRequests, accepts or rejects sending file via in-band bytestream."
+
+-- vim: se ts=4: --
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/xep0077.lua	Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,171 @@
+
+function parse_iq_register ( node )
+	local form = { title = 'jabber:iq:register', exp = '', val = { } }
+	if node:child ( 'instructions' ) then
+		form.exp = form.exp .. 'Instructions: ' .. node:child( 'instructions' ):value () .. '\n'
+	end
+	if node:child ( 'registered' ) then
+		form.exp = form.exp .. 'Registered: yes\n'
+	end
+	form.exp = form.exp .. 'Fields:\n'
+	local field = node:children ()
+	while field do
+		local name = field:name ()
+		if name ~= 'instructions' and name ~= 'registered' then
+			form.exp = form.exp .. ' - ' .. name .. '\n'
+			if field:value () and field:value () ~= '' then
+				form.exp = form.exp .. '   Default value: ' .. field:value () .. '\n'
+			end
+			table.insert ( form.val, { type = 'text-single', var = name, value = { field:value () or '' } } )
+		end
+		field = field:next ()
+	end
+	table.insert ( forms, form )
+	return #forms
+end
+
+function format_iq_register ( fields )
+	local result = { xmlns = 'jabber:iq:register' }
+	for index, field in ipairs ( fields ) do
+		result[field.var] = field.value
+	end
+	return result
+end
+
+function register_to ( who )
+	lm.connection.bless( main.connection () ):send (
+		lm.message.create { mtype = 'iq-get', to = who,
+			query = { xmlns = 'jabber:iq:register' }
+		},
+		function ( conn, mess )
+			local node = mess:child ( 'query' )
+			if node and node:attribute ( 'xmlns' ) == 'jabber:iq:register' then
+				main.print_info ( who, 'D: Got:\n' .. mess:xml () )
+				local x = node:child ( 'x' )
+				local id
+				local finalizer =
+					function ( conn, mess )
+						local mt, st = mess:type ()
+						if st == 'result' then
+							main.print_info ( who, 'Now you can run /form del ' .. id .. ' to delete form from list' )
+							forms[id].status = 'acquired'
+						else
+							main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
+							forms[id].status = 'rejected'
+						end
+						return true
+					end
+				if x and x:attribute ( 'xmlns' ) == 'jabber:x:data' then
+					id = parse_form ( x )
+					-- local sid = mess:child( 'command' ):attribute ( 'sessionid' )
+					forms[id].send =
+						function ( form )
+							conn:send (
+								lm.message.create { mtype = 'iq-set', to = who,
+									query = { xmlns = 'jabber:iq:register',
+										x = { xmlns = 'jabber:x:data', type = 'submit',
+											field = form.val,
+										},
+									},
+								}, finalizer )
+						end
+					forms[id].status = 'filling'
+					main.print_info ( who, 'You have new form. To fill it, use /form ' .. id .. ' fieldname value' )
+				else
+					id = parse_iq_register ( mess:child ( 'query' ) )
+					forms[id].send =
+						function ( form )
+							conn:send (
+								lm.message.create { mtype = 'iq-set', to = who,
+									query = format_iq_register ( form.val ),
+								}, finalizer )
+						end
+					forms[id].status = 'filling'
+					main.print_info ( who, 'You have new form. To fill it, use /form ' .. id .. ' fieldname value' )
+				end
+			else
+				main.print_info ( who, 'Error response:\n' .. mess:xml () )
+			end
+			return true
+		end )
+end
+
+function unregister_from ( who )
+	lm.connection.bless( main.connection () ):send (
+		lm.message.create { mtype = 'iq-set', to = who,
+			query = { xmlns = 'jabber:iq:register',
+				remove = { },
+			},
+		},
+		function ( conn, mess )
+			local mt, st = mess:type ()
+			if st == 'result' then
+				main.print_info ( who, 'Registration cancelled' )
+			elseif st == 'error' then
+				if mess:child ( 'error' ) then
+					main.print_info ( who, 'Error response: ' .. mess:child( 'error' ):children():name () )
+				else
+					local query = mess:child ( 'query' )
+					if query and query:child ( 'x' ) then
+						local id = parse_form ( query:child ( 'x' ) )
+						forms[id].send =
+							function ( form )
+								conn:send (
+									lm.message.create { mtype = 'iq-set', to = who,
+										query = { xmlns = 'jabber:iq:register',
+											x = { xmlns = 'jabber:x:data', type = 'submit',
+												field = form.val,
+											},
+										},
+									},
+									function ( conn, mess )
+										local mt, st = mess:type ()
+										if st == 'result' then
+											main.print_info ( who, 'Now you can run /form del ' .. id .. ' to delete form from list' )
+											forms[id].status = 'acquired'
+										else
+											main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
+											forms[id].status = 'rejected'
+										end
+										return true
+									end )
+							end
+						forms[id].status = 'filling'
+						main.print_info ( who, 'You have new form. To fill it, use /form ' .. id .. ' fieldname value' )
+					else
+						main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
+					end
+				end
+			else
+				main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
+			end
+			return true
+		end )
+end
+
+main.add_command ( 'register',
+	function ( args )
+		local who
+		if args[1] then
+			who = rebuild_args_string ( args )
+		else
+			who = full_current_jid ()
+		end
+		register_to ( who )
+	end )
+
+main.add_command ( 'cancel',
+	function ( args )
+		local who
+		if args and args ~= '' then
+			who = args
+		else
+			who = full_current_jid ()
+		end
+		unregister_from ( who )
+	end )
+
+commands_help['register'] = "[jid]\n\nSends registration request to jid (or current buddy). You, probably, then will need to fill and send some form."
+commands_help['cancel'] = "[jid]\n\nSends registration cancellation request to jid (or current buddy). May require a form filling."
+
+-- vim: se ts=4: --
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/xep0146.lua	Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,70 @@
+
+function remote_command ( who, command )
+	lm.connection.bless( main.connection () ):send (
+		lm.message.create { mtype = 'iq-set', to = who,
+			command = { xmlns = 'http://jabber.org/protocol/commands', action = 'execute', node = command }
+		},
+		function ( conn, mess )
+			if mess:child ( 'command' ) and mess:child( 'command' ):child ( 'x' ) then
+				local id = parse_form ( mess:child( 'command' ):child ( 'x' ) )
+				local sid = mess:child( 'command' ):attribute ( 'sessionid' )
+				forms[id].send =
+					function ( form )
+						conn:send (
+							lm.message.create { mtype = 'iq-set', to = who,
+								command = { xmlns = 'http://jabber.org/protocol/commands', node = command, sessionid = sid,
+									x = { xmlns = 'jabber:x:data', type = 'form',
+										field = form.val,
+									},
+								},
+							},
+							function ( conn, mess )
+								if mess:child ( 'command' ) and mess:child( 'command' ):attribute ( 'status' ) == 'completed' then
+									main.print_info ( who, 'Now you can run /form del ' .. id .. ' to delete form from list' )
+									forms[id].status = 'acquired'
+								else
+									main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
+									forms[id].status = 'rejected'
+								end
+								return true
+							end )
+					end
+				forms[id].status = 'filling'
+				main.print_info ( who, 'You have new form. To fill it, use /form ' .. id .. ' fieldname value' )
+			else
+				main.print_info ( who, 'Got response to command request:\n' .. mess:xml () )
+			end
+			return true
+		end )
+end
+
+main.add_command ( 'remote',
+	function ( args )
+		args = parse_args ( args )
+		local who
+		if args.t then
+			who = args.t
+			args.t = nil
+		else
+			who = full_current_jid ()
+		end
+		if args[1] == 'list' or not args[1] then
+			disco_items (
+				function ( items )
+					if type ( items ) == 'string' then
+						main.print_info ( who, string.format ( "Service items discovery for %s (http://jabber.org/protocol/commands) failed: %s", who, items ) )
+					else
+						main.print_info ( who, 'Available commands:' )
+						for index, item in ipairs ( items ) do
+							main.print_info ( who, ' - ' .. item.node )
+						end
+					end
+				end, who, 'http://jabber.org/protocol/commands' )
+		elseif args[1] then
+			remote_command ( who, args[1] )
+		end
+	end )
+
+commands_help['remote'] = "[-t target_jid] [list | command]\n\nPrints list of available remote command or requests execution of specified command."
+
+-- vim: se ts=4: --
--- a/scripts/marking.lua	Mon Feb 23 23:16:46 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-
-marked_jids = {}
-
-function mark ()
-	local jid = main.current_buddy ()
-	marked_jids[jid] = true
-	main.print_info ( jid, "Marked" )
-end
-
-function unmark ()
-	local jid = main.current_buddy ()
-	marked_jids[jid] = nil
-	main.print_info ( jid, "Unmarked" )
-end
-
-function mark_toggle ()
-	local jid = main.current_buddy ()
-	if marked_jids[jid] then
-		return unmark ()
-	else
-		return mark ()
-	end
-end
-
-function marked ()
-	local ret = {}
-	for jid, v in pairs ( marked_jids ) do
-		table.insert ( ret, jid )
-	end
-	return ret
-end
-
-function foreach_marked ( callback )
-	for jid, v in pairs ( marked_jids ) do
-		if v then
-			callback ( jid )
-		end
-	end
-end
-
-function marked_clear ()
-	marked_jids = {}
-end
-
-main.add_command ( 'marked',
-	function ( args )
-		local cmd = args:match ( "^%s*(%w+)" )
-		if cmd == 'clear' then
-			marked_clear ()
-		elseif cmd == 'do' then
-			local command = args:match ( "^%s*%w+%s+(.+)" )
-			foreach_marked (
-				function ( jid )
-					main.run ( string.format ( command, jid ) )
-				end )
-		else
-			print ( "Marked jids:" )
-			foreach_marked (
-				function ( jid )
-					print ( ' - ' .. jid )
-				end )
-		end
-	end )
-
-commands_help['marked'] = "[clear | do mcabber_command]\n\nOperates on marked buddies. Without arguments prints list of marked jids.\nCommand should contain %s in place, where jid should be inserted."
-
--- vim: se ts=4: --
--- a/scripts/mcabberrc.lua	Mon Feb 23 23:16:46 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,456 +0,0 @@
-
-
---[[
-
-DESCRIPTION
-
-This is a demo config file to show, what you can do with lua.
-
-Feature list:
-XEP-0004 Forms parsing and filling
-XEP-0030 Info/items discovery requests (mcabber already can do replies)
-XEP-0047 In-Bound Byte Streams (sending, receiving, saving with specified name, rejecting)
-XEP-0077 In-Band Registration (only registration, but with data forms too)
-XEP-0146 Remote commands requests
-Jobs (actions, fired when some event occurs, now in one file, updated on exit)
-MPD status polling (can be turned off)
-Beep on all messages, even on chatroom ones
-Url saving to file (for urlview)
-Transported buddies availability indication
-Actions on multiple marked buddies
-Fallback commands (localized also! :) )
-Help for fallback commands (well, I know, that it can be done with mcabber's help system, but it requires access to system files...)
-All features have native mcabber interface
-
-REQUIREMENTS
-
-liblua-loudmouth (lm.lua and loudmouth.so)
-liblua-socket - mpd
-
-NOTES
-
-Most hooks get one incoming parameter - hash table with some fields in it.
-This allows further extending and adding arguments without breaking
-previous implementations.
-
-Ibb uses own iq handler. This is the laziest way to implement this.
-
-BUILTINS
-
-print (global) - prints to log
-dofile (global) - loads lua file from default mcabber location
-
-main methods:
-- run           - run literal mcabber command
-- beep          - beep
-- log           - print to log w/specified priority
-- print_info    - print info into specified buffer
-- config_file   - format full file name from relative to mcabber's config dir
-- status        - get current user status and message
-- roster        - get list of roster jids (rooms, buddies and agents)
-- current_buddy - get jid of current buddy
-- buddy_info    - get table with info about jid and its resources
-- connection    - get lightuserdata for mcabber's lm connection
-- timer         - run function periodically
-- bgread        - run command and read it's output in background
-- add_feature   - add string to feature list (for disco#info)
-- del_feature   - delete string from feature list
-- add_command   - adds mcabber command
-- del_command   - remove mcabber command
-
---]]
-
--- This is a hack to allow loading of lm.lua and loudmouth.so from ~/.mcabber
--- instead of installing them system-wide
-package.path = main.config_file ( '?.lua' ) .. ';' .. package.path
-package.cpath = main.config_file ( '?.so' ) .. ';' .. package.cpath
-
-require 'lm'
-
--- OPTIONS, COMMON SUPPORT ROUTINES
-
-url_file      = main.config_file ( 'urls.log' )
-transport_jid = 'icq.jabber.kiev.ua' -- TODO: allow multiple transports
-beep_enable   = false
-
--- XXX: to C?
-char2status = {
-	f = 'free',
-	o = 'online',
-	a = 'away',
-	d = 'dnd',
-	n = 'notavail',
-	i = 'invisible',
-	['_'] = 'offline',
-	['?'] = 'message',
-}
-
-function shell_escape ( str )
-	if str then
-		return "'" .. str:gsub ( "'", "'\\''" ) .. "'"
-	else
-		return "''"
-	end
-end
-
--- This is for debugging purposes, for real reloading need to quote and bracket keys.
-function table_to_string ( tab, pre )
-	local prefix = pre or ""
-	local tbls, jk = "", ""
-
-	for key, val in pairs ( tab ) do
-		if type ( val ) == 'table' then
-			tbls = string.format ( "%s  %s%s = %s,\n", tbls, prefix, tostring(key), table_to_string ( val, "  " .. prefix ) )
-		else
-			jk = string.format ( "%s %s = %q,", jk, tostring(key), tostring(val) )
-		end
-	end
-
-	if tbls == "" then
-		return string.format ( "{%s }", jk:sub ( 1, -2 ) )
-	else
-		return string.format ( "{%s\n%s%s}", jk, tbls, prefix )
-	end
-end
-
--- XXX to C?
-function full_current_jid ()
-	local jid = main.current_buddy ()
-	if jid then
-		local info = main.buddy_info ( jid )
-		local prio, resource = 0
-		for res, par in pairs ( info.resources ) do
-			if prio <= par.priority then
-				resource = res
-				prio = par.priority
-			end
-		end
-		if resource then
-			return jid .. '/' .. resource
-		else
-			return jid
-		end
-	else
-		return nil
-	end
-end
-
--- COMMANDS
-
-function yesno ( value )
-	if value == 'enable' or value == 'yes' or value == 'true' or value == 'on' or value == true then
-		return true
-	elseif value == 'disable' or value == 'no' or value == 'false' or value == 'off' or value == false then
-		return false
-	else
-		return nil
-	end
-end
-
--- FIXME: eats spaces
-function parse_args ( args )
-	local ret = {}
-	local still_opts = true
-	local optname
-	local option = false
-	for word in args:gmatch ( "%S+" ) do
-		if still_opts and not option and word:sub ( 1, 1 ) == '-' then
-			option = true
-			optname = word:sub ( 2 )
-		elseif option then
-			ret[optname] = word
-			option = false
-		else
-			still_opts = false
-			table.insert ( ret, word )
-		end
-	end
-	return ret
-end
-
--- Help strings should not contain command, only arguments. This is necessary to support soft aliases.
-commands_help = {
-	file      = "filename\n\nSends file as a message. Just shorthand.",
-	s         = "status [message]\n\nSets your status, but takes into account mpd (if enabled).",
-	beep      = "[enable|disable|on|off|yes|no|true|false]\n\nEnables or disables beeping on all messages.\nIf state is omitted, prints current state.",
-	cmd       = "shell_command\n\nRuns shell command in background and sends output to current buddy.\nWorks asynchroneously, and may break long output in the middle of line",
-	exthelp   = "[command]\n\nPrints help for a given command, or list of available help topics.",
-	reload    = "\n\nJust a shorthand to reload lua config file. Note, that for now this discards all changes to configuration, open forms, transferred files.",
-	['join!'] = "\n\nForcibly joins to current buddy. Just saves you typing of full room name (that can be quite long) in a case of a non-bookmarked rooms.",
-	count     = "\n\nPrints number of resources of current buddy. Useful to determine member count of large room."
-}
-
-main.add_command ( "lua",
-	function ( args )
-		assert ( loadstring ( args ) ) ()
-	end )
-main.add_command ( 'file',
-	function ( args )
-		main.run ( 'say_to -f ' .. args .. ' .' )
-	end )
-main.add_command ( 's',
-	function ( args )
-		main.run ( ('status %s %s'):format ( args, mpd_getstatus () ) )
-	end )
-main.add_command ( 'beep',
-	function ( args )
-		local enable = yesno ( args )
-		if enable == nil then
-			if beep_enable then
-				print ( "Beep on message is enabled" )
-			else
-				print ( "Beep on message is disabled" )
-			end
-		else
-			beep_enable = enable
-		end
-	end )
-main.add_command ( 'cmd',
-	function ( args )
-		local to = main.current_buddy ()
-		main.run ( ('send_to -q %q $ %s'):format ( to, args ) )
-		main.bgread ( args,
-			function ( data )
-				if data then
-					main.run ( ('send_to -q %q %s'):format ( to, data ) )
-					return true
-				else
-					return false
-				end
-			end )
-	end )
-main.add_command ( 'exthelp',
-	function ( args )
-		if commands_help[args] then
-			print ( "\n /" .. args .. ' ' .. commands_help[args] )
-		else
-			print ( "No help for this command." )
-			list = "Help available for commands: "
-			for k in pairs (commands_help) do
-				list = list .. k .. ', '
-			end
-			print ( list:sub ( 1, -3 ) )
-			print ( "For built-in mcabber commands see /help" )
-		end
-	end )
-main.add_command ( 'reload',
-	function ( args )
-		dofile ( main.config_file ( 'mcabberrc.lua' ) )
-	end )
-main.add_command ( 'join!',
-	function ( args )
-		main.run ( 'room join ' .. main.current_buddy () )
-	end )
-main.add_command ( 'count',
-	function ( args )
-		local count = 0
-		for resource in pairs ( main.buddy_info ( main.current_buddy () ).resources ) do
-			count = count + 1
-		end
-		print ( "Resource count: " .. count )
-	end )
-
-for k, arg in ipairs ( { ')', '/', '(', 'D', '-/', 'S', '1', ']', '[' } ) do
-	main.add_command ( arg,
-		function ( args )
-			main.run ( 'say :' .. arg .. ' ' .. args )
-		end )
-end
-
--- MARKING
-
-dopath 'marking'
-
--- MPD
-
-dopath 'mpd'
-
--- FORMS (XEP-0004)
-
-dopath 'xep0004'
-
--- DISCO (XEP-0030)
-
-dopath 'xep0030'
-
--- IBB (XEP-0047)
-
-dopath 'xep0047'
-
--- IN-BAND REGISTRATION (XEP-0077)
-
-dopath 'xep0077'
-
--- REMOTE CONTROLLING CLIENTS (XEP-0146)
-
-dopath 'xep0146'
-
--- JOBS
-
-delayed_jobs = {}
-
--- FIXME: do only if it exists
-dopath 'jobs.lua'
-
-function save_jobs ()
-	local h = io.open ( main.config_file ( 'jobs.lua' ), "w" )
-	if not h then
-		print ( 'Cannot open jobs file for writing!' )
-		return
-	end
-	h:write ( "-- This is autogenerated file, do not edit it manually\n\ndelayed_jobs = {\n" );
-	for jid, more in pairs ( delayed_jobs ) do
-		h:write ( string.format ( "\t[%q] = {\n", jid ) )
-		for status, action in pairs ( more ) do
-			if action then -- remove fired jobs
-				h:write ( string.format ( "\t\t[%q] = %q,\n", status, action ) )
-			end
-		end
-		h:write ( "\t},\n" )
-	end
-	h:write ( "}\n" )
-	h:close ()
-end
-
-main.add_command ( 'delay',
-	function ( args )
-		args = parse_args ( args )
-		local who
-		if args.t then
-			who = args.t
-			args.t = nil
-		else
-			who = main.current_buddy ()
-		end
-		local stat = args[1]
-		args[1] = nil
-		delayed_jobs[who] = { }
-		delayed_jobs[who][stat] =
-			function ()
-				main.run ( 'say_to -q ' .. who .. ' ' .. rebuild_args_string ( args ) )
-			end
-	end )
-
-main.add_command ( 'job',
-	function ( args )
-		local action, jid, stat = args:match ( "(%w+)%s+(%w+)%s+(%w)" )
-		if action == 'del' then
-			delayed_jobs[jid][stat] = nil
-		else
-			print ( 'List of jobs:' )
-			for jid, jobs in pairs ( delayed_jobs ) do
-				for status in pairs ( jobs ) do
-					print ( ' - ' .. jid .. ' -> ' .. status )
-				end
-			end
-		end
-	end )
-
-commands_help['delay'] = "[-t target_jid] status_letter message\n\nDelays sending a message to target jid (or current buddy) until it switches to specified status."
-commands_help['job'] = "[del jid status_letter]\n\nLists available jobs or deletes specified one."
-
--- HOOKS
-
-ibb_handler_registered = false
-
--- Soft hooks, implemented through mcabber options
-function hook_post_connect ()
-	main.run ( 'group fold テフノ' )
-	main.run ( 'group fold にゃ' )
-	main.run ( 'group fold にゃ - Друзі' )
-
-	main.run ( 'color muc * on' )
-
-	main.run ( ("color roster * *@%s red"):format ( transport_jid ) )
-	main.run ( ("color roster dn_? *@%s red"):format ( transport_jid ) )
-
-	if mpd_enabled then
-		mpd_callback ()
-	end
-
-	-- FIXME
-	if not ibb_handler_registered then
-		lm.connection.bless( main.connection () ):handler ( ibb_incoming_iq_handler, 'iq', 'normal' )
-		main.add_feature ( 'http://jabber.org/protocol/ibb' )
-		ibb_handler_registered = true
-	end
-end
-
-function hook_pre_disconnect ()
-	main.run ( ("color roster * *@%s white"):format ( transport_jid ) )
-	main.run ( ("color roster dn_? *@%s brightblack"):format ( transport_jid ) )
-end
-
--- Hard hooks, implemented in C
-
--- hook
--- - message_in
---   jid
---   groupchat
---   message
--- - message_out
---   jid
---   message
--- - status_change
---   jid
---   resource
---   new_status
---   old_status
---   message
--- - my_status_change
---   new_status
---   message
-function hook_handler ( args )
-	if args.hook == 'message_in' then
-
-		-- beep on ALL messages, no matter, is it chat or something else.
-		if beep_enable then
-			main.beep ()
-		end
-	
-		-- save urls to file from where urlview can get them...
-		for url in args.message:gmatch ( "https?://[%w%p]+" ) do
-			fd = io.open ( url_file, "a" )
-			if fd then
-				fd:write ( url .. "\n" )
-				fd:close ()
-			else
-				print 'Cannot open urls log file'
-			end
-		end
-
-	elseif args.hook == 'status_change' then
-
-		-- delayed actions
-		if delayed_jobs[args.jid] and delayed_jobs[args.jid][args.new_status] then
-			delayed_jobs[args.jid][args.new_status] ()
-			delayed_jobs[args.jid][args.new_status] = nil
-		end
-		
-		-- transported buddies availability indication
-		if args.jid == transport_jid then
-			if args.new_status == '_' then
-				main.run ( ("color roster * *@%s red"):format ( transport_jid ) )
-				main.run ( ("color roster dn_? *@%s red"):format ( transport_jid ) )
-			else
-				main.run ( ("color roster * *@%s white"):format ( transport_jid ) )
-				main.run ( ("color roster dn_? *@%s brightblack"):format ( transport_jid ) )
-			end
-		end
-
-	end
-end
-
--- (hook_start)
-
-function hook_quit ()
-	save_jobs ()
-
-	-- FIXME
-	if ibb_handler_registered then
-		lm.connection.bless( main.connection () ):handler ( ibb_incoming_iq_handler, 'iq' )
-	end
-end
-
-
--- The End -- vim: se ts=4: --
--- a/scripts/mpd.lua	Mon Feb 23 23:16:46 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-
--- Requires libsocket
-
--- TODO:
--- do pubsub tunes+notify instead of status hacking
-
-require 'socket'
-
-local settings = {
-	hostname     = "localhost",
-	password     = nil,
-	port         = 6600,
-}
-
-mpd = {}
-
--- separator allows split output into records, that are started by any of present in separator keys
--- returns table of field (lowercase) - value records
--- command status is returned in STATUS field
--- on unexpected errors returns just false, dropping any available data
-function mpd.receive_message ( tcp, separator )
-	local ret  = {}
-	local line = tcp:receive ( '*l' )
-	while line and not ( line:find ( '^OK' ) or line:find ( '^ACK' ) ) do
-		local key, val = line:match ( '^(.-):%s*(.*)$' )
-		if key then
-			if separator then
-				key = key:lower ()
-				if separator[key] then
-					table.insert ( ret, {} )
-				end
-				ret[#ret][key]   = val
-			else
-				ret[key:lower()] = val
-			end
-		end
-		line = tcp:receive ( '*l' )
-	end
-	if not line then
-		return false -- an error occured, ret, most likely, does not contains exact and complete info...
-	else
-		ret.STATUS = line:match ( '^%S+' )
-		return ret
-	end
-end
-
--- use: mpd.call_command { 'status' }
---      mpd.call_command { 'lsinfo misc', list = { file = true, directory = true } }
---      mpd.call_command { 'next', noret = true }
---      mpd.call_command { 'status', 'currentsong' }
--- on one command returns just results of that command, on multi - array of results
--- on errors returns nil
--- noret can terminate socket too early, thus, do not use it with lists of commands
-function mpd.call_command ( opts )
-	local tcp = socket.tcp ()
-	if not tcp then
-		print ( 'mpd: cannot get master tcp object' )
-		return nil
-	elseif not tcp:connect ( settings.hostname, settings.port ) then
-		tcp:close ()
-		print ( 'mpd: cannot connect to server' )
-		return nil
-	end
-
-	local ret = {}
-	if not opts.noret then
-		ret = mpd.receive_message ( tcp )
-		if not ret then
-			tcp:close ()
-			print ( 'mpd: error getting greeting from server' )
-			return nil
-		elseif ret.STATUS ~= 'OK' then
-			print ( 'mpd: server ack\'s in greeting' )
-		end
-	end
-
-	for num, command in ipairs ( opts ) do
-		if not tcp:send ( command .. "\n" ) then
-			tcp:close ()
-			print ( 'mpd: error sending command ' .. command )
-			return nil
-		end
-		if not opts.noret then
-			ret[num] = mpd.receive_message ( tcp, opts.list )
-			if not ret[num] then
-				print ( 'mpd: error getting result' )
-			end
-			if ret[num]['STATUS'] ~= 'OK' then
-				print ( 'mpd: server acks our command ' .. command )
-			end
-		end
-	end
-
-	tcp:close ()
-	if #ret > 1 then
-		return ret
-	else
-		return ret[1]
-	end
-end
-
--- MCABBER PART --
-
-mpd_enabled = false
-
-function mpd_getstatus ()
-	if not mpd_enabled then
-		return ''
-	end
-	
-	local stats = mpd.call_command { 'status', 'currentsong' }
-	if stats[1].state ~= 'play' and stats[1].state ~= 'pause' then
-		return ''
-	end
-
-	local title = stats[2].title
-	if not title then
-		if stats[2].file then
-			title = stats[2].file
-		else
-			title = ''
-		end
-	elseif not stats[2].artist then
-		title = string.format ( "%s (%s)", title, stats[2].file )
-	else
-		title = string.format ( "%s - %s", stats[2].artist, title )
-	end
-
-	if stats[1].state == 'pause' then
-		return string.format ( "[mpd: <зупинено> %s]", title )
-	else
-		return string.format ( "[mpd: %s]", title )
-	end
-end
-
-function parse_status ()
-	local stletter, stmessage = main.status ()
-	local cmd = char2status[stletter]
-	local message, mpd_string = stmessage:match ( "^(.-)%s+(%[mpd:%s+.+%s*%])" )
-	if message then
-		return cmd, message, mpd_string
-	else
-		return cmd, stmessage, ''
-	end
-end
-
-function mpd_callback ()
-	local new_mpd_string = mpd_getstatus ()
-	local status, message, mpd_string = parse_status ()
-	if new_mpd_string ~= mpd_string then
-		main.run ( string.format ( 'status %s %s %s', status, message, new_mpd_string ) )
-	end
-	if mpd_enabled then
-		return true
-	else
-		return false
-	end
-end
-
--- do not call it too fast, or you end up with many daemons at once
-function enable_mpd ( yn )
-	if yn == nil then
-		yn = true
-	end
-	if yn then
-		if not mpd_enabled then
-			main.timer ( 15, mpd_callback )
-			mpd_enabled = true
-			-- update status
-		end
-	else
-		if mpd_enabled then
-			mpd_enabled = false
-			-- update status
-		end
-	end
-end
-
-main.add_command ( 'mpd',
-	function ( args )
-		local enable = yesno ( args )
-		if enable == nil then
-			if mpd_enabled then
-				print ( "MPD status string is enabled" )
-			else
-				print ( "MPD status string is disabled" )
-			end
-		else
-			enable_mpd ( enable )
-		end
-	end )
-
-commands_help['mpd'] = "[enable|disable|on|off|yes|no|true|false]\n\nSets state of mpd string in your status.\nIf state is omitted, prints current state."
-
--- vim: se ts=4: --
--- a/scripts/xep0004.lua	Mon Feb 23 23:16:46 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-
-forms = { }
-
--- expects lm node   x = { xmlns = 'jabber:x:data', type = 'form', ... }
--- returns form index in forms table, you can do whatever you want to upper level table, except exp and val fields.
-function parse_form ( node )
-	local form = { title = 'unknown', exp = '', val = { } }
-	if node:child ( 'title' ) then
-		form.title = node:child( 'title' ):value ()
-	end
-	if node:child ( 'instructions' ) then
-		form.exp = form.exp .. 'Instructions: ' .. node:child( 'instructions' ):value () .. '\n'
-	end
-	form.exp = form.exp .. 'Fields:\n'
-	local field = node:children ()
-	while field do
-		if field:name () == 'field' then
-			local field_type  = field:attribute ( 'type' ) or 'text-single'
-			local field_var   = field:attribute ( 'var' ) or ''
-			form.exp = form.exp .. ' - ' .. field_var .. '\n   Type: ' .. field_type .. '\n'
-			if field:attribute ( 'label' ) then
-				form.exp = form.exp .. '   Label: ' .. ( field:attribute ( 'label' ) or '' ) .. '\n'
-			end
-			if field:child ( 'desc' ) then
-				form.exp = form.exp .. '   Description: ' .. field:child( 'desc' ):value () .. '\n'
-			end
-			if field:child ( 'required' ) then
-				form.exp = form.exp .. '   Required: yes\n'
-			end
-
-			local field_value
-			if field_type == 'jid-multi' or field_type == 'list-multi' or field_type == 'text-multi' then
-				field_value = { }
-				local value = field:children ()
-				form.exp = form.exp .. '   Default values:\n'
-				while value do
-					if value:name () == 'value' then
-						table.insert ( field_value, { value:value () } )
-						form.exp = form.exp .. '    - ' .. value:value () .. '\n'
-					end
-					value = value:next ()
-				end
-			else
-				if field:child ( 'value' ) then
-					field_value = field:child( 'value' ):value ()
-					form.exp = form.exp .. '   Default value: ' .. field_value .. '\n'
-				end
-			end
-
-			if field_type == 'list-single' or field_type == 'list-multi' then
-				form.exp = form.exp .. '   List options:\n'
-				local option = field:children ()
-				while option do
-					if option:name () == 'option' then
-						form.exp = form.exp .. '    - ' .. ( option:child( 'value' ):value () or '' ) .. ': ' .. ( option:attribute ( 'label' ) or '' ) .. '\n'
-					end
-					option = option:next ()
-				end
-			end
-
-			if field_type == 'boolean' then
-				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '0' } } )
-			elseif field_type == 'fixed' then
-			elseif field_type == 'hidden' then
-				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '' } } )
-			elseif field_type == 'list-single' then
-				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '' } } )
-			elseif field_type == 'list-multi' then
-				table.insert ( form.val, { type = field_type, var = field_var, value = field_value or { } } )
-			elseif field_type == 'jid-multi' or field_type == 'text-multi' then
-				table.insert ( form.val, { type = field_type, var = field_var, value = field_value or { } } )
-			elseif field_type == 'jid-single' or field_type == 'text-single' then
-				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '' } } )
-			elseif field_type == 'text-private' then
-				table.insert ( form.val, { type = field_type, var = field_var, value = { field_value or '' } } )
-			end
-		end
-		field = field:next ()
-	end
-	table.insert ( forms, form )
-	return #forms
-end
-
-function form_set ( id, name, value )
-	if forms[id] then
-		for index, field in ipairs ( forms[id].val ) do
-			if field.var == name then
-				if value == nil then
-					field.value = { }
-				else
-					if field.type == 'jid-multi' or field.type == 'list-multi' or field.type == 'text-multi' then
-						table.insert ( field.value, { value } )
-					else
-						field.value = { value }
-					end
-				end
-			end
-		end
-	end
-end
-
-main.add_command ( 'form',
-	function ( args )
-		args = parse_args ( args )
-		local action = args[1]
-		local id = tonumber (args[1])
-		if forms[id] then
-			if args[2] then
-				local field = args[2]
-				if args[3] == 'clear' then
-					form_set ( id, field, nil )
-				else
-					args[1] = nil
-					args[2] = nil
-					if args[3] == 'set' then
-						args[3] = nil
-					end
-					form_set ( id, field, rebuild_args_string ( args ) )
-				end
-			else
-				print ( 'Form: ' .. ( forms[id].title or '' ) .. '\n' .. forms[id].exp )
-				print ( 'Fields:' )
-				for index, field in ipairs ( forms[id].val ) do -- this should not be here, but setting up callback just for this...
-					if field.type == 'jid-multi' or field.type == 'list-multi' or field.type == 'text-multi' then
-						print ( ' - ' .. field.var .. ' [' .. field.type .. ']:' )
-						for vin, value in ipairs ( field.value ) do
-							print ( '    * ' .. value[1] )
-						end
-					else
-						print ( ' - ' .. field.var .. ' [' .. field.type .. ']: ' .. field.value[1] )
-					end
-				end
-			end
-		elseif action == 'del' then
-			forms[tonumber(args[2])] = nil
-		elseif action == 'send' then
-			local form = forms[tonumber(args[2])]
-			if form then
-				form.send ( form )
-			end
-		else
-			print ( 'Forms list:' )
-			for id, form in ipairs ( forms ) do
-				print ( ' - ' .. tostring(id) .. ' ' .. form.title .. ' [' .. ( form.status or 'unknown' ) .. ']' )
-			end
-		end
-	end )
-
-commands_help['form'] = "[del form_id | send form_id | form_id [field_name {clear | [set] value}]\n\nWith bare form id prints info on that form.\nWith field name sets or clears field value. Set subcommand is optional, just to allow values, starting with 'clear'.\nWithout arguments prints form list."
-
--- vim: se ts=4: --
--- a/scripts/xep0030.lua	Mon Feb 23 23:16:46 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-
-function disco_items ( callback, what, node )
-	local request =
-		lm.message.create { to = what, mtype = 'iq-get',
-			query = { xmlns = 'http://jabber.org/protocol/disco#items' }
-		}
-	if node then
-		request:child( 'query' ):attribute ( 'node', node )
-	end
-	return lm.connection.bless( main.connection () ):send ( request,
-		function ( conn, message )
-			if message:child ( 'error' ) then
-				callback ( message:child( 'error' ):children():name () )
-			else
-				local item = message:child( 'query' ):children ()
-				local items = { }
-				while item do
-					if item:name () == 'item' then
-						table.insert ( items, { jid = item:attribute ( 'jid' ), node = item:attribute ( 'node' ), name = item:attribute ( 'name' ) } )
-					end
-					item = item:next ()
-				end
-				callback ( items )
-			end
-			return true
-		end )
-end
-
-function disco_info ( callback, what )
-	return lm.connection.bless( main.connection () ):send (
-		lm.message.create { to = what, mtype = 'iq-get',
-			query = { xmlns='http://jabber.org/protocol/disco#info' }
-		},
-		function ( conn, message )
-			local items_supported = false
-			if message:child ( 'error' ) then
-				callback ( message:child( 'error' ):children():name () )
-			else
-				local item = message:child( 'query' ):children ()
-				local identities = { }
-				local features   = { }
-				while item do
-					if item:name () == 'identity' then
-						table.insert ( identities, { category = item:attribute ( 'category' ), type = item:attribute ( 'type' ), name = item:attribute ( 'name' ) } )
-					elseif item:name () == 'feature' then
-						table.insert ( features, item:attribute ( 'var' ) )
-					end
-					item = item:next ()
-				end
-				callback ( identities, features )
-			end
-			return true
-		end )
-end
-
-main.add_command ( 'disco',
-	function ( args )
-		args = parse_args ( args )
-		local who
-		if args.t then
-			who = args.t
-			args.t = nil
-		else
-			who = full_current_jid ()
-		end
-		if args[1] == 'items' then
-			local node = nil
-			if args[2] then
-				args[1] = nil
-				node = rebuild_args_string ( args )
-			end
-			disco_items (
-				function ( items )
-					if type ( items ) == 'string' then
-						main.print_info ( who, string.format ( "Service items discovery for %s (%s) failed: %s", who, node or '', items ) )
-					else
-						main.print_info ( who, string.format ( "Service items discovery result for %s (%s):", who, node or '' ) )
-						for index, item in ipairs ( items ) do
-							main.print_info ( who, string.format ( "    [%s (%s)] %s", item.jid or '', item.node or '', item.name or '' ) )
-						end
-					end
-				end, who, node )
-		else
-			disco_info (
-				function ( identities, features )
-					if type ( identities ) == 'string' then
-						main.print_info ( who, string.format ( "Service info discovery for %s failed: %s", who, identities ) )
-					else
-						main.print_info ( who, string.format ( "Service info discovery result for %s:", who ) )
-						main.print_info ( who, "  Identities:" )
-						for index, identity in ipairs ( identities ) do
-							main.print_info ( who, string.format ( "    [%s (%s)] %s", identity.category or '', identity.type or '', identity.name or '' ) )
-						end
-						main.print_info ( who, "  Features:" )
-						for index, feature in ipairs ( features ) do
-							main.print_info ( who, string.format ( "    [%s]", feature or '' ) )
-						end
-					end
-				end, who )
-		end
-	end )
-
-commands_help['disco'] = "[-t target_jid] [info | items] [node]\n\nService discovery request.\nInfo is sent if omitted.\nIf info reveals, that buddy can do items, items request also will be sent."
-
--- vim: se ts=4: --
--- a/scripts/xep0047.lua	Mon Feb 23 23:16:46 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-
-receiving_files = {}
-ibb_block_size  = 4096
-current_sid_number = 0
-
--- FIXME: read from /dev/urandom?
-function gen_unique_sid ()
-	current_sid_number = current_sid_number + 1
-	return 'mc-' .. tostring ( current_sid_number )
-end
-
-ibb_incoming_iq_handler = lm.message_handler.new ( 
-	function ( conn, mess )
-		local id   = mess:attribute ( 'id' )
-		local from = mess:attribute ( 'from' )
-		if mess:child ( 'open' ) and mess:child( 'open' ):attribute ( 'xmlns' ) == 'http://jabber.org/protocol/ibb' then
-			local sid  = mess:child( 'open' ):attribute ( 'sid' )
-			if not receiving_files[sid] then
-				local buffer = ''
-				receiving_files[sid] = { from = from, status = 'pending' }
-				receiving_files[sid].accept =
-					function ( name )
-						main.print_info ( from, string.format ( "Receiving stream from %s, id %s", from, sid ) )
-						conn:send ( lm.message.create { to = from, mtype = 'iq-result', id = id } )
-						receiving_files[sid].name = name
-						receiving_files[sid].status = 'accepted'
-					end
-				receiving_files[sid].reject =
-					function ()
-						conn:send (
-							lm.message.create { to = from, mtype = 'iq-error', id = id,
-								error = { code = '405', type = 'cancel',
-									['not-allowed'] = { xmlns = 'urn:ietf:params:xml:ns:xmpp-stanzas' }
-								}
-							} )
-						receiving_files[sid].status = 'rejected'
-					end
-				print ( 'You have a new bytestream to receive. To save it use /ibb accept ' .. sid .. ' filename' )
-			else
-				conn:send (
-					lm.message.create { to = from, mtype = 'iq-error', id = id,
-						error = { code = '409', type = 'cancel',
-							conflict = { xmlns = 'urn:ietf:params:xml:ns:xmpp-stanzas' }
-						}
-					} )
-			end
-		elseif mess:child ( 'data' ) and mess:child( 'data' ):attribute ( 'xmlns' ) == 'http://jabber.org/protocol/ibb' then
-			local sid  = mess:child( 'data' ):attribute ( 'sid' )
-			local seq  = mess:child( 'data' ):attribute ( 'seq' )
-			if receiving_files[sid] and from == receiving_files[sid].from and not receiving_files[sid][tonumber(seq)+1] then
-				local data = mess:child( 'data' ):value ()
-				main.print_info ( from, string.format ( " - stream part %s, id %s, %d bytes", seq, sid, data:len() ) )
-				conn:send ( lm.message.create { to = from, mtype = 'iq-result', id = id } )
-				receiving_files[sid][tonumber(seq)+1] = data
-			else
-				receiving_files[sid] = nil -- invalidate session
-				conn:send (
-					lm.message.create { to = from, mtype = 'iq-error', id = id,
-						error = { code = '409', type = 'cancel',
-							conflict = { xmlns = 'urn:ietf:params:xml:ns:xmpp-stanzas' }
-						}
-					} )
-			end
-		elseif mess:child ( 'close' ) and mess:child( 'close' ):attribute ( 'xmlns' ) == 'http://jabber.org/protocol/ibb' then
-			local sid  = mess:child( 'close' ):attribute ( 'sid' )
-			if receiving_files[sid] and from == receiving_files[sid].from then
-				main.print_info ( from, "Done with stream id " .. sid )
-				conn:send ( lm.message.create { to = from, mtype = 'iq-result', id = id } )
-				local decoder = io.popen ( string.format ( "base64 -d -i >%q", receiving_files[sid].name ), "w" )
-				if not decoder then
-					main.print_info ( from, "Error opening decoder" )
-				else
-					for i, v in ipairs ( receiving_files[sid] ) do
-						decoder:write ( v )
-					end
-					decoder:close ()
-				end
-			else
-				receiving_files[sid] = nil -- invalidate session
-				conn:send (
-					lm.message.create { to = from, mtype = 'iq-error', id = id,
-						error = { code = '409', type = 'cancel',
-							conflict = { xmlns = 'urn:ietf:params:xml:ns:xmpp-stanzas' }
-						}
-					} )
-			end
-		else
-			return false
-		end
-		return true
-	end )
-
--- You must specify a full jid with resource!
-function send_file ( to, name )
-	local sid = gen_unique_sid ()
-	local conn = lm.connection.bless ( main.connection () )
-	conn:send (
-		lm.message.create { to = to, mtype = 'iq-set',
-			open = { sid = sid, ['block-size'] = ibb_block_size, xmlns = 'http://jabber.org/protocol/ibb' }
-		},
-		function ( conn, message )
-			if message:child ( 'error' ) then
-				main.print_info ( to, "Stream request refused: " .. message:child( 'error' ):children():name () )
-			else
-				main.print_info ( to, "Stream accepted, starting sequence" )
-				local buffer = ''
-				main.bgread ( string.format ( 'base64 -w 0 %q', name ),
-					function ( data )
-						if data then
-							buffer = buffer .. data
-							return true
-						else
-							local seq = 0
-							local msgbuf = buffer:sub ( 1, ibb_block_size )
-							buffer = buffer:sub ( ibb_block_size + 1 )
-							local function handler ( conn, message )
-								if message:child ( 'error' ) then
-									main.print_info ( to, "Stream error, transfer ceased at seq = " .. seq .. ": " .. message:child( 'error' ):children():name () )
-								else
-									main.print_info ( to, " - acquired seq = " .. seq )
-									seq = seq + 1
-									if buffer:len () == 0 then
-										conn:send (
-											lm.message.create { to = to, mtype = 'iq-set',
-												close = { sid = sid, xmlns = 'http://jabber.org/protocol/ibb' }
-											},
-											function ( conn, message )
-												if message:child ( 'error' ) then
-													main.print_info ( to, "Error at closing stream: " .. message:child( 'error' ):children():name () )
-												else
-													main.print_info ( to, "File successfully transferred" )
-												end
-												return true
-											end )
-									else
-										local msgbuf = buffer:sub ( 1, ibb_block_size )
-										buffer = buffer:sub ( ibb_block_size )
-										conn:send (
-											lm.message.create { to = to, mtype = 'iq-set',
-												data = { sid = sid, xmlns = 'http://jabber.org/protocol/ibb', seq = seq,
-													msgbuf
-												}
-											},
-											handler )
-									end
-								end
-								return true
-							end
-							conn:send (
-								lm.message.create { to = to, mtype = 'iq-set',
-									data = { sid = sid, xmlns = 'http://jabber.org/protocol/ibb', seq = seq,
-										msgbuf
-									}
-								},
-								handler )
-							return false
-						end
-					end )
-			end
-			return true
-		end )
-end
-
-main.add_command ( 'ibb',
-	function ( args )
-		args = parse_args ( args )
-		if args[1] == 'send' then
-			local who
-			if args.t then
-				who = args.t
-				args.t = nil
-			else
-				who = full_current_jid ()
-			end
-			args[1] = nil
-			send_file ( who, rebuild_args_string ( args ) )
-		elseif args[1] == 'accept' then
-			local id = args[2]
-			args[1] = nil
-			args[2] = nil
-			if receiving_files[id] then
-				receiving_files[id].accept ( rebuild_args_string ( args ) )
-			end
-		elseif args[1] == 'reject' then
-			local id = args[2]
-			if receiving_files[id] then
-				receiving_files[id].reject ()
-			end
-		elseif args[1] == 'del' then
-			local id = args[2]
-			receiving_files[id] = nil
-		else
-			print ( 'List of incoming streams:' )
-			for sid, data in pairs ( receiving_files ) do
-				print ( sid .. ': ' .. ( data.name or '(not set)' ) .. ' [' .. data.status .. ']' )
-			end
-		end
-	end )
-
-commands_help['ibb'] = "[[-t target_jid] send filename | accept sid filename | reject sid filename | del sid]\n\nRequests, accepts or rejects sending file via in-band bytestream."
-
--- vim: se ts=4: --
--- a/scripts/xep0077.lua	Mon Feb 23 23:16:46 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-
-function parse_iq_register ( node )
-	local form = { title = 'jabber:iq:register', exp = '', val = { } }
-	if node:child ( 'instructions' ) then
-		form.exp = form.exp .. 'Instructions: ' .. node:child( 'instructions' ):value () .. '\n'
-	end
-	if node:child ( 'registered' ) then
-		form.exp = form.exp .. 'Registered: yes\n'
-	end
-	form.exp = form.exp .. 'Fields:\n'
-	local field = node:children ()
-	while field do
-		local name = field:name ()
-		if name ~= 'instructions' and name ~= 'registered' then
-			form.exp = form.exp .. ' - ' .. name .. '\n'
-			if field:value () and field:value () ~= '' then
-				form.exp = form.exp .. '   Default value: ' .. field:value () .. '\n'
-			end
-			table.insert ( form.val, { type = 'text-single', var = name, value = { field:value () or '' } } )
-		end
-		field = field:next ()
-	end
-	table.insert ( forms, form )
-	return #forms
-end
-
-function format_iq_register ( fields )
-	local result = { xmlns = 'jabber:iq:register' }
-	for index, field in ipairs ( fields ) do
-		result[field.var] = field.value
-	end
-	return result
-end
-
-function register_to ( who )
-	lm.connection.bless( main.connection () ):send (
-		lm.message.create { mtype = 'iq-get', to = who,
-			query = { xmlns = 'jabber:iq:register' }
-		},
-		function ( conn, mess )
-			local node = mess:child ( 'query' )
-			if node and node:attribute ( 'xmlns' ) == 'jabber:iq:register' then
-				main.print_info ( who, 'D: Got:\n' .. mess:xml () )
-				local x = node:child ( 'x' )
-				local id
-				local finalizer =
-					function ( conn, mess )
-						local mt, st = mess:type ()
-						if st == 'result' then
-							main.print_info ( who, 'Now you can run /form del ' .. id .. ' to delete form from list' )
-							forms[id].status = 'acquired'
-						else
-							main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
-							forms[id].status = 'rejected'
-						end
-						return true
-					end
-				if x and x:attribute ( 'xmlns' ) == 'jabber:x:data' then
-					id = parse_form ( x )
-					-- local sid = mess:child( 'command' ):attribute ( 'sessionid' )
-					forms[id].send =
-						function ( form )
-							conn:send (
-								lm.message.create { mtype = 'iq-set', to = who,
-									query = { xmlns = 'jabber:iq:register',
-										x = { xmlns = 'jabber:x:data', type = 'submit',
-											field = form.val,
-										},
-									},
-								}, finalizer )
-						end
-					forms[id].status = 'filling'
-					main.print_info ( who, 'You have new form. To fill it, use /form ' .. id .. ' fieldname value' )
-				else
-					id = parse_iq_register ( mess:child ( 'query' ) )
-					forms[id].send =
-						function ( form )
-							conn:send (
-								lm.message.create { mtype = 'iq-set', to = who,
-									query = format_iq_register ( form.val ),
-								}, finalizer )
-						end
-					forms[id].status = 'filling'
-					main.print_info ( who, 'You have new form. To fill it, use /form ' .. id .. ' fieldname value' )
-				end
-			else
-				main.print_info ( who, 'Error response:\n' .. mess:xml () )
-			end
-			return true
-		end )
-end
-
-function unregister_from ( who )
-	lm.connection.bless( main.connection () ):send (
-		lm.message.create { mtype = 'iq-set', to = who,
-			query = { xmlns = 'jabber:iq:register',
-				remove = { },
-			},
-		},
-		function ( conn, mess )
-			local mt, st = mess:type ()
-			if st == 'result' then
-				main.print_info ( who, 'Registration cancelled' )
-			elseif st == 'error' then
-				if mess:child ( 'error' ) then
-					main.print_info ( who, 'Error response: ' .. mess:child( 'error' ):children():name () )
-				else
-					local query = mess:child ( 'query' )
-					if query and query:child ( 'x' ) then
-						local id = parse_form ( query:child ( 'x' ) )
-						forms[id].send =
-							function ( form )
-								conn:send (
-									lm.message.create { mtype = 'iq-set', to = who,
-										query = { xmlns = 'jabber:iq:register',
-											x = { xmlns = 'jabber:x:data', type = 'submit',
-												field = form.val,
-											},
-										},
-									},
-									function ( conn, mess )
-										local mt, st = mess:type ()
-										if st == 'result' then
-											main.print_info ( who, 'Now you can run /form del ' .. id .. ' to delete form from list' )
-											forms[id].status = 'acquired'
-										else
-											main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
-											forms[id].status = 'rejected'
-										end
-										return true
-									end )
-							end
-						forms[id].status = 'filling'
-						main.print_info ( who, 'You have new form. To fill it, use /form ' .. id .. ' fieldname value' )
-					else
-						main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
-					end
-				end
-			else
-				main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
-			end
-			return true
-		end )
-end
-
-main.add_command ( 'register',
-	function ( args )
-		local who
-		if args[1] then
-			who = rebuild_args_string ( args )
-		else
-			who = full_current_jid ()
-		end
-		register_to ( who )
-	end )
-
-main.add_command ( 'cancel',
-	function ( args )
-		local who
-		if args and args ~= '' then
-			who = args
-		else
-			who = full_current_jid ()
-		end
-		unregister_from ( who )
-	end )
-
-commands_help['register'] = "[jid]\n\nSends registration request to jid (or current buddy). You, probably, then will need to fill and send some form."
-commands_help['cancel'] = "[jid]\n\nSends registration cancellation request to jid (or current buddy). May require a form filling."
-
--- vim: se ts=4: --
--- a/scripts/xep0146.lua	Mon Feb 23 23:16:46 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-
-function remote_command ( who, command )
-	lm.connection.bless( main.connection () ):send (
-		lm.message.create { mtype = 'iq-set', to = who,
-			command = { xmlns = 'http://jabber.org/protocol/commands', action = 'execute', node = command }
-		},
-		function ( conn, mess )
-			if mess:child ( 'command' ) and mess:child( 'command' ):child ( 'x' ) then
-				local id = parse_form ( mess:child( 'command' ):child ( 'x' ) )
-				local sid = mess:child( 'command' ):attribute ( 'sessionid' )
-				forms[id].send =
-					function ( form )
-						conn:send (
-							lm.message.create { mtype = 'iq-set', to = who,
-								command = { xmlns = 'http://jabber.org/protocol/commands', node = command, sessionid = sid,
-									x = { xmlns = 'jabber:x:data', type = 'form',
-										field = form.val,
-									},
-								},
-							},
-							function ( conn, mess )
-								if mess:child ( 'command' ) and mess:child( 'command' ):attribute ( 'status' ) == 'completed' then
-									main.print_info ( who, 'Now you can run /form del ' .. id .. ' to delete form from list' )
-									forms[id].status = 'acquired'
-								else
-									main.print_info ( who, 'Got non-successful response to form:\n' .. mess:xml () )
-									forms[id].status = 'rejected'
-								end
-								return true
-							end )
-					end
-				forms[id].status = 'filling'
-				main.print_info ( who, 'You have new form. To fill it, use /form ' .. id .. ' fieldname value' )
-			else
-				main.print_info ( who, 'Got response to command request:\n' .. mess:xml () )
-			end
-			return true
-		end )
-end
-
-main.add_command ( 'remote',
-	function ( args )
-		args = parse_args ( args )
-		local who
-		if args.t then
-			who = args.t
-			args.t = nil
-		else
-			who = full_current_jid ()
-		end
-		if args[1] == 'list' or not args[1] then
-			disco_items (
-				function ( items )
-					if type ( items ) == 'string' then
-						main.print_info ( who, string.format ( "Service items discovery for %s (http://jabber.org/protocol/commands) failed: %s", who, items ) )
-					else
-						main.print_info ( who, 'Available commands:' )
-						for index, item in ipairs ( items ) do
-							main.print_info ( who, ' - ' .. item.node )
-						end
-					end
-				end, who, 'http://jabber.org/protocol/commands' )
-		elseif args[1] then
-			remote_command ( who, args[1] )
-		end
-	end )
-
-commands_help['remote'] = "[-t target_jid] [list | command]\n\nPrints list of available remote command or requests execution of specified command."
-
--- vim: se ts=4: --