aboutsummaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/discohelper.lua79
-rw-r--r--util/jid.lua21
-rw-r--r--util/logger.lua2
-rw-r--r--util/stanza.lua9
-rw-r--r--util/ztact.lua364
5 files changed, 466 insertions, 9 deletions
diff --git a/util/discohelper.lua b/util/discohelper.lua
new file mode 100644
index 00000000..4ac8f227
--- /dev/null
+++ b/util/discohelper.lua
@@ -0,0 +1,79 @@
+
+local t_insert = table.insert;
+local jid_split = require "util.jid".split;
+local ipairs = ipairs;
+local st = require "util.stanza";
+
+module "discohelper";
+
+local function addDiscoItemsHandler(self, jid, func)
+ if self.item_handlers[jid] then
+ t_insert(self.item_handlers[jid], func);
+ else
+ self.item_handlers[jid] = {func};
+ end
+end
+
+local function addDiscoInfoHandler(self, jid, func)
+ if self.info_handlers[jid] then
+ t_insert(self.info_handlers[jid], func);
+ else
+ self.info_handlers[jid] = {func};
+ end
+end
+
+local function handle(self, stanza)
+ if stanza.name == "iq" and stanza.tags[1].name == "query" then
+ local query = stanza.tags[1];
+ local to = stanza.attr.to;
+ local from = stanza.attr.from
+ local node = query.attr.node or "";
+ local to_node, to_host = jid_split(to);
+
+ local reply = st.reply(stanza):query(query.attr.xmlns);
+ local handlers;
+ if query.attr.xmlns == "http://jabber.org/protocol/disco#info" then -- select handler set
+ handlers = self.info_handlers;
+ elseif query.attr.xmlns == "http://jabber.org/protocol/disco#items" then
+ handlers = self.item_handlers;
+ end
+ local handler = handlers[to]; -- get the handler
+ if not handler then -- if not found then use default handler
+ if to_node then
+ handler = handlers["*defaultnode"];
+ else
+ handler = handlers["*defaulthost"];
+ end
+ end
+ local found; -- to keep track of any handlers found
+ if handler then
+ for _, h in ipairs(handler) do
+ if h(reply, to, from, node) then found = true; end
+ end
+ end
+ if to_node then -- handlers which get called always
+ handler = handlers["*node"];
+ else
+ handler = handlers["*host"];
+ end
+ if handler then -- call always called handler
+ for _, h in ipairs(handler) do
+ if h(reply, to, from, node) then found = true; end
+ end
+ end
+ if found then return reply; end -- return the reply if there was one
+ return st.error_reply(stanza, "cancel", "service-unavailable");
+ end
+end
+
+function new()
+ return {
+ item_handlers = {};
+ info_handlers = {};
+ addDiscoItemsHandler = addDiscoItemsHandler;
+ addDiscoInfoHandler = addDiscoInfoHandler;
+ handle = handle;
+ };
+end
+
+return _M;
diff --git a/util/jid.lua b/util/jid.lua
index b1e4131d..065f176f 100644
--- a/util/jid.lua
+++ b/util/jid.lua
@@ -5,11 +5,20 @@ module "jid"
function split(jid)
if not jid then return; end
- -- TODO verify JID, and return; if invalid
- local node = match(jid, "^([^@]+)@");
- local server = (node and match(jid, ".-@([^@/]+)")) or match(jid, "^([^@/]+)");
- local resource = match(jid, "/(.+)$");
- return node, server, resource;
+ local node, nodepos = match(jid, "^([^@]+)@()");
+ local host, hostpos = match(jid, "^([^@/]+)()", nodepos)
+ if node and not host then return nil, nil, nil; end
+ local resource = match(jid, "^/(.+)$", hostpos);
+ if (not host) or ((not resource) and #jid >= hostpos) then return nil, nil, nil; end
+ return node, host, resource;
end
-return _M; \ No newline at end of file
+function bare(jid)
+ local node, host = split(jid);
+ if node and host then
+ return node.."@"..host;
+ end
+ return host;
+end
+
+return _M;
diff --git a/util/logger.lua b/util/logger.lua
index f93cafc1..e9440a04 100644
--- a/util/logger.lua
+++ b/util/logger.lua
@@ -33,4 +33,4 @@ function init(name)
end
end
-return _M; \ No newline at end of file
+return _M;
diff --git a/util/stanza.lua b/util/stanza.lua
index 5a6ba8c5..df0d43ff 100644
--- a/util/stanza.lua
+++ b/util/stanza.lua
@@ -30,6 +30,11 @@ end
function stanza_mt:query(xmlns)
return self:tag("query", { xmlns = xmlns });
end
+
+function stanza_mt:body(text, attr)
+ return self:tag("body", attr):text(text);
+end
+
function stanza_mt:tag(name, attrs)
local s = stanza(name, attrs);
(self.last_add[#self.last_add] or self):add_direct_child(s);
@@ -103,7 +108,7 @@ function stanza_mt.__tostring(t)
local attr_string = "";
if t.attr then
- for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(" %s='%s'", k, tostring(v)); end end
+ for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(" %s='%s'", k, xml_escape(tostring(v))); end end
end
return s_format("<%s%s>%s</%s>", t.name, attr_string, children_text, t.name);
end
@@ -111,7 +116,7 @@ end
function stanza_mt.top_tag(t)
local attr_string = "";
if t.attr then
- for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(" %s='%s'", k, tostring(v)); end end
+ for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(" %s='%s'", k, xml_escape(tostring(v))); end end
end
return s_format("<%s%s>", t.name, attr_string);
end
diff --git a/util/ztact.lua b/util/ztact.lua
new file mode 100644
index 00000000..15bcffad
--- /dev/null
+++ b/util/ztact.lua
@@ -0,0 +1,364 @@
+
+
+-- public domain 20080410 lua@ztact.com
+
+
+pcall (require, 'lfs') -- lfs may not be installed/necessary.
+pcall (require, 'pozix') -- pozix may not be installed/necessary.
+
+
+local getfenv, ipairs, next, pairs, pcall, require, select, tostring, type =
+ getfenv, ipairs, next, pairs, pcall, require, select, tostring, type
+local unpack, xpcall =
+ unpack, xpcall
+
+local io, lfs, os, string, table, pozix = io, lfs, os, string, table, pozix
+
+local assert, print = assert, print
+
+local error = error
+
+
+module ((...) or 'ztact') ------------------------------------- module ztact
+
+
+-- dir -------------------------------------------------------------------- dir
+
+
+function dir (path) -- - - - - - - - - - - - - - - - - - - - - - - - - - dir
+ local it = lfs.dir (path)
+ return function ()
+ repeat
+ local dir = it ()
+ if dir ~= '.' and dir ~= '..' then return dir end
+ until not dir
+ end end
+
+
+function is_file (path) -- - - - - - - - - - - - - - - - - - is_file (path)
+ local mode = lfs.attributes (path, 'mode')
+ return mode == 'file' and path
+ end
+
+
+-- network byte ordering -------------------------------- network byte ordering
+
+
+function htons (word) -- - - - - - - - - - - - - - - - - - - - - - - - htons
+ return (word-word%0x100)/0x100, word%0x100
+ end
+
+
+-- pcall2 -------------------------------------------------------------- pcall2
+
+
+getfenv ().pcall = pcall -- store the original pcall as ztact.pcall
+
+
+local argc, argv, errorhandler, pcall2_f
+
+
+local function _pcall2 () -- - - - - - - - - - - - - - - - - - - - - _pcall2
+ local tmpv = argv
+ argv = nil
+ return pcall2_f (unpack (tmpv, 1, argc))
+ end
+
+
+function seterrorhandler (func) -- - - - - - - - - - - - - - seterrorhandler
+ errorhandler = func
+ end
+
+
+function pcall2 (f, ...) -- - - - - - - - - - - - - - - - - - - - - - pcall2
+
+ pcall2_f = f
+ argc = select ('#', ...)
+ argv = { ... }
+
+ if not errorhandler then
+ local debug = require ('debug')
+ errorhandler = debug.traceback
+ end
+
+ return xpcall (_pcall2, errorhandler)
+ end
+
+
+function append (t, ...) -- - - - - - - - - - - - - - - - - - - - - - append
+ local insert = table.insert
+ for i,v in ipairs {...} do
+ insert (t, v)
+ end end
+
+
+function print_r (d, indent) -- - - - - - - - - - - - - - - - - - - print_r
+ local rep = string.rep (' ', indent or 0)
+ if type (d) == 'table' then
+ for k,v in pairs (d) do
+ if type (v) == 'table' then
+ io.write (rep, k, '\n')
+ print_r (v, (indent or 0) + 1)
+ else io.write (rep, k, ' = ', tostring (v), '\n') end
+ end
+ else io.write (d, '\n') end
+ end
+
+
+function tohex (s) -- - - - - - - - - - - - - - - - - - - - - - - - - tohex
+ return string.format (string.rep ('%02x ', #s), string.byte (s, 1, #s))
+ end
+
+
+function tostring_r (d, indent, tab0) -- - - - - - - - - - - - - tostring_r
+
+ tab1 = tab0 or {}
+ local rep = string.rep (' ', indent or 0)
+ if type (d) == 'table' then
+ for k,v in pairs (d) do
+ if type (v) == 'table' then
+ append (tab1, rep, k, '\n')
+ tostring_r (v, (indent or 0) + 1, tab1)
+ else append (tab1, rep, k, ' = ', tostring (v), '\n') end
+ end
+ else append (tab1, d, '\n') end
+
+ if not tab0 then return table.concat (tab1) end
+ end
+
+
+-- queue manipulation -------------------------------------- queue manipulation
+
+
+-- Possible queue states. 1 (i.e. queue.p[1]) is head of queue.
+--
+-- 1..2
+-- 3..4 1..2
+-- 3..4 1..2 5..6
+-- 1..2 5..6
+-- 1..2
+
+
+local function print_queue (queue, ...) -- - - - - - - - - - - - print_queue
+ for i=1,10 do io.write ((queue[i] or '.')..' ') end
+ io.write ('\t')
+ for i=1,6 do io.write ((queue.p[i] or '.')..' ') end
+ print (...)
+ end
+
+
+function dequeue (queue) -- - - - - - - - - - - - - - - - - - - - - dequeue
+
+ local p = queue.p
+ if not p and queue[1] then queue.p = { 1, #queue } p = queue.p end
+
+ if not p[1] then return nil end
+
+ local element = queue[p[1]]
+ queue[p[1]] = nil
+
+ if p[1] < p[2] then p[1] = p[1] + 1
+
+ elseif p[4] then p[1], p[2], p[3], p[4] = p[3], p[4], nil, nil
+
+ elseif p[5] then p[1], p[2], p[5], p[6] = p[5], p[6], nil, nil
+
+ else p[1], p[2] = nil, nil end
+
+ print_queue (queue, ' de '..element)
+ return element
+ end
+
+
+function enqueue (queue, element) -- - - - - - - - - - - - - - - - - enqueue
+
+ local p = queue.p
+ if not p then queue.p = {} p = queue.p end
+
+ if p[5] then -- p3..p4 p1..p2 p5..p6
+ p[6] = p[6]+1
+ queue[p[6]] = element
+
+ elseif p[3] then -- p3..p4 p1..p2
+
+ if p[4]+1 < p[1] then
+ p[4] = p[4] + 1
+ queue[p[4]] = element
+
+ else
+ p[5] = p[2]+1
+ p[6], queue[p[5]] = p[5], element
+ end
+
+ elseif p[1] then -- p1..p2
+ if p[1] == 1 then
+ p[2] = p[2] + 1
+ queue[p[2]] = element
+
+ else
+ p[3], p[4], queue[1] = 1, 1, element
+ end
+
+ else -- empty queue
+ p[1], p[2], queue[1] = 1, 1, element
+ end
+
+ print_queue (queue, ' '..element)
+ end
+
+
+local function test_queue ()
+ t = {}
+ enqueue (t, 1)
+ enqueue (t, 2)
+ enqueue (t, 3)
+ enqueue (t, 4)
+ enqueue (t, 5)
+ dequeue (t)
+ dequeue (t)
+ enqueue (t, 6)
+ enqueue (t, 7)
+ enqueue (t, 8)
+ enqueue (t, 9)
+ dequeue (t)
+ dequeue (t)
+ dequeue (t)
+ dequeue (t)
+ enqueue (t, 'a')
+ dequeue (t)
+ enqueue (t, 'b')
+ enqueue (t, 'c')
+ dequeue (t)
+ dequeue (t)
+ dequeue (t)
+ dequeue (t)
+ dequeue (t)
+ enqueue (t, 'd')
+ dequeue (t)
+ dequeue (t)
+ dequeue (t)
+ end
+
+
+-- test_queue ()
+
+
+function queue_len (queue)
+ end
+
+
+function queue_peek (queue)
+ end
+
+
+-- tree manipulation ---------------------------------------- tree manipulation
+
+
+function set (parent, ...) --- - - - - - - - - - - - - - - - - - - - - - set
+
+ -- print ('set', ...)
+
+ local len = select ('#', ...)
+ local key, value = select (len-1, ...)
+ local cutpoint, cutkey
+
+ for i=1,len-2 do
+
+ local key = select (i, ...)
+ local child = parent[key]
+
+ if value == nil then
+ if child == nil then return
+ elseif next (child, next (child)) then cutpoint = nil cutkey = nil
+ elseif cutpoint == nil then cutpoint = parent cutkey = key end
+
+ elseif child == nil then child = {} parent[key] = child end
+
+ parent = child
+ end
+
+ if value == nil and cutpoint then cutpoint[cutkey] = nil
+ else parent[key] = value return value end
+ end
+
+
+function get (parent, ...) --- - - - - - - - - - - - - - - - - - - - - - get
+ local len = select ('#', ...)
+ for i=1,len do
+ parent = parent[select (i, ...)]
+ if parent == nil then break end
+ end
+ return parent
+ end
+
+
+-- misc ------------------------------------------------------------------ misc
+
+
+function find (path, ...) --------------------------------------------- find
+
+ local dirs, operators = { path }, {...}
+ for operator in ivalues (operators) do
+ if not operator (path) then break end end
+
+ while next (dirs) do
+ local parent = table.remove (dirs)
+ for child in assert (pozix.opendir (parent)) do
+ if child and child ~= '.' and child ~= '..' then
+ local path = parent..'/'..child
+ if pozix.stat (path, 'is_dir') then table.insert (dirs, path) end
+ for operator in ivalues (operators) do
+ if not operator (path) then break end end
+ end end end end
+
+
+function ivalues (t) ----------------------------------------------- ivalues
+ local i = 0
+ return function () if t[i+1] then i = i + 1 return t[i] end end
+ end
+
+
+function lson_encode (mixed, f, indent, indents) --------------- lson_encode
+
+
+ local capture
+ if not f then
+ capture = {}
+ f = function (s) append (capture, s) end
+ end
+
+ indent = indent or 0
+ indents = indents or {}
+ indents[indent] = indents[indent] or string.rep (' ', 2*indent)
+
+ local type = type (mixed)
+
+ if type == 'number' then f (mixed)
+
+ else if type == 'string' then f (string.format ('%q', mixed))
+
+ else if type == 'table' then
+ f ('{')
+ for k,v in pairs (mixed) do
+ f ('\n')
+ f (indents[indent])
+ f ('[') f (lson_encode (k)) f ('] = ')
+ lson_encode (v, f, indent+1, indents)
+ f (',')
+ end
+ f (' }')
+ end end end
+
+ if capture then return table.concat (capture) end
+ end
+
+
+function timestamp (time) ---------------------------------------- timestamp
+ return os.date ('%Y%m%d.%H%M%S', time)
+ end
+
+
+function values (t) ------------------------------------------------- values
+ local k, v
+ return function () k, v = next (t, k) return v end
+ end