Page MenuHomePhorge

No OneTemporary

Size
11 KB
Referenced Files
None
Subscribers
None
diff --git a/src/matrix-link.cpp b/src/matrix-link.cpp
index 7ed81c2..ad02ec4 100644
--- a/src/matrix-link.cpp
+++ b/src/matrix-link.cpp
@@ -1,103 +1,149 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <kazv-defs.hpp>
#include <QUrl>
#include <QUrlQuery>
#include <QDebug>
#include <QString>
#include "matrix-link.hpp"
using namespace Qt::Literals::StringLiterals;
std::pair<MatrixLink::Type, QString> parseMatrixToComp(QString comp)
{
comp = QUrl(u"foo:#"_s + comp).fragment(QUrl::FullyDecoded);
if (comp.startsWith(u'@')) {
return {MatrixLink::User, comp};
} else if (comp.startsWith(u'#')) {
return {MatrixLink::RoomAlias, comp};
} else if (comp.startsWith(u'!')) {
return {MatrixLink::RoomId, comp};
} else if (comp.startsWith(u'$')) {
return {MatrixLink::Event, comp};
} else {
return {MatrixLink::None, comp};
}
}
QStringList parseMatrixToQuery(QString query)
{
auto q = QUrlQuery(query);
return q.allQueryItemValues(u"via"_s);
}
+std::pair<MatrixLink::Type, QString> parseMatrixSchemeComp(
+ const QString &type, const QString &id) {
+ if (type == u"u"_s) {
+ return {MatrixLink::User, u"@"_s + id};
+ } else if (type == u"r"_s) {
+ return {MatrixLink::RoomAlias, u"#"_s + id};
+ } else if (type == u"roomid"_s) {
+ return {MatrixLink::RoomId, u"!"_s + id};
+ } else if (type == u"e"_s) {
+ return {MatrixLink::Event, u"$"_s + id};
+ } else {
+ return {MatrixLink::None, id};
+ }
+}
+
+QString parseMatrixSchemeAction(QString query)
+{
+ auto q = QUrlQuery{query};
+ auto actions = q.allQueryItemValues(u"action"_s);
+ if (actions.isEmpty()) {
+ return u""_s;
+ } else {
+ return actions.last();
+ }
+}
+
MatrixLink::MatrixLink(const QUrl &url)
{
// matrix.to link
if (url.scheme() == u"https"_s
&& url.host() == u"matrix.to"_s) {
auto frag = url.fragment();
auto parts = frag.split(u'?');
QString ids = parts[0];
QString query = parts.size() > 1 ? parts[1] : u""_s;
auto comps = ids.split(u'/');
if (comps.empty() || !comps[0].isEmpty()) {
return;
}
comps.pop_front();
for (auto comp : comps) {
m_identifiers.push_back(parseMatrixToComp(comp));
}
m_routingServers = parseMatrixToQuery(query);
+ } else if (url.scheme() == u"matrix"_s) { // Matrix URI scheme
+ auto path = url.path();
+ auto query = url.query();
+ auto segments = path.split(u'/');
+ if (segments.size() != 2 && segments.size() != 4) {
+ return;
+ }
+ m_identifiers.push_back(
+ parseMatrixSchemeComp(segments[0], segments[1]));
+ if (segments.size() == 4) {
+ m_identifiers.push_back(
+ parseMatrixSchemeComp(segments[2], segments[3]));
+ }
+ m_routingServers = parseMatrixToQuery(query);
+ m_action = parseMatrixSchemeAction(query);
}
}
bool MatrixLink::isValid() const
{
return !m_identifiers.empty()
&& m_identifiers[0].first != None
&& m_identifiers[0].first != Event
&& (m_identifiers.size() == 1 || (
m_identifiers[1].first == Event
&& (m_identifiers[0].first == RoomId
|| m_identifiers[0].first == RoomAlias)));
}
bool MatrixLink::isUser() const
{
return isValid() && m_identifiers[0].first == User;
}
bool MatrixLink::isRoom() const
{
return isValid() && (
m_identifiers[0].first == RoomId
|| m_identifiers[0].first == RoomAlias);
}
bool MatrixLink::isEvent() const
{
return isValid() && m_identifiers.size() == 2;
}
QStringList MatrixLink::identifiers() const
{
QStringList ret;
for (auto [_, id] : m_identifiers) {
ret.push_back(id);
}
return ret;
}
QStringList MatrixLink::routingServers() const
{
return m_routingServers;
}
+
+QString MatrixLink::action() const
+{
+ return m_action;
+}
diff --git a/src/matrix-link.hpp b/src/matrix-link.hpp
index be928b8..544d6b2 100644
--- a/src/matrix-link.hpp
+++ b/src/matrix-link.hpp
@@ -1,50 +1,52 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include <kazv-defs.hpp>
#include <tuple>
#include <vector>
#include <QObject>
#include <QStringList>
class QUrl;
/**
* A link that represents a Matrix object.
*/
class MatrixLink
{
Q_GADGET
Q_PROPERTY(bool isUser READ isUser CONSTANT)
Q_PROPERTY(bool isRoom READ isRoom CONSTANT)
Q_PROPERTY(bool isEvent READ isEvent CONSTANT)
Q_PROPERTY(QStringList identifiers READ identifiers CONSTANT)
Q_PROPERTY(QStringList routingServers READ routingServers CONSTANT)
public:
enum Type {
None,
User,
RoomId,
RoomAlias,
Event,
};
MatrixLink(const QUrl &url);
bool isValid() const;
bool isUser() const;
bool isRoom() const;
bool isEvent() const;
QStringList identifiers() const;
QStringList routingServers() const;
+ QString action() const;
private:
std::vector<std::pair<Type, QString>> m_identifiers;
QStringList m_routingServers;
+ QString m_action;
};
diff --git a/src/tests/matrix-link-test.cpp b/src/tests/matrix-link-test.cpp
index ecf4a39..4adcaf9 100644
--- a/src/tests/matrix-link-test.cpp
+++ b/src/tests/matrix-link-test.cpp
@@ -1,107 +1,138 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <kazv-defs.hpp>
#include <vector>
#include <QtTest>
#include "matrix-link.hpp"
using namespace Qt::Literals::StringLiterals;
class MatrixLinkTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testInvalidLink();
void testUserLink();
void testRoomLink();
void testEventLink();
void testRoutingServers();
+ void testAction();
};
void MatrixLinkTest::testInvalidLink()
{
std::vector<QUrl> links = {
QUrl(u"https://matrix.to/#"_s),
QUrl(u"https://matrix.to/#/"_s),
QUrl(u"https://matrix.to/#//"_s),
QUrl(u"https://matrix.to/#///"_s),
QUrl(u"http://matrix.to/#/%40alice%3Aexample.org"_s),
QUrl(u"https://lol.lol/#/%40alice%3Aexample.org"_s),
QUrl(u"https://matrix.to/#%40alice%3Aexample.org"_s),
+ QUrl(u"matrix:/"_s),
+ QUrl(u"matrix://"_s),
+ QUrl(u"matrix:///"_s),
+ QUrl(u"matrix:r"_s),
+ QUrl(u"matrix:r/somewhere:example.org/e"_s),
+ QUrl(u"matrix:r/somewhere:example.org/e/event/e"_s),
};
for (auto link : links) {
MatrixLink ml(link);
QVERIFY(!ml.isValid());
}
}
void MatrixLinkTest::testUserLink()
{
std::vector<QUrl> links = {
QUrl(u"https://matrix.to/#/%40alice%3Aexample.org"_s),
QUrl(u"https://matrix.to/#/@alice%3Aexample.org"_s),
QUrl(u"https://matrix.to/#/%40alice:example.org"_s),
QUrl(u"https://matrix.to/#/@alice:example.org"_s),
+ QUrl(u"matrix:u/alice:example.org"_s),
+ QUrl(u"matrix:u/alice%3Aexample.org"_s),
};
for (auto link : links) {
MatrixLink ml(link);
QVERIFY(ml.isUser());
QCOMPARE(ml.identifiers(), QStringList{u"@alice:example.org"_s});
}
}
void MatrixLinkTest::testRoomLink()
{
std::vector<std::tuple<QUrl, QString>> links = {
{QUrl(u"https://matrix.to/#/%23somewhere%3Aexample.org"_s), u"#somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/%23somewhere:example.org"_s), u"#somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/#somewhere%3Aexample.org"_s), u"#somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/#somewhere:example.org"_s), u"#somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/!somewhere%3Aexample.org?via=elsewhere.ca"_s), u"!somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/!somewhere:example.org?via=elsewhere.ca"_s), u"!somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/!somewhere%3Aexample.org"_s), u"!somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/!somewhere:example.org"_s), u"!somewhere:example.org"_s},
+ {QUrl(u"matrix:r/somewhere:example.org"_s), u"#somewhere:example.org"_s},
+ {QUrl{u"matrix:r/somewhere%3Aexample.org"_s}, u"#somewhere:example.org"_s},
+ {QUrl(u"matrix:roomid/somewhere:example.org"_s), u"!somewhere:example.org"_s},
+ {QUrl(u"matrix:roomid/somewhere%3Aexample.org"_s), u"!somewhere:example.org"_s},
};
for (auto [link, pointed] : links) {
MatrixLink ml(link);
QVERIFY(ml.isRoom());
QCOMPARE(ml.identifiers(), QStringList{pointed});
}
}
void MatrixLinkTest::testEventLink()
{
std::vector<std::tuple<QUrl, QString>> links = {
{QUrl(u"https://matrix.to/#/%23somewhere%3Aexample.org/%24event%3Aexample.org"_s), u"#somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org"_s), u"#somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/!somewhere%3Aexample.org/%24event%3Aexample.org?via=elsewhere.ca"_s), u"!somewhere:example.org"_s},
{QUrl(u"https://matrix.to/#/!somewhere%3Aexample.org/$event:example.org?via=elsewhere.ca"_s), u"!somewhere:example.org"_s},
+ {QUrl(u"matrix:r/somewhere:example.org/e/event:example.org"_s), u"#somewhere:example.org"_s},
+ {QUrl(u"matrix:r/somewhere%3Aexample.org/e/event:example.org"_s), u"#somewhere:example.org"_s},
+ {QUrl(u"matrix:roomid/somewhere:example.org/e/event:example.org"_s), u"!somewhere:example.org"_s},
+ {QUrl(u"matrix:roomid/somewhere%3Aexample.org/e/event:example.org"_s), u"!somewhere:example.org"_s},
};
for (auto [link, pointed] : links) {
MatrixLink ml(link);
QVERIFY(ml.isRoom());
QCOMPARE(ml.identifiers(), (QStringList{pointed, u"$event:example.org"_s}));
}
}
void MatrixLinkTest::testRoutingServers()
{
QCOMPARE(MatrixLink(QUrl(u"https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org"_s)).routingServers(), (QStringList{}));
QCOMPARE(MatrixLink(QUrl(u"https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org?via=a.org"_s)).routingServers(), (QStringList{u"a.org"_s}));
QCOMPARE(MatrixLink(QUrl(u"https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org?via=a.org&via=b.org"_s)).routingServers(), (QStringList{u"a.org"_s, u"b.org"_s}));
QCOMPARE(MatrixLink(QUrl(u"https://matrix.to/#/%23somewhere%3Aexample.org/%24event:example.org?foo=bar&via=a.org&via=b.org"_s)).routingServers(), (QStringList{u"a.org"_s, u"b.org"_s}));
+
+ QCOMPARE(MatrixLink(QUrl(u"matrix:r/somewhere:example.org/e/event:example.org"_s)).routingServers(), (QStringList{}));
+
+ QCOMPARE(MatrixLink(QUrl(u"matrix:r/somewhere:example.org/e/event:example.org?via=a.org"_s)).routingServers(), (QStringList{u"a.org"_s}));
+
+ QCOMPARE(MatrixLink(QUrl(u"matrix:r/somewhere:example.org/e/event:example.org?via=a.org&via=b.org"_s)).routingServers(), (QStringList{u"a.org"_s, u"b.org"_s}));
+
+ QCOMPARE(MatrixLink(QUrl(u"matrix:r/somewhere:example.org/e/event:example.org?foo=bar&via=a.org&via=b.org"_s)).routingServers(), (QStringList{u"a.org"_s, u"b.org"_s}));
+}
+
+void MatrixLinkTest::testAction()
+{
+ QCOMPARE(MatrixLink(QUrl(u"matrix:u/alice:example.org?action=chat"_s)).action(), u"chat"_s);
+ QCOMPARE(MatrixLink(QUrl(u"matrix:r/somewhere:example.org?action=join&via=a.org"_s)).action(), u"join");
}
QTEST_MAIN(MatrixLinkTest)
#include "matrix-link-test.moc"

File Metadata

Mime Type
text/x-diff
Expires
Mon, Aug 10, 2:16 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1724846
Default Alt Text
(11 KB)

Event Timeline