2023-02-22 01:48:49 +03:00
|
|
|
// SPDX-FileCopyrightText: Nheko Contributors
|
2022-04-14 18:02:55 +03:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
#include "NhekoDBusApi.h"
|
|
|
|
|
2022-04-18 19:50:15 +03:00
|
|
|
#include <QDBusInterface>
|
2022-04-14 18:02:55 +03:00
|
|
|
#include <QDBusMetaType>
|
2022-04-18 19:50:15 +03:00
|
|
|
#include <QDBusReply>
|
2022-04-14 18:02:55 +03:00
|
|
|
|
|
|
|
namespace nheko::dbus {
|
|
|
|
void
|
|
|
|
init()
|
|
|
|
{
|
|
|
|
qDBusRegisterMetaType<RoomInfoItem>();
|
|
|
|
qDBusRegisterMetaType<QVector<RoomInfoItem>>();
|
|
|
|
qDBusRegisterMetaType<QImage>();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
apiVersionIsCompatible(const QVersionNumber &clientAppVersion)
|
|
|
|
{
|
2022-04-18 19:50:15 +03:00
|
|
|
if (clientAppVersion.majorVersion() != nheko::dbus::dbusApiVersion.majorVersion())
|
2022-04-14 18:02:55 +03:00
|
|
|
return false;
|
2022-04-18 19:50:15 +03:00
|
|
|
if (clientAppVersion.minorVersion() > nheko::dbus::dbusApiVersion.minorVersion())
|
2022-04-14 18:02:55 +03:00
|
|
|
return false;
|
2022-04-18 19:50:15 +03:00
|
|
|
if (clientAppVersion.minorVersion() == nheko::dbus::dbusApiVersion.minorVersion() &&
|
|
|
|
clientAppVersion.microVersion() < nheko::dbus::dbusApiVersion.microVersion())
|
2022-04-14 18:02:55 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
RoomInfoItem::RoomInfoItem(const QString &roomId,
|
|
|
|
const QString &alias,
|
|
|
|
const QString &title,
|
2022-10-09 01:56:02 +03:00
|
|
|
const QString &avatarUrl,
|
2022-04-14 18:02:55 +03:00
|
|
|
const int unreadNotifications,
|
|
|
|
QObject *parent)
|
|
|
|
: QObject{parent}
|
|
|
|
, roomId_{roomId}
|
|
|
|
, alias_{alias}
|
|
|
|
, roomName_{title}
|
2022-10-09 01:56:02 +03:00
|
|
|
, avatarUrl_{avatarUrl}
|
2022-04-14 18:02:55 +03:00
|
|
|
, unreadNotifications_{unreadNotifications}
|
2022-09-25 21:05:08 +03:00
|
|
|
{
|
|
|
|
}
|
2022-04-14 18:02:55 +03:00
|
|
|
|
|
|
|
RoomInfoItem::RoomInfoItem(const RoomInfoItem &other)
|
|
|
|
: QObject{other.parent()}
|
|
|
|
, roomId_{other.roomId_}
|
|
|
|
, alias_{other.alias_}
|
|
|
|
, roomName_{other.roomName_}
|
2022-10-09 01:56:02 +03:00
|
|
|
, avatarUrl_{other.avatarUrl_}
|
2022-04-14 18:02:55 +03:00
|
|
|
, unreadNotifications_{other.unreadNotifications_}
|
2022-09-25 21:05:08 +03:00
|
|
|
{
|
|
|
|
}
|
2022-04-14 18:02:55 +03:00
|
|
|
|
|
|
|
RoomInfoItem &
|
|
|
|
RoomInfoItem::operator=(const RoomInfoItem &other)
|
|
|
|
{
|
|
|
|
roomId_ = other.roomId_;
|
|
|
|
alias_ = other.alias_;
|
|
|
|
roomName_ = other.roomName_;
|
2022-10-09 01:56:02 +03:00
|
|
|
avatarUrl_ = other.avatarUrl_;
|
2022-04-14 18:02:55 +03:00
|
|
|
unreadNotifications_ = other.unreadNotifications_;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
QDBusArgument &
|
|
|
|
operator<<(QDBusArgument &arg, const RoomInfoItem &item)
|
|
|
|
{
|
|
|
|
arg.beginStructure();
|
2022-10-09 01:56:02 +03:00
|
|
|
arg << item.roomId_ << item.alias_ << item.roomName_ << item.avatarUrl_
|
2022-04-14 18:02:55 +03:00
|
|
|
<< item.unreadNotifications_;
|
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QDBusArgument &
|
|
|
|
operator>>(const QDBusArgument &arg, RoomInfoItem &item)
|
|
|
|
{
|
|
|
|
arg.beginStructure();
|
2022-10-09 01:56:02 +03:00
|
|
|
arg >> item.roomId_ >> item.alias_ >> item.roomName_ >> item.avatarUrl_ >>
|
2022-04-14 18:02:55 +03:00
|
|
|
item.unreadNotifications_;
|
|
|
|
|
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
2022-04-18 19:50:15 +03:00
|
|
|
|
|
|
|
QString
|
|
|
|
apiVersion()
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
|
|
|
return QDBusReply<QString>{interface.call(QStringLiteral("apiVersion"))}.value();
|
|
|
|
else
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
QString
|
|
|
|
nhekoVersion()
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
|
|
|
return QDBusReply<QString>{interface.call(QStringLiteral("nhekoVersion"))}.value();
|
|
|
|
else
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<RoomInfoItem>
|
|
|
|
rooms()
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
2022-04-18 19:54:32 +03:00
|
|
|
return QDBusReply<QVector<RoomInfoItem>>{interface.call(QStringLiteral("rooms"))}.value();
|
2022-04-18 19:50:15 +03:00
|
|
|
else
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-10-09 01:56:02 +03:00
|
|
|
QImage
|
|
|
|
image(const QString &mxcuri)
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
|
|
|
return QDBusReply<QImage>{interface.call(QStringLiteral("image"), mxcuri)}.value();
|
|
|
|
else
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-04-18 19:50:15 +03:00
|
|
|
void
|
|
|
|
activateRoom(const QString &alias)
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
|
|
|
interface.call(QDBus::NoBlock, QStringLiteral("activateRoom"), alias);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
joinRoom(const QString &alias)
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
|
|
|
interface.call(QDBus::NoBlock, QStringLiteral("joinRoom"), alias);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
directChat(const QString &userId)
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
|
|
|
interface.call(QDBus::NoBlock, QStringLiteral("directChat"), userId);
|
|
|
|
}
|
2022-11-05 20:13:18 +03:00
|
|
|
|
2023-03-31 02:59:56 +03:00
|
|
|
QString
|
|
|
|
statusMessage()
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
|
|
|
return QDBusReply<QString>{interface.call(QStringLiteral("statusMessage"))}.value();
|
|
|
|
else
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-11-05 20:13:18 +03:00
|
|
|
void
|
|
|
|
setStatusMessage(const QString &message)
|
|
|
|
{
|
|
|
|
if (QDBusInterface interface{QStringLiteral(NHEKO_DBUS_SERVICE_NAME), QStringLiteral("/")};
|
|
|
|
interface.isValid())
|
|
|
|
interface.call(QDBus::NoBlock, QStringLiteral("setStatusMessage"), message);
|
|
|
|
}
|
|
|
|
|
2022-04-14 18:02:55 +03:00
|
|
|
} // nheko::dbus
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Automatic marshaling of a QImage for org.freedesktop.Notifications.Notify
|
|
|
|
*
|
|
|
|
* This function is heavily based on a function from the Clementine project (see
|
|
|
|
* http://www.clementine-player.org) and licensed under the GNU General Public
|
|
|
|
* License, version 3 or later.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
QDBusArgument &
|
|
|
|
operator<<(QDBusArgument &arg, const QImage &image)
|
|
|
|
{
|
|
|
|
if (image.isNull()) {
|
|
|
|
arg.beginStructure();
|
|
|
|
arg << 0 << 0 << 0 << false << 0 << 0 << QByteArray();
|
|
|
|
arg.endStructure();
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
2023-06-08 01:32:02 +03:00
|
|
|
QImage i = image.height() > 100 || image.width() > 100
|
|
|
|
? image.scaledToHeight(100, Qt::SmoothTransformation)
|
|
|
|
: image;
|
|
|
|
bool hasAlpha = i.hasAlphaChannel();
|
|
|
|
i = std::move(i).convertToFormat(hasAlpha ? QImage::Format_RGBA8888 : QImage::Format_RGB888);
|
|
|
|
|
|
|
|
int channels = hasAlpha ? 4 : 3;
|
|
|
|
QByteArray arr(reinterpret_cast<const char *>(i.bits()), static_cast<int>(i.sizeInBytes()));
|
2022-04-14 18:02:55 +03:00
|
|
|
arg.beginStructure();
|
2023-06-08 01:32:02 +03:00
|
|
|
arg << i.width() << i.height() << (int)i.bytesPerLine() << i.hasAlphaChannel()
|
|
|
|
<< i.depth() / channels << channels << arr;
|
2022-04-14 18:02:55 +03:00
|
|
|
arg.endStructure();
|
|
|
|
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function, however, was merely reverse-engineered from the above function
|
|
|
|
// and is not from the Clementine project.
|
|
|
|
const QDBusArgument &
|
|
|
|
operator>>(const QDBusArgument &arg, QImage &image)
|
|
|
|
{
|
|
|
|
// garbage is used as a sort of /dev/null
|
|
|
|
int width, height, garbage;
|
|
|
|
QByteArray bits;
|
|
|
|
|
|
|
|
arg.beginStructure();
|
|
|
|
arg >> width >> height >> garbage >> garbage >> garbage >> garbage >> bits;
|
|
|
|
arg.endStructure();
|
|
|
|
|
2022-04-18 19:50:15 +03:00
|
|
|
// Unfortunately, this copy-and-detach is necessary to ensure that the source buffer
|
|
|
|
// is copied properly. If anybody finds a better solution, please implement it.
|
|
|
|
auto temp =
|
|
|
|
QImage(reinterpret_cast<uchar *>(bits.data()), width, height, QImage::Format_RGBA8888);
|
|
|
|
image = temp;
|
|
|
|
image.detach();
|
2022-04-14 18:02:55 +03:00
|
|
|
|
|
|
|
return arg;
|
|
|
|
}
|