Also support caps on irc server JIDs

This commit is contained in:
Stephen Paul Weber
2026-09-24 21:10:55 -05:00
parent 3dbbf5910e
commit 69b8797d3b
3 changed files with 75 additions and 29 deletions
+47 -28
View File
@@ -576,9 +576,10 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
}
else if (iid.type == Iid::Type::Server)
{
if (node.empty())
const std::string expected_node_name = std::string(NODE_NAME) + "#" + get_irc_server_ver(to_str);
if (node.empty() || node == expected_node_name)
{
this->send_irc_server_disco_info(id, from, to_str);
this->send_irc_server_disco_info(id, from, to_str, node);
stanza_error.disable();
}
}
@@ -1074,28 +1075,35 @@ void BiboumiComponent::send_self_disco_info(const std::string& id, const std::st
this->send_stanza(iq);
}
void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const std::string& jid_to, const std::string& jid_from)
void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const std::string& jid_to,
const std::string& jid_from, const std::string& node)
{
Stanza iq = get_irc_server_disco_info(jid_from, node);
iq["id"] = id;
iq["to"] = jid_to;
iq["from"] = jid_from;
this->send_stanza(iq);
}
Stanza BiboumiComponent::get_irc_server_disco_info(const std::string& jid_from, const std::string& node)
{
Jid from(jid_from);
Stanza iq("iq");
{
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"] = "gateway";
identity["type"] = "irc";
identity["name"] = "IRC server " + 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);
iq["type"] = "result";
XmlSubNode query(iq, "query");
query["xmlns"] = DISCO_INFO_NS;
if (!node.empty())
query["node"] = node;
XmlSubNode identity(query, "identity");
identity["category"] = "gateway";
identity["type"] = "irc";
identity["name"] = "IRC server " + from.local + " over Biboumi";
for (const char *ns: {DISCO_INFO_NS, CAPS_NS, ADHOC_NS, PING_NS, VERSION_NS})
{
XmlSubNode feature(query, "feature");
feature["var"] = ns;
}
return iq;
}
void BiboumiComponent::send_irc_channel_muc_traffic_info(const std::string& id, const std::string& jid_to, const std::string& jid_from)
@@ -1303,13 +1311,24 @@ void BiboumiComponent::send_presence_to_contact(const std::string& from, const s
if (!id.empty())
presence["id"] = id;
if (type.empty() && from == this->served_hostname) {
XmlSubNode c(presence, "c");
c["xmlns"] = CAPS_NS;
c["hash"] = "sha-1";
c["node"] = NODE_NAME;
c["ver"] = this->get_self_ver();
}
if (type.empty())
{
Jid from_jid(from);
const Iid from_iid(from_jid.local, {'&', '#', '+', '!'});
const std::string fixed_irc_server = Config::get("fixed_irc_server", "");
const bool is_server_jid = !from_jid.local.empty() && from_jid.resource.empty() &&
((fixed_irc_server.empty() && from_iid.type == Iid::Type::Server) ||
(!fixed_irc_server.empty() && from_jid.local == fixed_irc_server));
if (from == this->served_hostname ||
(from_jid.domain == this->served_hostname && is_server_jid))
{
XmlSubNode c(presence, "c");
c["xmlns"] = CAPS_NS;
c["hash"] = "sha-1";
c["node"] = NODE_NAME;
c["ver"] = from == this->served_hostname ? this->get_self_ver() : get_irc_server_ver(from);
}
}
this->send_stanza(presence);
}
+5 -1
View File
@@ -68,7 +68,8 @@ public:
/**
* Send a result IQ with the disco informations regarding IRC server JIDs.
*/
void send_irc_server_disco_info(const std::string& id, const std::string& jid_to, const std::string& jid_from);
void send_irc_server_disco_info(const std::string& id, const std::string& jid_to,
const std::string& jid_from, const std::string& node);
/**
* Sends the allowed namespaces in MUC message, according to
* http://xmpp.org/extensions/xep-0045.html#impl-service-traffic
@@ -93,6 +94,9 @@ private:
void send_invitation_from_fulljid(const std::string& room_target, const std::string& jid_to, const std::string& from);
static Stanza get_self_disco_info(const std::string &node);
static std::string get_self_ver() { return Xmpp::hash_disco_sha1(get_self_disco_info("")); };
static Stanza get_irc_server_disco_info(const std::string& jid_from, const std::string& node);
static std::string get_irc_server_ver(const std::string& jid_from)
{ return Xmpp::hash_disco_sha1(get_irc_server_disco_info(jid_from, "")); }
#ifdef CURL_FOUND
std::optional<Stanza> handle_iq_gateway(const Stanza *stanza, const Jid *from, const std::string to, const std::string id);
#endif
@@ -0,0 +1,23 @@
from scenarios import *
scenario = (
# IRC server JIDs advertise caps for their own disco info
send_stanza("<iq type='get' id='get6' from='{jid_one}/{resource_one}' to='{irc_server_one}'><query xmlns='http://jabber.org/protocol/disco#info'/></iq>"),
expect_stanza("/iq[@from='{irc_server_one}'][@to='{jid_one}/{resource_one}'][@type='result']/disco_info:query/disco_info:identity[@category='gateway'][@type='irc']",
"/iq/disco_info:query/disco_info:feature[@var='http://jabber.org/protocol/disco#info']",
"/iq/disco_info:query/disco_info:feature[@var='http://jabber.org/protocol/caps']"
),
send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/{nick_one}'><x xmlns='http://jabber.org/protocol/muc'/></presence>"),
sequences.connection(),
scenarios.simple_channel_join.expect_self_join_presence(),
send_stanza("<presence from='{jid_one}/{resource_one}' to='{irc_server_one}' type='subscribe'/>"),
expect_stanza("/presence[@from='{irc_server_one}'][@to='{jid_one}'][@type='subscribed']"),
expect_stanza("/presence[@from='{irc_server_one}'][@to='{jid_one}']/caps:c[@hash='sha-1'][@node][@ver]",
after = (
save_value("server_ver", extract_attribute("/presence/caps:c[@hash='sha-1'][@node][@ver]", "ver")),
save_value("server_node", extract_attribute("/presence/caps:c[@hash='sha-1'][@node][@ver]", "node")),
)
),
send_stanza("<iq type='get' id='get8' from='{jid_one}/{resource_one}' to='{irc_server_one}'><query xmlns='http://jabber.org/protocol/disco#info' node='{server_node}#{server_ver}'/></iq>"),
expect_stanza("/iq[@from='{irc_server_one}'][@type='result']/disco_info:query[@node='{server_node}#{server_ver}']"),
)