Mercurial > 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 |
| 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 }; |
