Add support for XEP-0100 jabber:iq:gateway
This commit is contained in:
@@ -14,6 +14,8 @@ For users
|
|||||||
- XMPP users can send multiline messages on IRC servers which support
|
- XMPP users can send multiline messages on IRC servers which support
|
||||||
draft/multiline, as well as IRC users sending multiline messages will appear as
|
draft/multiline, as well as IRC users sending multiline messages will appear as
|
||||||
one message on XMPP.
|
one message on XMPP.
|
||||||
|
- Add partial support for XEP-0100. Specifically section 6.3 "The
|
||||||
|
jabber:iq:gateway Protocol".
|
||||||
|
|
||||||
For admins
|
For admins
|
||||||
----------
|
----------
|
||||||
@@ -33,6 +35,7 @@ For packagers
|
|||||||
- The minimum required version of botan has been upgraded to version 3
|
- The minimum required version of botan has been upgraded to version 3
|
||||||
- clang 3.4 and gcc 5.0 are no longer supported. The new minimum required
|
- clang 3.4 and gcc 5.0 are no longer supported. The new minimum required
|
||||||
versions are clang >= 14 and gcc >= 11.2
|
versions are clang >= 14 and gcc >= 11.2
|
||||||
|
- Add optional curl library for XEP-0100 jabber:iq:gateway support
|
||||||
|
|
||||||
Version 9.0 - 2020-09-22
|
Version 9.0 - 2020-09-22
|
||||||
========================
|
========================
|
||||||
|
|||||||
@@ -131,6 +131,12 @@ elseif(NOT WITHOUT_POSTGRESQL)
|
|||||||
find_package(PQ)
|
find_package(PQ)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CURL)
|
||||||
|
find_package(CURL REQUIRED)
|
||||||
|
elseif(NOT WITHOUT_CURL)
|
||||||
|
find_package(CURL)
|
||||||
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
## Set all the include directories, depending on what libraries are used
|
## Set all the include directories, depending on what libraries are used
|
||||||
#
|
#
|
||||||
@@ -146,6 +152,9 @@ endif()
|
|||||||
if(UDNS_FOUND)
|
if(UDNS_FOUND)
|
||||||
include_directories(${UDNS_INCLUDE_DIRS})
|
include_directories(${UDNS_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
if(CURL_FOUND)
|
||||||
|
include_directories(${CURL_INCLUDE_DIRS})
|
||||||
|
endif()
|
||||||
|
|
||||||
# To be able to include the config.h and other files generated by cmake
|
# To be able to include the config.h and other files generated by cmake
|
||||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}/src/")
|
include_directories("${CMAKE_CURRENT_BINARY_DIR}/src/")
|
||||||
@@ -270,6 +279,10 @@ if(UDNS_FOUND)
|
|||||||
target_link_libraries(${PROJECT_NAME} ${UDNS_LIBRARIES})
|
target_link_libraries(${PROJECT_NAME} ${UDNS_LIBRARIES})
|
||||||
target_link_libraries(test_suite ${UDNS_LIBRARIES})
|
target_link_libraries(test_suite ${UDNS_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
if(CURL_FOUND)
|
||||||
|
target_link_libraries(${PROJECT_NAME} ${CURL_LIBRARIES})
|
||||||
|
target_link_libraries(test_suite ${CURL_LIBRARIES})
|
||||||
|
endif()
|
||||||
if(LIBIDN_FOUND)
|
if(LIBIDN_FOUND)
|
||||||
target_link_libraries(${PROJECT_NAME} ${LIBIDN_LIBRARIES})
|
target_link_libraries(${PROJECT_NAME} ${LIBIDN_LIBRARIES})
|
||||||
target_link_libraries(test_suite ${LIBIDN_LIBRARIES})
|
target_link_libraries(test_suite ${LIBIDN_LIBRARIES})
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ systemd_ (optional)
|
|||||||
Provides the support for a systemd service of Type=notify. This is useful only
|
Provides the support for a systemd service of Type=notify. This is useful only
|
||||||
if you are packaging biboumi in a distribution with Systemd.
|
if you are packaging biboumi in a distribution with Systemd.
|
||||||
|
|
||||||
|
curl_ (optional)
|
||||||
|
Provides support for XEP-0100 jabber:iq:gateway (to parse URL).
|
||||||
|
|
||||||
Customize
|
Customize
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@@ -189,6 +192,7 @@ man page biboumi(1)) or the usage page.
|
|||||||
.. _udns: http://www.corpit.ru/mjt/udns.html
|
.. _udns: http://www.corpit.ru/mjt/udns.html
|
||||||
.. _sqlite3: https://sqlite.org
|
.. _sqlite3: https://sqlite.org
|
||||||
.. _systemd: https://www.freedesktop.org/wiki/Software/systemd/
|
.. _systemd: https://www.freedesktop.org/wiki/Software/systemd/
|
||||||
|
.. _curl: https://curl.se/
|
||||||
.. _biboumi.1.rst: doc/biboumi.1.rst
|
.. _biboumi.1.rst: doc/biboumi.1.rst
|
||||||
.. _gcrypt: https://www.gnu.org/software/libgcrypt/
|
.. _gcrypt: https://www.gnu.org/software/libgcrypt/
|
||||||
.. _libpq: https://www.postgresql.org/docs/current/static/libpq.html
|
.. _libpq: https://www.postgresql.org/docs/current/static/libpq.html
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
FROM docker.io/alpine:latest as builder
|
FROM docker.io/alpine:latest as builder
|
||||||
|
|
||||||
RUN apk add --no-cache --virtual .build cmake expat-dev g++ git libidn-dev \
|
RUN apk add --no-cache --virtual .build cmake expat-dev g++ git curl-dev libidn-dev \
|
||||||
make postgresql-dev python3 sqlite-dev udns-dev util-linux-dev botan3-dev
|
make postgresql-dev python3 sqlite-dev udns-dev util-linux-dev botan3-dev
|
||||||
|
|
||||||
COPY . /source
|
COPY . /source
|
||||||
@@ -31,7 +31,7 @@ RUN mkdir build && cd build && \
|
|||||||
|
|
||||||
FROM docker.io/alpine:latest
|
FROM docker.io/alpine:latest
|
||||||
|
|
||||||
RUN apk add --no-cache libidn libpq libstdc++ libuuid postgresql-libs \
|
RUN apk add --no-cache libcurl libidn libpq libstdc++ libuuid postgresql-libs \
|
||||||
sqlite-libs udns expat ca-certificates botan3
|
sqlite-libs udns expat ca-certificates botan3
|
||||||
|
|
||||||
COPY --from=builder /etc/biboumi /etc/biboumi
|
COPY --from=builder /etc/biboumi /etc/biboumi
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ make \
|
|||||||
cmake \
|
cmake \
|
||||||
g++ \
|
g++ \
|
||||||
libuuid \
|
libuuid \
|
||||||
|
curl-dev \
|
||||||
udns-dev \
|
udns-dev \
|
||||||
expat-dev \
|
expat-dev \
|
||||||
libidn-dev \
|
libidn-dev \
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ make \
|
|||||||
cmake \
|
cmake \
|
||||||
g++ \
|
g++ \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
|
libcurl4-openssl-dev \
|
||||||
libuuid1 \
|
libuuid1 \
|
||||||
libudns-dev \
|
libudns-dev \
|
||||||
libexpat1-dev \
|
libexpat1-dev \
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ libidn-devel \
|
|||||||
sqlite-devel \
|
sqlite-devel \
|
||||||
botan3-devel \
|
botan3-devel \
|
||||||
systemd-devel \
|
systemd-devel \
|
||||||
|
libcurl-devel \
|
||||||
libuuid-devel \
|
libuuid-devel \
|
||||||
libgcrypt-devel \
|
libgcrypt-devel \
|
||||||
postgresql-devel \
|
postgresql-devel \
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#cmakedefine USE_DATABASE
|
#cmakedefine USE_DATABASE
|
||||||
#cmakedefine ICONV_SECOND_ARGUMENT_IS_CONST
|
#cmakedefine ICONV_SECOND_ARGUMENT_IS_CONST
|
||||||
#cmakedefine LIBIDN_FOUND
|
#cmakedefine LIBIDN_FOUND
|
||||||
|
#cmakedefine CURL_FOUND
|
||||||
#cmakedefine SYSTEMD_FOUND
|
#cmakedefine SYSTEMD_FOUND
|
||||||
#cmakedefine POLLER ${POLLER}
|
#cmakedefine POLLER ${POLLER}
|
||||||
#cmakedefine BOTAN_FOUND
|
#cmakedefine BOTAN_FOUND
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#include <irc/irc_uri.hpp>
|
||||||
|
|
||||||
|
#include <utils/split.hpp>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
IrcUri::IrcUri(const std::string &uri) {
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
this->url = curl_url();
|
||||||
|
curl_url_set(this->url, CURLUPART_URL, uri.c_str(), CURLU_NON_SUPPORT_SCHEME | CURLU_NO_AUTHORITY);
|
||||||
|
#endif
|
||||||
|
(void)uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrcUri::~IrcUri(void) {
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
curl_url_cleanup(this->url);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::optional<std::string> IrcUri::get_server(void) const {
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
char *server;
|
||||||
|
CURLUcode rc = curl_url_get(this->url, CURLUPART_HOST, &server, 0);
|
||||||
|
if (rc) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return server;
|
||||||
|
#else
|
||||||
|
return std::nullopt;
|
||||||
|
#endif // CURL_FOUND
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::optional<std::string> IrcUri::get_entity(void) const {
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
char *entity;
|
||||||
|
std::string output;
|
||||||
|
CURLUcode rc;
|
||||||
|
rc = curl_url_get(this->url, CURLUPART_PATH, &entity, CURLU_URLDECODE);
|
||||||
|
if (rc)
|
||||||
|
return std::nullopt;
|
||||||
|
output = entity;
|
||||||
|
if (!output.empty())
|
||||||
|
output.erase(0, 1);
|
||||||
|
if (output.empty()) {
|
||||||
|
rc = curl_url_get(this->url, CURLUPART_FRAGMENT, &entity, CURLU_URLDECODE);
|
||||||
|
if (rc)
|
||||||
|
return std::nullopt;
|
||||||
|
output = entity;
|
||||||
|
output.insert(0, 1, '#');
|
||||||
|
}
|
||||||
|
return IrcUri::parse_entity(output);
|
||||||
|
#else
|
||||||
|
return std::nullopt;
|
||||||
|
#endif // CURL_FOUND
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string IrcUri::parse_entity(const std::string entity) {
|
||||||
|
const std::vector<std::string> entity_name_and_type =
|
||||||
|
utils::split(entity, ',');
|
||||||
|
|
||||||
|
if (entity_name_and_type.size() > 0)
|
||||||
|
return entity_name_and_type.at(0);
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <biboumi.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <xmpp/jid.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <curl/urlapi.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and keeps information about one IRC URI
|
||||||
|
*
|
||||||
|
* https://datatracker.ietf.org/doc/html/draft-butcher-irc-url-04
|
||||||
|
*
|
||||||
|
* Requires CURL
|
||||||
|
*/
|
||||||
|
class IrcUri
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit IrcUri(const std::string &uri);
|
||||||
|
~IrcUri(void);
|
||||||
|
|
||||||
|
IrcUri(const IrcUri&) = delete;
|
||||||
|
IrcUri(IrcUri&&) = delete;
|
||||||
|
IrcUri& operator=(const IrcUri&) = delete;
|
||||||
|
IrcUri& operator=(IrcUri&&) = delete;
|
||||||
|
|
||||||
|
const std::optional<std::string> get_server(void) const;
|
||||||
|
const std::optional<std::string> get_entity(void) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
CURLU *url;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const std::string parse_entity(const std::string entity);
|
||||||
|
};
|
||||||
@@ -1,19 +1,23 @@
|
|||||||
#include <xmpp/biboumi_component.hpp>
|
#include <xmpp/biboumi_component.hpp>
|
||||||
|
|
||||||
|
#include <utils/empty_if_fixed_server.hpp>
|
||||||
#include <utils/timed_events.hpp>
|
#include <utils/timed_events.hpp>
|
||||||
#include <utils/scopeguard.hpp>
|
#include <utils/scopeguard.hpp>
|
||||||
#include <utils/tolower.hpp>
|
#include <utils/tolower.hpp>
|
||||||
#include <logger/logger.hpp>
|
#include <logger/logger.hpp>
|
||||||
#include <xmpp/adhoc_command.hpp>
|
#include <xmpp/adhoc_command.hpp>
|
||||||
#include <xmpp/biboumi_adhoc_commands.hpp>
|
#include <xmpp/biboumi_adhoc_commands.hpp>
|
||||||
|
#include <xmpp/xmpp_component.hpp>
|
||||||
#include <bridge/list_element.hpp>
|
#include <bridge/list_element.hpp>
|
||||||
#include <utils/encoding.hpp>
|
#include <utils/encoding.hpp>
|
||||||
#include <config/config.hpp>
|
#include <config/config.hpp>
|
||||||
#include <utils/time.hpp>
|
#include <utils/time.hpp>
|
||||||
#include <xmpp/jid.hpp>
|
#include <xmpp/jid.hpp>
|
||||||
|
#include <irc/irc_uri.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
@@ -449,9 +453,10 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
|
|||||||
// the scopeguard.
|
// the scopeguard.
|
||||||
std::string error_type("cancel");
|
std::string error_type("cancel");
|
||||||
std::string error_name("internal-server-error");
|
std::string error_name("internal-server-error");
|
||||||
utils::ScopeGuard stanza_error([this, &from, &to_str, &id, &error_type, &error_name](){
|
std::string error_text("");
|
||||||
|
utils::ScopeGuard stanza_error([this, &from, &to_str, &id, &error_type, &error_name, &error_text](){
|
||||||
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, error_text);
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
if (type == "set")
|
if (type == "set")
|
||||||
@@ -518,6 +523,21 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
|
|||||||
this->send_stanza(response);
|
this->send_stanza(response);
|
||||||
stanza_error.disable();
|
stanza_error.disable();
|
||||||
}
|
}
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
else if ((query = stanza.get_child("query", GATEWAY_NS))) {
|
||||||
|
std::optional<Stanza> stanza =
|
||||||
|
this->handle_iq_gateway(query, &to, from, id);
|
||||||
|
if (stanza.has_value()) {
|
||||||
|
this->send_stanza(stanza.value());
|
||||||
|
stanza_error.disable();
|
||||||
|
} else {
|
||||||
|
error_name = "bad-request";
|
||||||
|
error_type = "modify";
|
||||||
|
error_text = "Invalid input. Check that the provided link is a valid irc URI";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CURL_FOUND
|
||||||
#ifdef USE_DATABASE
|
#ifdef USE_DATABASE
|
||||||
else if ((query = stanza.get_child("query", MAM_NS)))
|
else if ((query = stanza.get_child("query", MAM_NS)))
|
||||||
{
|
{
|
||||||
@@ -673,6 +693,28 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
|
|||||||
}
|
}
|
||||||
stanza_error.disable();
|
stanza_error.disable();
|
||||||
}
|
}
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
else if ((query = stanza.get_child("query", GATEWAY_NS)))
|
||||||
|
{
|
||||||
|
Stanza iq("iq");
|
||||||
|
{
|
||||||
|
iq["from"] = to_str;
|
||||||
|
iq["to"] = from;
|
||||||
|
iq["id"] = id;
|
||||||
|
iq["type"] = "result";
|
||||||
|
XmlSubNode query(iq, GATEWAY_NS, "query");
|
||||||
|
{
|
||||||
|
query["xmlns"] = GATEWAY_NS;
|
||||||
|
XmlSubNode desc(query, "desc");
|
||||||
|
desc.set_inner("Enter an IRC URI. For example "
|
||||||
|
"irc://irc.example.com/#channame");
|
||||||
|
XmlSubNode prompt(query, "prompt");
|
||||||
|
prompt.set_inner("IRC URI");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this->send_stanza(iq);
|
||||||
|
}
|
||||||
|
#endif // CURL_FOUND
|
||||||
#ifdef USE_DATABASE
|
#ifdef USE_DATABASE
|
||||||
else if ((query = stanza.get_child("query", MUC_OWNER_NS)))
|
else if ((query = stanza.get_child("query", MUC_OWNER_NS)))
|
||||||
{
|
{
|
||||||
@@ -736,6 +778,50 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
|
|||||||
error_name = "feature-not-implemented";
|
error_name = "feature-not-implemented";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
std::optional<Stanza>
|
||||||
|
BiboumiComponent::handle_iq_gateway(const Stanza *stanza, const Jid *from,
|
||||||
|
const std::string to,
|
||||||
|
const std::string id) {
|
||||||
|
const XmlNode *prompt = stanza->get_child("prompt", GATEWAY_NS);
|
||||||
|
const std::string inner = prompt->get_inner();
|
||||||
|
|
||||||
|
std::string local;
|
||||||
|
bool is_irc_uri =
|
||||||
|
(inner.starts_with("irc://") || inner.starts_with("ircs://"));
|
||||||
|
if (is_irc_uri) {
|
||||||
|
IrcUri irc_uri(inner);
|
||||||
|
const std::optional<std::string> entity = irc_uri.get_entity();
|
||||||
|
const std::optional<std::string> server = irc_uri.get_server();
|
||||||
|
const std::string irc_server = utils::empty_if_fixed_server("%" + server.value_or(""));
|
||||||
|
if (irc_server != "%")
|
||||||
|
local = entity.value_or("") + irc_server;
|
||||||
|
} else {
|
||||||
|
Iid i(inner, this->get_user_bridge(to));
|
||||||
|
const std::string iid_local = i.get_local();
|
||||||
|
if (!iid_local.empty())
|
||||||
|
local = iid_local + utils::empty_if_fixed_server("%" + i.get_server());
|
||||||
|
}
|
||||||
|
if (local.empty())
|
||||||
|
return std::nullopt;
|
||||||
|
Jid j(local + "@" + from->domain);
|
||||||
|
Stanza iq("iq");
|
||||||
|
{
|
||||||
|
iq["from"] = from->full();
|
||||||
|
iq["to"] = to;
|
||||||
|
iq["id"] = id;
|
||||||
|
iq["type"] = "result";
|
||||||
|
XmlSubNode query(iq, GATEWAY_NS, "query");
|
||||||
|
{
|
||||||
|
query["xmlns"] = GATEWAY_NS;
|
||||||
|
XmlSubNode jid(query, "jid");
|
||||||
|
jid.set_inner(j.full());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return iq;
|
||||||
|
}
|
||||||
|
#endif // CURL_FOUND
|
||||||
|
|
||||||
#ifdef USE_DATABASE
|
#ifdef USE_DATABASE
|
||||||
bool BiboumiComponent::handle_mam_request(const Stanza& stanza)
|
bool BiboumiComponent::handle_mam_request(const Stanza& stanza)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ public:
|
|||||||
void send_invitation(const std::string& room_target, const std::string& jid_to, const std::string& author_nick);
|
void send_invitation(const std::string& room_target, const std::string& jid_to, const std::string& author_nick);
|
||||||
private:
|
private:
|
||||||
void send_invitation_from_fulljid(const std::string& room_target, const std::string& jid_to, const std::string& from);
|
void send_invitation_from_fulljid(const std::string& room_target, const std::string& jid_to, const std::string& 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
|
||||||
public:
|
public:
|
||||||
void accept_subscription(const std::string& from, const std::string& to);
|
void accept_subscription(const std::string& from, const std::string& to);
|
||||||
void ask_subscription(const std::string& from, const std::string& to);
|
void ask_subscription(const std::string& from, const std::string& to);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#define STABLE_MUC_ID_NS "http://jabber.org/protocol/muc#stable_id"
|
#define STABLE_MUC_ID_NS "http://jabber.org/protocol/muc#stable_id"
|
||||||
#define SELF_PING_FLAG MUC_NS"#self-ping-optimization"
|
#define SELF_PING_FLAG MUC_NS"#self-ping-optimization"
|
||||||
#define MESSAGE_CORRECT_NS "urn:xmpp:message-correct:0"
|
#define MESSAGE_CORRECT_NS "urn:xmpp:message-correct:0"
|
||||||
|
#define GATEWAY_NS "jabber:iq:gateway"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An XMPP component, communicating with an XMPP server using the protocole
|
* An XMPP component, communicating with an XMPP server using the protocole
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ def match(stanza, xpath):
|
|||||||
'disco_info': 'http://jabber.org/protocol/disco#info',
|
'disco_info': 'http://jabber.org/protocol/disco#info',
|
||||||
'muc_traffic': 'http://jabber.org/protocol/muc#traffic',
|
'muc_traffic': 'http://jabber.org/protocol/muc#traffic',
|
||||||
'disco_items': 'http://jabber.org/protocol/disco#items',
|
'disco_items': 'http://jabber.org/protocol/disco#items',
|
||||||
|
'gateway': 'jabber:iq:gateway',
|
||||||
'commands': 'http://jabber.org/protocol/commands',
|
'commands': 'http://jabber.org/protocol/commands',
|
||||||
'dataform': 'jabber:x:data',
|
'dataform': 'jabber:x:data',
|
||||||
'version': 'jabber:iq:version',
|
'version': 'jabber:iq:version',
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
from scenarios import *
|
||||||
|
|
||||||
|
conf = 'fixed_server'
|
||||||
|
|
||||||
|
def _test_case(input: str, output: str):
|
||||||
|
return (
|
||||||
|
send_stanza(f"<iq type='set' to='{{biboumi_host}}' from='{{jid_one}}/{{resource_one}}' id='iq1' xmlns='jabber:client'><query xmlns='jabber:iq:gateway'><prompt>{input}</prompt></query></iq>"),
|
||||||
|
expect_stanza(f"/iq[@type='result'][@to='{{jid_one}}/{{resource_one}}'][@from='{{biboumi_host}}']/gateway:query/gateway:jid[text()='{output}']"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def _error_case(input: str):
|
||||||
|
return (
|
||||||
|
send_stanza(f"<iq type='set' to='{{biboumi_host}}' from='{{jid_one}}/{{resource_one}}' id='iq1' xmlns='jabber:client'><query xmlns='jabber:iq:gateway'><prompt>{input}</prompt></query></iq>"),
|
||||||
|
expect_stanza(f"/iq[@type='error'][@to='{{jid_one}}/{{resource_one}}'][@from='{{biboumi_host}}']/error[@type='modify']/stanza:bad-request"),
|
||||||
|
)
|
||||||
|
|
||||||
|
scenario = (
|
||||||
|
*_test_case("ircs://{irc_host_one}/%23test", "#test@{biboumi_host}"),
|
||||||
|
*_test_case("ircs://{irc_host_one}/#test", "#test@{biboumi_host}"),
|
||||||
|
*_test_case("irc://{irc_host_one}/%23test", "#test@{biboumi_host}"),
|
||||||
|
*_test_case("irc://{irc_host_one}/#test", "#test@{biboumi_host}"),
|
||||||
|
*_test_case("ircs:///#test", "#test@{biboumi_host}"),
|
||||||
|
*_test_case("irc:///#test", "#test@{biboumi_host}"),
|
||||||
|
# TODO: Some applications use the following URL scheme which should be supported
|
||||||
|
# *_test_case("ircs:///user,isuser", "user@{biboumi_host}"),
|
||||||
|
# *_test_case("irc:///user,isuser", "user@{biboumi_host}"),
|
||||||
|
*_test_case("#test", "#test@{biboumi_host}"),
|
||||||
|
*_test_case("#test%{irc_host_one}", "#test%{irc_host_one}@{biboumi_host}"),
|
||||||
|
*_test_case("nick", "nick@{biboumi_host}"),
|
||||||
|
*_test_case("{nick_one}%{irc_host_one}", "{lower_nick_one}%{irc_host_one}@{biboumi_host}"),
|
||||||
|
*_error_case(""),
|
||||||
|
*_error_case("irc://"),
|
||||||
|
*_error_case("irc:// asdf"),
|
||||||
|
*_error_case("ircs://"),
|
||||||
|
*_error_case("ircs:// asdf"),
|
||||||
|
)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
from scenarios import *
|
||||||
|
|
||||||
|
def _test_case(input: str, output: str):
|
||||||
|
return (
|
||||||
|
send_stanza(f"<iq type='set' to='{{biboumi_host}}' from='{{jid_one}}/{{resource_one}}' id='iq1' xmlns='jabber:client'><query xmlns='jabber:iq:gateway'><prompt>{input}</prompt></query></iq>"),
|
||||||
|
expect_stanza(f"/iq[@type='result'][@to='{{jid_one}}/{{resource_one}}'][@from='{{biboumi_host}}']/gateway:query/gateway:jid[text()='{output}']"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def _error_case(input: str):
|
||||||
|
return (
|
||||||
|
send_stanza(f"<iq type='set' to='{{biboumi_host}}' from='{{jid_one}}/{{resource_one}}' id='iq1' xmlns='jabber:client'><query xmlns='jabber:iq:gateway'><prompt>{input}</prompt></query></iq>"),
|
||||||
|
expect_stanza(f"/iq[@type='error'][@to='{{jid_one}}/{{resource_one}}'][@from='{{biboumi_host}}']/error[@type='modify']/stanza:bad-request"),
|
||||||
|
)
|
||||||
|
|
||||||
|
scenario = (
|
||||||
|
*_test_case("ircs://{irc_host_one}/%23test", "#test%{irc_host_one}@{biboumi_host}"),
|
||||||
|
*_test_case("ircs://{irc_host_one}/#test", "#test%{irc_host_one}@{biboumi_host}"),
|
||||||
|
*_test_case("irc://{irc_host_one}/%23test", "#test%{irc_host_one}@{biboumi_host}"),
|
||||||
|
*_test_case("irc://{irc_host_one}/#test", "#test%{irc_host_one}@{biboumi_host}"),
|
||||||
|
*_test_case("#test%{irc_host_one}", "#test%{irc_host_one}@{biboumi_host}"),
|
||||||
|
*_test_case("{nick_one}%{irc_host_one}", "{lower_nick_one}%{irc_host_one}@{biboumi_host}"),
|
||||||
|
*_error_case(""),
|
||||||
|
*_error_case("#test"),
|
||||||
|
*_error_case("{lower_nick_one}"),
|
||||||
|
*_error_case("irc:///#test"),
|
||||||
|
*_error_case("irc://"),
|
||||||
|
*_error_case("irc:// asdf"),
|
||||||
|
*_error_case("ircs:///#test"),
|
||||||
|
*_error_case("ircs://"),
|
||||||
|
*_error_case("ircs:// asdf"),
|
||||||
|
)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#include <biboumi.h>
|
||||||
|
|
||||||
|
#include "catch2/catch_test_macros.hpp"
|
||||||
|
#include "catch2/generators/catch_generators.hpp"
|
||||||
|
|
||||||
|
#include <irc/irc_uri.hpp>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#ifdef CURL_FOUND
|
||||||
|
TEST_CASE("URI") {
|
||||||
|
auto scheme = GENERATE("irc", "ircs");
|
||||||
|
auto i = GENERATE("%23channame", "%23channame,ischannel", "#channame",
|
||||||
|
"#channame,ischannel");
|
||||||
|
const std::string input =
|
||||||
|
std::string(scheme) + "://irc.example.com/" + std::string(i);
|
||||||
|
IrcUri uri(input);
|
||||||
|
CHECK(uri.get_server() == "irc.example.com");
|
||||||
|
CHECK(uri.get_entity() == "#channame");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
TEST_CASE("No CURL") {
|
||||||
|
auto scheme = GENERATE("irc", "ircs");
|
||||||
|
auto i = GENERATE("%23channame", "%23channame,ischannel", "#channame",
|
||||||
|
"#channame,ischannel");
|
||||||
|
const std::string input =
|
||||||
|
std::string(scheme) + "://irc.example.com/" + std::string(i);
|
||||||
|
IrcUri uri(input);
|
||||||
|
CHECK(uri.get_server() == std::nullopt);
|
||||||
|
CHECK(uri.get_entity() == std::nullopt);
|
||||||
|
}
|
||||||
|
#endif // CURL_FOUND
|
||||||
Reference in New Issue
Block a user