comparison mod_vjud/vcard.lib.lua @ 732:317e142fe6f1

mod_vjud: Update util.vcard from verse
author Kim Alvefur <zash@zash.se>
date Sun, 01 Jul 2012 12:47:51 +0200
parents dac33b8f190b
children 81de1e446bfe
comparison
equal deleted inserted replaced
731:15a8b717597b 732:317e142fe6f1
3 -- This project is MIT/X11 licensed. Please see the 3 -- This project is MIT/X11 licensed. Please see the
4 -- COPYING file in the source package for more information. 4 -- COPYING file in the source package for more information.
5 -- 5 --
6 6
7 -- TODO 7 -- TODO
8 -- function lua_to_xep54() 8 -- Fix folding.
9 -- function lua_to_text()
10 -- replace text_to_xep54() and xep54_to_text() with intermediate lua?
11 9
12 local st = require "util.stanza"; 10 local st = require "util.stanza";
13 local t_insert, t_concat = table.insert, table.concat; 11 local t_insert, t_concat = table.insert, table.concat;
14 local type = type; 12 local type = type;
15 local next, pairs, ipairs = next, pairs, ipairs; 13 local next, pairs, ipairs = next, pairs, ipairs;
16 14
17 local lua_to_text, lua_to_xep54, text_to_lua, text_to_xep54, xep54_to_lua, xep54_to_text; 15 local from_text, to_text, from_xep54, to_xep54;
18 local from_text, to_text, from_xep54, to_xep54; --TODO implement these, replace the above 16
19 17 local line_sep = "\n";
20 18
21 local vCard_dtd; 19 local vCard_dtd; -- See end of file
20
21 local function fold_line()
22 error "Not implemented" --TODO
23 end
24 local function unfold_line()
25 error "Not implemented"
26 -- gsub("\r?\n[ \t]([^\r\n])", "%1");
27 end
22 28
23 local function vCard_esc(s) 29 local function vCard_esc(s)
24 return s:gsub("[,:;\\]", "\\%1"):gsub("\n","\\n"); 30 return s:gsub("[,:;\\]", "\\%1"):gsub("\n","\\n");
25 end 31 end
26 32
27 local function vCard_unesc(s) 33 local function vCard_unesc(s)
28 return s:gsub("\\?[\\nt:;,]", { 34 return s:gsub("\\?[\\nt:;,]", {
29 ["\\\\"] = "\\", 35 ["\\\\"] = "\\",
30 ["\\n"] = "\n", 36 ["\\n"] = "\n",
37 ["\\r"] = "\r",
31 ["\\t"] = "\t", 38 ["\\t"] = "\t",
32 ["\\:"] = ":", -- FIXME Shouldn't need to espace : in values, just params 39 ["\\:"] = ":", -- FIXME Shouldn't need to espace : in values, just params
33 ["\\;"] = ";", 40 ["\\;"] = ";",
34 ["\\,"] = ",", 41 ["\\,"] = ",",
35 [":"] = "\29", 42 [":"] = "\29",
36 [";"] = "\30", 43 [";"] = "\30",
37 [","] = "\31", 44 [","] = "\31",
38 }); 45 });
39 end 46 end
40 47
41 function text_to_xep54(data) 48 local function item_to_xep54(item)
42 --[[ TODO 49 local t = st.stanza(item.name, { xmlns = "vcard-temp" });
43 return lua_to_xep54(text_to_lua(data)); 50
44 --]] 51 local prop_def = vCard_dtd[item.name];
45 data = data 52 if prop_def == "text" then
46 :gsub("\r\n","\n") 53 t:text(item[1]);
47 :gsub("\n ", "") 54 elseif type(prop_def) == "table" then
48 :gsub("\n\n+","\n"); 55 if prop_def.types and item.TYPE then
49 local c = st.stanza("xCard", { xmlns = "vcard-temp" }); 56 if type(item.TYPE) == "table" then
50 for line in data:gmatch("[^\n]+") do 57 for _,v in pairs(prop_def.types) do
51 local line = vCard_unesc(line); 58 for _,typ in pairs(item.TYPE) do
52 local name, params, value = line:match("^([-%a]+)(\30?[^\29]*)\29(.*)$"); 59 if typ:upper() == v then
53 value = value:gsub("\29",":"); 60 t:tag(v):up();
54 if #params > 0 then 61 break;
55 local _params = {};
56 for k,isval,v in params:gmatch("\30([^=]+)(=?)([^\30]*)") do
57 k = k:upper();
58 local _vt = {};
59 for _p in v:gmatch("[^\31]+") do
60 _vt[#_vt+1]=_p
61 _vt[_p]=true;
62 end
63 if isval == "=" then
64 _params[k]=_vt;
65 else
66 _params[k]=true;
67 end
68 end
69 params = _params;
70 end
71 if name == "BEGIN" and value == "VCARD" then
72 c:tag("vCard", { xmlns = "vcard-temp" });
73 elseif name == "END" and value == "VCARD" then
74 c:up();
75 elseif vCard_dtd[name] then
76 local dtd = vCard_dtd[name];
77 c:tag(name);
78 if dtd.types then
79 for _, t in ipairs(dtd.types) do
80 if ( params.TYPE and params.TYPE[t] == true)
81 or params[t] == true then
82 c:tag(t):up();
83 end
84 end
85 end
86 if dtd.props then
87 for _, p in ipairs(dtd.props) do
88 if params[p] then
89 if params[p] == true then
90 c:tag(p):up();
91 else
92 for _, prop in ipairs(params[p]) do
93 c:tag(p):text(prop):up();
94 end
95 end 62 end
96 end 63 end
97 end 64 end
98 end 65 else
99 if dtd == "text" then 66 t:tag(item.TYPE:upper()):up();
100 c:text(value); 67 end
101 elseif dtd.value then 68 end
102 c:tag(dtd.value):text(value):up(); 69
103 elseif dtd.values then 70 if prop_def.props then
104 local values = dtd.values; 71 for _,v in pairs(prop_def.props) do
105 local i = 1; 72 if item[v] then
106 local value = "\30"..value; 73 t:tag(v):up();
107 for p in value:gmatch("\30([^\30]*)") do 74 end
108 c:tag(values[i]):text(p):up(); 75 end
109 if i < #values then 76 end
110 i = i + 1; 77
111 end 78 if prop_def.value then
112 end 79 t:tag(prop_def.value):text(item[1]):up();
113 end 80 elseif prop_def.values then
114 c:up(); 81 local prop_def_values = prop_def.values;
115 end 82 local repeat_last = prop_def_values.behaviour == "repeat-last" and prop_def_values[#prop_def_values];
116 end 83 for i=1,#item do
117 return c; 84 t:tag(prop_def.values[i] or repeat_last):text(item[i]):up();
118 end 85 end
119 86 end
120 function text_to_lua(data) --table 87 end
121 data = data 88
89 return t;
90 end
91
92 local function vcard_to_xep54(vCard)
93 local t = st.stanza("vCard", { xmlns = "vcard-temp" });
94 for i=1,#vCard do
95 t:add_child(item_to_xep54(vCard[i]));
96 end
97 return t;
98 end
99
100 function to_xep54(vCards)
101 if vCards[1].name then
102 return vcard_to_xep54(vCards)
103 else
104 local t = st.stanza("xCard", { xmlns = "vcard-temp" });
105 for i=1,#vCards do
106 t:add_child(vcard_to_xep54(vCards[i]));
107 end
108 return t;
109 end
110 end
111
112 function from_text(data)
113 data = data -- unfold and remove empty lines
122 :gsub("\r\n","\n") 114 :gsub("\r\n","\n")
123 :gsub("\n ", "") 115 :gsub("\n ", "")
124 :gsub("\n\n+","\n"); 116 :gsub("\n\n+","\n");
125 local vCards = {}; 117 local vCards = {};
126 local c; -- current item 118 local c; -- current item
191 end 183 end
192 end 184 end
193 return vCards; 185 return vCards;
194 end 186 end
195 187
196 function to_text(vcard) 188 local function item_to_text(item)
189 local value = {};
190 for i=1,#item do
191 value[i] = vCard_esc(item[i]);
192 end
193 value = t_concat(value, ";");
194
195 local params = "";
196 for k,v in pairs(item) do
197 if type(k) == "string" and k ~= "name" then
198 params = params .. (";%s=%s"):format(k, type(v) == "table" and t_concat(v,",") or v);
199 end
200 end
201
202 return ("%s%s:%s"):format(item.name, params, value)
203 end
204
205 local function vcard_to_text(vcard)
197 local t={}; 206 local t={};
198 t_insert(t, "BEGIN:VCARD") 207 t_insert(t, "BEGIN:VCARD")
199 for i=1,#vcard do 208 for i=1,#vcard do
200 t_insert(t, ("%s:%s"):format(vcard[i].name, t_concat(vcard[i], ";"))); 209 t_insert(t, item_to_text(vcard[i]));
201 end 210 end
202 t_insert(t, "END:VCARD") 211 t_insert(t, "END:VCARD")
203 return t_concat(t,"\n"); 212 return t_concat(t, line_sep);
204 end 213 end
205 214
206 local function vCard_prop(item) -- single item staza object to text line 215 function to_text(vCards)
207 local prop_name = item.name; 216 if vCards[1].name then
208 local prop_def = vCard_dtd[prop_name]; 217 return vcard_to_text(vCards)
209 if not prop_def then return nil end
210
211 local value, params = "", {};
212
213 if prop_def == "text" then
214 value = item:get_text();
215 elseif type(prop_def) == "table" then
216 if prop_def.value then --single item
217 value = item:get_child_text(prop_def.value) or "";
218 elseif prop_def.values then --array
219 local value_names = prop_def.values;
220 value = {};
221 if value_names.behaviour == "repeat-last" then
222 for i=1,#item do
223 t_insert(value, item[i]:get_text() or "");
224 end
225 else
226 for i=1,#value_names do
227 t_insert(value, item:get_child_text(value_names[i]) or "");
228 end
229 end
230 elseif prop_def.names then
231 local names = prop_def.names;
232 for i=1,#names do
233 if item:get_child(names[i]) then
234 value = names[i];
235 break;
236 end
237 end
238 end
239
240 if prop_def.props_verbatim then
241 for k,v in pairs(prop_def.props_verbatim) do
242 params[k] = v;
243 end
244 end
245
246 if prop_def.types then
247 local types = prop_def.types;
248 params.TYPE = {};
249 for i=1,#types do
250 if item:get_child(types[i]) then
251 t_insert(params.TYPE, types[i]:lower());
252 end
253 end
254 if #params.TYPE == 0 then
255 params.TYPE = nil;
256 end
257 end
258
259 if prop_def.props then
260 local props = prop_def.props;
261 for i=1,#props do
262 local prop = props[i]
263 local p = item:get_child_text(prop);
264 if p then
265 params[prop] = params[prop] or {};
266 t_insert(params[prop], p);
267 end
268 end
269 end
270 else 218 else
271 return nil 219 local t = {};
272 end 220 for i=1,#vCards do
273 221 t[i]=vcard_to_text(vCards[i]);
274 if type(value) == "table" then 222 end
275 for i=1,#value do 223 return t_concat(t, line_sep);
276 value[i]=vCard_esc(value[i]); 224 end
277 end 225 end
278 value = t_concat(value, ";"); 226
279 else 227 local function from_xep54_item(item)
280 value = vCard_esc(value);
281 end
282
283 if next(params) then
284 local sparams = "";
285 for k,v in pairs(params) do
286 sparams = sparams .. (";%s=%s"):format(k, t_concat(v,","));
287 end
288 params = sparams;
289 else
290 params = "";
291 end
292
293 return ("%s%s:%s"):format(item.name, params, value)
294 :gsub(("."):rep(75), "%0\r\n "):gsub("\r\n $","");
295 end
296
297 function xep54_to_text(vCard)
298 --[[ TODO
299 return lua_to_text(xep54_to_lua(vCard))
300 --]]
301 local r = {};
302 t_insert(r, "BEGIN:VCARD");
303 for i = 1,#vCard do
304 local item = vCard[i];
305 if item.name then
306 local s = vCard_prop(item);
307 if s then
308 t_insert(r, s);
309 end
310 end
311 end
312 t_insert(r, "END:VCARD");
313 return t_concat(r, "\r\n");
314 end
315
316 local function xep54_item_to_lua(item)
317 local prop_name = item.name; 228 local prop_name = item.name;
318 local prop_def = vCard_dtd[prop_name]; 229 local prop_def = vCard_dtd[prop_name];
319 if not prop_def then return nil end 230 if not prop_def then return nil end
320 231
321 local prop = { name = prop_name }; 232 local prop = { name = prop_name };
382 end 293 end
383 294
384 return prop; 295 return prop;
385 end 296 end
386 297
387 local function xep54_vCard_to_lua(vCard) 298 local function from_xep54_vCard(vCard)
388 local tags = vCard.tags; 299 local tags = vCard.tags;
389 local t = {}; 300 local t = {};
390 for i=1,#tags do 301 for i=1,#tags do
391 t[i] = xep54_item_to_lua(tags[i]); 302 t[i] = from_xep54_item(tags[i]);
392 end 303 end
393 return t 304 return t
394 end 305 end
395 306
396 function xep54_to_lua(vCard) 307 function from_xep54(vCard)
397 if vCard.attr.xmlns ~= "vcard-temp" then 308 if vCard.attr.xmlns ~= "vcard-temp" then
398 return false 309 return nil, "wrong-xmlns";
399 end 310 end
400 if vCard.name == "xCard" then 311 if vCard.name == "xCard" then -- A collection of vCards
401 local t = {}; 312 local t = {};
402 local vCards = vCard.tags; 313 local vCards = vCard.tags;
403 for i=1,#vCards do 314 for i=1,#vCards do
404 local ti = xep54_vCard_to_lua(vCards[i]); 315 local ti = from_xep54_vCard(vCards[i]);
405 t[i] = ti; 316 t[i] = ti;
406 --t[ti.name] = ti; 317 --t[ti.name] = ti;
407 end 318 end
408 return t 319 return t
409 elseif vCard.name == "vCard" then 320 elseif vCard.name == "vCard" then -- A single vCard
410 return xep54_vCard_to_lua(vCard) 321 return from_xep54_vCard(vCard)
411 end 322 end
412 end 323 end
413 324
414 -- This was adapted from http://xmpp.org/extensions/xep-0054.html#dtd 325 -- This was adapted from http://xmpp.org/extensions/xep-0054.html#dtd
415 vCard_dtd = { 326 vCard_dtd = {
536 }; 447 };
537 vCard_dtd.LOGO = vCard_dtd.PHOTO; 448 vCard_dtd.LOGO = vCard_dtd.PHOTO;
538 vCard_dtd.SOUND = vCard_dtd.PHOTO; 449 vCard_dtd.SOUND = vCard_dtd.PHOTO;
539 450
540 return { 451 return {
541 text_to_xep54 = text_to_xep54;
542 text_to_lua = text_to_lua;
543 xep54_to_text = xep54_to_text;
544 xep54_to_lua = xep54_to_lua;
545 --[[ TODO
546 from_text = from_text; 452 from_text = from_text;
547 to_text = to_text; 453 to_text = to_text;
454
548 from_xep54 = from_xep54; 455 from_xep54 = from_xep54;
549 to_xep54 = to_xep54; 456 to_xep54 = to_xep54;
550 --]] 457
458 -- COMPAT:
459 lua_to_text = to_text;
460 lua_to_xep54 = to_xep54;
461
462 text_to_lua = from_text;
463 text_to_xep54 = function (...) return to_xep54(from_text(...)); end;
464
465 xep54_to_lua = from_xep54;
466 xep54_to_text = function (...) return to_text(from_xep54(...)) end;
551 }; 467 };