Comparison

util/stanza.lua @ 12687:5b69ecaf3427

util.stanza: Add add_error() to simplify adding error tags to existing stanzas Some fiddling is required now in error_reply() to ensure the cursor is in the same place as before this change (a lot of code apparently uses that feature).
author Matthew Wild <mwild1@gmail.com>
date Mon, 29 Aug 2022 14:59:46 +0100
parent 12636:e8934ce6ea0f
child 12725:12ced5db29b2
comparison
equal deleted inserted replaced
12686:5f182bccf33f 12687:5b69ecaf3427
27 local valid_utf8 = require "util.encodings".utf8.valid; 27 local valid_utf8 = require "util.encodings".utf8.valid;
28 28
29 local do_pretty_printing, termcolours = pcall(require, "util.termcolours"); 29 local do_pretty_printing, termcolours = pcall(require, "util.termcolours");
30 30
31 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 };
32 33
33 local _ENV = nil; 34 local _ENV = nil;
34 -- luacheck: std none 35 -- luacheck: std none
35 36
36 local stanza_mt = { __name = "stanza" }; 37 local stanza_mt = { __name = "stanza" };
394 end 395 end
395 end 396 end
396 return error_type, condition or "undefined-condition", text, extra_tag; 397 return error_type, condition or "undefined-condition", text, extra_tag;
397 end 398 end
398 399
400 function stanza_mt.add_error(stanza, error_type, condition, error_message, error_by)
401 local extra;
402 if type(error_type) == "table" then -- an util.error or similar object
403 if type(error_type.extra) == "table" then
404 extra = error_type.extra;
405 end
406 if type(error_type.context) == "table" and type(error_type.context.by) == "string" then error_by = error_type.context.by; end
407 error_type, condition, error_message = error_type.type, error_type.condition, error_type.text;
408 end
409 if stanza.attr.from == error_by then
410 error_by = nil;
411 end
412 stanza:tag("error", {type = error_type, by = error_by}) --COMPAT: Some day xmlns:stanzas goes here
413 :tag(condition, xmpp_stanzas_attr);
414 if extra and condition == "gone" and type(extra.uri) == "string" then
415 stanza:text(extra.uri);
416 end
417 stanza:up();
418 if error_message then stanza:text_tag("text", error_message, xmpp_stanzas_attr); end
419 if extra and is_stanza(extra.tag) then
420 stanza:add_child(extra.tag);
421 elseif extra and extra.namespace and extra.condition then
422 stanza:tag(extra.condition, { xmlns = extra.namespace }):up();
423 end
424 return stanza:up();
425 end
426
399 local function preserialize(stanza) 427 local function preserialize(stanza)
400 local s = { name = stanza.name, attr = stanza.attr }; 428 local s = { name = stanza.name, attr = stanza.attr };
401 for _, child in ipairs(stanza) do 429 for _, child in ipairs(stanza) do
402 if type(child) == "table" then 430 if type(child) == "table" then
403 t_insert(s, preserialize(child)); 431 t_insert(s, preserialize(child));
468 id = orig.attr.id, 496 id = orig.attr.id,
469 type = ((orig.name == "iq" and "result") or orig.attr.type) 497 type = ((orig.name == "iq" and "result") or orig.attr.type)
470 }); 498 });
471 end 499 end
472 500
473 local xmpp_stanzas_attr = { xmlns = xmlns_stanzas };
474 local function error_reply(orig, error_type, condition, error_message, error_by) 501 local function error_reply(orig, error_type, condition, error_message, error_by)
475 if not is_stanza(orig) then 502 if not is_stanza(orig) then
476 error("bad argument to error_reply: expected stanza, got "..type(orig)); 503 error("bad argument to error_reply: expected stanza, got "..type(orig));
477 elseif orig.attr.type == "error" then 504 elseif orig.attr.type == "error" then
478 error("bad argument to error_reply: got stanza of type error which must not be replied to"); 505 error("bad argument to error_reply: got stanza of type error which must not be replied to");
479 end 506 end
480 local t = reply(orig); 507 local t = reply(orig);
481 t.attr.type = "error"; 508 t.attr.type = "error";
482 local extra; 509 t:add_error(error_type, condition, error_message, error_by);
483 if type(error_type) == "table" then -- an util.error or similar object 510 t.last_add = { t[1] }; -- ready to add application-specific errors
484 if type(error_type.extra) == "table" then 511 return t;
485 extra = error_type.extra;
486 end
487 if type(error_type.context) == "table" and type(error_type.context.by) == "string" then error_by = error_type.context.by; end
488 error_type, condition, error_message = error_type.type, error_type.condition, error_type.text;
489 end
490 if t.attr.from == error_by then
491 error_by = nil;
492 end
493 t:tag("error", {type = error_type, by = error_by}) --COMPAT: Some day xmlns:stanzas goes here
494 :tag(condition, xmpp_stanzas_attr);
495 if extra and condition == "gone" and type(extra.uri) == "string" then
496 t:text(extra.uri);
497 end
498 t:up();
499 if error_message then t:text_tag("text", error_message, xmpp_stanzas_attr); end
500 if extra and is_stanza(extra.tag) then
501 t:add_child(extra.tag);
502 elseif extra and extra.namespace and extra.condition then
503 t:tag(extra.condition, { xmlns = extra.namespace }):up();
504 end
505 return t; -- stanza ready for adding app-specific errors
506 end 512 end
507 513
508 local function presence(attr) 514 local function presence(attr)
509 return new_stanza("presence", attr); 515 return new_stanza("presence", attr);
510 end 516 end