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