~singpolyma/biboumi

1c93afc9a7ec33d90c81062c3f1077b5cf84c212 — Florent Le Coz 10 years ago a350caf
Change the way the namespaces are handled in the XmlNode class
M src/test.cpp => src/test.cpp +6 -5
@@ 154,14 154,15 @@ int main()
  xml.add_stanza_callback([](const Stanza& stanza)
      {
        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_inner() == "inner");
        assert(stanza.get_tail() == "");
        assert(stanza.get_child("stream_ns:child1") != nullptr);
        assert(stanza.get_child("stream_ns:child2") == nullptr);
        assert(stanza.get_child("child2_ns:child2") != nullptr);
        assert(stanza.get_child("child2_ns:child2")->get_tail() == "tail");
        assert(stanza.get_child("child1", "stream_ns") != nullptr);
        assert(stanza.get_child("child2", "stream_ns") == nullptr);
        assert(stanza.get_child("child2", "child2_ns") != nullptr);
        assert(stanza.get_child("child2", "child2_ns")->get_tail() == "tail");
      });
  xml.feed(doc.data(), doc.size(), true);


M src/xmpp/xmpp_component.cpp => src/xmpp/xmpp_component.cpp +17 -29
@@ 17,19 17,6 @@
# include <systemd/sd-daemon.h>
#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;

unsigned long XmppComponent::current_id = 0;


@@ 106,7 93,8 @@ void XmppComponent::on_connection_failed(const std::string& reason)
void XmppComponent::on_connected()
{
  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:stream"] = STREAM_NS;
  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]);
  digest[HASH_LENGTH * 2] = '\0';

  Stanza handshake("handshake");
  Stanza handshake(COMPONENT_NS":handshake");
  handshake.set_inner(digest);
  handshake.close();
  this->send_stanza(handshake);


@@ 329,7 317,7 @@ void XmppComponent::handle_presence(const Stanza& stanza)
        }
      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()) : "");
        }
    }


@@ 363,19 351,19 @@ void XmppComponent::handle_message(const Stanza& stanza)
      this->send_stanza_error("message", from, to_str, id,
                              error_type, error_name, "");
        });
  XmlNode* body = stanza.get_child(COMPONENT_NS":body");
  XmlNode* body = stanza.get_child("body", COMPONENT_NS);
  if (type == "groupchat")
    {
      if (to.resource.empty())
        if (body && !body->get_inner().empty())
          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)
        bridge->set_channel_topic(iid, subject->get_inner());
    }
  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
      // them, we purge (we disconnect the user from all the IRC servers).
      // 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([&](){
      this->send_stanza_error("iq", from, to_str, id,
                              error_type, error_name, "");
        });
    });
  if (type == "set")
    {
      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)
            {
              std::string nick = child->get_tag("nick");


@@ 450,7 438,7 @@ void XmppComponent::handle_iq(const Stanza& stanza)
              if (!nick.empty() && role == "none")
                {               // This is a kick
                  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)
                    reason = reason_el->get_inner();
                  Iid iid(to.local);


@@ 463,7 451,7 @@ void XmppComponent::handle_iq(const Stanza& stanza)
  else if (type == "get")
    {
      XmlNode* query;
      if ((query = stanza.get_child(DISCO_INFO_NS":query")))
      if ((query = stanza.get_child("query", DISCO_INFO_NS)))
        { // Disco info
          if (to_str == this->served_hostname)
            { // On the gateway itself


@@ 476,11 464,11 @@ void XmppComponent::handle_iq(const Stanza& stanza)
    {
      stanza_error.disable();
      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* version_node = query->get_child(VERSION_NS":version");
          XmlNode* os_node = query->get_child(VERSION_NS":os");
          XmlNode* name_node = query->get_child("name", VERSION_NS);
          XmlNode* version_node = query->get_child("version", VERSION_NS);
          XmlNode* os_node = query->get_child("os", VERSION_NS);
          std::string name;
          std::string version;
          std::string os;


@@ 500,7 488,7 @@ void XmppComponent::handle_iq(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");
  if (text)
    error_message = text->get_inner();

M src/xmpp/xmpp_component.hpp => src/xmpp/xmpp_component.hpp +14 -0
@@ 9,6 9,20 @@
#include <memory>
#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
 * described in XEP-0114: Jabber Component Protocol

M src/xmpp/xmpp_stanza.cpp => src/xmpp/xmpp_stanza.cpp +18 -9
@@ 84,10 84,18 @@ std::string xml_unescape(const std::string& data)
}

XmlNode::XmlNode(const std::string& name, XmlNode* parent):
  name(name),
  parent(parent),
  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):


@@ 144,11 152,11 @@ std::string XmlNode::get_tail() const
  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)
    {
      if (child->name == name)
      if (child->name == name && child->get_tag("xmlns") == xmlns)
        return child;
    }
  return nullptr;


@@ 184,13 192,14 @@ XmlNode* XmlNode::get_parent() const
  return this->parent;
}

void XmlNode::set_name(const std::string& name)
{
  this->name = name;
}

const std::string XmlNode::get_name() const
{
  const std::vector<std::string> splited = utils::split(this->name, ':', false);
  if (splited.empty())
    return "";
  const std::string res = splited.back();
  return res;
  return this->name;
}

std::string XmlNode::to_string() const


@@ 209,7 218,7 @@ std::string XmlNode::to_string() const
        res += child->to_string();
      if (this->closed)
        {
          res += "</" + this->name + ">";
          res += "</" + this->get_name() + ">";
        }
    }
  res += utils::remove_invalid_xml_chars(this->tail);

M src/xmpp/xmpp_stanza.hpp => src/xmpp/xmpp_stanza.hpp +2 -1
@@ 69,7 69,7 @@ public:
  /**
   * 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.
   * Returns a pointer to the newly added child.


@@ 87,6 87,7 @@ public:
   */
  void close();
  XmlNode* get_parent() const;
  void set_name(const std::string& name);
  const std::string get_name() const;
  /**
   * Serialize the stanza into a string