From 5a5bb7f63222189ea0dcfbd387d5e34458ccefe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Dec 2016 18:28:44 +0100 Subject: Introduce a XmlSubNode class that automatically adds itself into its parent --- louloulibs/xmpp/adhoc_command.cpp | 32 +- louloulibs/xmpp/adhoc_commands_handler.cpp | 30 +- louloulibs/xmpp/xmpp_component.cpp | 539 ++++++++++++++--------------- louloulibs/xmpp/xmpp_stanza.hpp | 14 + src/xmpp/biboumi_adhoc_commands.cpp | 253 +++++--------- src/xmpp/biboumi_component.cpp | 227 ++++++------ tests/xmpp.cpp | 17 + 7 files changed, 513 insertions(+), 599 deletions(-) diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp index 99701d7..08d2d17 100644 --- a/louloulibs/xmpp/adhoc_command.cpp +++ b/louloulibs/xmpp/adhoc_command.cpp @@ -18,30 +18,24 @@ bool AdhocCommand::is_admin_only() const void PingStep1(XmppComponent&, AdhocSession&, XmlNode& command_node) { - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Pong"); - command_node.add_child(std::move(note)); } void HelloStep1(XmppComponent&, AdhocSession&, XmlNode& command_node) { - XmlNode x("jabber:x:data:x"); + XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; - XmlNode title("title"); + XmlSubNode title(x, "title"); title.set_inner("Configure your name."); - x.add_child(std::move(title)); - XmlNode instructions("instructions"); + XmlSubNode instructions(x, "instructions"); instructions.set_inner("Please provide your name."); - x.add_child(std::move(instructions)); - XmlNode name_field("field"); + XmlSubNode name_field(x, "field"); name_field["var"] = "name"; name_field["type"] = "text-single"; name_field["label"] = "Your name"; - XmlNode required("required"); - name_field.add_child(std::move(required)); - x.add_child(std::move(name_field)); - command_node.add_child(std::move(x)); + XmlSubNode required(name_field, "required"); } void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) @@ -60,21 +54,18 @@ void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) { if (const XmlNode* value = name_field->get_child("value", "jabber:x:data")) { - XmlNode note("note"); + command_node.delete_all_children(); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Hello "s + value->get_inner() + "!"s); - command_node.delete_all_children(); - command_node.add_child(std::move(note)); return; } } } command_node.delete_all_children(); - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); session.terminate(); } @@ -82,8 +73,7 @@ void Reload(XmppComponent&, AdhocSession&, XmlNode& command_node) { ::reload_process(); command_node.delete_all_children(); - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Configuration reloaded."); - command_node.add_child(std::move(note)); } diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp index 540cac0..d3ede2d 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -36,20 +36,16 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co auto command_it = this->commands.find(node); if (command_it == this->commands.end()) { - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "cancel"; - XmlNode condition(STANZA_NS":item-not-found"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":item-not-found"); } else if (command_it->second.is_admin_only() && Config::get("admin", "") != jid.local + "@" + jid.domain) { - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "cancel"; - XmlNode condition(STANZA_NS":forbidden"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":forbidden"); } else { @@ -68,11 +64,9 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co auto session_it = this->sessions.find(std::make_pair(sessionid, executor_jid)); if (session_it == this->sessions.end()) { - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); } else if (action == "execute" || action == "next" || action == "complete") { @@ -90,10 +84,8 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co else { command_node["status"] = "executing"; - XmlNode actions("actions"); - XmlNode next("next"); - actions.add_child(std::move(next)); - command_node.add_child(std::move(actions)); + XmlSubNode actions(command_node, "actions"); + XmlSubNode next(actions, "next"); } } else if (action == "cancel") @@ -104,11 +96,9 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co } else // unsupported action { - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); } } return command_node; diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index f0b0de7..e1b6131 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -172,12 +172,13 @@ void XmppComponent::on_stanza(const Stanza& stanza) void XmppComponent::send_stream_error(const std::string& name, const std::string& explanation) { - XmlNode node("stream:error"); - XmlNode error(name); - error["xmlns"] = STREAM_NS; - if (!explanation.empty()) - error.set_inner(explanation); - node.add_child(std::move(error)); + Stanza node("stream:error"); + { + XmlSubNode error(node, name); + error["xmlns"] = STREAM_NS; + if (!explanation.empty()) + error.set_inner(explanation); + } this->send_stanza(node); } @@ -187,31 +188,34 @@ void XmppComponent::send_stanza_error(const std::string& kind, const std::string const bool fulljid) { Stanza node(kind); - if (!to.empty()) - node["to"] = to; - if (!from.empty()) + { + if (!to.empty()) + node["to"] = to; + if (!from.empty()) + { + if (fulljid) + node["from"] = from; + else + node["from"] = from + "@" + this->served_hostname; + } + if (!id.empty()) + node["id"] = id; + node["type"] = "error"; { - if (fulljid) - node["from"] = from; - else - node["from"] = from + "@" + this->served_hostname; + XmlSubNode error(node, "error"); + error["type"] = error_type; + { + XmlSubNode inner_error(error, defined_condition); + inner_error["xmlns"] = STANZA_NS; + } + if (!text.empty()) + { + XmlSubNode text_node(error, "text"); + text_node["xmlns"] = STANZA_NS; + text_node.set_inner(text); + } } - if (!id.empty()) - node["id"] = id; - node["type"] = "error"; - XmlNode error("error"); - error["type"] = error_type; - XmlNode inner_error(defined_condition); - inner_error["xmlns"] = STANZA_NS; - error.add_child(std::move(inner_error)); - if (!text.empty()) - { - XmlNode text_node("text"); - text_node["xmlns"] = STANZA_NS; - text_node.set_inner(text); - error.add_child(std::move(text_node)); - } - node.add_child(std::move(error)); + } this->send_stanza(node); } @@ -264,38 +268,33 @@ void* XmppComponent::get_receive_buffer(const size_t size) const void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, const std::string& to, const std::string& type, const bool fulljid, const bool nocopy) { - XmlNode node("message"); - node["to"] = to; - if (fulljid) - node["from"] = from; - else - node["from"] = from + "@" + this->served_hostname; - if (!type.empty()) - node["type"] = type; - XmlNode body_node("body"); - body_node.set_inner(std::get<0>(body)); - node.add_child(std::move(body_node)); - if (std::get<1>(body)) - { - XmlNode html("html"); - html["xmlns"] = XHTMLIM_NS; - // Pass the ownership of the pointer to this xmlnode - html.add_child(std::move(std::get<1>(body))); - node.add_child(std::move(html)); - } - - if (nocopy) - { - XmlNode private_node("private"); - private_node["xmlns"] = "urn:xmpp:carbons:2"; - node.add_child(std::move(private_node)); - - XmlNode nocopy("no-copy"); - nocopy["xmlns"] = "urn:xmpp:hints"; - node.add_child(std::move(nocopy)); - } - - this->send_stanza(node); + Stanza message("message"); + { + message["to"] = to; + if (fulljid) + message["from"] = from; + else + message["from"] = from + "@" + this->served_hostname; + if (!type.empty()) + message["type"] = type; + XmlSubNode body_node(message, "body"); + body_node.set_inner(std::get<0>(body)); + if (std::get<1>(body)) + { + XmlSubNode html(message, "html"); + html["xmlns"] = XHTMLIM_NS; + // Pass the ownership of the pointer to this xmlnode + html.add_child(std::move(std::get<1>(body))); + } + if (nocopy) + { + XmlSubNode private_node(message, "private"); + private_node["xmlns"] = "urn:xmpp:carbons:2"; + XmlSubNode nocopy(message, "no-copy"); + nocopy["xmlns"] = "urn:xmpp:hints"; + } + } + this->send_stanza(message); } void XmppComponent::send_user_join(const std::string& from, @@ -306,34 +305,33 @@ void XmppComponent::send_user_join(const std::string& from, const std::string& to, const bool self) { - XmlNode node("presence"); - node["to"] = to; - node["from"] = from + "@" + this->served_hostname + "/" + nick; - - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - - XmlNode item("item"); - if (!affiliation.empty()) - item["affiliation"] = affiliation; - if (!role.empty()) - item["role"] = role; - if (!realjid.empty()) - { - const std::string preped_jid = jidprep(realjid); - if (!preped_jid.empty()) - item["jid"] = preped_jid; - } - x.add_child(std::move(item)); - - if (self) - { - XmlNode status("status"); - status["code"] = "110"; - x.add_child(std::move(status)); - } - node.add_child(std::move(x)); - this->send_stanza(node); + Stanza presence("presence"); + { + presence["to"] = to; + presence["from"] = from + "@" + this->served_hostname + "/" + nick; + + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + + XmlSubNode item(x, "item"); + if (!affiliation.empty()) + item["affiliation"] = affiliation; + if (!role.empty()) + item["role"] = role; + if (!realjid.empty()) + { + const std::string preped_jid = jidprep(realjid); + if (!preped_jid.empty()) + item["jid"] = preped_jid; + } + + if (self) + { + XmlSubNode status(x, "status"); + status["code"] = "110"; + } + } + this->send_stanza(presence); } void XmppComponent::send_invalid_room_error(const std::string& muc_name, @@ -341,44 +339,43 @@ void XmppComponent::send_invalid_room_error(const std::string& muc_name, const std::string& to) { Stanza presence("presence"); - if (!muc_name.empty()) - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; - else - presence["from"] = this->served_hostname; - presence["to"] = to; - presence["type"] = "error"; - XmlNode x("x"); - x["xmlns"] = MUC_NS; - presence.add_child(std::move(x)); - XmlNode error("error"); - error["by"] = muc_name + "@" + this->served_hostname; - error["type"] = "cancel"; - XmlNode item_not_found("item-not-found"); - item_not_found["xmlns"] = STANZA_NS; - error.add_child(std::move(item_not_found)); - XmlNode text("text"); - text["xmlns"] = STANZA_NS; - text["xml:lang"] = "en"; - text.set_inner(muc_name + - " is not a valid IRC channel name. A correct room jid is of the form: #%@" + - this->served_hostname); - error.add_child(std::move(text)); - presence.add_child(std::move(error)); + { + if (!muc_name.empty ()) + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; + else + presence["from"] = this->served_hostname; + presence["to"] = to; + presence["type"] = "error"; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_NS; + XmlSubNode error(presence, "error"); + error["by"] = muc_name + "@" + this->served_hostname; + error["type"] = "cancel"; + XmlSubNode item_not_found(error, "item-not-found"); + item_not_found["xmlns"] = STANZA_NS; + XmlSubNode text(error, "text"); + text["xmlns"] = STANZA_NS; + text["xml:lang"] = "en"; + text.set_inner(muc_name + + " is not a valid IRC channel name. A correct room jid is of the form: #%@" + + this->served_hostname); + } this->send_stanza(presence); } void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to, const std::string& who) { - XmlNode message("message"); - message["to"] = to; - if (who.empty()) - message["from"] = from + "@" + this->served_hostname; - else - message["from"] = from + "@" + this->served_hostname + "/" + who; - message["type"] = "groupchat"; - XmlNode subject("subject"); - subject.set_inner(std::get<0>(topic)); - message.add_child(std::move(subject)); + Stanza message("message"); + { + message["to"] = to; + if (who.empty()) + message["from"] = from + "@" + this->served_hostname; + else + message["from"] = from + "@" + this->served_hostname + "/" + who; + message["type"] = "groupchat"; + XmlSubNode subject(message, "subject"); + subject.set_inner(std::get<0>(topic)); + } this->send_stanza(message); } @@ -391,16 +388,18 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str else // Message from the room itself message["from"] = muc_name + "@" + this->served_hostname; message["type"] = "groupchat"; - XmlNode body("body"); - body.set_inner(std::get<0>(xmpp_body)); - message.add_child(std::move(body)); + + { + XmlSubNode body(message, "body"); + body.set_inner(std::get<0>(xmpp_body)); + } + if (std::get<1>(xmpp_body)) { - XmlNode html("html"); + XmlSubNode html(message, "html"); html["xmlns"] = XHTMLIM_NS; // Pass the ownership of the pointer to this xmlnode html.add_child(std::move(std::get<1>(xmpp_body))); - message.add_child(std::move(html)); } this->send_stanza(message); } @@ -415,41 +414,41 @@ void XmppComponent::send_history_message(const std::string& muc_name, const std: message["from"] = muc_name + "@" + this->served_hostname; message["type"] = "groupchat"; - XmlNode body("body"); - body.set_inner(body_txt); - message.add_child(std::move(body)); - - XmlNode delay("delay"); - delay["xmlns"] = DELAY_NS; - delay["from"] = muc_name + "@" + this->served_hostname; - delay["stamp"] = utils::to_string(timestamp); + { + XmlSubNode body(message, "body"); + body.set_inner(body_txt); + } + { + XmlSubNode delay(message, "delay"); + delay["xmlns"] = DELAY_NS; + delay["from"] = muc_name + "@" + this->served_hostname; + delay["stamp"] = utils::to_string(timestamp); + } - message.add_child(std::move(delay)); this->send_stanza(message); } void XmppComponent::send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self) { Stanza presence("presence"); - presence["to"] = jid_to; - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; - presence["type"] = "unavailable"; - const std::string message_str = std::get<0>(message); - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - if (self) - { - XmlNode status("status"); - status["code"] = "110"; - x.add_child(std::move(status)); - } - presence.add_child(std::move(x)); - if (!message_str.empty()) - { - XmlNode status("status"); - status.set_inner(message_str); - presence.add_child(std::move(status)); - } + { + presence["to"] = jid_to; + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; + presence["type"] = "unavailable"; + const std::string message_str = std::get<0>(message); + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + if (self) + { + XmlSubNode status(x, "status"); + status["code"] = "110"; + } + if (!message_str.empty()) + { + XmlSubNode status(presence, "status"); + status.set_inner(message_str); + } + } this->send_stanza(presence); } @@ -462,24 +461,22 @@ void XmppComponent::send_nick_change(const std::string& muc_name, const bool self) { Stanza presence("presence"); - presence["to"] = jid_to; - presence["from"] = muc_name + "@" + this->served_hostname + "/" + old_nick; - presence["type"] = "unavailable"; - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - XmlNode item("item"); - item["nick"] = new_nick; - x.add_child(std::move(item)); - XmlNode status("status"); - status["code"] = "303"; - x.add_child(std::move(status)); - if (self) - { - XmlNode status2("status"); - status2["code"] = "110"; - x.add_child(std::move(status2)); - } - presence.add_child(std::move(x)); + { + presence["to"] = jid_to; + presence["from"] = muc_name + "@" + this->served_hostname + "/" + old_nick; + presence["type"] = "unavailable"; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + XmlSubNode item(x, "item"); + item["nick"] = new_nick; + XmlSubNode status(x, "status"); + status["code"] = "303"; + if (self) + { + XmlSubNode status(x, "status"); + status["code"] = "110"; + } + } this->send_stanza(presence); this->send_user_join(muc_name, new_nick, "", affiliation, role, jid_to, self); @@ -489,32 +486,28 @@ void XmppComponent::kick_user(const std::string& muc_name, const std::string& ta const std::string& author, const std::string& jid_to, const bool self) { Stanza presence("presence"); - presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; - presence["to"] = jid_to; - presence["type"] = "unavailable"; - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - XmlNode item("item"); - item["affiliation"] = "none"; - item["role"] = "none"; - XmlNode actor("actor"); - actor["nick"] = author; - actor["jid"] = author; // backward compatibility with old clients - item.add_child(std::move(actor)); - XmlNode reason("reason"); - reason.set_inner(txt); - item.add_child(std::move(reason)); - x.add_child(std::move(item)); - XmlNode status("status"); - status["code"] = "307"; - x.add_child(std::move(status)); - if (self) - { - XmlNode status("status"); - status["code"] = "110"; - x.add_child(std::move(status)); - } - presence.add_child(std::move(x)); + { + presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; + presence["to"] = jid_to; + presence["type"] = "unavailable"; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + XmlSubNode item(x, "item"); + item["affiliation"] = "none"; + item["role"] = "none"; + XmlSubNode actor(item, "actor"); + actor["nick"] = author; + actor["jid"] = author; // backward compatibility with old clients + XmlSubNode reason(item, "reason"); + reason.set_inner(txt); + XmlSubNode status(x, "status"); + status["code"] = "307"; + if (self) + { + XmlSubNode status(x, "status"); + status["code"] = "110"; + } + } this->send_stanza(presence); } @@ -527,28 +520,26 @@ void XmppComponent::send_presence_error(const std::string& muc_name, const std::string& text) { Stanza presence("presence"); - presence["from"] = muc_name + "@" + this->served_hostname + "/" + nickname; - presence["to"] = jid_to; - presence["type"] = "error"; - XmlNode x("x"); - x["xmlns"] = MUC_NS; - presence.add_child(std::move(x)); - XmlNode error("error"); - error["by"] = muc_name + "@" + this->served_hostname; - error["type"] = type; - if (!text.empty()) - { - XmlNode text_node("text"); - text_node["xmlns"] = STANZA_NS; - text_node.set_inner(text); - error.add_child(std::move(text_node)); - } - if (!error_code.empty()) - error["code"] = error_code; - XmlNode subnode(condition); - subnode["xmlns"] = STANZA_NS; - error.add_child(std::move(subnode)); - presence.add_child(std::move(error)); + { + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nickname; + presence["to"] = jid_to; + presence["type"] = "error"; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_NS; + XmlSubNode error(presence, "error"); + error["by"] = muc_name + "@" + this->served_hostname; + error["type"] = type; + if (!text.empty()) + { + XmlSubNode text_node(error, "text"); + text_node["xmlns"] = STANZA_NS; + text_node.set_inner(text); + } + if (!error_code.empty()) + error["code"] = error_code; + XmlSubNode subnode(error, condition); + subnode["xmlns"] = STANZA_NS; + } this->send_stanza(presence); } @@ -559,15 +550,15 @@ void XmppComponent::send_affiliation_role_change(const std::string& muc_name, const std::string& jid_to) { Stanza presence("presence"); - presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; - presence["to"] = jid_to; - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - XmlNode item("item"); - item["affiliation"] = affiliation; - item["role"] = role; - x.add_child(std::move(item)); - presence.add_child(std::move(x)); + { + presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; + presence["to"] = jid_to; + XmlSubNode x(presence, "x"); + x["xmlns"] = MUC_USER_NS; + XmlSubNode item(x, "item"); + item["affiliation"] = affiliation; + item["role"] = role; + } this->send_stanza(presence); } @@ -579,27 +570,30 @@ void XmppComponent::send_version(const std::string& id, const std::string& jid_t iq["id"] = id; iq["to"] = jid_to; iq["from"] = jid_from; - XmlNode query("query"); - query["xmlns"] = VERSION_NS; - if (version.empty()) - { - XmlNode name("name"); - name.set_inner("biboumi"); - query.add_child(std::move(name)); - XmlNode version("version"); - version.set_inner(SOFTWARE_VERSION); - query.add_child(std::move(version)); - XmlNode os("os"); - os.set_inner(SYSTEM_NAME); - query.add_child(std::move(os)); + { + XmlSubNode query(iq, "query"); + query["xmlns"] = VERSION_NS; + if (version.empty()) + { + { + XmlSubNode name(query, "name"); + name.set_inner("biboumi"); + } + { + XmlSubNode version(query, "version"); + version.set_inner(SOFTWARE_VERSION); + } + { + XmlSubNode os(query, "os"); + os.set_inner(SYSTEM_NAME); + } } - else + else { - XmlNode name("name"); + XmlSubNode name(query, "name"); name.set_inner(version); - query.add_child(std::move(name)); } - iq.add_child(std::move(query)); + } this->send_stanza(iq); } @@ -608,24 +602,24 @@ void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::s const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler) { Stanza iq("iq"); - iq["type"] = "result"; - iq["id"] = id; - iq["to"] = requester_jid; - iq["from"] = from_jid; - XmlNode query("query"); - query["xmlns"] = DISCO_ITEMS_NS; - query["node"] = ADHOC_NS; - for (const auto& kv: adhoc_handler.get_commands()) - { - if (kv.second.is_admin_only() && !with_admin_only) - continue; - XmlNode item("item"); - item["jid"] = from_jid; - item["node"] = kv.first; - item["name"] = kv.second.name; - query.add_child(std::move(item)); - } - iq.add_child(std::move(query)); + { + iq["type"] = "result"; + iq["id"] = id; + iq["to"] = requester_jid; + iq["from"] = from_jid; + XmlSubNode query(iq, "query"); + query["xmlns"] = DISCO_ITEMS_NS; + query["node"] = ADHOC_NS; + for (const auto &kv: adhoc_handler.get_commands()) + { + if (kv.second.is_admin_only() && !with_admin_only) + continue; + XmlSubNode item(query, "item"); + item["jid"] = from_jid; + item["node"] = kv.first; + item["name"] = kv.second.name; + } + } this->send_stanza(iq); } @@ -633,13 +627,14 @@ void XmppComponent::send_iq_version_request(const std::string& from, const std::string& jid_to) { Stanza iq("iq"); - iq["type"] = "get"; - iq["id"] = "version_"s + XmppComponent::next_id(); - iq["from"] = from + "@" + this->served_hostname; - iq["to"] = jid_to; - XmlNode query("query"); - query["xmlns"] = VERSION_NS; - iq.add_child(std::move(query)); + { + iq["type"] = "get"; + iq["id"] = "version_"s + XmppComponent::next_id(); + iq["from"] = from + "@" + this->served_hostname; + iq["to"] = jid_to; + XmlSubNode query(iq, "query"); + query["xmlns"] = VERSION_NS; + } this->send_stanza(iq); } diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index 4ca758e..f4b3948 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -143,4 +143,18 @@ std::ostream& operator<<(std::ostream& os, const XmlNode& node); */ using Stanza = XmlNode; +class XmlSubNode: public XmlNode +{ +public: + XmlSubNode(XmlNode& parent_ref, const std::string& name): + XmlNode(name), + parent_to_add(parent_ref) + {} + ~XmlSubNode() + { + this->parent_to_add.add_child(std::move(*this)); + } +private: + XmlNode& parent_to_add; +}; \ No newline at end of file diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 309cd82..f6f3cd1 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -26,40 +26,31 @@ void DisconnectUserStep1(XmppComponent& xmpp_component, AdhocSession&, XmlNode& { auto& biboumi_component = static_cast(xmpp_component); - XmlNode x("jabber:x:data:x"); + XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; - XmlNode title("title"); + XmlSubNode title(x, "title"); title.set_inner("Disconnect a user from the gateway"); - x.add_child(std::move(title)); - XmlNode instructions("instructions"); + XmlSubNode instructions(x, "instructions"); instructions.set_inner("Choose a user JID and a quit message"); - x.add_child(std::move(instructions)); - XmlNode jids_field("field"); + XmlSubNode jids_field(x, "field"); jids_field["var"] = "jids"; jids_field["type"] = "list-multi"; jids_field["label"] = "The JIDs to disconnect"; - XmlNode required("required"); - jids_field.add_child(std::move(required)); + XmlSubNode required(jids_field, "required"); for (Bridge* bridge: biboumi_component.get_bridges()) { - XmlNode option("option"); + XmlSubNode option(jids_field, "option"); option["label"] = bridge->get_jid(); - XmlNode value("value"); + XmlSubNode value(option, "value"); value.set_inner(bridge->get_jid()); - option.add_child(std::move(value)); - jids_field.add_child(std::move(option)); } - x.add_child(std::move(jids_field)); - XmlNode message_field("field"); + XmlSubNode message_field(x, "field"); message_field["var"] = "quit-message"; message_field["type"] = "text-single"; message_field["label"] = "Quit message"; - XmlNode message_value("value"); + XmlSubNode message_value(message_field, "value"); message_value.set_inner("Disconnected by admin"); - message_field.add_child(std::move(message_value)); - x.add_child(std::move(message_field)); - command_node.add_child(std::move(x)); } void DisconnectUserStep2(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node) @@ -98,7 +89,7 @@ void DisconnectUserStep2(XmppComponent& xmpp_component, AdhocSession& session, X } command_node.delete_all_children(); - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; if (num == 0) note.set_inner("No user were disconnected."); @@ -106,15 +97,12 @@ void DisconnectUserStep2(XmppComponent& xmpp_component, AdhocSession& session, X note.set_inner("1 user has been disconnected."); else note.set_inner(std::to_string(num) + " users have been disconnected."); - command_node.add_child(std::move(note)); return; } } - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); session.terminate(); } @@ -127,43 +115,38 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman auto options = Database::get_global_options(owner.bare()); - XmlNode x("jabber:x:data:x"); + XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; - XmlNode title("title"); + XmlSubNode title(x, "title"); title.set_inner("Configure some global default settings."); - x.add_child(std::move(title)); - XmlNode instructions("instructions"); + XmlSubNode instructions(x, "instructions"); instructions.set_inner("Edit the form, to configure your global settings for the component."); - x.add_child(std::move(instructions)); - - XmlNode required("required"); - XmlNode max_histo_length("field"); + XmlSubNode max_histo_length(x, "field"); max_histo_length["var"] = "max_history_length"; max_histo_length["type"] = "text-single"; max_histo_length["label"] = "Max history length"; max_histo_length["desc"] = "The maximum number of lines in the history that the server sends when joining a channel"; - XmlNode value("value"); - value.set_inner(std::to_string(options.maxHistoryLength.value())); - max_histo_length.add_child(std::move(value)); - x.add_child(std::move(max_histo_length)); + { + XmlSubNode value(max_histo_length, "value"); + value.set_inner(std::to_string(options.maxHistoryLength.value())); + } - XmlNode record_history("field"); + XmlSubNode record_history(x, "field"); record_history["var"] = "record_history"; record_history["type"] = "boolean"; record_history["label"] = "Record history"; record_history["desc"] = "Whether to save the messages into the database, or not"; - value.set_name("value"); - if (options.recordHistory.value()) - value.set_inner("true"); - else - value.set_inner("false"); - record_history.add_child(std::move(value)); - x.add_child(std::move(record_history)); - - command_node.add_child(std::move(x)); + { + XmlSubNode value(record_history, "value"); + value.set_name("value"); + if (options.recordHistory.value()) + value.set_inner("true"); + else + value.set_inner("false"); + } } void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node) @@ -195,17 +178,14 @@ void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session, options.update(); command_node.delete_all_children(); - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Configuration successfully applied."); - command_node.add_child(std::move(note)); return; } - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); session.terminate(); } @@ -219,18 +199,16 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain, server_domain); - XmlNode x("jabber:x:data:x"); + XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; - XmlNode title("title"); + XmlSubNode title(x, "title"); title.set_inner("Configure the IRC server "s + server_domain); - x.add_child(std::move(title)); - XmlNode instructions("instructions"); + XmlSubNode instructions(x, "instructions"); instructions.set_inner("Edit the form, to configure the settings of the IRC server "s + server_domain); - x.add_child(std::move(instructions)); XmlNode required("required"); - XmlNode ports("field"); + XmlSubNode ports(x, "field"); ports["var"] = "ports"; ports["type"] = "text-multi"; ports["label"] = "Ports"; @@ -238,15 +216,13 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com auto vals = utils::split(options.ports.value(), ';', false); for (const auto& val: vals) { - XmlNode ports_value("value"); + XmlSubNode ports_value(ports, "value"); ports_value.set_inner(val); - ports.add_child(std::move(ports_value)); } ports.add_child(required); - x.add_child(std::move(ports)); #ifdef BOTAN_FOUND - XmlNode tls_ports("field"); + XmlSubNode tls_ports(x, "field"); tls_ports["var"] = "tls_ports"; tls_ports["type"] = "text-multi"; tls_ports["label"] = "TLS ports"; @@ -254,126 +230,105 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com vals = utils::split(options.tlsPorts.value(), ';', false); for (const auto& val: vals) { - XmlNode tls_ports_value("value"); + XmlSubNode tls_ports_value(tls_ports, "value"); tls_ports_value.set_inner(val); - tls_ports.add_child(std::move(tls_ports_value)); } tls_ports.add_child(required); - x.add_child(std::move(tls_ports)); - XmlNode verify_cert("field"); + XmlSubNode verify_cert(x, "field"); verify_cert["var"] = "verify_cert"; verify_cert["type"] = "boolean"; verify_cert["label"] = "Verify certificate"; verify_cert["desc"] = "Whether or not to abort the connection if the server’s TLS certificate is invalid"; - XmlNode verify_cert_value("value"); + XmlSubNode verify_cert_value(verify_cert, "value"); if (options.verifyCert.value()) verify_cert_value.set_inner("true"); else verify_cert_value.set_inner("false"); - verify_cert.add_child(std::move(verify_cert_value)); - x.add_child(std::move(verify_cert)); - XmlNode fingerprint("field"); + XmlSubNode fingerprint(x, "field"); fingerprint["var"] = "fingerprint"; fingerprint["type"] = "text-single"; fingerprint["label"] = "SHA-1 fingerprint of the TLS certificate to trust."; if (!options.trustedFingerprint.value().empty()) { - XmlNode fingerprint_value("value"); + XmlSubNode fingerprint_value(fingerprint, "value"); fingerprint_value.set_inner(options.trustedFingerprint.value()); - fingerprint.add_child(std::move(fingerprint_value)); } fingerprint.add_child(required); - x.add_child(std::move(fingerprint)); #endif - XmlNode pass("field"); + XmlSubNode pass(x, "field"); pass["var"] = "pass"; pass["type"] = "text-private"; pass["label"] = "Server password (to be used in a PASS command when connecting)"; if (!options.pass.value().empty()) { - XmlNode pass_value("value"); + XmlSubNode pass_value(pass, "value"); pass_value.set_inner(options.pass.value()); - pass.add_child(std::move(pass_value)); } pass.add_child(required); - x.add_child(std::move(pass)); - XmlNode after_cnt_cmd("field"); + XmlSubNode after_cnt_cmd(x, "field"); after_cnt_cmd["var"] = "after_connect_command"; after_cnt_cmd["type"] = "text-single"; after_cnt_cmd["desc"] = "Custom IRC command sent after the connection is established with the server."; after_cnt_cmd["label"] = "After-connection IRC command"; if (!options.afterConnectionCommand.value().empty()) { - XmlNode after_cnt_cmd_value("value"); + XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value"); after_cnt_cmd_value.set_inner(options.afterConnectionCommand.value()); - after_cnt_cmd.add_child(std::move(after_cnt_cmd_value)); } after_cnt_cmd.add_child(required); - x.add_child(std::move(after_cnt_cmd)); if (Config::get("realname_customization", "true") == "true") { - XmlNode username("field"); + XmlSubNode username(x, "field"); username["var"] = "username"; username["type"] = "text-single"; username["label"] = "Username"; if (!options.username.value().empty()) { - XmlNode username_value("value"); + XmlSubNode username_value(username, "value"); username_value.set_inner(options.username.value()); - username.add_child(std::move(username_value)); } username.add_child(required); - x.add_child(std::move(username)); - XmlNode realname("field"); + XmlSubNode realname(x, "field"); realname["var"] = "realname"; realname["type"] = "text-single"; realname["label"] = "Realname"; if (!options.realname.value().empty()) { - XmlNode realname_value("value"); + XmlSubNode realname_value(realname, "value"); realname_value.set_inner(options.realname.value()); - realname.add_child(std::move(realname_value)); } realname.add_child(required); - x.add_child(std::move(realname)); } - XmlNode encoding_out("field"); + XmlSubNode encoding_out(x, "field"); encoding_out["var"] = "encoding_out"; encoding_out["type"] = "text-single"; encoding_out["desc"] = "The encoding used when sending messages to the IRC server."; encoding_out["label"] = "Out encoding"; if (!options.encodingOut.value().empty()) { - XmlNode encoding_out_value("value"); + XmlSubNode encoding_out_value(encoding_out, "value"); encoding_out_value.set_inner(options.encodingOut.value()); - encoding_out.add_child(std::move(encoding_out_value)); } encoding_out.add_child(required); - x.add_child(std::move(encoding_out)); - XmlNode encoding_in("field"); + XmlSubNode encoding_in(x, "field"); encoding_in["var"] = "encoding_in"; encoding_in["type"] = "text-single"; encoding_in["desc"] = "The encoding used to decode message received from the IRC server."; encoding_in["label"] = "In encoding"; if (!options.encodingIn.value().empty()) { - XmlNode encoding_in_value("value"); + XmlSubNode encoding_in_value(encoding_in, "value"); encoding_in_value.set_inner(options.encodingIn.value()); - encoding_in.add_child(std::move(encoding_in_value)); } encoding_in.add_child(required); - x.add_child(std::move(encoding_in)); - - - command_node.add_child(std::move(x)); } void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) @@ -458,17 +413,14 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com options.update(); command_node.delete_all_children(); - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Configuration successfully applied."); - command_node.add_child(std::move(note)); return; } - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); session.terminate(); } @@ -480,46 +432,38 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co auto options = Database::get_irc_channel_options_with_server_default(owner.local + "@" + owner.domain, iid.get_server(), iid.get_local()); - XmlNode x("jabber:x:data:x"); + XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; - XmlNode title("title"); + XmlSubNode title(x, "title"); title.set_inner("Configure the IRC channel "s + iid.get_local() + " on server "s + iid.get_server()); - x.add_child(std::move(title)); - XmlNode instructions("instructions"); + XmlSubNode instructions(x, "instructions"); instructions.set_inner("Edit the form, to configure the settings of the IRC channel "s + iid.get_local()); - x.add_child(std::move(instructions)); XmlNode required("required"); - XmlNode encoding_out("field"); + XmlSubNode encoding_out(x, "field"); encoding_out["var"] = "encoding_out"; encoding_out["type"] = "text-single"; encoding_out["desc"] = "The encoding used when sending messages to the IRC server. Defaults to the server's “out encoding” if unset for the channel"; encoding_out["label"] = "Out encoding"; if (!options.encodingOut.value().empty()) { - XmlNode encoding_out_value("value"); + XmlSubNode encoding_out_value(encoding_out, "value"); encoding_out_value.set_inner(options.encodingOut.value()); - encoding_out.add_child(std::move(encoding_out_value)); } encoding_out.add_child(required); - x.add_child(std::move(encoding_out)); - XmlNode encoding_in("field"); + XmlSubNode encoding_in(x, "field"); encoding_in["var"] = "encoding_in"; encoding_in["type"] = "text-single"; encoding_in["desc"] = "The encoding used to decode message received from the IRC server. Defaults to the server's “in encoding” if unset for the channel"; encoding_in["label"] = "In encoding"; if (!options.encodingIn.value().empty()) { - XmlNode encoding_in_value("value"); + XmlSubNode encoding_in_value(encoding_in, "value"); encoding_in_value.set_inner(options.encodingIn.value()); - encoding_in.add_child(std::move(encoding_in_value)); } encoding_in.add_child(required); - x.add_child(std::move(encoding_in)); - - command_node.add_child(std::move(x)); } void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) @@ -548,17 +492,14 @@ void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& co options.update(); command_node.delete_all_children(); - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("Configuration successfully applied."); - command_node.add_child(std::move(note)); return; } - XmlNode error(ADHOC_NS":error"); + XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "modify"; - XmlNode condition(STANZA_NS":bad-request"); - error.add_child(std::move(condition)); - command_node.add_child(std::move(error)); + XmlSubNode condition(error, STANZA_NS":bad-request"); session.terminate(); } #endif // USE_DATABASE @@ -576,31 +517,24 @@ void DisconnectUserFromServerStep1(XmppComponent& xmpp_component, AdhocSession& { // Send a form to select the user to disconnect auto& biboumi_component = static_cast(xmpp_component); - XmlNode x("jabber:x:data:x"); + XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; - XmlNode title("title"); + XmlSubNode title(x, "title"); title.set_inner("Disconnect a user from selected IRC servers"); - x.add_child(std::move(title)); - XmlNode instructions("instructions"); + XmlSubNode instructions(x, "instructions"); instructions.set_inner("Choose a user JID"); - x.add_child(std::move(instructions)); - XmlNode jids_field("field"); + XmlSubNode jids_field(x, "field"); jids_field["var"] = "jid"; jids_field["type"] = "list-single"; jids_field["label"] = "The JID to disconnect"; - XmlNode required("required"); - jids_field.add_child(std::move(required)); + XmlSubNode required(jids_field, "required"); for (Bridge* bridge: biboumi_component.get_bridges()) { - XmlNode option("option"); + XmlSubNode option(jids_field, "option"); option["label"] = bridge->get_jid(); - XmlNode value("value"); + XmlSubNode value(option, "value"); value.set_inner(bridge->get_jid()); - option.add_child(std::move(value)); - jids_field.add_child(std::move(option)); } - x.add_child(std::move(jids_field)); - command_node.add_child(std::move(x)); } } @@ -628,53 +562,42 @@ void DisconnectUserFromServerStep2(XmppComponent& xmpp_component, AdhocSession& command_node.delete_all_children(); auto& biboumi_component = static_cast(xmpp_component); - XmlNode x("jabber:x:data:x"); + XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; - XmlNode title("title"); + XmlSubNode title(x, "title"); title.set_inner("Disconnect a user from selected IRC servers"); - x.add_child(std::move(title)); - XmlNode instructions("instructions"); + XmlSubNode instructions(x, "instructions"); instructions.set_inner("Choose one or more servers to disconnect this JID from"); - x.add_child(std::move(instructions)); - XmlNode jids_field("field"); + XmlSubNode jids_field(x, "field"); jids_field["var"] = "irc-servers"; jids_field["type"] = "list-multi"; jids_field["label"] = "The servers to disconnect from"; - XmlNode required("required"); - jids_field.add_child(std::move(required)); + XmlSubNode required(jids_field, "required"); Bridge* bridge = biboumi_component.find_user_bridge(jid_to_disconnect); if (!bridge || bridge->get_irc_clients().empty()) { - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner("User "s + jid_to_disconnect + " is not connected to any IRC server."); - command_node.add_child(std::move(note)); session.terminate(); return ; } for (const auto& pair: bridge->get_irc_clients()) { - XmlNode option("option"); + XmlSubNode option(jids_field, "option"); option["label"] = pair.first; - XmlNode value("value"); + XmlSubNode value(option, "value"); value.set_inner(pair.first); - option.add_child(std::move(value)); - jids_field.add_child(std::move(option)); } - x.add_child(std::move(jids_field)); - XmlNode message_field("field"); + XmlSubNode message_field(x, "field"); message_field["var"] = "quit-message"; message_field["type"] = "text-single"; message_field["label"] = "Quit message"; - XmlNode message_value("value"); + XmlSubNode message_value(message_field, "value"); message_value.set_inner("Killed by admin"); - message_field.add_child(std::move(message_value)); - x.add_child(std::move(message_field)); - - command_node.add_child(std::move(x)); } void DisconnectUserFromServerStep3(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node) @@ -719,14 +642,13 @@ void DisconnectUserFromServerStep3(XmppComponent& xmpp_component, AdhocSession& } } command_node.delete_all_children(); - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; std::string msg = jid_to_disconnect + " was disconnected from " + std::to_string(number) + " IRC server"; if (number > 1) msg += "s"; msg += "."; note.set_inner(msg); - command_node.add_child(std::move(note)); } void GetIrcConnectionInfoStep1(XmppComponent& component, AdhocSession& session, XmlNode& command_node) @@ -742,10 +664,9 @@ void GetIrcConnectionInfoStep1(XmppComponent& component, AdhocSession& session, utils::ScopeGuard sg([&message, &command_node]() { command_node.delete_all_children(); - XmlNode note("note"); + XmlSubNode note(command_node, "note"); note["type"] = "info"; note.set_inner(message); - command_node.add_child(std::move(note)); }); Bridge* bridge = biboumi_component.get_user_bridge(owner.bare()); diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index bd05bdc..985b252 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -625,39 +625,33 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) void BiboumiComponent::send_archived_message(const db::MucLogLine& log_line, const std::string& from, const std::string& to, const std::string& queryid) { - Stanza message("message"); + Stanza message("message"); + { message["from"] = from; message["to"] = to; - XmlNode result("result"); + XmlSubNode result(message, "result"); result["xmlns"] = MAM_NS; if (!queryid.empty()) result["queryid"] = queryid; result["id"] = log_line.uuid.value(); - XmlNode forwarded("forwarded"); + XmlSubNode forwarded(result, "forwarded"); forwarded["xmlns"] = FORWARD_NS; - XmlNode delay("delay"); + XmlSubNode delay(forwarded, "delay"); delay["xmlns"] = DELAY_NS; delay["stamp"] = utils::to_string(log_line.date.value().timeStamp()); - forwarded.add_child(std::move(delay)); - - XmlNode submessage("message"); + XmlSubNode submessage(forwarded, "message"); submessage["xmlns"] = CLIENT_NS; submessage["from"] = from + "/" + log_line.nick.value(); submessage["type"] = "groupchat"; - XmlNode body("body"); + XmlSubNode body(submessage, "body"); body.set_inner(log_line.body.value()); - submessage.add_child(std::move(body)); - - forwarded.add_child(std::move(submessage)); - result.add_child(std::move(forwarded)); - message.add_child(std::move(result)); - - this->send_stanza(message); + } + this->send_stanza(message); } #endif @@ -699,24 +693,23 @@ std::vector BiboumiComponent::get_bridges() const void BiboumiComponent::send_self_disco_info(const std::string& id, const std::string& jid_to) { Stanza iq("iq"); - iq["type"] = "result"; - iq["id"] = id; - iq["to"] = jid_to; - iq["from"] = this->served_hostname; - XmlNode query("query"); - query["xmlns"] = DISCO_INFO_NS; - XmlNode identity("identity"); - identity["category"] = "conference"; - identity["type"] = "irc"; - identity["name"] = "Biboumi XMPP-IRC gateway"; - query.add_child(std::move(identity)); - for (const char* ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS}) - { - XmlNode feature("feature"); - feature["var"] = ns; - query.add_child(std::move(feature)); - } - iq.add_child(std::move(query)); + { + iq["type"] = "result"; + iq["id"] = id; + iq["to"] = jid_to; + iq["from"] = this->served_hostname; + XmlSubNode query(iq, "query"); + query["xmlns"] = DISCO_INFO_NS; + XmlSubNode identity(query, "identity"); + identity["category"] = "conference"; + identity["type"] = "irc"; + identity["name"] = "Biboumi XMPP-IRC gateway"; + for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS}) + { + XmlSubNode feature(query, "feature"); + feature["var"] = ns; + } + } this->send_stanza(iq); } @@ -724,44 +717,42 @@ void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const s { Jid from(jid_from); Stanza iq("iq"); - iq["type"] = "result"; - iq["id"] = id; - iq["to"] = jid_to; - iq["from"] = jid_from; - XmlNode query("query"); - query["xmlns"] = DISCO_INFO_NS; - XmlNode identity("identity"); - identity["category"] = "conference"; - identity["type"] = "irc"; - identity["name"] = "IRC server "s + from.local + " over Biboumi"; - query.add_child(std::move(identity)); - for (const char* ns: {DISCO_INFO_NS, ADHOC_NS, PING_NS, VERSION_NS}) - { - XmlNode feature("feature"); - feature["var"] = ns; - query.add_child(std::move(feature)); - } - iq.add_child(std::move(query)); + { + iq["type"] = "result"; + iq["id"] = id; + iq["to"] = jid_to; + iq["from"] = jid_from; + XmlSubNode query(iq, "query"); + query["xmlns"] = DISCO_INFO_NS; + XmlSubNode identity(query, "identity"); + identity["category"] = "conference"; + identity["type"] = "irc"; + identity["name"] = "IRC server "s + from.local + " over Biboumi"; + for (const char *ns: {DISCO_INFO_NS, ADHOC_NS, PING_NS, VERSION_NS}) + { + XmlSubNode feature(query, "feature"); + feature["var"] = ns; + } + } this->send_stanza(iq); } void BiboumiComponent::send_irc_channel_muc_traffic_info(const std::string id, const std::string& jid_from, const std::string& jid_to) { Stanza iq("iq"); - iq["type"] = "result"; - iq["id"] = id; - iq["from"] = jid_from; - iq["to"] = jid_to; - - XmlNode query("query"); - query["xmlns"] = DISCO_INFO_NS; - query["node"] = MUC_TRAFFIC_NS; - // We drop all “special” traffic (like xhtml-im, chatstates, etc), so - // don’t include any - iq.add_child(std::move(query)); - + { + iq["type"] = "result"; + iq["id"] = id; + iq["from"] = jid_from; + iq["to"] = jid_to; + + XmlSubNode query(iq, "query"); + query["xmlns"] = DISCO_INFO_NS; + query["node"] = MUC_TRAFFIC_NS; + // We drop all “special” traffic (like xhtml-im, chatstates, etc), so + // don’t include any + } this->send_stanza(iq); - } void BiboumiComponent::send_ping_request(const std::string& from, @@ -769,13 +760,14 @@ void BiboumiComponent::send_ping_request(const std::string& from, const std::string& id) { Stanza iq("iq"); - iq["type"] = "get"; - iq["id"] = id; - iq["from"] = from + "@" + this->served_hostname; - iq["to"] = jid_to; - XmlNode ping("ping"); - ping["xmlns"] = PING_NS; - iq.add_child(std::move(ping)); + { + iq["type"] = "get"; + iq["id"] = id; + iq["from"] = from + "@" + this->served_hostname; + iq["to"] = jid_to; + XmlSubNode ping(iq, "ping"); + ping["xmlns"] = PING_NS; + } this->send_stanza(iq); auto result_cb = [from, id](Bridge* bridge, const Stanza& stanza) @@ -799,48 +791,43 @@ void BiboumiComponent::send_iq_room_list_result(const std::string& id, const std const ResultSetInfo& rs_info) { Stanza iq("iq"); - iq["from"] = from + "@" + this->served_hostname; - iq["to"] = to_jid; - iq["id"] = id; - iq["type"] = "result"; - XmlNode query("query"); - query["xmlns"] = DISCO_ITEMS_NS; + { + iq["from"] = from + "@" + this->served_hostname; + iq["to"] = to_jid; + iq["id"] = id; + iq["type"] = "result"; + XmlSubNode query(iq, "query"); + query["xmlns"] = DISCO_ITEMS_NS; for (auto it = begin; it != end; ++it) - { - XmlNode item("item"); + { + XmlSubNode item(query, "item"); item["jid"] = it->channel + "@" + this->served_hostname; - query.add_child(std::move(item)); - } - - if ((rs_info.max >= 0 || !rs_info.after.empty() || !rs_info.before.empty())) - { - XmlNode set_node("set"); - set_node["xmlns"] = RSM_NS; + } - if (begin != channel_list.channels.cend()) - { - XmlNode first_node("first"); - first_node["index"] = std::to_string(std::distance(channel_list.channels.cbegin(), begin)); - first_node.set_inner(begin->channel + "@" + this->served_hostname); - set_node.add_child(std::move(first_node)); - } - if (end != channel_list.channels.cbegin()) - { - XmlNode last_node("last"); - last_node.set_inner(std::prev(end)->channel + "@" + this->served_hostname); - set_node.add_child(std::move(last_node)); - } - if (channel_list.complete) - { - XmlNode count_node("count"); - count_node.set_inner(std::to_string(channel_list.channels.size())); - set_node.add_child(std::move(count_node)); - } - query.add_child(std::move(set_node)); - } + if ((rs_info.max >= 0 || !rs_info.after.empty() || !rs_info.before.empty())) + { + XmlSubNode set_node(query, "set"); + set_node["xmlns"] = RSM_NS; - iq.add_child(std::move(query)); + if (begin != channel_list.channels.cend()) + { + XmlSubNode first_node(set_node, "first"); + first_node["index"] = std::to_string(std::distance(channel_list.channels.cbegin(), begin)); + first_node.set_inner(begin->channel + "@" + this->served_hostname); + } + if (end != channel_list.channels.cbegin()) + { + XmlSubNode last_node(set_node, "last"); + last_node.set_inner(std::prev(end)->channel + "@" + this->served_hostname); + } + if (channel_list.complete) + { + XmlSubNode count_node(set_node, "count"); + count_node.set_inner(std::to_string(channel_list.channels.size())); + } + } + } this->send_stanza(iq); } @@ -849,17 +836,17 @@ void BiboumiComponent::send_invitation(const std::string& room_target, const std::string& author_nick) { Stanza message("message"); - message["from"] = room_target + "@" + this->served_hostname; - message["to"] = jid_to; - XmlNode x("x"); - x["xmlns"] = MUC_USER_NS; - XmlNode invite("invite"); - if (author_nick.empty()) - invite["from"] = room_target + "@" + this->served_hostname; - else - invite["from"] = room_target + "@" + this->served_hostname + "/" + author_nick; - x.add_child(std::move(invite)); - message.add_child(std::move(x)); + { + message["from"] = room_target + "@" + this->served_hostname; + message["to"] = jid_to; + XmlSubNode x(message, "x"); + x["xmlns"] = MUC_USER_NS; + XmlSubNode invite(x, "invite"); + if (author_nick.empty()) + invite["from"] = room_target + "@" + this->served_hostname; + else + invite["from"] = room_target + "@" + this->served_hostname + "/" + author_nick; + } this->send_stanza(message); } @@ -875,7 +862,7 @@ void BiboumiComponent::accept_subscription(const std::string& from, const std::s void BiboumiComponent::ask_subscription(const std::string& from, const std::string& to) { - Stanza presence("presence"); + Stanza presence("presence"); presence["from"] = from; presence["to"] = to; presence["id"] = this->next_id(); diff --git a/tests/xmpp.cpp b/tests/xmpp.cpp index 37d2b54..42b7c08 100644 --- a/tests/xmpp.cpp +++ b/tests/xmpp.cpp @@ -52,3 +52,20 @@ TEST_CASE("handshake_digest") const auto res = get_handshake_digest("id1234", "S4CR3T"); CHECK(res == "c92901b5d376ad56269914da0cce3aab976847df"); } + +TEST_CASE("substanzas") +{ + Stanza a("a"); + { + XmlSubNode b(a, "b"); + { + CHECK(!a.has_children()); + XmlSubNode c(b, "c"); + XmlSubNode d(b, "d"); + CHECK(!c.has_children()); + CHECK(!d.has_children()); + } + CHECK(b.has_children()); + } + CHECK(a.has_children()); +} \ No newline at end of file -- cgit v1.2.3