Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85630911
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rK kazv
Attached
Detach File
Event Timeline
Log In to Comment