Change the way the namespaces are handled in the XmlNode class
This commit is contained in:
+6
-5
@@ -154,14 +154,15 @@ int main()
|
|||||||
xml.add_stanza_callback([](const Stanza& stanza)
|
xml.add_stanza_callback([](const Stanza& stanza)
|
||||||
{
|
{
|
||||||
std::cout << stanza.to_string() << std::endl;
|
std::cout << stanza.to_string() << std::endl;
|
||||||
assert(stanza.get_name() == "stream_ns:stanza");
|
assert(stanza.get_name() == "stanza");
|
||||||
|
assert(stanza.get_tag("xmlns") == "stream_ns");
|
||||||
assert(stanza.get_tag("b") == "c");
|
assert(stanza.get_tag("b") == "c");
|
||||||
assert(stanza.get_inner() == "inner");
|
assert(stanza.get_inner() == "inner");
|
||||||
assert(stanza.get_tail() == "");
|
assert(stanza.get_tail() == "");
|
||||||
assert(stanza.get_child("stream_ns:child1") != nullptr);
|
assert(stanza.get_child("child1", "stream_ns") != nullptr);
|
||||||
assert(stanza.get_child("stream_ns:child2") == nullptr);
|
assert(stanza.get_child("child2", "stream_ns") == nullptr);
|
||||||
assert(stanza.get_child("child2_ns:child2") != nullptr);
|
assert(stanza.get_child("child2", "child2_ns") != nullptr);
|
||||||
assert(stanza.get_child("child2_ns:child2")->get_tail() == "tail");
|
assert(stanza.get_child("child2", "child2_ns")->get_tail() == "tail");
|
||||||
});
|
});
|
||||||
xml.feed(doc.data(), doc.size(), true);
|
xml.feed(doc.data(), doc.size(), true);
|
||||||
|
|
||||||
|
|||||||
+17
-29
@@ -17,19 +17,6 @@
|
|||||||
# include <systemd/sd-daemon.h>
|
# include <systemd/sd-daemon.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define STREAM_NS "http://etherx.jabber.org/streams"
|
|
||||||
#define COMPONENT_NS "jabber:component:accept"
|
|
||||||
#define MUC_NS "http://jabber.org/protocol/muc"
|
|
||||||
#define MUC_USER_NS MUC_NS"#user"
|
|
||||||
#define MUC_ADMIN_NS MUC_NS"#admin"
|
|
||||||
#define DISCO_NS "http://jabber.org/protocol/disco"
|
|
||||||
#define DISCO_ITEMS_NS DISCO_NS"#items"
|
|
||||||
#define DISCO_INFO_NS DISCO_NS"#info"
|
|
||||||
#define XHTMLIM_NS "http://jabber.org/protocol/xhtml-im"
|
|
||||||
#define STANZA_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
|
|
||||||
#define STREAMS_NS "urn:ietf:params:xml:ns:xmpp-streams"
|
|
||||||
#define VERSION_NS "jabber:iq:version"
|
|
||||||
|
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
unsigned long XmppComponent::current_id = 0;
|
unsigned long XmppComponent::current_id = 0;
|
||||||
@@ -106,7 +93,8 @@ void XmppComponent::on_connection_failed(const std::string& reason)
|
|||||||
void XmppComponent::on_connected()
|
void XmppComponent::on_connected()
|
||||||
{
|
{
|
||||||
log_info("connected to XMPP server");
|
log_info("connected to XMPP server");
|
||||||
XmlNode node("stream:stream", nullptr);
|
XmlNode node("", nullptr);
|
||||||
|
node.set_name("stream:stream");
|
||||||
node["xmlns"] = COMPONENT_NS;
|
node["xmlns"] = COMPONENT_NS;
|
||||||
node["xmlns:stream"] = STREAM_NS;
|
node["xmlns:stream"] = STREAM_NS;
|
||||||
node["to"] = this->served_hostname;
|
node["to"] = this->served_hostname;
|
||||||
@@ -183,7 +171,7 @@ void XmppComponent::on_remote_stream_open(const XmlNode& node)
|
|||||||
sprintf(digest + (i*2), "%02x", result[i]);
|
sprintf(digest + (i*2), "%02x", result[i]);
|
||||||
digest[HASH_LENGTH * 2] = '\0';
|
digest[HASH_LENGTH * 2] = '\0';
|
||||||
|
|
||||||
Stanza handshake("handshake");
|
Stanza handshake(COMPONENT_NS":handshake");
|
||||||
handshake.set_inner(digest);
|
handshake.set_inner(digest);
|
||||||
handshake.close();
|
handshake.close();
|
||||||
this->send_stanza(handshake);
|
this->send_stanza(handshake);
|
||||||
@@ -329,7 +317,7 @@ void XmppComponent::handle_presence(const Stanza& stanza)
|
|||||||
}
|
}
|
||||||
else if (type == "unavailable")
|
else if (type == "unavailable")
|
||||||
{
|
{
|
||||||
XmlNode* status = stanza.get_child(COMPONENT_NS":status");
|
XmlNode* status = stanza.get_child("status", COMPONENT_NS);
|
||||||
bridge->leave_irc_channel(std::move(iid), status ? std::move(status->get_inner()) : "");
|
bridge->leave_irc_channel(std::move(iid), status ? std::move(status->get_inner()) : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,19 +351,19 @@ void XmppComponent::handle_message(const Stanza& stanza)
|
|||||||
this->send_stanza_error("message", from, to_str, id,
|
this->send_stanza_error("message", from, to_str, id,
|
||||||
error_type, error_name, "");
|
error_type, error_name, "");
|
||||||
});
|
});
|
||||||
XmlNode* body = stanza.get_child(COMPONENT_NS":body");
|
XmlNode* body = stanza.get_child("body", COMPONENT_NS);
|
||||||
if (type == "groupchat")
|
if (type == "groupchat")
|
||||||
{
|
{
|
||||||
if (to.resource.empty())
|
if (to.resource.empty())
|
||||||
if (body && !body->get_inner().empty())
|
if (body && !body->get_inner().empty())
|
||||||
bridge->send_channel_message(iid, body->get_inner());
|
bridge->send_channel_message(iid, body->get_inner());
|
||||||
XmlNode* subject = stanza.get_child(COMPONENT_NS":subject");
|
XmlNode* subject = stanza.get_child("subject", COMPONENT_NS);
|
||||||
if (subject)
|
if (subject)
|
||||||
bridge->set_channel_topic(iid, subject->get_inner());
|
bridge->set_channel_topic(iid, subject->get_inner());
|
||||||
}
|
}
|
||||||
else if (type == "error")
|
else if (type == "error")
|
||||||
{
|
{
|
||||||
const XmlNode* error = stanza.get_child(COMPONENT_NS":error");
|
const XmlNode* error = stanza.get_child("error", COMPONENT_NS);
|
||||||
// Only a set of errors are considered “fatal”. If we encounter one of
|
// Only a set of errors are considered “fatal”. If we encounter one of
|
||||||
// them, we purge (we disconnect the user from all the IRC servers).
|
// them, we purge (we disconnect the user from all the IRC servers).
|
||||||
// We consider this to be true, unless the error condition is
|
// We consider this to be true, unless the error condition is
|
||||||
@@ -436,13 +424,13 @@ void XmppComponent::handle_iq(const Stanza& stanza)
|
|||||||
utils::ScopeGuard stanza_error([&](){
|
utils::ScopeGuard stanza_error([&](){
|
||||||
this->send_stanza_error("iq", from, to_str, id,
|
this->send_stanza_error("iq", from, to_str, id,
|
||||||
error_type, error_name, "");
|
error_type, error_name, "");
|
||||||
});
|
});
|
||||||
if (type == "set")
|
if (type == "set")
|
||||||
{
|
{
|
||||||
XmlNode* query;
|
XmlNode* query;
|
||||||
if ((query = stanza.get_child(MUC_ADMIN_NS":query")))
|
if ((query = stanza.get_child("query", MUC_ADMIN_NS)))
|
||||||
{
|
{
|
||||||
const XmlNode* child = query->get_child(MUC_ADMIN_NS":item");
|
const XmlNode* child = query->get_child("item", MUC_ADMIN_NS);
|
||||||
if (child)
|
if (child)
|
||||||
{
|
{
|
||||||
std::string nick = child->get_tag("nick");
|
std::string nick = child->get_tag("nick");
|
||||||
@@ -450,7 +438,7 @@ void XmppComponent::handle_iq(const Stanza& stanza)
|
|||||||
if (!nick.empty() && role == "none")
|
if (!nick.empty() && role == "none")
|
||||||
{ // This is a kick
|
{ // This is a kick
|
||||||
std::string reason;
|
std::string reason;
|
||||||
XmlNode* reason_el = child->get_child(MUC_ADMIN_NS":reason");
|
XmlNode* reason_el = child->get_child("reason", MUC_ADMIN_NS);
|
||||||
if (reason_el)
|
if (reason_el)
|
||||||
reason = reason_el->get_inner();
|
reason = reason_el->get_inner();
|
||||||
Iid iid(to.local);
|
Iid iid(to.local);
|
||||||
@@ -463,7 +451,7 @@ void XmppComponent::handle_iq(const Stanza& stanza)
|
|||||||
else if (type == "get")
|
else if (type == "get")
|
||||||
{
|
{
|
||||||
XmlNode* query;
|
XmlNode* query;
|
||||||
if ((query = stanza.get_child(DISCO_INFO_NS":query")))
|
if ((query = stanza.get_child("query", DISCO_INFO_NS)))
|
||||||
{ // Disco info
|
{ // Disco info
|
||||||
if (to_str == this->served_hostname)
|
if (to_str == this->served_hostname)
|
||||||
{ // On the gateway itself
|
{ // On the gateway itself
|
||||||
@@ -476,11 +464,11 @@ void XmppComponent::handle_iq(const Stanza& stanza)
|
|||||||
{
|
{
|
||||||
stanza_error.disable();
|
stanza_error.disable();
|
||||||
XmlNode* query;
|
XmlNode* query;
|
||||||
if ((query = stanza.get_child(VERSION_NS":query")))
|
if ((query = stanza.get_child("query", VERSION_NS)))
|
||||||
{
|
{
|
||||||
XmlNode* name_node = query->get_child(VERSION_NS":name");
|
XmlNode* name_node = query->get_child("name", VERSION_NS);
|
||||||
XmlNode* version_node = query->get_child(VERSION_NS":version");
|
XmlNode* version_node = query->get_child("version", VERSION_NS);
|
||||||
XmlNode* os_node = query->get_child(VERSION_NS":os");
|
XmlNode* os_node = query->get_child("os", VERSION_NS);
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string version;
|
std::string version;
|
||||||
std::string os;
|
std::string os;
|
||||||
@@ -500,7 +488,7 @@ void XmppComponent::handle_iq(const Stanza& stanza)
|
|||||||
|
|
||||||
void XmppComponent::handle_error(const Stanza& stanza)
|
void XmppComponent::handle_error(const Stanza& stanza)
|
||||||
{
|
{
|
||||||
XmlNode* text = stanza.get_child(STREAMS_NS":text");
|
XmlNode* text = stanza.get_child("text", STREAMS_NS);
|
||||||
std::string error_message("Unspecified error");
|
std::string error_message("Unspecified error");
|
||||||
if (text)
|
if (text)
|
||||||
error_message = text->get_inner();
|
error_message = text->get_inner();
|
||||||
|
|||||||
@@ -9,6 +9,20 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#define STREAM_NS "http://etherx.jabber.org/streams"
|
||||||
|
#define COMPONENT_NS "jabber:component:accept"
|
||||||
|
#define MUC_NS "http://jabber.org/protocol/muc"
|
||||||
|
#define MUC_USER_NS MUC_NS"#user"
|
||||||
|
#define MUC_ADMIN_NS MUC_NS"#admin"
|
||||||
|
#define DISCO_NS "http://jabber.org/protocol/disco"
|
||||||
|
#define DISCO_ITEMS_NS DISCO_NS"#items"
|
||||||
|
#define DISCO_INFO_NS DISCO_NS"#info"
|
||||||
|
#define XHTMLIM_NS "http://jabber.org/protocol/xhtml-im"
|
||||||
|
#define STANZA_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
|
||||||
|
#define STREAMS_NS "urn:ietf:params:xml:ns:xmpp-streams"
|
||||||
|
#define VERSION_NS "jabber:iq:version"
|
||||||
|
#define ADHOC_NS "http://jabber.org/protocol/commands"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An XMPP component, communicating with an XMPP server using the protocole
|
* An XMPP component, communicating with an XMPP server using the protocole
|
||||||
* described in XEP-0114: Jabber Component Protocol
|
* described in XEP-0114: Jabber Component Protocol
|
||||||
|
|||||||
@@ -84,10 +84,18 @@ std::string xml_unescape(const std::string& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
XmlNode::XmlNode(const std::string& name, XmlNode* parent):
|
XmlNode::XmlNode(const std::string& name, XmlNode* parent):
|
||||||
name(name),
|
|
||||||
parent(parent),
|
parent(parent),
|
||||||
closed(false)
|
closed(false)
|
||||||
{
|
{
|
||||||
|
// split the namespace and the name
|
||||||
|
auto n = name.rfind(":");
|
||||||
|
if (n == std::string::npos)
|
||||||
|
this->name = name;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->name = name.substr(n+1);
|
||||||
|
this->attributes["xmlns"] = name.substr(0, n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlNode::XmlNode(const std::string& name):
|
XmlNode::XmlNode(const std::string& name):
|
||||||
@@ -144,11 +152,11 @@ std::string XmlNode::get_tail() const
|
|||||||
return xml_unescape(this->tail);
|
return xml_unescape(this->tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlNode* XmlNode::get_child(const std::string& name) const
|
XmlNode* XmlNode::get_child(const std::string& name, const std::string& xmlns) const
|
||||||
{
|
{
|
||||||
for (auto& child: this->children)
|
for (auto& child: this->children)
|
||||||
{
|
{
|
||||||
if (child->name == name)
|
if (child->name == name && child->get_tag("xmlns") == xmlns)
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -184,13 +192,14 @@ XmlNode* XmlNode::get_parent() const
|
|||||||
return this->parent;
|
return this->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XmlNode::set_name(const std::string& name)
|
||||||
|
{
|
||||||
|
this->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string XmlNode::get_name() const
|
const std::string XmlNode::get_name() const
|
||||||
{
|
{
|
||||||
const std::vector<std::string> splited = utils::split(this->name, ':', false);
|
return this->name;
|
||||||
if (splited.empty())
|
|
||||||
return "";
|
|
||||||
const std::string res = splited.back();
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string XmlNode::to_string() const
|
std::string XmlNode::to_string() const
|
||||||
@@ -209,7 +218,7 @@ std::string XmlNode::to_string() const
|
|||||||
res += child->to_string();
|
res += child->to_string();
|
||||||
if (this->closed)
|
if (this->closed)
|
||||||
{
|
{
|
||||||
res += "</" + this->name + ">";
|
res += "</" + this->get_name() + ">";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res += utils::remove_invalid_xml_chars(this->tail);
|
res += utils::remove_invalid_xml_chars(this->tail);
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Get a pointer to the first child element with that name
|
* Get a pointer to the first child element with that name
|
||||||
*/
|
*/
|
||||||
XmlNode* get_child(const std::string& name) const;
|
XmlNode* get_child(const std::string& name, const std::string& xmlns) const;
|
||||||
/**
|
/**
|
||||||
* Add a node child to this node. Assign this node to the child’s parent.
|
* Add a node child to this node. Assign this node to the child’s parent.
|
||||||
* Returns a pointer to the newly added child.
|
* Returns a pointer to the newly added child.
|
||||||
@@ -87,6 +87,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
void close();
|
void close();
|
||||||
XmlNode* get_parent() const;
|
XmlNode* get_parent() const;
|
||||||
|
void set_name(const std::string& name);
|
||||||
const std::string get_name() const;
|
const std::string get_name() const;
|
||||||
/**
|
/**
|
||||||
* Serialize the stanza into a string
|
* Serialize the stanza into a string
|
||||||
|
|||||||
Reference in New Issue
Block a user