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