From 3fd77923dafc04d26a6b101c46e853ca65e9afae Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 4 Oct 2013 16:40:27 +0200 Subject: mod_pubsub, util.pubsub: Keep track of the order of items --- util/pubsub.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'util') diff --git a/util/pubsub.lua b/util/pubsub.lua index 0dfd196b..e0d428c0 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -258,6 +258,7 @@ function service:publish(node, actor, id, item) end node_obj = self.nodes[node]; end + node_obj.data[#node_obj.data + 1] = id; node_obj.data[id] = item; self.events.fire_event("item-published", { node = node, actor = actor, id = id, item = item }); self.config.broadcaster("items", node, node_obj.subscribers, item); @@ -275,6 +276,12 @@ function service:retract(node, actor, id, retract) return false, "item-not-found"; end node_obj.data[id] = nil; + for i, _id in ipairs(node_obj.data) do + if id == _id then + table.remove(node_obj, i); + break; + end + end if retract then self.config.broadcaster("items", node, node_obj.subscribers, retract); end @@ -309,7 +316,7 @@ function service:get_items(node, actor, id) return false, "item-not-found"; end if id then -- Restrict results to a single specific item - return true, { [id] = node_obj.data[id] }; + return true, { id, [id] = node_obj.data[id] }; else return true, node_obj.data; end -- cgit v1.2.3 From 86e7a96d76ab04d32f92beace38ab0593e8d1b02 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 30 Oct 2013 17:30:35 -0400 Subject: util.indexedbheap: A priority queue implementation with a reverse index with no per-entry memory allocation. --- util/indexedbheap.lua | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 util/indexedbheap.lua (limited to 'util') diff --git a/util/indexedbheap.lua b/util/indexedbheap.lua new file mode 100644 index 00000000..3cb03037 --- /dev/null +++ b/util/indexedbheap.lua @@ -0,0 +1,153 @@ + +local setmetatable = setmetatable; +local math_floor = math.floor; +local t_remove = table.remove; + +local function _heap_insert(self, item, sync, item2, index) + local pos = #self + 1; + while true do + local half_pos = math_floor(pos / 2); + if half_pos == 0 or item > self[half_pos] then break; end + self[pos] = self[half_pos]; + sync[pos] = sync[half_pos]; + index[sync[pos]] = pos; + pos = half_pos; + end + self[pos] = item; + sync[pos] = item2; + index[item2] = pos; +end + +local function _percolate_up(self, k, sync, index) + local tmp = self[k]; + local tmp_sync = sync[k]; + while k ~= 1 do + local parent = math_floor(k/2); + if tmp < self[parent] then break; end + self[k] = self[parent]; + sync[k] = sync[parent]; + index[sync[k]] = k; + k = parent; + end + self[k] = tmp; + sync[k] = tmp_sync; + index[tmp_sync] = k; + return k; +end + +local function _percolate_down(self, k, sync, index) + local tmp = self[k]; + local tmp_sync = sync[k]; + local size = #self; + local child = 2*k; + while 2*k <= size do + if child ~= size and self[child] > self[child + 1] then + child = child + 1; + end + if tmp > self[child] then + self[k] = self[child]; + sync[k] = sync[child]; + index[sync[k]] = k; + else + break; + end + + k = child; + child = 2*k; + end + self[k] = tmp; + sync[k] = tmp_sync; + index[tmp_sync] = k; + return k; +end + +local function _heap_pop(self, sync, index) + local size = #self; + if size == 0 then return nil; end + + local result = self[1]; + local result_sync = sync[1]; + index[result_sync] = nil; + if size == 1 then + self[1] = nil; + sync[1] = nil; + return result, result_sync; + end + self[1] = t_remove(self); + sync[1] = t_remove(sync); + index[sync[1]] = 1; + + _percolate_down(self, 1, sync, index); + + return result, result_sync; +end + +local indexed_heap = {}; + +function indexed_heap:insert(item, priority, id) + if id == nil then + id = self.current_id; + self.current_id = id + 1; + end + self.items[id] = item; + _heap_insert(self.priorities, priority, self.ids, id, self.index); + return id; +end +function indexed_heap:pop() + local priority, id = _heap_pop(self.priorities, self.ids, self.index); + if id then + local item = self.items[id]; + self.items[id] = nil; + return priority, item, id; + end +end +function indexed_heap:peek() + return self.priorities[1]; +end +function indexed_heap:reprioritize(id, priority) + local k = self.index[id]; + if k == nil then return; end + self.priorities[k] = priority; + + k = _percolate_up(self.priorities, k, self.ids, self.index); + k = _percolate_down(self.priorities, k, self.ids, self.index); +end +function indexed_heap:remove_index(k) + local size = #self.priorities; + + local result = self.priorities[k]; + local result_sync = self.ids[k]; + local item = self.items[result_sync]; + if result == nil then return; end + self.index[result_sync] = nil; + self.items[result_sync] = nil; + + self.priorities[k] = self.priorities[size]; + self.ids[k] = self.ids[size]; + self.index[self.ids[k]] = k; + t_remove(self.priorities); + t_remove(self.ids); + + k = _percolate_up(self.priorities, k, self.ids, self.index); + k = _percolate_down(self.priorities, k, self.ids, self.index); + + return result, item, result_sync; +end +function indexed_heap:remove(id) + return self:remove_index(self.index[id]); +end + +local mt = { __index = indexed_heap }; + +local _M = { + create = function() + return setmetatable({ + ids = {}; -- heap of ids, sync'd with priorities + items = {}; -- map id->items + priorities = {}; -- heap of priorities + index = {}; -- map of id->index of id in ids + current_id = 1.5 + }, mt); + end +}; +return _M; -- cgit v1.2.3 From 792398b07ef11702ddc6b842744840969e48b0e6 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 30 Oct 2013 17:44:42 -0400 Subject: util.timer: Updated to use util.indexedbheap to provide a more complete API. Timers can now be stopped or rescheduled. Callbacks are now pcall'd. Adding/removing timers from within timer callbacks works better. Optional parameter can be passed when creating timer which gets passed to callback, eliminating the need for closures in various timer uses. Timers are now much more lightweight. --- util/timer.lua | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'util') diff --git a/util/timer.lua b/util/timer.lua index 0e10e144..d7a9b0bf 100644 --- a/util/timer.lua +++ b/util/timer.lua @@ -6,6 +6,8 @@ -- COPYING file in the source package for more information. -- +local indexedbheap = require "util.indexedbheap"; +local log = require "util.logger".init("timer"); local server = require "net.server"; local math_min = math.min local math_huge = math.huge @@ -78,6 +80,60 @@ else end end -add_task = _add_task; +--add_task = _add_task; + +local h = indexedbheap.create(); +local params = {}; +local next_time = nil; +local _id, _callback, _now, _param; +local function _call() return _callback(_now, _id, _param); end +local function _traceback_handler(err) log("error", "Traceback[timer]: %s", traceback(tostring(err), 2)); end +local function _on_timer(now) + local peek; + while true do + peek = h:peek(); + if peek == nil or peek > now then break; end + local _; + _, _callback, _id = h:pop(); + _now = now; + _param = params[id]; + params[id] = nil; + --item(now, id, _param); -- FIXME pcall + local success, err = xpcall(_call, _traceback_handler); + if success and type(err) == "number" then + h:insert(_callback, err + now, _id); -- re-add + end + end + next_time = peek; + if peek ~= nil then + return peek - now; + end +end +function add_task(delay, callback, param) + local current_time = get_time(); + local event_time = current_time + delay; + + local id = h:insert(callback, event_time); + params[id] = param; + if next_time == nil or event_time < next_time then + next_time = event_time; + _add_task(next_time - current_time, on_timer); + end + return id; +end +function stop(id) + params[id] = nil; + return h:remove(id); +end +function reschedule(id, delay) + local current_time = get_time(); + local event_time = current_time + delay; + h:reprioritize(id, delay); + if next_time == nil or event_time < next_time then + next_time = event_time; + _add_task(next_time - current_time, on_timer); + end + return id; +end return _M; -- cgit v1.2.3 From 0f260f9b4e23572e8063c0e4302ca9bccac117d0 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 30 Oct 2013 17:51:37 -0400 Subject: util.timer: Fix variable name typo. --- util/timer.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'util') diff --git a/util/timer.lua b/util/timer.lua index d7a9b0bf..99aade15 100644 --- a/util/timer.lua +++ b/util/timer.lua @@ -117,7 +117,7 @@ function add_task(delay, callback, param) params[id] = param; if next_time == nil or event_time < next_time then next_time = event_time; - _add_task(next_time - current_time, on_timer); + _add_task(next_time - current_time, _on_timer); end return id; end @@ -131,7 +131,7 @@ function reschedule(id, delay) h:reprioritize(id, delay); if next_time == nil or event_time < next_time then next_time = event_time; - _add_task(next_time - current_time, on_timer); + _add_task(next_time - current_time, _on_timer); end return id; end -- cgit v1.2.3 From ad2211ad5722c3f1e46587682eaa85210321a68d Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 30 Oct 2013 17:56:00 -0400 Subject: util.timer: Fix another variable name typo (thanks again zash). --- util/timer.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'util') diff --git a/util/timer.lua b/util/timer.lua index 99aade15..76deaff1 100644 --- a/util/timer.lua +++ b/util/timer.lua @@ -96,8 +96,8 @@ local function _on_timer(now) local _; _, _callback, _id = h:pop(); _now = now; - _param = params[id]; - params[id] = nil; + _param = params[_id]; + params[_id] = nil; --item(now, id, _param); -- FIXME pcall local success, err = xpcall(_call, _traceback_handler); if success and type(err) == "number" then -- cgit v1.2.3 From 9fde274e2174f63d3f50e38f2992b6019a106ec7 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 30 Oct 2013 17:58:17 -0400 Subject: util.timer: Import all require upvalues. --- util/timer.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'util') diff --git a/util/timer.lua b/util/timer.lua index 76deaff1..451e27d3 100644 --- a/util/timer.lua +++ b/util/timer.lua @@ -15,6 +15,9 @@ local get_time = require "socket".gettime; local t_insert = table.insert; local pairs = pairs; local type = type; +local debug_traceback = debug.traceback; +local tostring = tostring; +local xpcall = xpcall; local data = {}; local new_data = {}; @@ -87,7 +90,7 @@ local params = {}; local next_time = nil; local _id, _callback, _now, _param; local function _call() return _callback(_now, _id, _param); end -local function _traceback_handler(err) log("error", "Traceback[timer]: %s", traceback(tostring(err), 2)); end +local function _traceback_handler(err) log("error", "Traceback[timer]: %s", debug_traceback(tostring(err), 2)); end local function _on_timer(now) local peek; while true do -- cgit v1.2.3 From b3325a4073f83da672df19711e78be2d58c7ff92 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Wed, 6 Nov 2013 12:56:18 -0500 Subject: util/timer: Re-set params when timer is rescheduled --- util/timer.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'util') diff --git a/util/timer.lua b/util/timer.lua index 451e27d3..23bd6a37 100644 --- a/util/timer.lua +++ b/util/timer.lua @@ -105,6 +105,7 @@ local function _on_timer(now) local success, err = xpcall(_call, _traceback_handler); if success and type(err) == "number" then h:insert(_callback, err + now, _id); -- re-add + params[_id] = _param; end end next_time = peek; -- cgit v1.2.3 From 0f7452e6a709099cc722d9e7b6484b2cb12a417d Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Wed, 23 Apr 2014 11:38:34 -0400 Subject: util.indexedbheap: Fix a possible traceback when removing the last item. --- util/indexedbheap.lua | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'util') diff --git a/util/indexedbheap.lua b/util/indexedbheap.lua index 3cb03037..c60861e8 100644 --- a/util/indexedbheap.lua +++ b/util/indexedbheap.lua @@ -113,23 +113,27 @@ function indexed_heap:reprioritize(id, priority) k = _percolate_down(self.priorities, k, self.ids, self.index); end function indexed_heap:remove_index(k) - local size = #self.priorities; - local result = self.priorities[k]; + if result == nil then return; end + local result_sync = self.ids[k]; local item = self.items[result_sync]; - if result == nil then return; end - self.index[result_sync] = nil; - self.items[result_sync] = nil; + local size = #self.priorities; self.priorities[k] = self.priorities[size]; self.ids[k] = self.ids[size]; self.index[self.ids[k]] = k; + t_remove(self.priorities); t_remove(self.ids); - k = _percolate_up(self.priorities, k, self.ids, self.index); - k = _percolate_down(self.priorities, k, self.ids, self.index); + self.index[result_sync] = nil; + self.items[result_sync] = nil; + + if size > k then + k = _percolate_up(self.priorities, k, self.ids, self.index); + k = _percolate_down(self.priorities, k, self.ids, self.index); + end return result, item, result_sync; end -- cgit v1.2.3 From e8abeeee4dfbdd0234fa3c5b507a3e9aa64e7a4e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 28 May 2014 20:12:13 +0200 Subject: util.vcard: Library for parsing vCards --- util/vcard.lua | 454 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 454 insertions(+) create mode 100644 util/vcard.lua (limited to 'util') diff --git a/util/vcard.lua b/util/vcard.lua new file mode 100644 index 00000000..e3005801 --- /dev/null +++ b/util/vcard.lua @@ -0,0 +1,454 @@ +-- Copyright (C) 2011-2014 Kim Alvefur +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +-- TODO +-- Fix folding. + +local st = require "util.stanza"; +local t_insert, t_concat = table.insert, table.concat; +local type = type; +local next, pairs, ipairs = next, pairs, ipairs; + +local from_text, to_text, from_xep54, to_xep54; + +local line_sep = "\n"; + +local vCard_dtd; -- See end of file + +local function fold_line() + error "Not implemented" --TODO +end +local function unfold_line() + error "Not implemented" + -- gsub("\r?\n[ \t]([^\r\n])", "%1"); +end + +local function vCard_esc(s) + return s:gsub("[,:;\\]", "\\%1"):gsub("\n","\\n"); +end + +local function vCard_unesc(s) + return s:gsub("\\?[\\nt:;,]", { + ["\\\\"] = "\\", + ["\\n"] = "\n", + ["\\r"] = "\r", + ["\\t"] = "\t", + ["\\:"] = ":", -- FIXME Shouldn't need to espace : in values, just params + ["\\;"] = ";", + ["\\,"] = ",", + [":"] = "\29", + [";"] = "\30", + [","] = "\31", + }); +end + +local function item_to_xep54(item) + local t = st.stanza(item.name, { xmlns = "vcard-temp" }); + + local prop_def = vCard_dtd[item.name]; + if prop_def == "text" then + t:text(item[1]); + elseif type(prop_def) == "table" then + if prop_def.types and item.TYPE then + if type(item.TYPE) == "table" then + for _,v in pairs(prop_def.types) do + for _,typ in pairs(item.TYPE) do + if typ:upper() == v then + t:tag(v):up(); + break; + end + end + end + else + t:tag(item.TYPE:upper()):up(); + end + end + + if prop_def.props then + for _,v in pairs(prop_def.props) do + if item[v] then + t:tag(v):up(); + end + end + end + + if prop_def.value then + t:tag(prop_def.value):text(item[1]):up(); + elseif prop_def.values then + local prop_def_values = prop_def.values; + local repeat_last = prop_def_values.behaviour == "repeat-last" and prop_def_values[#prop_def_values]; + for i=1,#item do + t:tag(prop_def.values[i] or repeat_last):text(item[i]):up(); + end + end + end + + return t; +end + +local function vcard_to_xep54(vCard) + local t = st.stanza("vCard", { xmlns = "vcard-temp" }); + for i=1,#vCard do + t:add_child(item_to_xep54(vCard[i])); + end + return t; +end + +function to_xep54(vCards) + if not vCards[1] or vCards[1].name then + return vcard_to_xep54(vCards) + else + local t = st.stanza("xCard", { xmlns = "vcard-temp" }); + for i=1,#vCards do + t:add_child(vcard_to_xep54(vCards[i])); + end + return t; + end +end + +function from_text(data) + data = data -- unfold and remove empty lines + :gsub("\r\n","\n") + :gsub("\n ", "") + :gsub("\n\n+","\n"); + local vCards = {}; + local c; -- current item + for line in data:gmatch("[^\n]+") do + local line = vCard_unesc(line); + local name, params, value = line:match("^([-%a]+)(\30?[^\29]*)\29(.*)$"); + value = value:gsub("\29",":"); + if #params > 0 then + local _params = {}; + for k,isval,v in params:gmatch("\30([^=]+)(=?)([^\30]*)") do + k = k:upper(); + local _vt = {}; + for _p in v:gmatch("[^\31]+") do + _vt[#_vt+1]=_p + _vt[_p]=true; + end + if isval == "=" then + _params[k]=_vt; + else + _params[k]=true; + end + end + params = _params; + end + if name == "BEGIN" and value == "VCARD" then + c = {}; + vCards[#vCards+1] = c; + elseif name == "END" and value == "VCARD" then + c = nil; + elseif c and vCard_dtd[name] then + local dtd = vCard_dtd[name]; + local p = { name = name }; + c[#c+1]=p; + --c[name]=p; + local up = c; + c = p; + if dtd.types then + for _, t in ipairs(dtd.types) do + local t = t:lower(); + if ( params.TYPE and params.TYPE[t] == true) + or params[t] == true then + c.TYPE=t; + end + end + end + if dtd.props then + for _, p in ipairs(dtd.props) do + if params[p] then + if params[p] == true then + c[p]=true; + else + for _, prop in ipairs(params[p]) do + c[p]=prop; + end + end + end + end + end + if dtd == "text" or dtd.value then + t_insert(c, value); + elseif dtd.values then + local value = "\30"..value; + for p in value:gmatch("\30([^\30]*)") do + t_insert(c, p); + end + end + c = up; + end + end + return vCards; +end + +local function item_to_text(item) + local value = {}; + for i=1,#item do + value[i] = vCard_esc(item[i]); + end + value = t_concat(value, ";"); + + local params = ""; + for k,v in pairs(item) do + if type(k) == "string" and k ~= "name" then + params = params .. (";%s=%s"):format(k, type(v) == "table" and t_concat(v,",") or v); + end + end + + return ("%s%s:%s"):format(item.name, params, value) +end + +local function vcard_to_text(vcard) + local t={}; + t_insert(t, "BEGIN:VCARD") + for i=1,#vcard do + t_insert(t, item_to_text(vcard[i])); + end + t_insert(t, "END:VCARD") + return t_concat(t, line_sep); +end + +function to_text(vCards) + if vCards[1] and vCards[1].name then + return vcard_to_text(vCards) + else + local t = {}; + for i=1,#vCards do + t[i]=vcard_to_text(vCards[i]); + end + return t_concat(t, line_sep); + end +end + +local function from_xep54_item(item) + local prop_name = item.name; + local prop_def = vCard_dtd[prop_name]; + + local prop = { name = prop_name }; + + if prop_def == "text" then + prop[1] = item:get_text(); + elseif type(prop_def) == "table" then + if prop_def.value then --single item + prop[1] = item:get_child_text(prop_def.value) or ""; + elseif prop_def.values then --array + local value_names = prop_def.values; + if value_names.behaviour == "repeat-last" then + for i=1,#item.tags do + t_insert(prop, item.tags[i]:get_text() or ""); + end + else + for i=1,#value_names do + t_insert(prop, item:get_child_text(value_names[i]) or ""); + end + end + elseif prop_def.names then + local names = prop_def.names; + for i=1,#names do + if item:get_child(names[i]) then + prop[1] = names[i]; + break; + end + end + end + + if prop_def.props_verbatim then + for k,v in pairs(prop_def.props_verbatim) do + prop[k] = v; + end + end + + if prop_def.types then + local types = prop_def.types; + prop.TYPE = {}; + for i=1,#types do + if item:get_child(types[i]) then + t_insert(prop.TYPE, types[i]:lower()); + end + end + if #prop.TYPE == 0 then + prop.TYPE = nil; + end + end + + -- A key-value pair, within a key-value pair? + if prop_def.props then + local params = prop_def.props; + for i=1,#params do + local name = params[i] + local data = item:get_child_text(name); + if data then + prop[name] = prop[name] or {}; + t_insert(prop[name], data); + end + end + end + else + return nil + end + + return prop; +end + +local function from_xep54_vCard(vCard) + local tags = vCard.tags; + local t = {}; + for i=1,#tags do + t_insert(t, from_xep54_item(tags[i])); + end + return t +end + +function from_xep54(vCard) + if vCard.attr.xmlns ~= "vcard-temp" then + return nil, "wrong-xmlns"; + end + if vCard.name == "xCard" then -- A collection of vCards + local t = {}; + local vCards = vCard.tags; + for i=1,#vCards do + t[i] = from_xep54_vCard(vCards[i]); + end + return t + elseif vCard.name == "vCard" then -- A single vCard + return from_xep54_vCard(vCard) + end +end + +-- This was adapted from http://xmpp.org/extensions/xep-0054.html#dtd +vCard_dtd = { + VERSION = "text", --MUST be 3.0, so parsing is redundant + FN = "text", + N = { + values = { + "FAMILY", + "GIVEN", + "MIDDLE", + "PREFIX", + "SUFFIX", + }, + }, + NICKNAME = "text", + PHOTO = { + props_verbatim = { ENCODING = { "b" } }, + props = { "TYPE" }, + value = "BINVAL", --{ "EXTVAL", }, + }, + BDAY = "text", + ADR = { + types = { + "HOME", + "WORK", + "POSTAL", + "PARCEL", + "DOM", + "INTL", + "PREF", + }, + values = { + "POBOX", + "EXTADD", + "STREET", + "LOCALITY", + "REGION", + "PCODE", + "CTRY", + } + }, + LABEL = { + types = { + "HOME", + "WORK", + "POSTAL", + "PARCEL", + "DOM", + "INTL", + "PREF", + }, + value = "LINE", + }, + TEL = { + types = { + "HOME", + "WORK", + "VOICE", + "FAX", + "PAGER", + "MSG", + "CELL", + "VIDEO", + "BBS", + "MODEM", + "ISDN", + "PCS", + "PREF", + }, + value = "NUMBER", + }, + EMAIL = { + types = { + "HOME", + "WORK", + "INTERNET", + "PREF", + "X400", + }, + value = "USERID", + }, + JABBERID = "text", + MAILER = "text", + TZ = "text", + GEO = { + values = { + "LAT", + "LON", + }, + }, + TITLE = "text", + ROLE = "text", + LOGO = "copy of PHOTO", + AGENT = "text", + ORG = { + values = { + behaviour = "repeat-last", + "ORGNAME", + "ORGUNIT", + } + }, + CATEGORIES = { + values = "KEYWORD", + }, + NOTE = "text", + PRODID = "text", + REV = "text", + SORTSTRING = "text", + SOUND = "copy of PHOTO", + UID = "text", + URL = "text", + CLASS = { + names = { -- The item.name is the value if it's one of these. + "PUBLIC", + "PRIVATE", + "CONFIDENTIAL", + }, + }, + KEY = { + props = { "TYPE" }, + value = "CRED", + }, + DESC = "text", +}; +vCard_dtd.LOGO = vCard_dtd.PHOTO; +vCard_dtd.SOUND = vCard_dtd.PHOTO; + +return { + from_text = from_text; + to_text = to_text; + + from_xep54 = from_xep54; + to_xep54 = to_xep54; +}; -- cgit v1.2.3 From 72a1bf0bb532f8f8b6b66d4f67c41bb309cc9bbb Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 28 May 2014 21:11:02 +0200 Subject: util.vcard: Add support for converting to vcard4 --- util/vcard.lua | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) (limited to 'util') diff --git a/util/vcard.lua b/util/vcard.lua index e3005801..70c923b8 100644 --- a/util/vcard.lua +++ b/util/vcard.lua @@ -319,6 +319,68 @@ function from_xep54(vCard) end end +local vcard4 = { } + +function vcard4:text(node, params, value) + self:tag(node:lower()) + -- FIXME params + if type(value) == "string" then + self:tag("text"):text(value):up() + elseif vcard4[node] then + vcard4[node](value); + end + self:up(); +end + +function vcard4.N(value) + for i, k in ipairs(vCard_dtd.N.values) do + value:tag(k):text(value[i]):up(); + end +end + +local xmlns_vcard4 = "urn:ietf:params:xml:ns:vcard-4.0" + +local function item_to_vcard4(item) + local typ = item.name:lower(); + local t = st.stanza(typ, { xmlns = xmlns_vcard4 }); + + local prop_def = vCard4_dtd[typ]; + if prop_def == "text" then + t:tag("text"):text(item[1]):up(); + elseif type(prop_def) == "table" then + if prop_def.values then + for i, v in ipairs(prop_def.values) do + t:tag(v:lower()):text(item[i] or ""):up(); + end + else + t:tag("unsupported",{xmlns="http://zash.se/protocol/vcardlib"}) + end + else + t:tag("unsupported",{xmlns="http://zash.se/protocol/vcardlib"}) + end + return t; +end + +local function vcard_to_vcard4xml(vCard) + local t = st.stanza("vcard", { xmlns = xmlns_vcard4 }); + for i=1,#vCard do + t:add_child(item_to_vcard4(vCard[i])); + end + return t; +end + +local function vcards_to_vcard4xml(vCards) + if not vCards[1] or vCards[1].name then + return vcard_to_vcard4xml(vCards) + else + local t = st.stanza("vcards", { xmlns = xmlns_vcard4 }); + for i=1,#vCards do + t:add_child(vcard_to_vcard4xml(vCards[i])); + end + return t; + end +end + -- This was adapted from http://xmpp.org/extensions/xep-0054.html#dtd vCard_dtd = { VERSION = "text", --MUST be 3.0, so parsing is redundant @@ -445,10 +507,69 @@ vCard_dtd = { vCard_dtd.LOGO = vCard_dtd.PHOTO; vCard_dtd.SOUND = vCard_dtd.PHOTO; +vCard4_dtd = { + source = "uri", + kind = "text", + xml = "text", + fn = "text", + n = { + values = { + "family", + "given", + "middle", + "prefix", + "suffix", + }, + }, + nickname = "text", + photo = "uri", + bday = "date-and-or-time", + anniversary = "date-and-or-time", + gender = "text", + adr = { + values = { + "pobox", + "ext", + "street", + "locality", + "region", + "code", + "country", + } + }, + tel = "text", + email = "text", + impp = "uri", + lang = "language-tag", + tz = "text", + geo = "uri", + title = "text", + role = "text", + logo = "uri", + org = "text", + member = "uri", + related = "uri", + categories = "text", + note = "text", + prodid = "text", + rev = "timestamp", + sound = "uri", + uid = "uri", + clientpidmap = "number, uuid", + url = "uri", + version = "text", + key = "uri", + fburl = "uri", + caladruri = "uri", + caluri = "uri", +}; + return { from_text = from_text; to_text = to_text; from_xep54 = from_xep54; to_xep54 = to_xep54; + + to_vcard4 = vcards_to_vcard4xml; }; -- cgit v1.2.3 From f8321df6533ed9b1cc0e5945b3a3974df4963a4b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 28 May 2014 22:09:32 +0200 Subject: util.vcard: Add missing local declaration --- util/vcard.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'util') diff --git a/util/vcard.lua b/util/vcard.lua index 70c923b8..29a40844 100644 --- a/util/vcard.lua +++ b/util/vcard.lua @@ -17,6 +17,7 @@ local from_text, to_text, from_xep54, to_xep54; local line_sep = "\n"; local vCard_dtd; -- See end of file +local vCard4_dtd; local function fold_line() error "Not implemented" --TODO -- cgit v1.2.3 From ed90b8cac29a9890dc93d0f43b8cee84c960a1f1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 9 Jul 2014 08:23:16 +0200 Subject: util.vcard: Add support for uri types in vcard4 --- util/vcard.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'util') diff --git a/util/vcard.lua b/util/vcard.lua index 29a40844..152b0b2d 100644 --- a/util/vcard.lua +++ b/util/vcard.lua @@ -348,6 +348,8 @@ local function item_to_vcard4(item) local prop_def = vCard4_dtd[typ]; if prop_def == "text" then t:tag("text"):text(item[1]):up(); + elseif prop_def == "uri" then + t:tag("uri"):text(item[1]):up(); elseif type(prop_def) == "table" then if prop_def.values then for i, v in ipairs(prop_def.values) do -- cgit v1.2.3 From 534a115ec7aff123fa3358c500554d02b247e4a8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 10 Sep 2014 16:47:55 +0200 Subject: util.vcard: Turn PHOTO fields into data-uris --- util/vcard.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'util') diff --git a/util/vcard.lua b/util/vcard.lua index 152b0b2d..8aafa24d 100644 --- a/util/vcard.lua +++ b/util/vcard.lua @@ -349,7 +349,11 @@ local function item_to_vcard4(item) if prop_def == "text" then t:tag("text"):text(item[1]):up(); elseif prop_def == "uri" then - t:tag("uri"):text(item[1]):up(); + if item.ENCODING and item.ENCODING[1] == 'b' then + t:tag("uri"):text("data:;base64,"):text(item[1]):up(); + else + t:tag("uri"):text(item[1]):up(); + end elseif type(prop_def) == "table" then if prop_def.values then for i, v in ipairs(prop_def.values) do -- cgit v1.2.3 From dcd855afaa62797fc8285ff4a7a8e1a8f6279a1f Mon Sep 17 00:00:00 2001 From: daurnimator Date: Mon, 20 Oct 2014 16:13:24 -0400 Subject: Move timer code out of util.timer and into relevant net.server backends --- util/timer.lua | 67 +--------------------------------------------------------- 1 file changed, 1 insertion(+), 66 deletions(-) (limited to 'util') diff --git a/util/timer.lua b/util/timer.lua index 23bd6a37..0ec97585 100644 --- a/util/timer.lua +++ b/util/timer.lua @@ -9,80 +9,15 @@ local indexedbheap = require "util.indexedbheap"; local log = require "util.logger".init("timer"); local server = require "net.server"; -local math_min = math.min -local math_huge = math.huge local get_time = require "socket".gettime; -local t_insert = table.insert; -local pairs = pairs; local type = type; local debug_traceback = debug.traceback; local tostring = tostring; local xpcall = xpcall; -local data = {}; -local new_data = {}; - module "timer" -local _add_task; -if not server.event then - function _add_task(delay, callback) - local current_time = get_time(); - delay = delay + current_time; - if delay >= current_time then - t_insert(new_data, {delay, callback}); - else - local r = callback(current_time); - if r and type(r) == "number" then - return _add_task(r, callback); - end - end - end - - server._addtimer(function() - local current_time = get_time(); - if #new_data > 0 then - for _, d in pairs(new_data) do - t_insert(data, d); - end - new_data = {}; - end - - local next_time = math_huge; - for i, d in pairs(data) do - local t, callback = d[1], d[2]; - if t <= current_time then - data[i] = nil; - local r = callback(current_time); - if type(r) == "number" then - _add_task(r, callback); - next_time = math_min(next_time, r); - end - else - next_time = math_min(next_time, t - current_time); - end - end - return next_time; - end); -else - local event = server.event; - local event_base = server.event_base; - local EVENT_LEAVE = (event.core and event.core.LEAVE) or -1; - - function _add_task(delay, callback) - local event_handle; - event_handle = event_base:addevent(nil, 0, function () - local ret = callback(get_time()); - if ret then - return 0, ret; - elseif event_handle then - return EVENT_LEAVE; - end - end - , delay); - end -end - +local _add_task = server.add_task; --add_task = _add_task; local h = indexedbheap.create(); -- cgit v1.2.3