mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-10-30 17:40:47 +03:00
Handle matrix scheme
Link opening only works on Linux for now. See https://github.com/matrix-org/matrix-doc/pull/2312
This commit is contained in:
parent
cc9de7f3b0
commit
39f9b7d90a
7 changed files with 216 additions and 17 deletions
|
@ -8,3 +8,4 @@ Type=Application
|
|||
Categories=Network;InstantMessaging;Qt;
|
||||
StartupWMClass=nheko
|
||||
Terminal=false
|
||||
MimeType=x-scheme-handler/matrix;
|
||||
|
|
|
@ -2221,6 +2221,34 @@ Cache::getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb)
|
|||
return QString("1");
|
||||
}
|
||||
|
||||
std::optional<mtx::events::state::CanonicalAlias>
|
||||
Cache::getRoomAliases(const std::string &roomid)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
using namespace mtx::events::state;
|
||||
|
||||
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
||||
auto statesdb = getStatesDb(txn, roomid);
|
||||
|
||||
lmdb::val event;
|
||||
bool res = lmdb::dbi_get(
|
||||
txn, statesdb, lmdb::val(to_string(mtx::events::EventType::RoomCanonicalAlias)), event);
|
||||
|
||||
if (res) {
|
||||
try {
|
||||
StateEvent<CanonicalAlias> msg =
|
||||
json::parse(std::string_view(event.data(), event.size()));
|
||||
|
||||
return msg.content;
|
||||
} catch (const json::exception &e) {
|
||||
nhlog::db()->warn("failed to parse m.room.canonical_alias event: {}",
|
||||
e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QString
|
||||
Cache::getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb)
|
||||
{
|
||||
|
|
|
@ -81,6 +81,7 @@ public:
|
|||
std::vector<std::string> joinedRooms();
|
||||
|
||||
QMap<QString, RoomInfo> roomInfo(bool withInvites = true);
|
||||
std::optional<mtx::events::state::CanonicalAlias> getRoomAliases(const std::string &roomid);
|
||||
std::map<QString, bool> invites();
|
||||
|
||||
//! Calculate & return the name of the room.
|
||||
|
|
140
src/ChatPage.cpp
140
src/ChatPage.cpp
|
@ -918,6 +918,8 @@ ChatPage::joinRoom(const QString &room)
|
|||
} catch (const lmdb::error &e) {
|
||||
emit showNotification(tr("Failed to remove invite: %1").arg(e.what()));
|
||||
}
|
||||
|
||||
room_list_->highlightSelectedRoom(QString::fromStdString(room_id));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1268,3 +1270,141 @@ ChatPage::decryptDownloadedSecrets(mtx::secret_storage::AesHmacSha2KeyDescriptio
|
|||
cache::storeSecret(secretName, decrypted);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::startChat(QString userid)
|
||||
{
|
||||
auto joined_rooms = cache::joinedRooms();
|
||||
auto room_infos = cache::getRoomInfo(joined_rooms);
|
||||
|
||||
for (std::string room_id : joined_rooms) {
|
||||
if (room_infos[QString::fromStdString(room_id)].member_count == 2) {
|
||||
auto room_members = cache::roomMembers(room_id);
|
||||
if (std::find(room_members.begin(),
|
||||
room_members.end(),
|
||||
(userid).toStdString()) != room_members.end()) {
|
||||
room_list_->highlightSelectedRoom(QString::fromStdString(room_id));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mtx::requests::CreateRoom req;
|
||||
req.preset = mtx::requests::Preset::PrivateChat;
|
||||
req.visibility = mtx::requests::Visibility::Private;
|
||||
if (utils::localUser() != userid)
|
||||
req.invite = {userid.toStdString()};
|
||||
emit ChatPage::instance()->createRoom(req);
|
||||
}
|
||||
|
||||
static QString
|
||||
mxidFromSegments(QStringRef sigil, QStringRef mxid)
|
||||
{
|
||||
if (mxid.isEmpty())
|
||||
return "";
|
||||
|
||||
auto mxid_ = QUrl::fromPercentEncoding(mxid.toUtf8());
|
||||
|
||||
if (sigil == "user") {
|
||||
return "@" + mxid_;
|
||||
} else if (sigil == "roomid") {
|
||||
return "!" + mxid_;
|
||||
} else if (sigil == "room") {
|
||||
return "#" + mxid_;
|
||||
} else if (sigil == "group") {
|
||||
return "+" + mxid_;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::handleMatrixUri(const QByteArray &uri)
|
||||
{
|
||||
nhlog::ui()->info("Received uri! {}", uri.toStdString());
|
||||
QUrl uri_{QString::fromUtf8(uri)};
|
||||
|
||||
if (uri_.scheme() != "matrix")
|
||||
return;
|
||||
|
||||
auto tempPath = uri_.path(QUrl::ComponentFormattingOption::FullyEncoded);
|
||||
if (tempPath.startsWith('/'))
|
||||
tempPath.remove(0, 1);
|
||||
auto segments = tempPath.splitRef('/');
|
||||
|
||||
if (segments.size() != 2 && segments.size() != 4)
|
||||
return;
|
||||
|
||||
auto sigil1 = segments[0];
|
||||
auto mxid1 = mxidFromSegments(sigil1, segments[1]);
|
||||
if (mxid1.isEmpty())
|
||||
return;
|
||||
|
||||
QString mxid2;
|
||||
if (segments.size() == 4 && segments[2] == "event") {
|
||||
if (segments[3].isEmpty())
|
||||
return;
|
||||
else
|
||||
mxid2 = "$" + QUrl::fromPercentEncoding(segments[3].toUtf8());
|
||||
}
|
||||
|
||||
std::vector<std::string> vias;
|
||||
QString action;
|
||||
|
||||
for (QString item : uri_.query(QUrl::ComponentFormattingOption::FullyEncoded).split('&')) {
|
||||
nhlog::ui()->info("item: {}", item.toStdString());
|
||||
|
||||
if (item.startsWith("action=")) {
|
||||
action = item.remove("action=");
|
||||
} else if (item.startsWith("via=")) {
|
||||
vias.push_back(
|
||||
QUrl::fromPercentEncoding(item.remove("via=").toUtf8()).toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
if (sigil1 == "user") {
|
||||
if (action.isEmpty()) {
|
||||
view_manager_->activeTimeline()->openUserProfile(mxid1);
|
||||
} else if (action == "chat") {
|
||||
this->startChat(mxid1);
|
||||
}
|
||||
} else if (sigil1 == "roomid") {
|
||||
auto joined_rooms = cache::joinedRooms();
|
||||
auto targetRoomId = mxid1.toStdString();
|
||||
|
||||
for (auto roomid : joined_rooms) {
|
||||
if (roomid == targetRoomId) {
|
||||
room_list_->highlightSelectedRoom(mxid1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (action == "join") {
|
||||
joinRoom(mxid1);
|
||||
}
|
||||
} else if (sigil1 == "room") {
|
||||
auto joined_rooms = cache::joinedRooms();
|
||||
auto targetRoomAlias = mxid1.toStdString();
|
||||
|
||||
for (auto roomid : joined_rooms) {
|
||||
auto aliases = cache::client()->getRoomAliases(roomid);
|
||||
if (aliases) {
|
||||
if (aliases->alias == targetRoomAlias) {
|
||||
room_list_->highlightSelectedRoom(
|
||||
QString::fromStdString(roomid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (action == "join") {
|
||||
joinRoom(mxid1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::handleMatrixUri(const QUrl &uri)
|
||||
{
|
||||
handleMatrixUri(uri.toString(QUrl::ComponentFormattingOption::FullyEncoded).toUtf8());
|
||||
}
|
||||
|
|
|
@ -110,6 +110,10 @@ public:
|
|||
mtx::presence::PresenceState currentPresence() const;
|
||||
|
||||
public slots:
|
||||
void handleMatrixUri(const QByteArray &uri);
|
||||
void handleMatrixUri(const QUrl &uri);
|
||||
|
||||
void startChat(QString userid);
|
||||
void leaveRoom(const QString &room_id);
|
||||
void createRoom(const mtx::requests::CreateRoom &req);
|
||||
void joinRoom(const QString &room);
|
||||
|
|
52
src/main.cpp
52
src/main.cpp
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <QApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QDesktopServices>
|
||||
#include <QDesktopWidget>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
|
@ -33,6 +34,7 @@
|
|||
#include <QStandardPaths>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
|
@ -128,34 +130,43 @@ main(int argc, char *argv[])
|
|||
// This is some hacky programming, but it's necessary (AFAIK?) to get the unique config name
|
||||
// parsed before the SingleApplication userdata is set.
|
||||
QString userdata{""};
|
||||
QString matrixUri;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (QString{argv[i]}.startsWith("--profile=")) {
|
||||
QString q{argv[i]};
|
||||
q.remove("--profile=");
|
||||
userdata = q;
|
||||
} else if (QString{argv[i]}.startsWith("--p=")) {
|
||||
QString q{argv[i]};
|
||||
q.remove("-p=");
|
||||
userdata = q;
|
||||
} else if (QString{argv[i]} == "--profile" || QString{argv[i]} == "-p") {
|
||||
QString arg{argv[i]};
|
||||
if (arg.startsWith("--profile=")) {
|
||||
arg.remove("--profile=");
|
||||
userdata = arg;
|
||||
} else if (arg.startsWith("--p=")) {
|
||||
arg.remove("-p=");
|
||||
userdata = arg;
|
||||
} else if (arg == "--profile" || arg == "-p") {
|
||||
if (i < argc - 1) // if i is less than argc - 1, we still have a parameter
|
||||
// left to process as the name
|
||||
{
|
||||
++i; // the next arg is the name, so increment
|
||||
userdata = QString{argv[i]};
|
||||
}
|
||||
} else if (arg.startsWith("matrix:")) {
|
||||
matrixUri = arg;
|
||||
}
|
||||
}
|
||||
|
||||
SingleApplication app(argc,
|
||||
argv,
|
||||
false,
|
||||
true,
|
||||
SingleApplication::Mode::User |
|
||||
SingleApplication::Mode::ExcludeAppPath |
|
||||
SingleApplication::Mode::ExcludeAppVersion,
|
||||
SingleApplication::Mode::ExcludeAppVersion |
|
||||
SingleApplication::Mode::SecondaryNotification,
|
||||
100,
|
||||
userdata);
|
||||
|
||||
if (app.isSecondary()) {
|
||||
// open uri in main instance
|
||||
app.sendMessage(matrixUri.toUtf8());
|
||||
return 0;
|
||||
}
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
@ -245,6 +256,25 @@ main(int argc, char *argv[])
|
|||
w.activateWindow();
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
&app,
|
||||
&SingleApplication::receivedMessage,
|
||||
ChatPage::instance(),
|
||||
[&](quint32, QByteArray message) { ChatPage::instance()->handleMatrixUri(message); });
|
||||
|
||||
QMetaObject::Connection uriConnection;
|
||||
if (app.isPrimary() && !matrixUri.isEmpty()) {
|
||||
uriConnection = QObject::connect(ChatPage::instance(),
|
||||
&ChatPage::contentLoaded,
|
||||
ChatPage::instance(),
|
||||
[&uriConnection, matrixUri]() {
|
||||
ChatPage::instance()->handleMatrixUri(
|
||||
matrixUri.toUtf8());
|
||||
QObject::disconnect(uriConnection);
|
||||
});
|
||||
}
|
||||
QDesktopServices::setUrlHandler("matrix", ChatPage::instance(), "handleMatrixUri");
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
// Temporary solution for the emoji picker until
|
||||
// nheko has a proper menu bar with more functionality.
|
||||
|
|
|
@ -202,12 +202,7 @@ UserProfile::kickUser()
|
|||
void
|
||||
UserProfile::startChat()
|
||||
{
|
||||
mtx::requests::CreateRoom req;
|
||||
req.preset = mtx::requests::Preset::PrivateChat;
|
||||
req.visibility = mtx::requests::Visibility::Private;
|
||||
if (utils::localUser() != this->userid_)
|
||||
req.invite = {this->userid_.toStdString()};
|
||||
emit ChatPage::instance()->createRoom(req);
|
||||
ChatPage::instance()->startChat(this->userid_);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in a new issue