examples/x_data.lua
author Myhailo Danylenko <isbear@ukrpost.net>
Sun, 22 Mar 2009 19:46:26 +0200
changeset 53 2162188b20cf
parent 49 95f3bf77c598
child 60 b9fd051c0d7c
permissions -rw-r--r--
Fixes to form handling


-- DATA FORMS (XEP-0004)

-- library

require 'lm'

-- 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)

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
end

function x_data.parse ( x )
	local f = { xmlns = 'jabber:x:data', type = x:attribute ( 'type' ) }

	local title = x:child ( 'title' )
	if title then
		f.title = title:value ()
	end
	local instructions = x:child ( 'instructions' )
	if instructions then
		f.instructions = instructions:value ()
	end

	local field = x:children ()
	while field do
		if field:name () == 'field' then
			local ftype = field:attribute ( 'type' ) or 'text-single'
			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 ()
			end
			if field:child ( 'required' ) then
				r.required = true
			end

			if ftype == 'jid-multi' or ftype == 'list-multi' or ftype == 'text-multi' or ftype == 'list-single' then
				local values  = { }
				local options = { }

				local item = field:children ()
				while item do
					local name = item:name ()
					if name == 'value' then
						table.insert ( values, item:value () )
					elseif name == 'option' then
						table.insert ( options, item:child( 'value' ):value () ) -- FIXME labels
					end
					item = item:next ()
				end

				if ftype == 'list-single' then
					local value = field:child ( 'value' )
					if value then
						r.value = value:value ()
					end
				else
					r.value = values
				end

				if ftype == 'list-multi' or ftype == 'list-single' then
					r.options = options
				end
			else
				local value = field:child ( 'value' )
				if value then
					r.value = value:value ()
				end
			end

			table.insert ( f, 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
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
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 '<no name>' )
						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
				end
				print ( desc .. '\n' .. fields )
			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
		end
	end, true, form_cid )

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: --