2015-09-10 15:36:03 +01:00
|
|
|
/**
|
|
|
|
* Copyright 2015 Holger Kaelberer <holger.k@elberer.de>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of
|
|
|
|
* the License or (at your option) version 3 or any later version
|
|
|
|
* accepted by the membership of KDE e.V. (or its successor approved
|
|
|
|
* by the membership of KDE e.V.), which shall act as a proxy
|
|
|
|
* defined in Section 14 of version 3 of the license.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <QtDBus/QDBusConnection>
|
|
|
|
#include <QtDBus/QDBusInterface>
|
|
|
|
#include <QtDebug>
|
|
|
|
#include <QLoggingCategory>
|
2016-04-27 18:45:58 +01:00
|
|
|
#include <QStandardPaths>
|
|
|
|
#include <KConfig>
|
|
|
|
#include <KConfigGroup>
|
2015-09-10 15:36:03 +01:00
|
|
|
|
2016-01-07 16:37:35 +00:00
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kicontheme.h>
|
|
|
|
|
2015-09-10 15:36:03 +01:00
|
|
|
#include <core/device.h>
|
|
|
|
#include <core/kdeconnectplugin.h>
|
|
|
|
|
|
|
|
#include "notificationslistener.h"
|
2016-05-25 19:49:13 +01:00
|
|
|
#include "sendnotificationsplugin.h"
|
|
|
|
#include "sendnotification_debug.h"
|
2015-12-05 22:11:57 +00:00
|
|
|
#include "notifyingapplication.h"
|
2015-09-10 15:36:03 +01:00
|
|
|
|
2016-05-25 19:49:13 +01:00
|
|
|
NotificationsListener::NotificationsListener(KdeConnectPlugin* aPlugin)
|
2015-09-10 15:36:03 +01:00
|
|
|
: QDBusAbstractAdaptor(aPlugin),
|
2016-05-25 19:49:13 +01:00
|
|
|
mPlugin(aPlugin)
|
2015-09-10 15:36:03 +01:00
|
|
|
{
|
2015-12-05 22:11:57 +00:00
|
|
|
qRegisterMetaTypeStreamOperators<NotifyingApplication>("NotifyingApplication");
|
|
|
|
|
2015-09-10 15:36:03 +01:00
|
|
|
bool ret = QDBusConnection::sessionBus()
|
|
|
|
.registerObject("/org/freedesktop/Notifications",
|
|
|
|
this,
|
|
|
|
QDBusConnection::ExportScriptableContents);
|
|
|
|
if (!ret)
|
2016-05-25 19:49:13 +01:00
|
|
|
qCWarning(KDECONNECT_PLUGIN_SENDNOTIFICATION)
|
2015-09-10 15:36:03 +01:00
|
|
|
<< "Error registering notifications listener for device"
|
|
|
|
<< mPlugin->device()->name() << ":"
|
|
|
|
<< QDBusConnection::sessionBus().lastError();
|
|
|
|
else
|
2016-05-25 19:49:13 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION)
|
2015-09-10 15:36:03 +01:00
|
|
|
<< "Registered notifications listener for device"
|
|
|
|
<< mPlugin->device()->name();
|
|
|
|
|
|
|
|
QDBusInterface iface("org.freedesktop.DBus", "/org/freedesktop/DBus",
|
|
|
|
"org.freedesktop.DBus");
|
|
|
|
iface.call("AddMatch",
|
|
|
|
"interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
|
2015-12-05 22:11:57 +00:00
|
|
|
|
2016-04-27 18:45:58 +01:00
|
|
|
setTranslatedAppName();
|
2015-12-05 22:11:57 +00:00
|
|
|
loadApplications();
|
|
|
|
|
|
|
|
connect(mPlugin->config(), SIGNAL(configChanged()), this, SLOT(loadApplications()));
|
2015-09-10 15:36:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
NotificationsListener::~NotificationsListener()
|
|
|
|
{
|
2016-05-25 19:49:13 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Destroying NotificationsListener";
|
2015-09-10 15:36:03 +01:00
|
|
|
QDBusInterface iface("org.freedesktop.DBus", "/org/freedesktop/DBus",
|
|
|
|
"org.freedesktop.DBus");
|
|
|
|
QDBusMessage res = iface.call("RemoveMatch",
|
|
|
|
"interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
|
|
|
|
QDBusConnection::sessionBus().unregisterObject("/org/freedesktop/Notifications");
|
|
|
|
}
|
|
|
|
|
2016-04-27 18:45:58 +01:00
|
|
|
void NotificationsListener::setTranslatedAppName()
|
|
|
|
{
|
|
|
|
QString filePath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("knotifications5/kdeconnect.notifyrc"), QStandardPaths::LocateFile);
|
|
|
|
if (filePath.isEmpty()) {
|
2016-05-31 16:48:55 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Couldn't find kdeconnect.notifyrc to hide kdeconnect notifications on the devices. Using default name.";
|
2016-04-27 18:45:58 +01:00
|
|
|
mTranslatedAppName = QStringLiteral("KDE Connect");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KConfig config(filePath, KConfig::OpenFlag::SimpleConfig);
|
|
|
|
KConfigGroup globalgroup(&config, QStringLiteral("Global"));
|
|
|
|
mTranslatedAppName = globalgroup.readEntry(QStringLiteral("Name"), QStringLiteral("KDE Connect"));
|
|
|
|
}
|
|
|
|
|
2015-12-05 22:11:57 +00:00
|
|
|
void NotificationsListener::loadApplications()
|
|
|
|
{
|
|
|
|
applications.clear();
|
|
|
|
QVariantList list = mPlugin->config()->getList("applications");
|
2016-06-21 13:50:17 +01:00
|
|
|
Q_FOREACH (const auto& a, list) {
|
2015-12-05 22:11:57 +00:00
|
|
|
NotifyingApplication app = a.value<NotifyingApplication>();
|
|
|
|
if (!applications.contains(app.name))
|
|
|
|
applications.insert(app.name, app);
|
|
|
|
}
|
2016-05-25 19:49:13 +01:00
|
|
|
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Loaded" << applications.size() << " applications";
|
2015-12-05 22:11:57 +00:00
|
|
|
}
|
|
|
|
|
2015-09-10 15:36:03 +01:00
|
|
|
uint NotificationsListener::Notify(const QString &appName, uint replacesId,
|
|
|
|
const QString &appIcon,
|
|
|
|
const QString &summary, const QString &body,
|
|
|
|
const QStringList &actions,
|
|
|
|
const QVariantMap &hints, int timeout)
|
|
|
|
{
|
|
|
|
static int id = 0;
|
|
|
|
Q_UNUSED(actions);
|
2015-12-05 22:11:57 +00:00
|
|
|
|
2016-05-25 19:49:13 +01:00
|
|
|
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Got notification appName=" << appName << "replacesId=" << replacesId << "appIcon=" << appIcon << "summary=" << summary << "body=" << body << "actions=" << actions << "hints=" << hints << "timeout=" << timeout;
|
2015-09-10 15:36:03 +01:00
|
|
|
|
|
|
|
// skip our own notifications
|
2016-04-27 18:45:58 +01:00
|
|
|
if (appName == mTranslatedAppName)
|
2015-09-10 15:36:03 +01:00
|
|
|
return 0;
|
|
|
|
|
2015-12-05 22:11:57 +00:00
|
|
|
NotifyingApplication app;
|
|
|
|
if (!applications.contains(appName)) {
|
|
|
|
// new application -> add to config
|
|
|
|
app.name = appName;
|
|
|
|
app.icon = appIcon;
|
|
|
|
app.active = true;
|
|
|
|
app.blacklistExpression = QRegularExpression();
|
|
|
|
applications.insert(app.name, app);
|
|
|
|
// update config:
|
|
|
|
QVariantList list;
|
2016-06-21 13:50:17 +01:00
|
|
|
Q_FOREACH (const auto& a, applications)
|
2015-12-05 22:11:57 +00:00
|
|
|
list << QVariant::fromValue<NotifyingApplication>(a);
|
|
|
|
mPlugin->config()->setList("applications", list);
|
2016-05-25 19:49:13 +01:00
|
|
|
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Added new application to config:" << app;
|
2015-12-05 22:11:57 +00:00
|
|
|
} else
|
|
|
|
app = applications.value(appName);
|
|
|
|
|
|
|
|
if (!app.active)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (timeout > 0 && mPlugin->config()->get("generalPersistent", false))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int urgency = -1;
|
2015-12-07 02:21:35 +00:00
|
|
|
if (hints.contains("urgency")) {
|
|
|
|
bool ok;
|
2015-12-05 22:11:57 +00:00
|
|
|
urgency = hints["urgency"].toInt(&ok);
|
2015-12-07 02:21:35 +00:00
|
|
|
if (!ok)
|
|
|
|
urgency = -1;
|
|
|
|
}
|
2015-12-05 22:11:57 +00:00
|
|
|
if (urgency > -1 && urgency < mPlugin->config()->get<int>("generalUrgency", 0))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
QString ticker = summary;
|
|
|
|
if (!body.isEmpty() && mPlugin->config()->get("generalIncludeBody", true))
|
|
|
|
ticker += QLatin1String(": ") + body;
|
|
|
|
|
|
|
|
if (app.blacklistExpression.isValid() &&
|
|
|
|
!app.blacklistExpression.pattern().isEmpty() &&
|
|
|
|
app.blacklistExpression.match(ticker).hasMatch())
|
|
|
|
return 0;
|
|
|
|
|
2016-05-25 19:49:13 +01:00
|
|
|
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Sending notification from" << appName << ":" <<ticker << "; appIcon=" << appIcon;
|
2016-06-21 19:07:12 +01:00
|
|
|
NetworkPackage np(PACKAGE_TYPE_NOTIFICATION, {
|
|
|
|
{"id", QString::number(replacesId > 0 ? replacesId : ++id)},
|
|
|
|
{"appName", appName},
|
|
|
|
{"ticker", ticker},
|
|
|
|
{"isClearable", timeout == 0}
|
|
|
|
}); // KNotifications are persistent if
|
2015-09-10 15:36:03 +01:00
|
|
|
// timeout == 0, for other notifications
|
|
|
|
// clearability is pointless
|
|
|
|
|
2016-01-07 16:37:35 +00:00
|
|
|
if (!appIcon.isEmpty() && mPlugin->config()->get("generalSynchronizeIcons", true)) {
|
|
|
|
int size = KIconLoader::SizeEnormous; // use big size to allow for good
|
|
|
|
// quality on High-DPI mobile devices
|
|
|
|
QString iconPath = KIconLoader::global()->iconPath(appIcon, -size, true);
|
|
|
|
if (!iconPath.isEmpty()) {
|
|
|
|
if (!iconPath.endsWith(QLatin1String(".png")) &&
|
|
|
|
KIconLoader::global()->theme()->name() != QLatin1String("hicolor")) {
|
|
|
|
// try falling back to hicolor theme:
|
|
|
|
KIconTheme hicolor(QStringLiteral("hicolor"));
|
|
|
|
if (hicolor.isValid()) {
|
|
|
|
iconPath = hicolor.iconPath(appIcon + ".png", size, KIconLoader::MatchBest);
|
2016-05-25 19:49:13 +01:00
|
|
|
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Found non-png icon in default theme trying fallback to hicolor:" << iconPath;
|
2016-01-07 16:37:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (iconPath.endsWith(QLatin1String(".png"))) {
|
2016-05-25 19:49:13 +01:00
|
|
|
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Appending icon " << iconPath;
|
2016-01-07 16:37:35 +00:00
|
|
|
QSharedPointer<QIODevice> iconFile(new QFile(iconPath));
|
|
|
|
np.setPayload(iconFile, iconFile->size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 15:36:03 +01:00
|
|
|
mPlugin->sendPackage(np);
|
|
|
|
|
|
|
|
return (replacesId > 0 ? replacesId : id);
|
|
|
|
}
|