mod_statistics_statsman: Map 'cpu.clock' from mod_measure_cpu to 'cpu_total' of mod_statistics_cputotal
-- Copyright (C) 2011-2012 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 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;
-- COMPAT:
lua_to_text = to_text;
lua_to_xep54 = to_xep54;
text_to_lua = from_text;
text_to_xep54 = function (...) return to_xep54(from_text(...)); end;
xep54_to_lua = from_xep54;
xep54_to_text = function (...) return to_text(from_xep54(...)) end;
};