# HG changeset patch # User Myhailo Danylenko # Date 1238262192 -7200 # Node ID d33ca5572e91d84ca04fa073cf4ce897a4c67954 # Parent 542f61e113cbce7349d2129768eac3ad4466f665 Fully object forms interface (untested) diff -r 542f61e113cb -r d33ca5572e91 examples/form_field.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/form_field.lua Sat Mar 28 19:43:12 2009 +0200 @@ -0,0 +1,99 @@ + +-- DATA FORM FIELD + +local F = { } +local M = { } +M.__index = M + +-- field.new -- create new field +-- field:index -- get index +-- field:type -- get type +-- field:name -- get var +-- field:desc -- get label, desc +-- field:value -- get/set value +-- field:values -- get values +-- field:clear -- clear value +-- field:options -- get options +-- field:required -- get required + +function F.new ( args ) + local obj = { + t = args.type, + l = args.label, + d = args.desc, + o = args.options, -- XXX + v = args.value, -- XXX + r = args.required, + n = args.var, + i = args.index, -- XXX + } + setmetatable ( obj, M ) + return obj +end + +function M.index ( obj ) + return obj.i +end + +function M.type ( obj ) + return obj.t +end + +function M.name ( obj ) + return obj.n +end + +function M.desc ( obj ) + return obj.l, obj.d +end + +function M.options ( obj ) + return pairs ( obj.o ) +end + +function M.value ( obj, value ) + local ftype = obj.t + if value == nil then + -- XXX + return obj.v + else + if ftype == 'jid-multi' or ftype == 'list-multi' or ftype == 'text-multi' then + table.insert ( obj.v, value ) + else + obj.v = value + end + end +end + +function M.values ( obj ) + local ftype = obj.t + if ftype == 'jid-multi' or ftype == 'list-multi' or ftype == 'text-multi' then + return ipairs ( obj.v ) + else + return + function ( arg ) + if not arg then + return obj.v + else + return nil + end + end, nil + end +end + +function M.clear ( obj ) + local ftype = obj.t + if ftype == 'jid-multi' or ftype == 'list-multi' or ftype == 'text-multi' then + obj.v = { } + else + obj.v = '' + end +end + +function M.required ( obj ) + return obj.r +end + +return F + +-- vim: se ts=4: -- diff -r 542f61e113cb -r d33ca5572e91 examples/iq_register.lua --- a/examples/iq_register.lua Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/iq_register.lua Sat Mar 28 19:43:12 2009 +0200 @@ -3,60 +3,127 @@ -- library -local lm = require 'lm' -local iq = require 'iq' ---local x_data = -require 'x_data' +local iq = require 'iq' +local x_data = require 'x_data' +local form_field = require 'form_field' + +-- + +local F = { } +local M = { } +M.__index = M --- public - -iq_register = { } +function F.new ( args ) + local form = { + xmlns = 'jabber:iq:register', + ftype = args.type or 'form', + registered = args.registered, + -- XXX title + instructions = args.instructions, + x_data = args.x_data, + f = { }, + } + setmetatable ( form, M ) + return form +end -function iq_register.parse ( query ) - local form = { xmlns = 'jabber:iq:register', type = 'form' } - +function F.parse ( query ) local instructions = query:child ( 'instructions' ) if instructions then - form.instructions = instructions:value () + instructions = instructions:value () end - -- XXX how it can be mapped to common form? - -- and needs it be supplied? + + local registered if query:child ( 'registered' ) then - form.registered = true + registered = true end local x = query:child ( 'x' ) if x and x:attribute ( 'xmlns' ) == 'jabber:x:data' then - form = x_data.parse ( x ) - local format = form.format - form.format = - function ( form, root ) - root.query = format ( form, { xmlns = 'jabber:iq:register' } ) - return root - end - return form + return F.new { type = 'form', registered = registered, instructions = instructions, x_data = x_data.parse ( x ) } end + local form = F.new { type = 'form', registered = registered, instructions = instructions } + local field = query:child () while field do local name = field:name () if name ~= 'instructions' and name ~= 'registered' then - table.insert ( form, { type = 'text-single', var = name, value = field:value () or '' } ) + form:add ( name, { type = 'text-single', value = field:value () or '' } ) end field = field:next () end - form.format = - function ( form, root ) - root.query = { xmlns = 'jabber:iq:register' } - for index, field in ipairs ( form ) do - root.query[field.var] = field.value - end - return root - end + return form end -function iq_register.register ( conn, to, success, fail ) +function M.type ( form ) + return form.ftype +end + +function M.desc ( form ) + if form.x_data then + return form.x_data:desc () + else + return form.title, form.instructions + end +end + +function M.format ( form, root, format_as ) + local ft = format_as or form:type () + + if form.x_data then + root.query = form.x_data:format ( { xmlns = 'jabber:iq:register' }, ft ) + else + root.query = { xmlns = 'jabber:iq:register' } + for index, field in form:fields () do + root.query[field:name ()] = field:value () + end + end + + if ft == 'form' then + local title, instructions = form:desc () + if instructions then + root.query.instructions = { instructions } + end + if form.registered then + root.query.registered = { } + end + end + + return root +end + +function M.fields ( form ) + if form.x_data then + return form.x_data:fields () + else + return ipairs ( form.f ) + end +end + +function M.add ( form, name, fld ) + if form.x_data then + return form.x_data:add ( name, fld ) + else + fld.var = name + fld.index = #form.f + 1 + local obj = form_field.new ( fld ) + table.insert ( form.f, obj ) + form.f[name] = obj + return obj + end +end + +function M.field ( form, name ) + if form.x_data then + return form.x_data:field ( name ) + else + return form.f[name] + end +end + +function F.register ( conn, to, success, fail ) iq.send ( conn, to, 'get', { query = { xmlns = 'jabber:iq:register' }, @@ -64,10 +131,9 @@ function ( mess ) local query = mess:child ( 'query' ) if query and query:attribute ( 'xmlns' ) == 'jabber:iq:register' then - success ( iq_register.parse ( query ), + success ( F.parse ( query ), function ( form, success, fail ) - form.type = 'submit' -- XXX - iq.send ( conn, to, 'set', form.format ( form, { } ), success , fail ) + iq.send ( conn, to, 'set', form:format ( form, { }, 'submit' ), success , fail ) end, function ( form, success, fail ) success () @@ -76,7 +142,7 @@ end, fail ) end -function iq_register.unregister ( conn, to, success, fail ) +function F.unregister ( conn, to, success, fail ) iq.send ( conn, to, 'set', { query = { xmlns = 'jabber:iq:register', @@ -89,10 +155,9 @@ function ( mesg, mess ) local query = mess:child ( 'query' ) if query and query:attribute ( 'xmlns' ) == 'jabber:iq:register' then - success ( iq_register.parse ( query ), + success ( F.parse ( query ), function ( form, success, fail ) - form.type = 'submit' -- XXX - iq.send ( conn, to, 'set', form.format ( form, { } ), success, fail ) + iq.send ( conn, to, 'set', form:format ( form, { }, 'submit' ), success, fail ) end, function ( form, success, fail ) success () @@ -103,94 +168,6 @@ end ) end --- mcabber - -main.command ( 'register', - function ( args ) - local who - if args and args ~= '' then - who = args - else - who = main.full_jid () - end - iq_register.register ( lm.connection.bless ( main.connection () ), who, - function ( form, submit, reject ) - local id = #forms + 1 - forms[id] = { - form = form, - submit = - function ( form ) - submit ( form, - function () - main.print_info ( who, 'Successfully registered' ) - end, - function ( mesg ) - main.print_info ( who, 'Registration failed: ' .. mesg ) - end ) - end, - reject = - function ( form ) - reject ( form, - function () - main.print_info ( who, 'Registration cancelled' ) - end, - function ( mesg ) - main.print_info ( who, 'Registration cancellation failed: ' .. mesg ) - end ) - end, - } - print ( 'You have new form ' .. id ) - end, - function ( mesg ) - main.print_info ( who, 'Registration failed: ' .. mesg ) - end ) - end, false, 'jid' ) -main.command ( 'cancel', - function ( args ) - local who - if args and args ~= '' then - who = args - else - who = main.full_jid () - end - iq_register.unregister ( lm.connection.bless ( main.connection () ), who, - function ( form, submit, reject ) - if not form then - main.print_info ( who, 'Successfully unregistered' ) - else - local id = #forms + 1 - forms[id] = { - form = form, - submit = - function ( form ) - submit ( form, - function () - main.print_info ( who, 'Successfully unregistered' ) - end, - function ( mesg ) - main.print_info ( who, 'Unregistrering failed: ' .. mesg ) - end ) - end, - reject = - function ( form ) - reject ( form, - function () - main.print_info ( who, 'Unregistration cancelled' ) - end, - function ( mesg ) - main.print_info ( who, 'Unregistration cancellation failed: ' .. mesg ) - end ) - end, - } - print ( 'You have new form ' .. id ) - end - end, - function ( mesg ) - main.print_info ( who, 'Unregistering failed: ' .. mesg ) - end ) - end, false, 'jid' ) - -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." +return F -- vim: se ts=4: -- diff -r 542f61e113cb -r d33ca5572e91 examples/lua.rc --- a/examples/lua.rc Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/lua.rc Sat Mar 28 19:43:12 2009 +0200 @@ -6,7 +6,7 @@ set lua_hook_function = hook_handler # enable lua-loudmouth debug output to be shown in log -set lua_lm_debug = 0 +set lua_lm_debug = 1 # show notifications for pep events set lua_pep_notification = enable diff -r 542f61e113cb -r d33ca5572e91 examples/mc_forms.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/mc_forms.lua Sat Mar 28 19:43:12 2009 +0200 @@ -0,0 +1,114 @@ + +local form_cid = main.add_category { 'del', 'send' } +local forms = { } + +-- public +function insert_form ( form, submit, reject ) + table.insert ( forms, { + form = form, + submit = submit, + reject = reject, + } ) + main.add_completion ( form_cid, tostring(#forms) ) + print ( "You have new form. Use /form " .. #forms .. " to fill and submit or cancel it." ) + return #forms +end + +main.command ( 'form', + function ( args ) + local id, action = tonumber (args[1]), args[2] + if forms[id] then + local form = forms[id].form + if action == 'send' then + forms[id].submit ( form ) + elseif action == 'reject' then + forms[id].reject ( form ) + elseif action == 'del' then + main.del_completion ( form_cid, id ) + forms[id] = nil + elseif action then + local fname, value + if action == 'set' then + fname = args[3] + value = args[4] + else + fname = action + value = args[3] + end + local field = form:field ( fname ) + if field then + if value then + field:value ( value ) + else + field:clear () + end + else + -- XXX create? + print ( 'Field not found: ' .. fname ) + end + else + local desc = 'Form ' .. id .. '\n - Type: ' .. form:type () + local title, instructions = form:desc () + if title then + desc = desc .. '\n - Title: ' .. title + end + if instructions then + desc = desc .. '\n - Instructions: ' .. instructions + end + + local fields = 'Fields:' + for index, field in form:fields () do + local ftype = field:type () + + fields = fields .. '\n - ' + + if field:required () then + fields = fields .. '* ' + end + + local label, descr = field:desc () + if label then + fields = fields .. label .. ' (' .. ( field.var or '' ) .. ')' + else + fields = fields .. ( field:name () or '' ) + end + fields = fields .. ' [' .. ftype .. ']' + if descr then + fields = fields .. ': ' .. descr + end + + if ftype == 'list-single' or ftype == 'list-multi' then + fields = fields .. '\n Options:' + for option, label in field:options () do + fields = fields .. '\n * ' .. option .. ' - ' .. label + end + end + + if ftype == 'list-multi' or ftype == 'text-multi' or ftype == 'jid-multi' then + fields = fields .. '\n Values: ' + for vin, value in field:values () do + fields = fields .. '\n * ' .. value + end + else + fields = fields .. '\n Value: ' .. ( field:value () or '' ) + end + end + print ( desc .. '\n' .. fields ) + end + else + local text = '' + for id, form in pairs ( forms ) do + local title = form.form:desc () + text = text .. '\n - ' .. id .. ' ' .. ( title or 'Untitled' ) .. ' [' .. form.form:type () .. ']' + end + if text ~= '' then + print ( 'Forms list:' .. text ) + else + print ( 'No forms' ) + end + end + end, true, form_cid ) + +commands_help['form'] = "[form_id [send | reject | [set] fieldname [value]]]\n\nWithout arguments prints form list.\nWith bare form id prints info on that form.\nWhen setting multivalue field, new values are added, not replacing previous.\nWithout value unsets field, multivalue fields lose all their values." + +-- vim: se ts=4: -- diff -r 542f61e113cb -r d33ca5572e91 examples/mc_pubsub.lua --- a/examples/mc_pubsub.lua Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/mc_pubsub.lua Sat Mar 28 19:43:12 2009 +0200 @@ -68,31 +68,25 @@ elseif action:sub ( 1, 4 ) == 'conf' then pubsub.configure_node ( conn, who, node, function ( form, submit, reject ) - local id = #forms + 1 - forms[id] = { - form = form, - submit = - function ( form ) - submit ( form, - function () - main.print_info ( who, 'Node configuration completed' ) - end, - function ( mesg ) - main.print_info ( who, 'Node configuration failed: ' .. mesg ) - end ) - end, - reject = - function ( form ) - reject ( form, - function () - main.print_info ( who, 'Node configuration cancelled' ) - end, - function ( mesg ) - main.print_info ( who, 'Node configuration cancellation failed: ' .. mesg ) - end ) - end, - } - print ( 'You have new form ' .. id ) + insert_form ( form, + function ( form ) + submit ( form, + function () + main.print_info ( who, 'Node configuration completed' ) + end, + function ( mesg ) + main.print_info ( who, 'Node configuration failed: ' .. mesg ) + end ) + end, + function ( form ) + reject ( form, + function () + main.print_info ( who, 'Node configuration cancelled' ) + end, + function ( mesg ) + main.print_info ( who, 'Node configuration cancellation failed: ' .. mesg ) + end ) + end ) end, function ( mesg ) main.print_info ( who, 'Node configuration failed: ' .. mesg ) diff -r 542f61e113cb -r d33ca5572e91 examples/mc_register.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/mc_register.lua Sat Mar 28 19:43:12 2009 +0200 @@ -0,0 +1,81 @@ + +local lm = require 'lm' +local iq_register = require 'iq_register' + +main.command ( 'register', + function ( args ) + local who + if args and args ~= '' then + who = args + else + who = main.full_jid () + end + iq_register.register ( lm.connection.bless ( main.connection () ), who, + function ( form, submit, reject ) + insert_form ( form, + function ( form ) + submit ( form, + function () + main.print_info ( who, 'Successfully registered' ) + end, + function ( mesg ) + main.print_info ( who, 'Registration failed: ' .. mesg ) + end ) + end, + function ( form ) + reject ( form, + function () + main.print_info ( who, 'Registration cancelled' ) + end, + function ( mesg ) + main.print_info ( who, 'Registration cancellation failed: ' .. mesg ) + end ) + end ) + end, + function ( mesg ) + main.print_info ( who, 'Registration failed: ' .. mesg ) + end ) + end, false, 'jid' ) +main.command ( 'cancel', + function ( args ) + local who + if args and args ~= '' then + who = args + else + who = main.full_jid () + end + iq_register.unregister ( lm.connection.bless ( main.connection () ), who, + function ( form, submit, reject ) + if not form then + main.print_info ( who, 'Successfully unregistered' ) + else + insert_form ( form, + function ( form ) + submit ( form, + function () + main.print_info ( who, 'Successfully unregistered' ) + end, + function ( mesg ) + main.print_info ( who, 'Unregistrering failed: ' .. mesg ) + end ) + end, + function ( form ) + reject ( form, + function () + main.print_info ( who, 'Unregistration cancelled' ) + end, + function ( mesg ) + main.print_info ( who, 'Unregistration cancellation failed: ' .. mesg ) + end ) + end ) + end + end, + function ( mesg ) + main.print_info ( who, 'Unregistering failed: ' .. mesg ) + end ) + end, false, 'jid' ) + +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: -- diff -r 542f61e113cb -r d33ca5572e91 examples/mc_remote.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/mc_remote.lua Sat Mar 28 19:43:12 2009 +0200 @@ -0,0 +1,66 @@ + +local lm = require 'lm' +local remote = require 'remote' + +main.command ( 'remote', + function ( args ) + local who + if args.t then + who = args.t + else + who = main.full_jid () + end + local action = args[1] + local conn = lm.connection.bless ( main.connection () ) + if action then + remote.command ( conn, who, action, + function ( form, submit, reject ) + if not form then + main.print_info ( who, ('Command %s completed'):format ( action ) ) + else + insert_form ( form, -- XXX + function ( form ) + submit ( form, + function () + main.print_info ( who, ('Command %s completed'):format ( action ) ) + end, + function ( mesg ) + main.print_info ( who, ('Command %s execution failed: %s'):format ( action, mesg ) ) + end ) + end, + function ( form ) + reject ( form, + function () + main.print_info ( who, ('Command %s execution cancelled'):format ( action ) ) + end, + function ( mesg ) + main.print_info ( who, ('Command %s execution cancellation failed: %s'):format ( action, mesg ) ) + end ) + end ) + end + end, + function ( mesg ) + main.print_info ( who, ('Command %s execution failed: %s'):format ( action, mesg ) ) + end ) + else + remote.list ( conn, who, + function ( items ) + local text = '' + for index, item in ipairs ( items ) do + text = text .. '\n - ' .. item.node + end + if text ~= '' then + main.print_info ( who, 'Available commands:' .. text ) + else + main.print_info ( who, 'No commands available.' ) + end + end, + function ( mesg ) + main.print_info ( who, ("Remote commands list for %s failed: %s"):format ( who, mesg ) ) + end ) + end + end, true, 'jid' ) + +commands_help['remote'] = "[-t target_jid] [remote_command]\n\nPrints list of available remote command or requests execution of specified command." + +-- vim: se ts=4: -- diff -r 542f61e113cb -r d33ca5572e91 examples/mc_tune.lua --- a/examples/mc_tune.lua Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/mc_tune.lua Sat Mar 28 19:43:12 2009 +0200 @@ -85,7 +85,7 @@ local function mpd_callback () local sdata = mpd_getstatus () if sdata then - pep.publish ( lm.connection.bless ( main.connection () ), 'http://jabber.org/protocol/tune', + tune.publish ( lm.connection.bless ( main.connection () ), function () end, function ( mesg ) diff -r 542f61e113cb -r d33ca5572e91 examples/mc_vcard.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/mc_vcard.lua Sat Mar 28 19:43:12 2009 +0200 @@ -0,0 +1,34 @@ + +local lm = require 'lm' +local vcard = require 'vcard' + +main.command ( 'vcard-temp', + function ( args ) + vcard.retrieve ( lm.connection.bless ( main.connection () ), args[1], + function ( form, submit, reject ) + insert_form ( form, + function ( form ) + submit ( form, + function () + print ( 'Vcard changed' ) + end, + function ( mesg ) + print ( 'Vcard changing error: ' .. mesg ) + end ) + end, + function ( form ) + reject ( form, + function () + print ( 'Vcard changing cancelled' ) + end, + function ( mesg ) + print ( 'Vcard changing cancellation error: ' .. mesg ) + end ) + end ) + end, + function ( mesg ) + print ( 'Vcard obtaining error: ' .. mesg ) + end ) + end, true, 'jid' ) + +-- vim: se ts=4: -- diff -r 542f61e113cb -r d33ca5572e91 examples/mcabberrc.lua --- a/examples/mcabberrc.lua Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/mcabberrc.lua Sat Mar 28 19:43:12 2009 +0200 @@ -255,9 +255,11 @@ require 'room_priv' --- DATA FORMS (XEP-0004) +-- FORMS -require 'x_data' +require 'mc_forms' + +-- DATA FORMS (XEP-0004) -- SERVICE DISCOVERY (XEP-0030) @@ -269,7 +271,7 @@ -- VCARD-TEMP (XEP-0054) -require 'vcard' +require 'mc_vcard' -- PUBLISH-SUBSRIBE (XEP-0060) @@ -285,7 +287,7 @@ -- IN-BAND REGISTRATION (XEP-0077) -require 'iq_register' +require 'mc_register' -- USER LOCATION (XEP-0080) @@ -309,7 +311,7 @@ -- REMOTE CONTROLLING CLIENTS (XEP-0146) -require 'remote' +require 'mc_remote' -- PERSONAL EVENTING PROTOCOL (XEP-0163) diff -r 542f61e113cb -r d33ca5572e91 examples/pubsub.lua --- a/examples/pubsub.lua Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/pubsub.lua Sat Mar 28 19:43:12 2009 +0200 @@ -3,9 +3,8 @@ -- library -local lm = require 'lm' -local iq = require 'iq' -require 'x_data' +local iq = require 'iq' +local x_data = require 'x_data' -- @@ -163,11 +162,10 @@ if x then success ( x_data.parse ( x ), function ( form, success, fail ) - form.type = 'submit' iq.send ( conn, to, 'set', { pubsub = { xmlns = 'http://jabber.org/protocol/pubsub#owner', - configure = form.format ( form, { node = node } ), + configure = form:format ( { node = node }, 'submit' ), }, }, success, fail ) end, @@ -175,9 +173,7 @@ iq.send ( conn, to, 'set', { pubsub = { xmlns = 'http://jabber.org/protocol/pubsub#owner', - configure = { node = node, - x = { xmlns = 'jabber:x:data', type = 'cancel' }, -- FIXME - }, + configure = form:format ( { node = node }, 'cancel' ), }, }, success, fail ) end ) diff -r 542f61e113cb -r d33ca5572e91 examples/remote.lua --- a/examples/remote.lua Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/remote.lua Sat Mar 28 19:43:12 2009 +0200 @@ -3,20 +3,19 @@ -- library -local lm = require 'lm' -local iq = require 'iq' -require 'x_data' -local disco = require 'disco' +local iq = require 'iq' +local x_data = require 'x_data' +local disco = require 'disco' -- public -remote = { } +local F = { } -function remote.list ( conn, to, success, fail ) +function F.list ( conn, to, success, fail ) disco.items ( conn, to, success, fail, 'http://jabber.org/protocol/commands' ) end -function remote.command ( conn, to, command, success, fail ) +function F.command ( conn, to, command, success, fail ) iq.send ( conn, to, 'set', { command = { xmlns = 'http://jabber.org/protocol/commands', action = 'execute', node = command }, @@ -33,26 +32,23 @@ local sid = c:attribute ( 'sessionid' ) success ( x_data.parse ( x ), function ( form, success, fail ) - form.type = 'submit' -- XXX in standard there is 'form' :/ iq.send ( conn, to, 'set', { - command = form.format ( form, { xmlns = 'http://jabber.org/protocol/commands', node = command, sessionid = sid } ) + command = form:format ( { xmlns = 'http://jabber.org/protocol/commands', node = command, sessionid = sid }, 'submit' ), }, function ( mess ) local c = mess:child ( 'command' ) if c and c:attribute ( 'status' ) == 'completed' then success () else - fail ( mess:xml () ) -- XXX more forms? + fail ( mess:xml () ) -- XXX more forms? results? end end, fail ) end, function ( form, success, fail ) iq.send ( conn, to, 'set', { - command = { xmlns = 'http://jabber.org/protocol/commands', node = command, sessionid = sid, - x = { xmlns = 'jabber:x:data', type = 'cancel' }, -- FIXME - }, + command = form:format ( { xmlns = 'http://jabber.org/protocol/commands', node = command, sessionid = sid }, 'cancel' ), }, success, fail ) end ) else @@ -63,73 +59,6 @@ end, fail ) end --- mcabber - -main.command ( 'remote', - function ( args ) - local who - if args.t then - who = args.t - else - who = main.full_jid () - end - local action = args[1] - local conn = lm.connection.bless ( main.connection () ) - if action then - remote.command ( conn, who, action, - function ( form, submit, reject ) - if not form then - main.print_info ( who, ('Command %s completed'):format ( action ) ) - else - local id = #forms + 1 - forms[id] = { - form = form, - submit = - function ( form ) - submit ( form, - function () - main.print_info ( who, ('Command %s completed'):format ( action ) ) - end, - function ( mesg ) - main.print_info ( who, ('Command %s execution failed: %s'):format ( action, mesg ) ) - end ) - end, - reject = - function ( form ) - reject ( form, - function () - main.print_info ( who, ('Command %s execution cancelled'):format ( action ) ) - end, - function ( mesg ) - main.print_info ( who, ('Command %s execution cancellation failed: %s'):format ( action, mesg ) ) - end ) - end, - } - print ( 'You have new form ' .. id ) - end - end, - function ( mesg ) - main.print_info ( who, ('Command %s execution failed: %s'):format ( action, mesg ) ) - end ) - else - remote.list ( conn, who, - function ( items ) - local text = '' - for index, item in ipairs ( items ) do - text = text .. '\n - ' .. item.node - end - if text ~= '' then - main.print_info ( who, 'Available commands:' .. text ) - else - main.print_info ( who, 'No commands available.' ) - end - end, - function ( mesg ) - main.print_info ( who, ("Remote commands list for %s failed: %s"):format ( who, mesg ) ) - end ) - end - end, true, 'jid' ) - -commands_help['remote'] = "[-t target_jid] [remote_command]\n\nPrints list of available remote command or requests execution of specified command." +return F -- vim: se ts=4: -- diff -r 542f61e113cb -r d33ca5572e91 examples/vcard.lua --- a/examples/vcard.lua Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/vcard.lua Sat Mar 28 19:43:12 2009 +0200 @@ -3,48 +3,86 @@ -- library -local lm = require 'lm' -local iq = require 'iq' -require 'x_data' +local iq = require 'iq' +local form_field = require 'form_field' + +-- + +local F = { } +local M = { } +M.__index = M --- public +function F.new ( args ) + local form = { + xmlns = 'vcard-temp', + ftype = args.type or 'form', + title = args.title, + instructions = args.instructions, + f = { }, + } + setmetatable ( form, M ) + return form +end -vcard = { } - -local function vcard_parse ( node, path, ret ) +local function vcard_parse ( node, path, form ) local item = node:child () if item then while item do - vcard_parse ( item, ( path and path .. '/' or '' ) .. item:name (), ret ) + vcard_parse ( item, ( path and path .. '/' or '' ) .. item:name (), form ) item = item:next () end elseif path then - table.insert ( ret, { var = path, type = 'text-single', value = node:value () } ) + form:add ( path, { type = 'text-single', value = node:value () } ) end end -function vcard.parse ( card ) - local form = { xmlns = 'vcard-temp', type = 'form' } +function F.parse ( card ) + local form = F.new { type = 'form' } vcard_parse ( card, nil, form ) - form.format = - function ( form, root ) - root.vCard = { xmlns = 'vcard-temp' } - for k, field in ipairs ( form ) do - local el = root.vCard - for k in field.var:gmatch ( '[^/]+' ) do - if not el[k] then - el[k] = { } - end - el = el[k] - end - el[1] = field.value - end - return root - end return form end -function vcard.get ( conn, from, success, fail ) +function M.type ( form ) + return form.ftype +end + +function M.desc ( form ) + return form.title, form.instructions +end + +function M.format ( form, root, format_as ) + root.vCard = { xmlns = 'vcard-temp' } + for k, field in form:fields () do + local el = root.vCard + for k in field:name():gmatch ( '[^/]+' ) do + if not el[k] then + el[k] = { } + end + el = el[k] + end + el[1] = field:value () + end + return root +end + +function M.fields ( form ) + return ipairs ( form.f ) +end + +function M.add ( form, name, fld ) + fld.var = name + fld.index = #form.f + 1 + local obj = form_field.new ( fld ) + table.insert ( form.f, obj ) + form.f[name] = obj + return obj +end + +function M.field ( form, name ) + return form.f[name] +end + +function F.retrieve ( conn, from, success, fail ) iq.send ( conn, from, 'get', { vCard = { xmlns = 'vcard-temp' }, @@ -52,10 +90,9 @@ function ( mess ) local card = mess:child ( 'vCard' ) if card and card:attribute ( 'xmlns' ) == 'vcard-temp' then - success ( vcard.parse ( mess:child ( 'vCard' ) ), + success ( F.parse ( mess:child ( 'vCard' ) ), function ( form, success, fail ) - form.type = 'submit' -- :) - iq.send ( conn, from, 'set', form.format ( form, { } ), success, fail ) + iq.send ( conn, from, 'set', form:format ( form, { }, 'submit' ), success, fail ) end, function ( form, success, fail ) success () @@ -66,41 +103,6 @@ end, fail ) end --- mcabber - -main.command ( 'vcard-temp', - function ( args ) - vcard.get ( lm.connection.bless ( main.connection () ), args[1], - function ( form, submit, reject ) - local id = #forms + 1 - forms[id] = { - form = form, - submit = - function ( form ) - submit ( form, - function () - print ( 'Vcard changed' ) - end, - function ( mesg ) - print ( 'Vcard changing error: ' .. mesg ) - end ) - end, - reject = - function ( form ) - reject ( form, - function () - print ( 'Vcard changing cancelled' ) - end, - function ( mesg ) - print ( 'Vcard changing cancellation error: ' .. mesg ) - end ) - end, - } - print ( 'You have new form ' .. id ) - end, - function ( mesg ) - print ( 'Vcard obtaining error: ' .. mesg ) - end ) - end, true, 'jid' ) +return F -- vim: se ts=4: -- diff -r 542f61e113cb -r d33ca5572e91 examples/x_data.lua --- a/examples/x_data.lua Fri Mar 27 12:06:19 2009 +0200 +++ b/examples/x_data.lua Sat Mar 28 19:43:12 2009 +0200 @@ -3,64 +3,80 @@ -- library -local lm = require 'lm' +local form_field = require 'form_field' --- public +-- -x_data = { } - --- iq_register should encapsulate x_data in results, so, looks like we need callbacks again? --- though, it can redefine method... but it is not too pretty. for now it will be so. - --- result needs separate routine? (reported & item's) +local F = { } +local M = { } +M.__index = M -function x_data.format ( form, root ) - root.x = { xmlns = 'jabber:x:data', type = form.type } - local fields = { } - for i, field in ipairs ( form ) do - if field.type ~= 'fixed' then - local value - if field.type == 'list-multi' or field.type == 'text-multi' or field.type == 'jid-multi' then - value = { } - for j, v in ipairs ( field.value ) do - table.insert ( value, { v } ) - end - else - value = { field.value } - end - table.insert ( fields, { type = field.type, var = field.var, value = value } ) - end - end - root.x.field = fields - return root +-- form.new -- new form +-- form.parse -- parse existing form -- according to form type! +-- form:type -- get type +-- form:desc -- get title, instructions +-- form:format -- format form -- according to form type! +-- form:fields -- iterator, returns field objects +-- form:add -- create field +-- form:field -- get field +-- ?? form:del -- delete field +-- field.new -- create field +-- field:index -- get index +-- field:type -- get type +-- field:name -- get var +-- field:desc -- get label, desc +-- field:value -- get/set value +-- field:values -- get values +-- field:clear -- clear value +-- field:options -- get options +-- field:required -- get required + +-- form may have 'fixed' fields and should be ordered +-- submit must not have 'fixed' fields and may be not ordered +-- cancel must not have anything +-- result should not have 'fixed', may be not ordered and can contain reported/item... multiple instances. + +function F.new ( args ) + local form = { + xmlns = 'jabber:x:data', + ftype = args.type or 'form', + title = args.title, + instructions = args.instructions, + f = { }, + } + setmetatable ( form, M ) + return form end -function x_data.parse ( x ) - local f = { xmlns = 'jabber:x:data', type = x:attribute ( 'type' ) } - +function F.parse ( x ) local title = x:child ( 'title' ) if title then - f.title = title:value () + title = title:value () end + local instructions = x:child ( 'instructions' ) if instructions then - f.instructions = instructions:value () + instructions = instructions:value () end + local f = F.new { type = x:attribute ( 'type' ), title = title, instructions = instructions } + local field = x:child () while field do - if field:name () == 'field' then + local name = field:name () + if name == 'field' then local ftype = field:attribute ( 'type' ) or 'text-single' + local var = field:attribute ( 'var' ) local r = { type = ftype, - var = field:attribute ( 'var' ), -- may be absent on 'fixed' fields label = field:attribute ( 'label' ), } local desc = field:child ( 'desc' ) if desc then - r.decs = desc:value () + r.desc = desc:value () end + if field:child ( 'required' ) then r.required = true end @@ -75,7 +91,7 @@ if name == 'value' then table.insert ( values, item:value () ) elseif name == 'option' then - table.insert ( options, item:child( 'value' ):value () ) -- FIXME labels + options[item:child( 'value' ):value ()] = item:attribute ( 'label' ) or '' end item = item:next () end @@ -99,113 +115,112 @@ end end - table.insert ( f, r ) + f:add ( var, r ) end field = field:next () end - f.format = x_data.format - return f end -function x_data.set ( f, name, value ) - for i, field in ipairs ( f ) do - if field.var == name then - if field.type == 'jid-multi' or field.type == 'list-multi' or field.type == 'text-multi' then - if value == nil then - field.value = { } - else - table.insert ( field.value, value ) - end - else - field.value = value - end - end - end +function M.type ( form ) + return form.ftype end --- mcabber - -local form_cid = main.add_category { 'del', 'send' } -forms = { } - -function insert_form ( form ) - table.insert ( forms, form ) - main.add_completion ( form_cid, tostring(#forms) ) - return #forms +function M.desc ( form ) + return form.title, form.instructions end -main.command ( 'form', - function ( args ) - local id, action = tonumber (args[1]), args[2] - if forms[id] then - local form = forms[id].form - if action == 'send' then - forms[id].submit ( form ) - elseif action == 'reject' then - forms[id].reject ( form ) - elseif action == 'del' then - main.del_completion ( form_cid, id ) - forms[id] = nil - elseif action == 'set' then - x_data.set ( form, args[3], args[4] ) - elseif action then - x_data.set ( form, action, args[3] ) - else - local desc = 'Form ' .. id - local fields = 'Fields:' - for index, field in pairs ( form ) do - if type(index) == 'number' then - fields = fields .. '\n - ' - if field.required then - fields = fields .. '* ' - end - if field.label then - fields = fields .. field.label .. ' (' .. ( field.var or '' ) .. ')' - else - fields = fields .. ( field.var or '' ) - end - fields = fields .. ' [' .. field.type .. ']' - if field.desc then - fields = fields .. ': ' .. desc - end - if field.options then - fields = fields .. '\n Options:' - for i, opt in ipairs ( field.options ) do - fields = fields .. ' ' .. opt - end - end - if field.type == 'list-multi' or field.type == 'text-multi' or field.type == 'jid-multi' then - fields = fields .. '\n Values: ' - for vin, value in ipairs ( field.value ) do - fields = fields .. '\n * ' .. value - end - else - fields = fields .. '\n Value: ' .. ( field.value or '' ) - end - else - if type(field) ~= 'function' then -- skip any methods - desc = desc .. '\n - ' .. index .. ': ' .. field - end - end +function M.format ( form, root, format_as ) + local ft = format_as or form:type () + + root.x = { xmlns = 'jabber:x:data', type = ft } + + if ft == 'cancel' then + return root + end + + if ft == 'form' then + local title, instructions = form:desc () + if title then + root.x.title = { title } + end + if instructions then + root.x.instructions = { instructions } + end + end + + local fields = { } + for i, field in form:fields () do + local ftype = field:type () + + local options, label, desc, required + if ft == 'form' then + label, desc = field:desc () + if desc then + desc = { desc } + end + + if field:required () then + required = { } + end + + for option, label in field:options () do + table.insert ( options, { label = label, value = { option } } ) + end + end + + local value + if ftype == 'list-multi' or ftype == 'text-multi' or ftype == 'jid-multi' then + if ft == 'form' then + for option, label in field:options () do + table.insert ( options, { label = label, value = { option } } ) end - print ( desc .. '\n' .. fields ) + end + + value = { } + for j, v in ipairs ( field.value ) do + table.insert ( value, { v } ) end else - local text = '' - for id, form in pairs ( forms ) do - text = text .. '\n - ' .. id .. ' ' .. ( form.form.title or 'Untitled' ) .. ' [' .. form.form.xmlns .. ', ' .. form.form.type .. ']' - end - if text ~= '' then - print ( 'Forms list:' .. text ) - else - print ( 'No forms' ) - end + value = { field:value () } + end + + if ftype ~= 'fixed' or ft == 'form' then + table.insert ( fields, { + type = ftype, + var = field:name (), + label = label, + desc = desc, + value = value, + option = options + } ) end - end, true, form_cid ) + end + root.x.field = fields + + return root +end + +function M.fields ( form ) + return ipairs ( form.f ) +end -commands_help['form'] = "[form_id [send | reject | [set] fieldname [value]]]\n\nWithout arguments prints form list.\nWith bare form id prints info on that form.\nWhen setting multivalue field, new values are added, not replacing previous.\nWithout value unsets field, multivalue fields lose all their values." +function M.add ( form, var, fld ) + fld.var = var + fld.index = #form.f + 1 -- XXX + local obj = form_field.new ( fld ) + table.insert ( form.f, obj ) + form.f[var] = obj + return obj +end + +function M.field ( form, var ) + -- works well on indices + return form.f[var] +end + +return F -- vim: se ts=4: --