Commit 20f845ce authored by James Smith's avatar James Smith

Independent account presences.

Activities support.
Make unit testing compile.
Implement status message parser with Now Playing.
Status message parser unit testing.
REVIEW: 130192
FEATURE: 284517
FEATURE: 293443
FEATURE: 294940
BUG: 297924
BUG: 334542
parent e9e9efbd
......@@ -20,8 +20,8 @@ include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(FeatureSummary)
find_package (Qt5 REQUIRED COMPONENTS Concurrent Widgets Sql Network)
find_package (KF5 REQUIRED COMPONENTS DBusAddons WidgetsAddons Config I18n KIO Notifications ConfigWidgets IdleTime KCMUtils)
find_package (Qt5 REQUIRED COMPONENTS Concurrent Widgets Sql Network Test)
find_package (KF5 REQUIRED COMPONENTS DBusAddons WidgetsAddons Config I18n KIO Notifications ConfigWidgets IdleTime KCMUtils Activities)
find_package (KTp REQUIRED)
......@@ -43,13 +43,14 @@ set (kded_ktp_integration_module_SRCS
contact-request-handler.cpp
telepathy-kded-module-plugin.cpp
telepathy-module.cpp
account-status-helper.cpp
autoaway.cpp
telepathy-mpris.cpp
status-handler.cpp
autoconnect.cpp
error-handler.cpp
contactnotify.cpp
screensaveraway.cpp
status-message-parser.cpp
)
add_library (kded_ktp_integration_module MODULE ${kded_ktp_integration_module_SRCS}
......@@ -66,6 +67,7 @@ target_link_libraries (kded_ktp_integration_module
KF5::IdleTime
KF5::KIOWidgets
KF5::WidgetsAddons
KF5::Activities
${TELEPATHY_QT5_LIBRARIES}
Qt5::Concurrent
Qt5::Sql
......
/*
Status managing and auto connect class
Copyright (C) 2017 James D. Smith <smithjd15@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "account-status-helper.h"
#include "ktp_kded_debug.h"
#include <KTp/types.h>
#include <KConfig>
#include <KConfigGroup>
#include <KSharedConfig>
#include <KActivities/kactivities/consumer.h>
#include <QVariant>
#include <TelepathyQt/AccountManager>
#include <TelepathyQt/AccountSet>
#include <TelepathyQt/Account>
#include <TelepathyQt/Constants>
#include <TelepathyQt/Types>
AccountStatusHelper::AccountStatusHelper(QObject *parent)
: QDBusAbstractAdaptor(parent),
m_enabledAccounts(KTp::accountManager()->enabledAccounts()),
m_telepathyConfig(KSharedConfig::openConfig(QLatin1String("ktelepathyrc"))),
m_activities(new KActivities::Consumer())
{
Tp::registerTypes();
reloadConfig();
QDBusConnection::sessionBus().connect(QString(), QLatin1String("/Telepathy"),
QLatin1String("org.kde.Telepathy"),
QLatin1String("settingsChange"), this, SLOT(reloadConfig()));
connect(m_enabledAccounts.data(), &Tp::AccountSet::accountAdded, [&] (const Tp::AccountPtr &account) {
Tp::SimplePresence accountPresence = getDiskPresence(account->uniqueIdentifier(), m_activities->currentActivity());
m_requestedAccountPresences[account->uniqueIdentifier()] = QVariant::fromValue<Tp::SimplePresence>(accountPresence);
Q_EMIT statusChange(account->uniqueIdentifier());
});
connect(m_enabledAccounts.data(), &Tp::AccountSet::accountRemoved, [&] (const Tp::AccountPtr &account) {
m_requestedAccountPresences.remove(account->uniqueIdentifier());
});
auto loadActivity = [=] (const QString &id) {
m_requestedGlobalPresence = getDiskPresence(QLatin1String("LastPresence"), id);
for (const Tp::AccountPtr &account : m_enabledAccounts->accounts()) {
Tp::SimplePresence accountPresence = getDiskPresence(account->uniqueIdentifier(), id);
m_requestedAccountPresences[account->uniqueIdentifier()] = QVariant::fromValue<Tp::SimplePresence>(accountPresence);
}
};
auto activityServiceStatusChanged = [=] (KActivities::Consumer::ServiceStatus status) {
if (status == KActivities::Consumer::Running) {
loadActivity(m_activities->currentActivity());
if (m_autoConnect) {
for (const Tp::AccountPtr &account : m_enabledAccounts->accounts()) {
Q_EMIT statusChange(account->uniqueIdentifier());
}
}
} else if (status == KActivities::Consumer::NotRunning) {
qCWarning(KTP_KDED_MODULE) << "activity service not running, user account presences won't load or save";
}
};
connect(m_activities, &KActivities::Consumer::serviceStatusChanged, this, activityServiceStatusChanged);
connect(m_activities, &KActivities::Consumer::currentActivityChanged, [=] (const QString &id) {
if (m_activities->serviceStatus() == KActivities::Consumer::Running) {
if (getDiskPresence(QLatin1String("LastPresence"), id).type == Tp::ConnectionPresenceTypeUnset) {
setDiskPresence(QLatin1String("LastPresence"), m_requestedGlobalPresence, id);
}
loadActivity(id);
for (const Tp::AccountPtr &account : m_enabledAccounts->accounts()) {
Q_EMIT statusChange(account->uniqueIdentifier());
}
}
});
connect(m_activities, &KActivities::Consumer::activityRemoved, [this] (const QString &id) {
KConfigGroup activityGroup = m_telepathyConfig->group(id);
activityGroup.deleteGroup();
activityGroup.sync();
});
activityServiceStatusChanged(m_activities->serviceStatus());
}
AccountStatusHelper::~AccountStatusHelper()
{
}
QHash<QString, QVariant> AccountStatusHelper::requestedAccountPresences() const
{
return m_requestedAccountPresences;
}
Tp::SimplePresence AccountStatusHelper::requestedGlobalPresence() const
{
return m_requestedGlobalPresence;
}
void AccountStatusHelper::setRequestedGlobalPresence(const Tp::SimplePresence &presence, uint presenceClass)
{
if (PresenceClass(presenceClass) == PresenceClass::Session) {
if (presence.type == Tp::ConnectionPresenceTypeUnset) {
m_requestedGlobalPresence = getDiskPresence(QLatin1String("LastPresence"), m_activities->currentActivity());
} else if (presence.type == Tp::ConnectionPresenceTypeUnknown) {
m_requestedGlobalPresence.statusMessage = presence.statusMessage;
} else {
m_requestedGlobalPresence = presence;
}
} else if (PresenceClass(presenceClass) == PresenceClass::Persistent) {
m_requestedGlobalPresence = presence;
if (m_requestedGlobalPresence.type != Tp::ConnectionPresenceTypeOffline) {
setDiskPresence(QLatin1String("LastPresence"), presence, m_activities->currentActivity());
}
}
qCDebug(KTP_KDED_MODULE) << "new requested global presence"
<< PresenceClass(presenceClass) << presence.status << "with status message"
<< presence.statusMessage;
Q_EMIT statusChange();
}
void AccountStatusHelper::setRequestedAccountPresence(const QString &accountUID, const Tp::SimplePresence &presence, uint presenceClass)
{
if (PresenceClass(presenceClass) == PresenceClass::Session) {
if (presence.type == Tp::ConnectionPresenceTypeUnset) {
m_requestedAccountPresences[accountUID] = QVariant::fromValue<Tp::SimplePresence>(getDiskPresence(accountUID, m_activities->currentActivity()));
} else if (presence.type == Tp::ConnectionPresenceTypeUnknown) {
Tp::SimplePresence statusMessagePresence = qvariant_cast<Tp::SimplePresence>(m_requestedAccountPresences[accountUID]);
statusMessagePresence.statusMessage = presence.statusMessage;
m_requestedAccountPresences[accountUID] = QVariant::fromValue<Tp::SimplePresence>(statusMessagePresence);
} else {
m_requestedAccountPresences[accountUID] = QVariant::fromValue<Tp::SimplePresence>(presence);
}
} else if (PresenceClass(presenceClass) == PresenceClass::Persistent) {
m_requestedAccountPresences[accountUID] = QVariant::fromValue<Tp::SimplePresence>(presence);
setDiskPresence(accountUID, presence, m_activities->currentActivity());
}
qCDebug(KTP_KDED_MODULE) << "new requested account presence"
<< PresenceClass(presenceClass) << presence.status << "with status message"
<< presence.statusMessage << "for account" << accountUID;
Q_EMIT statusChange(accountUID);
}
void AccountStatusHelper::reloadConfig()
{
KConfigGroup kdedConfig = m_telepathyConfig->group("KDED");
m_autoConnect = kdedConfig.readEntry(QLatin1String("autoConnect"), false);
}
void AccountStatusHelper::setDiskPresence(const QString &presenceGroup, const Tp::SimplePresence &presence, const QString &activity)
{
KConfigGroup diskPresenceGroup = m_telepathyConfig->group(activity).group(presenceGroup);
if (m_activities->serviceStatus() != KActivities::Consumer::Running) {
return;
}
if (presence.type != Tp::ConnectionPresenceTypeUnset) {
diskPresenceGroup.writeEntry(QLatin1String("PresenceType"), (uint)presence.type);
diskPresenceGroup.writeEntry(QLatin1String("PresenceStatus"), presence.status);
diskPresenceGroup.writeEntry(QLatin1String("PresenceMessage"), presence.statusMessage);
} else if (diskPresenceGroup.exists()) {
diskPresenceGroup.deleteGroup();
}
m_telepathyConfig->sync();
}
Tp::SimplePresence AccountStatusHelper::getDiskPresence(const QString &presenceGroup, const QString &activity) const
{
Tp::SimplePresence diskPresence;
KConfigGroup diskPresenceGroup = m_telepathyConfig->group(activity).group(presenceGroup);
diskPresence.type = diskPresenceGroup.readEntry<uint>(QLatin1String("PresenceType"), (uint)Tp::ConnectionPresenceTypeUnset);
diskPresence.status = diskPresenceGroup.readEntry<QString>(QLatin1String("PresenceStatus"), QLatin1String("unset"));
diskPresence.statusMessage = diskPresenceGroup.readEntry<QString>(QLatin1String("PresenceMessage"), QString());
return diskPresence;
}
/*
Status managing and auto connect class
Copyright (C) 2017 James D. Smith <smithjd15@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ACCOUNTSTATUSHELPER_H
#define ACCOUNTSTATUSHELPER_H
#include <KConfigGroup>
#include <KSharedConfig>
#include <KActivities/kactivities/consumer.h>
#include <QHash>
#include <QDBusAbstractAdaptor>
#include <TelepathyQt/AccountSet>
#include <TelepathyQt/Types>
/* This class contains incoming global and account presence change related
* functionality. Its responsibilities include receiving and exporting
* requested global and account presences, and autoconnect.
*/
class AccountStatusHelper : public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.Telepathy.AccountStatusHelper")
Q_PROPERTY(QVariantHash requestedAccountPresences READ requestedAccountPresences)
Q_PROPERTY(Tp::SimplePresence requestedGlobalPresence READ requestedGlobalPresence)
public:
AccountStatusHelper(QObject *parent = 0);
~AccountStatusHelper();
enum PresenceClass
{
Persistent = 0,
Session = 1
};
Q_ENUM(PresenceClass)
/**
* \brief A hash of the accounts and account presences.
*
* \return A Tp::AccountPtr::uniqueIdentifier() and Tp::SimplePresence QVariantHash.
*/
QVariantHash requestedAccountPresences() const;
/**
* \brief The requested global presence.
*
* \return A Tp::SimplePresence.
*/
Tp::SimplePresence requestedGlobalPresence() const;
public Q_SLOTS:
/**
* \brief Set the user requested global presence.
*
* \param presence A Tp::SimplePresence. A session presence of type unknown
* with a status message will attach the status message to the persistent
* presence. A presence type of unset will clear a presence.
*
* \param presenceClass The PresenceClass, e.g. Persistent or Session.
*/
void setRequestedGlobalPresence(const Tp::SimplePresence &presence, uint presenceClass);
/**
* \brief Set the account user requested presence.
*
* \param accountUID A Tp::AccountPtr::uniqueIdentifier().
*
* \param presence A Tp::SimplePresence. A session presence of type unknown
* with a status message will attach the status message to the persistent
* presence. A presence type of unset will clear a presence.
*
* \param presenceClass The PresenceClass, e.g. Persistent or Session.
*/
void setRequestedAccountPresence(const QString &accountUID, const Tp::SimplePresence &presence, uint presenceClass);
void reloadConfig();
Q_SIGNALS:
void statusChange(const QString &accountUID = QString());
private:
void setDiskPresence(const QString &presenceGroup, const Tp::SimplePresence &presence, const QString &activity);
Tp::SimplePresence getDiskPresence(const QString &presenceGroup, const QString &activity) const;
Tp::AccountSetPtr m_enabledAccounts;
KSharedConfigPtr m_telepathyConfig;
KActivities::Consumer *m_activities;
QHash<QString, QVariant> m_requestedAccountPresences;
Tp::SimplePresence m_requestedGlobalPresence;
bool m_autoConnect;
};
#endif // ACCOUNTSTATUSHELPER_H
......@@ -18,27 +18,21 @@
*/
#include "autoaway.h"
#include "ktp_kded_debug.h"
#include <KTp/global-presence.h>
#include <KIdleTime>
#include <KConfig>
#include <KSharedConfig>
#include <KConfigGroup>
#include <KSharedConfig>
#include <KIdleTime>
AutoAway::AutoAway(KTp::GlobalPresence *globalPresence, QObject *parent)
: TelepathyKDEDModulePlugin(globalPresence, parent),
m_awayTimeoutId(-1),
m_extAwayTimeoutId(-1)
AutoAway::AutoAway(QObject *parent)
: TelepathyKDEDModulePlugin(parent),
m_awayTimeoutId(-1),
m_extAwayTimeoutId(-1),
m_awayPresence(Tp::Presence::away()),
m_extAwayPresence(Tp::Presence::xa())
{
reloadConfig();
connect(KIdleTime::instance(), SIGNAL(timeoutReached(int)),
this, SLOT(timeoutReached(int)));
connect(KIdleTime::instance(), SIGNAL(resumingFromIdle()),
this, SLOT(backFromIdle()));
}
AutoAway::~AutoAway()
......@@ -52,61 +46,57 @@ QString AutoAway::pluginName() const
void AutoAway::timeoutReached(int id)
{
if (!isEnabled()) {
return;
}
KIdleTime::instance()->catchNextResumeEvent();
if (id == m_awayTimeoutId) {
if (m_globalPresence->currentPresence().type() != Tp::Presence::away().type() &&
m_globalPresence->currentPresence().type() != Tp::Presence::xa().type() &&
m_globalPresence->currentPresence().type() != Tp::Presence::hidden().type() &&
m_globalPresence->currentPresence().type() != Tp::Presence::offline().type()) {
m_awayMessage.replace(QLatin1String("%time"), QDateTime::currentDateTimeUtc().toString(QLatin1String("hh:mm:ss (%t)")), Qt::CaseInsensitive);
setRequestedPresence(Tp::Presence::away(m_awayMessage));
setActive(true);
}
setPlugin(m_awayPresence);
} else if (id == m_extAwayTimeoutId) {
if (m_globalPresence->currentPresence().type() == Tp::Presence::away().type()) {
m_xaMessage.replace(QLatin1String("%time"), QDateTime::currentDateTimeUtc().toString(QLatin1String("hh:mm:ss (%t)")), Qt::CaseInsensitive);
setRequestedPresence(Tp::Presence::xa(m_xaMessage));
setActive(true);
}
setPlugin(m_extAwayPresence);
} else {
return;
}
KIdleTime::instance()->catchNextResumeEvent();
}
void AutoAway::backFromIdle()
{
qCDebug(KTP_KDED_MODULE);
setActive(false);
setPlugin(Enabled);
}
void AutoAway::reloadConfig()
{
KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String("ktelepathyrc"));
config.data()->reparseConfiguration();
KConfigGroup kdedConfig = config->group("KDED");
bool autoAwayEnabled = kdedConfig.readEntry("autoAwayEnabled", true);
bool autoXAEnabled = kdedConfig.readEntry("autoXAEnabled", true);
m_awayMessage = kdedConfig.readEntry(QLatin1String("awayMessage"), QString());
m_xaMessage = kdedConfig.readEntry(QLatin1String("xaMessage"), QString());
//remove all our timeouts and only readd them if auto-away is enabled
//WARNING: can't use removeAllTimeouts because this runs inside KDED, it would remove other KDED timeouts as well
KIdleTime::instance()->removeIdleTimeout(m_awayTimeoutId);
m_awayTimeoutId = -1;
KIdleTime::instance()->removeIdleTimeout(m_extAwayTimeoutId);
m_extAwayTimeoutId = -1;
if (autoAwayEnabled) {
connect(KIdleTime::instance(), static_cast<void (KIdleTime::*)(int)>(&KIdleTime::timeoutReached), this, &AutoAway::timeoutReached);
connect(KIdleTime::instance(), &KIdleTime::resumingFromIdle, this, &AutoAway::backFromIdle);
int awayTime = kdedConfig.readEntry("awayAfter", 5);
QString awayMessage = kdedConfig.readEntry(QLatin1String("awayMessage"), QString());
awayMessage.replace(QRegularExpression(QLatin1String("%te\\b")), QLatin1String("%te+") + QString::number(awayTime));
m_awayPresence.setStatusMessage(awayMessage);
m_awayTimeoutId = KIdleTime::instance()->addIdleTimeout(awayTime * 60 * 1000);
setEnabled(true);
} else {
setEnabled(false);
disconnect(KIdleTime::instance());
}
if (autoAwayEnabled && autoXAEnabled) {
int xaTime = kdedConfig.readEntry("xaAfter", 15);
QString xaMessage = kdedConfig.readEntry(QLatin1String("xaMessage"), QString());
xaMessage.replace(QRegularExpression(QLatin1String("%te\\b")), QLatin1String("%te+") + QString::number(xaTime));
m_extAwayPresence.setStatusMessage(xaMessage);
m_extAwayTimeoutId = KIdleTime::instance()->addIdleTimeout(xaTime * 60 * 1000);
}
setPlugin(State(autoAwayEnabled));
}
......@@ -23,16 +23,12 @@
#include "telepathy-kded-module-plugin.h"
namespace KTp {
class GlobalPresence;
}
class AutoAway : public TelepathyKDEDModulePlugin
{
Q_OBJECT
public:
explicit AutoAway(KTp::GlobalPresence *globalPresence, QObject *parent = 0);
explicit AutoAway(QObject *parent = 0);
~AutoAway();
QString pluginName() const;
......@@ -41,15 +37,15 @@ public Q_SLOTS:
void reloadConfig();
private Q_SLOTS:
void timeoutReached(int);
void timeoutReached(int id);
void backFromIdle();
private:
int m_awayTimeoutId;
int m_extAwayTimeoutId;
QString m_awayMessage;
QString m_xaMessage;
Tp::Presence m_awayPresence;
Tp::Presence m_extAwayPresence;
};
#endif // AUTOAWAY_H
/*
Manage auto-connecting and restoring of the last presence
Copyright (C) 2012 Dominik Cermak <d.cermak@arcor.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "autoconnect.h"
#include <KTp/presence.h>
#include <KTp/core.h>
#include <TelepathyQt/AccountManager>
#include <KSharedConfig>
#include <KConfig>
AutoConnect::AutoConnect(QObject *parent)
: QObject(parent)
{
KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String("ktelepathyrc"));
m_kdedConfig = config->group("KDED");
m_presenceConfig = config->group("LastPresence");
uint presenceType = m_presenceConfig.readEntry<uint>(QLatin1String("PresenceType"), (uint)Tp::ConnectionPresenceTypeOffline);
QString presenceStatus = m_presenceConfig.readEntry(QLatin1String("PresenceStatus"), QString());
QString presenceMessage = m_presenceConfig.readEntry(QLatin1String("PresenceMessage"), QString());
QString autoConnectString = m_kdedConfig.readEntry(QLatin1String("autoConnect"), modeToString(AutoConnect::Manual));
Mode autoConnectMode = stringToMode(autoConnectString);
if (autoConnectMode == AutoConnect::Enabled) {
Q_FOREACH(Tp::AccountPtr account, KTp::accountManager()->allAccounts()) {
account->setRequestedPresence(Tp::Presence((Tp::ConnectionPresenceType)presenceType, presenceStatus, presenceMessage));
}
}
}
AutoConnect::~AutoConnect()
{
}
void AutoConnect::savePresence(const KTp::Presence &presence)
{
m_presenceConfig.writeEntry(QLatin1String("PresenceType"), (uint)presence.type());
m_presenceConfig.writeEntry(QLatin1String("PresenceStatus"), presence.status());
m_presenceConfig.writeEntry(QLatin1String("PresenceMessage"), presence.statusMessage());
m_presenceConfig.sync();
}
/*
Manage auto-connecting and restoring of the last presence
Copyright (C) 2012 Dominik Cermak <d.cermak@arcor.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AUTOCONNECT_H
#define AUTOCONNECT_H
#include <QDebug>
#include <KConfigGroup>
#include <TelepathyQt/Presence>
namespace KTp {
class Presence;
}
class AutoConnect : public QObject
{
Q_OBJECT
public:
enum Mode {
Disabled,
Enabled,
Manual
};
AutoConnect(QObject *parent = 0 );
~AutoConnect();
void savePresence(const KTp::Presence &presence);
/**
* \brief Returns a string for the given enum value.
*
* \param mode The enum value to convert to a string.
*
* \return The string for the enum value.
*/
static inline QString modeToString(const Mode mode)
{
switch (mode) {
case AutoConnect::Disabled:
return QString::fromLatin1