1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
#include "resourceresolver.h"
#include "settings.h"
#include <QtCore/QRegularExpression>
using namespace Quotient;
QString ResourceResolver::toMatrixId(const QString& uriOrId,
QStringList uriServers)
{
auto id = QUrl::fromPercentEncoding(uriOrId.toUtf8());
const auto MatrixScheme = "matrix:"_ls;
if (id.startsWith(MatrixScheme)) {
id.remove(0, MatrixScheme.size());
for (const auto& p: { std::pair { "user/"_ls, '@' },
{ "roomid/"_ls, '!' },
{ "room/"_ls, '#' } })
if (id.startsWith(p.first)) {
id.replace(0, p.first.size(), p.second);
break;
}
// The below assumes that /event/ cannot show up in normal Matrix ids.
id.replace("/event/"_ls, "/$"_ls);
} else {
const auto MatrixTo_ServerName = QStringLiteral("matrix.to");
if (!uriServers.contains(MatrixTo_ServerName))
uriServers.push_back(MatrixTo_ServerName);
id.remove(
QRegularExpression("^https://(" + uriServers.join('|') + ")/?#/"));
}
return id;
}
ResourceResolver::Result ResourceResolver::visitResource(
Connection* account, const QString& identifier,
std::function<void(User*)> userHandler,
std::function<void(Room*, QString)> roomEventHandler)
{
const auto& normalizedId = toMatrixId(identifier);
auto&& [sigil, mainId, secondaryId] = parseIdentifier(normalizedId);
Room* room = nullptr;
switch (sigil) {
case char(-1):
return MalformedMatrixId;
case char(0):
return EmptyMatrixId;
case '@':
if (auto* user = account->user(mainId)) {
userHandler(user);
return Success;
}
return MalformedMatrixId;
case '!':
if ((room = account->room(mainId)))
break;
return UnknownMatrixId;
case '#':
if ((room = account->roomByAlias(mainId)))
break;
[[fallthrough]];
default:
return UnknownMatrixId;
}
roomEventHandler(room, secondaryId);
return Success;
}
ResourceResolver::IdentifierParts
ResourceResolver::parseIdentifier(const QString& identifier)
{
if (identifier.isEmpty())
return {};
// The regex is quick and dirty, only intending to triage the id.
static const QRegularExpression IdRE {
"^(?<main>(?<sigil>.)([^/]+))(/(?<sec>[^?]+))?"
};
auto dissectedId = IdRE.match(identifier);
if (!dissectedId.hasMatch())
return { char(-1) };
const auto sigil = dissectedId.captured("sigil");
return { sigil.size() != 1 ? char(-1) : sigil[0].toLatin1(),
dissectedId.captured("main"), dissectedId.captured("sec") };
}
ResourceResolver::Result
ResourceResolver::openResource(Connection* account, const QString& identifier,
const QString& action)
{
return visitResource(account, identifier,
[this, &action](User* u) { emit userAction(u, action); },
[this, &action](Room* room, const QString& eventId) {
emit roomAction(room, eventId, action);
});
}
|