Software /
code /
prosody-modules
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 |
parent | 716:dac33b8f190b |
child | 734: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 }; |