diff -r 000000000000 -r 84fdfb0344c9 lm.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lm.lua Sun Feb 01 21:28:57 2009 +0200 @@ -0,0 +1,298 @@ + +require ( 'loudmouth' ) + +-- argument is a table with keys, +-- corresponding to method names. +function lm.proxy.create ( a ) + if type ( a ) ~= "table" then + error ( "arguments should be in a table" ) + end + local p = lm.proxy.new () + if a.server then + p:server ( a.server ) + end + if a.port then + p:port ( a.port ) + end + if a['type'] then + p:type ( a['type'] ) + end + if a.username then + p:username ( a.username ) + end + if a.password then + p:password ( a.password ) + end + return p +end + +-- argument is a table with two keys: +-- callback and fingerprint +function lm.ssl.create ( a ) + if not lm.ssl.supported () then + -- XXX + -- error ( "ssl is not supported by your loudmouth library" ) + return nil + end + local fp, cb + local st = type ( a ) + if st == "table" then + fp = a.fingerprint + cb = a.callback + elseif st == "function" then + cb = a + elseif st == "string" then + fp = a + elseif st ~= "nil" then + error ( "unexpected type of argument" ) + end + if fp then + if cb then + return lm.ssl.new ( fp, cb ) + else + return lm.ssl.new ( fp ) + end + else + if cb then + return lm.ssl.new ( cb ) + else + return lm.ssl.new () + end + end +end + +-- basically, it just provides a way +-- to initialize many parameters at once. +-- keys in a table correspond to methods +-- of connection object, except for handlers, +-- where format is { +-- "type/priority" = function/object, +-- ... +-- } +-- two extra keys - server and context. +-- ssl and proxy objects can either be objects +-- or tables, directly passed to corresponding +-- create routine. +function lm.connection.create ( a ) + local at = type (a) + if at == "string" then + return lm.connection.new ( a ) + elseif at == "table" then + local server = a.server + if not server then + error ( "server name parameter required" ) + end + + -- create connection object + local c + if a.context then + c = lm.connection.new ( server, a.context ) + else + c = lm.connection.new ( server ) + end + + -- connection parameters + if a.port then + c:port ( a.port ) + end + if a.jid then + c:jid ( a.jid ) + end + if a.keep_alive_rate then + c:keep_alive_rate ( a.keep_alive_rate ) + end + + -- proxy + if a.proxy then + local pt = type ( a.proxy ) + if pt == "userdata" then + c:proxy ( a.proxy ) + else + local proxy = lm.proxy.create ( a.proxy ) + c:proxy ( proxy ) + end + end + + -- ssl + if a.ssl then + local st = type ( a.ssl ) + if st == "userdata" then + c:ssl ( a.ssl ) + else + local ssl = lm.ssl.create ( a.ssl ) + c:ssl ( ssl ) + end + end + + -- disconnect callback + if a.ondisconnect then + c:ondisconnect ( a.ondisconnect ) + end + + -- message handlers + if a.handlers then + if type ( a.handlers ) ~= "table" then + error ( "handlers parameter expected to be a table " .. + "of the form { \"type/priority\" = function/object }" ) + end + for mhtype, handler in pairs ( a.handlers ) do + local mtype, prio = mhtype:match ( "(.-)/(%d+)" ) + if not mtype then + mtype = mhtype + prio = 0 + else + prio = tonumber ( prio ) + end + c:handler ( handler, mtype, prio ) + end + end + + return c + else + error ( "at least server name parameter required" ) + end +end + +-- recursively fills a node, see lm.message.create +function lm.message_node.fill ( n, a ) + for name, value in pairs ( a ) do + if type ( value ) == "table" then + if type ( value[1] ) == "table" then + for index, instance in ipairs ( value ) do + lm.message_node.fill ( n:child ( name, "" ), instance ) + end + else + lm.message_node.fill ( n:child ( name, "" ), value ) + end + elseif name == 1 then + n:value ( value ) + else + n:attribute ( name, value ) + end + end +end + +--[[ +-- recursively fills a message +lm.message.create { mtype = 'iq-result', to = 'foo@bar.xyz', + command = { xmlns = 'http://jabber.org/protocol/commands', node = 'http://jabber.org/protocol/rc#set-status', status = 'executing', sessionid = 'set-status:aaa3', + x = { xmlns = 'jabber:x:data', type = 'form', + title = { "Change Status" }, + instructions = { "Choose the status and status message" }, + field = {{ type = 'hidden', var = 'FORM_TYPE', + value = { "http://jabber.org/protocol/rc" }, + },{ type = 'list-single', label = 'Status', var = 'status', + required = { }, + value = { "online" }, + option = {{ label = 'Chat', + value = { "chat" }, + },{ label = 'Online', + value = { "online" }, + },{ label = 'Away', + value = { "away" }, + },{ label = 'Extended Away', + value = { "xa" }, + },{ label = 'Do Not Disturb', + value = { "dnd" }, + },{ label = 'Invisible', + value = { "invisible" }, + },{ label = 'Offline', + value = { "offline" }, + }}, + },{ type = 'text-single', label = 'Priority', var = 'status-priority', + value = { "5" }, + },{ type = 'text-multi', label = 'Message', var = 'status-message' }}, + }, + }, +} +--]] +function lm.message.create ( a ) + if type ( a ) ~= "table" then + error ( "table expected as argument" ) + end + if not a.mtype or not a.to then + error ( "you must specify message type and destination" ) + end + local mtype, subtype = a.mtype:match ( "(.-)%-(.+)" ) + local m + if not mtype then + m = lm.message.new ( a.to, a.mtype ) + else + m = lm.message.new ( a.to, mtype, subtype ) + end + a.to = nil + a.mtype = nil + lm.message_node.fill ( m:node(), a ) + return m +end + +-- TODO: multiple nodes with same name +function lm.message_node.parse ( node, r ) + local n = node:children () + while n do + local name = n:name () + r[name] = { } + local value = n:value () + if value then + r[name][1] = value + end + lm.message_node.parse ( n, r[name] ) + n = n:next () + end +end + +-- There are NO WAY to get a list of node attributes, +-- except brute force... +function lm.message.parse ( message ) + local node = message:node () + local mtype, subtype = message:type () + if subtype then + mtype = mtype .. '-' .. subtype + end + local r = { mtype = mtype } + local value = node:value () + if value then + r[1] = value + end + lm.message_node.parse ( node, r ) + return r +end + +-- the same table, as for lm.connection.create, but with few more fields: +-- ssl.validate +-- onconnect +-- onopen +-- username +-- password +-- resource +function lm.connect ( a ) + if type ( a ) ~= "table" then + error ( "table expected as argument" ) + end + if a.ssl then + if a.ssl.validate and not a.ssl.callback then + a.ssl.callback = + function ( obj, status ) + return false + end + end + end + local c = lm.connection.create ( a ) + c:open ( + function ( obj, status ) + if status then + if type ( a.onopen ) == "function" then + a.onopen ( obj ) + end + c:authenticate ( a.username, a.password, a.resource, + function ( obj, status ) + if type ( a.onconnect ) == "function" then + a.onconnect ( obj ) + end + end ) + end + end ) + return c +end + +-- vim: se ts=4: --