Mercurial > prosody-hg
comparison util/stanza.lua @ 12802:4a8740e01813
Merge 0.12->trunk
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Mon, 12 Dec 2022 07:10:54 +0100 |
| parents | 12ced5db29b2 |
| children | d10957394a3c |
comparison
equal
deleted
inserted
replaced
| 12801:ebd6b4d8bf04 | 12802:4a8740e01813 |
|---|---|
| 19 local ipairs = ipairs; | 19 local ipairs = ipairs; |
| 20 local type = type; | 20 local type = type; |
| 21 local s_gsub = string.gsub; | 21 local s_gsub = string.gsub; |
| 22 local s_sub = string.sub; | 22 local s_sub = string.sub; |
| 23 local s_find = string.find; | 23 local s_find = string.find; |
| 24 local t_move = table.move or require "util.table".move; | |
| 25 local t_create = require"util.table".create; | |
| 24 | 26 |
| 25 local valid_utf8 = require "util.encodings".utf8.valid; | 27 local valid_utf8 = require "util.encodings".utf8.valid; |
| 26 | 28 |
| 27 local do_pretty_printing, termcolours = pcall(require, "util.termcolours"); | 29 local do_pretty_printing, termcolours = pcall(require, "util.termcolours"); |
| 28 | 30 |
| 29 local xmlns_stanzas = "urn:ietf:params:xml:ns:xmpp-stanzas"; | 31 local xmlns_stanzas = "urn:ietf:params:xml:ns:xmpp-stanzas"; |
| 32 local xmpp_stanzas_attr = { xmlns = xmlns_stanzas }; | |
| 30 | 33 |
| 31 local _ENV = nil; | 34 local _ENV = nil; |
| 32 -- luacheck: std none | 35 -- luacheck: std none |
| 33 | 36 |
| 34 local stanza_mt = { __name = "stanza" }; | 37 local stanza_mt = { __name = "stanza" }; |
| 173 | 176 |
| 174 function stanza_mt:get_child_text(name, xmlns) | 177 function stanza_mt:get_child_text(name, xmlns) |
| 175 local tag = self:get_child(name, xmlns); | 178 local tag = self:get_child(name, xmlns); |
| 176 if tag then | 179 if tag then |
| 177 return tag:get_text(); | 180 return tag:get_text(); |
| 181 end | |
| 182 return nil; | |
| 183 end | |
| 184 | |
| 185 function stanza_mt:get_child_attr(name, xmlns, attr) | |
| 186 local tag = self:get_child(name, xmlns); | |
| 187 if tag then | |
| 188 return tag.attr[attr]; | |
| 178 end | 189 end |
| 179 return nil; | 190 return nil; |
| 180 end | 191 end |
| 181 | 192 |
| 182 function stanza_mt:child_with_name(name) | 193 function stanza_mt:child_with_name(name) |
| 281 self = self:get_child(name, xmlns); | 292 self = self:get_child(name, xmlns); |
| 282 until not self | 293 until not self |
| 283 end | 294 end |
| 284 | 295 |
| 285 local function _clone(stanza, only_top) | 296 local function _clone(stanza, only_top) |
| 286 local attr, tags = {}, {}; | 297 local attr = {}; |
| 287 for k,v in pairs(stanza.attr) do attr[k] = v; end | 298 for k,v in pairs(stanza.attr) do attr[k] = v; end |
| 288 local old_namespaces, namespaces = stanza.namespaces; | 299 local old_namespaces, namespaces = stanza.namespaces; |
| 289 if old_namespaces then | 300 if old_namespaces then |
| 290 namespaces = {}; | 301 namespaces = {}; |
| 291 for k,v in pairs(old_namespaces) do namespaces[k] = v; end | 302 for k,v in pairs(old_namespaces) do namespaces[k] = v; end |
| 292 end | 303 end |
| 293 local new = { name = stanza.name, attr = attr, namespaces = namespaces, tags = tags }; | 304 local tags, new; |
| 305 if only_top then | |
| 306 tags = {}; | |
| 307 new = { name = stanza.name, attr = attr, namespaces = namespaces, tags = tags }; | |
| 308 else | |
| 309 tags = t_create(#stanza.tags, 0); | |
| 310 new = t_create(#stanza, 4); | |
| 311 new.name = stanza.name; | |
| 312 new.attr = attr; | |
| 313 new.namespaces = namespaces; | |
| 314 new.tags = tags; | |
| 315 end | |
| 316 | |
| 317 setmetatable(new, stanza_mt); | |
| 294 if not only_top then | 318 if not only_top then |
| 295 for i=1,#stanza do | 319 t_move(stanza, 1, #stanza, 1, new); |
| 296 local child = stanza[i]; | 320 t_move(stanza.tags, 1, #stanza.tags, 1, tags); |
| 297 if child.name then | 321 new:maptags(_clone); |
| 298 child = _clone(child); | 322 end |
| 299 t_insert(tags, child); | 323 return new; |
| 300 end | |
| 301 t_insert(new, child); | |
| 302 end | |
| 303 end | |
| 304 return setmetatable(new, stanza_mt); | |
| 305 end | 324 end |
| 306 | 325 |
| 307 local function clone(stanza, only_top) | 326 local function clone(stanza, only_top) |
| 308 if not is_stanza(stanza) then | 327 if not is_stanza(stanza) then |
| 309 error("bad argument to clone: expected stanza, got "..type(stanza)); | 328 error("bad argument to clone: expected stanza, got "..type(stanza)); |
| 383 if condition and text and extra_tag then | 402 if condition and text and extra_tag then |
| 384 break; | 403 break; |
| 385 end | 404 end |
| 386 end | 405 end |
| 387 return error_type, condition or "undefined-condition", text, extra_tag; | 406 return error_type, condition or "undefined-condition", text, extra_tag; |
| 407 end | |
| 408 | |
| 409 function stanza_mt.add_error(stanza, error_type, condition, error_message, error_by) | |
| 410 local extra; | |
| 411 if type(error_type) == "table" then -- an util.error or similar object | |
| 412 if type(error_type.extra) == "table" then | |
| 413 extra = error_type.extra; | |
| 414 end | |
| 415 if type(error_type.context) == "table" and type(error_type.context.by) == "string" then error_by = error_type.context.by; end | |
| 416 error_type, condition, error_message = error_type.type, error_type.condition, error_type.text; | |
| 417 end | |
| 418 if stanza.attr.from == error_by then | |
| 419 error_by = nil; | |
| 420 end | |
| 421 stanza:tag("error", {type = error_type, by = error_by}) --COMPAT: Some day xmlns:stanzas goes here | |
| 422 :tag(condition, xmpp_stanzas_attr); | |
| 423 if extra and condition == "gone" and type(extra.uri) == "string" then | |
| 424 stanza:text(extra.uri); | |
| 425 end | |
| 426 stanza:up(); | |
| 427 if error_message then stanza:text_tag("text", error_message, xmpp_stanzas_attr); end | |
| 428 if extra and is_stanza(extra.tag) then | |
| 429 stanza:add_child(extra.tag); | |
| 430 elseif extra and extra.namespace and extra.condition then | |
| 431 stanza:tag(extra.condition, { xmlns = extra.namespace }):up(); | |
| 432 end | |
| 433 return stanza:up(); | |
| 388 end | 434 end |
| 389 | 435 |
| 390 local function preserialize(stanza) | 436 local function preserialize(stanza) |
| 391 local s = { name = stanza.name, attr = stanza.attr }; | 437 local s = { name = stanza.name, attr = stanza.attr }; |
| 392 for _, child in ipairs(stanza) do | 438 for _, child in ipairs(stanza) do |
| 459 id = orig.attr.id, | 505 id = orig.attr.id, |
| 460 type = ((orig.name == "iq" and "result") or orig.attr.type) | 506 type = ((orig.name == "iq" and "result") or orig.attr.type) |
| 461 }); | 507 }); |
| 462 end | 508 end |
| 463 | 509 |
| 464 local xmpp_stanzas_attr = { xmlns = xmlns_stanzas }; | |
| 465 local function error_reply(orig, error_type, condition, error_message, error_by) | 510 local function error_reply(orig, error_type, condition, error_message, error_by) |
| 466 if not is_stanza(orig) then | 511 if not is_stanza(orig) then |
| 467 error("bad argument to error_reply: expected stanza, got "..type(orig)); | 512 error("bad argument to error_reply: expected stanza, got "..type(orig)); |
| 468 elseif orig.attr.type == "error" then | 513 elseif orig.attr.type == "error" then |
| 469 error("bad argument to error_reply: got stanza of type error which must not be replied to"); | 514 error("bad argument to error_reply: got stanza of type error which must not be replied to"); |
| 470 end | 515 end |
| 471 local t = reply(orig); | 516 local t = reply(orig); |
| 472 t.attr.type = "error"; | 517 t.attr.type = "error"; |
| 473 local extra; | 518 t:add_error(error_type, condition, error_message, error_by); |
| 474 if type(error_type) == "table" then -- an util.error or similar object | 519 t.last_add = { t[1] }; -- ready to add application-specific errors |
| 475 if type(error_type.extra) == "table" then | 520 return t; |
| 476 extra = error_type.extra; | |
| 477 end | |
| 478 if type(error_type.context) == "table" and type(error_type.context.by) == "string" then error_by = error_type.context.by; end | |
| 479 error_type, condition, error_message = error_type.type, error_type.condition, error_type.text; | |
| 480 end | |
| 481 if t.attr.from == error_by then | |
| 482 error_by = nil; | |
| 483 end | |
| 484 t:tag("error", {type = error_type, by = error_by}) --COMPAT: Some day xmlns:stanzas goes here | |
| 485 :tag(condition, xmpp_stanzas_attr); | |
| 486 if extra and condition == "gone" and type(extra.uri) == "string" then | |
| 487 t:text(extra.uri); | |
| 488 end | |
| 489 t:up(); | |
| 490 if error_message then t:text_tag("text", error_message, xmpp_stanzas_attr); end | |
| 491 if extra and is_stanza(extra.tag) then | |
| 492 t:add_child(extra.tag); | |
| 493 elseif extra and extra.namespace and extra.condition then | |
| 494 t:tag(extra.condition, { xmlns = extra.namespace }):up(); | |
| 495 end | |
| 496 return t; -- stanza ready for adding app-specific errors | |
| 497 end | 521 end |
| 498 | 522 |
| 499 local function presence(attr) | 523 local function presence(attr) |
| 500 return new_stanza("presence", attr); | 524 return new_stanza("presence", attr); |
| 501 end | 525 end |
