File indexing completed on 2023-05-30 11:40:29

0001 /*
0002     Copyright (C) 2017-2018  James D. Smith <smithjd15@gmail.com>
0003     Copyright (C) 2014  David Edmundson <kde@davidedmundson.co.uk>
0004     Copyright (C) 2011  Martin Klapetek <martin.klapetek@gmail.com>
0005 
0006     This library is free software; you can redistribute it and/or
0007     modify it under the terms of the GNU Lesser General Public
0008     License as published by the Free Software Foundation; either
0009     version 2.1 of the License, or (at your option) any later version.
0010 
0011     This library is distributed in the hope that it will be useful,
0012     but WITHOUT ANY WARRANTY; without even the implied warranty of
0013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014     Lesser General Public License for more details.
0015 
0016     You should have received a copy of the GNU Lesser General Public
0017     License along with this library; if not, write to the Free Software
0018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0019 */
0020 
0021 #include "status-handler.h"
0022 
0023 #include "autoaway.h"
0024 #include "screensaveraway.h"
0025 
0026 #include "account-status-helper.h"
0027 #include "status-message-parser.h"
0028 
0029 #include "ktp_kded_debug.h"
0030 
0031 #include <QTimer>
0032 #include <QVariant>
0033 #include <QHash>
0034 
0035 #include <TelepathyQt/Account>
0036 #include <TelepathyQt/AccountSet>
0037 #include <TelepathyQt/AccountManager>
0038 #include <TelepathyQt/Constants>
0039 #include <TelepathyQt/Presence>
0040 
0041 StatusHandler::StatusHandler(QObject* parent)
0042     : QObject(parent),
0043     m_enabledAccounts(KTp::accountManager()->enabledAccounts())
0044 {
0045     QDBusConnection::sessionBus().registerObject(QLatin1String("/StatusHandler"), this);
0046 
0047     QDBusConnection::sessionBus().connect(QString(), QLatin1String("/Telepathy"), QLatin1String("org.kde.Telepathy"),
0048                                       QLatin1String("settingsChange"), this, SIGNAL(settingsChanged()));
0049 
0050     m_accountStatusHelper = new AccountStatusHelper(this);
0051 
0052     m_parsers[QLatin1String("GlobalPresence")] = new StatusMessageParser(this);
0053     connect(m_parsers[QLatin1String("GlobalPresence")], &StatusMessageParser::statusMessageChanged, [=] {
0054         qCDebug(KTP_KDED_MODULE) << "global presence parser has new status message" << m_parsers[QLatin1String("GlobalPresence")]->statusMessage();
0055         setPresence();
0056     });
0057 
0058     m_parsers[QLatin1String("PluginPresence")] = new StatusMessageParser(this);
0059     connect(m_parsers[QLatin1String("PluginPresence")], &StatusMessageParser::statusMessageChanged, [=] {
0060         qCDebug(KTP_KDED_MODULE) << "plugin presence parser has new status message" << m_parsers[QLatin1String("PluginPresence")]->statusMessage();
0061         setPresence();
0062     });
0063 
0064     auto addAccount = [=] (const Tp::AccountPtr &account) {
0065         // Connect a new status message parser for the account.
0066         m_parsers[account->uniqueIdentifier()] = new StatusMessageParser(this);
0067         connect(m_parsers[account->uniqueIdentifier()], &StatusMessageParser::statusMessageChanged, m_parsers[account->uniqueIdentifier()], [=] {
0068             qCDebug(KTP_KDED_MODULE) << "account" << account->uniqueIdentifier() << "parser has new status message" << m_parsers[account->uniqueIdentifier()]->statusMessage();
0069             setPresence(account->uniqueIdentifier());
0070         });
0071 
0072         qCDebug(KTP_KDED_MODULE) << "new parser:" << account->uniqueIdentifier();
0073 
0074         // Watch for automatic presence changes from the account.
0075         connect(account.data(), &Tp::Account::automaticPresenceChanged, account.data(), [=] (const Tp::Presence &automaticPresence) {
0076             m_accountStatusHelper->setRequestedAccountPresence(account->uniqueIdentifier(), automaticPresence.barePresence(), AccountStatusHelper::Persistent);
0077         });
0078     };
0079 
0080     for (const Tp::AccountPtr &account : m_enabledAccounts->accounts()) {
0081         addAccount(account);
0082     }
0083 
0084     m_pluginPresence.setStatus(Tp::ConnectionPresenceTypeUnset, QLatin1String("unset"), QString());
0085 
0086     AutoAway *autoAway = new AutoAway(this);
0087     ScreenSaverAway *screenSaverAway = new ScreenSaverAway(this);
0088 
0089     //earlier in list = lower priority
0090     m_queuePlugins << screenSaverAway << autoAway;
0091 
0092     for (TelepathyKDEDModulePlugin* plugin : m_queuePlugins) {
0093         connect(plugin, &TelepathyKDEDModulePlugin::pluginChanged, [=] () {
0094             QList<TelepathyKDEDModulePlugin*> activePlugins;
0095             for (TelepathyKDEDModulePlugin* plugin : m_queuePlugins) {
0096                 if (plugin->pluginState() != TelepathyKDEDModulePlugin::Active)
0097                     continue;
0098 
0099                 if (KTp::Presence::sortPriority(plugin->requestedPresence().type())
0100                     >= KTp::Presence::sortPriority(m_pluginPresence.type())) {
0101                     activePlugins.prepend(plugin);
0102                 } else {
0103                     activePlugins.append(plugin);
0104                 }
0105             }
0106 
0107             if (activePlugins.isEmpty()) {
0108                 m_pluginPresence.setStatus(Tp::ConnectionPresenceTypeUnset, QLatin1String("unset"), QString());
0109             } else {
0110                 m_pluginPresence = activePlugins.at(0)->requestedPresence();
0111             }
0112 
0113             m_parsers[(QLatin1String("PluginPresence"))]->parseStatusMessage(m_pluginPresence.statusMessage());
0114             qCDebug(KTP_KDED_MODULE) << "plugin queue activation:" << m_pluginPresence.status()
0115               << m_parsers[(QLatin1String("PluginPresence"))]->statusMessage();
0116 
0117             setPresence();
0118         });
0119 
0120         connect(this, &StatusHandler::settingsChanged, plugin, &TelepathyKDEDModulePlugin::reloadConfig);
0121     }
0122 
0123     connect(m_accountStatusHelper, &AccountStatusHelper::statusChange, [=] (const QString &accountUID) {
0124         if (accountUID.isEmpty()) {
0125             m_parsers[QLatin1String("GlobalPresence")]->parseStatusMessage(m_accountStatusHelper->requestedGlobalPresence().statusMessage);
0126         } else {
0127             Tp::Presence presence = Tp::Presence(qvariant_cast<Tp::SimplePresence>(m_accountStatusHelper->requestedAccountPresences().value(accountUID)));
0128             m_parsers[accountUID]->parseStatusMessage(presence.statusMessage());
0129 
0130             // The global presence parser must be set for accounts using the global presence.
0131             if ((presence.type() == Tp::ConnectionPresenceTypeUnset)
0132               && (m_parsers[QLatin1String("GlobalPresence")]->statusMessage().isEmpty()
0133               != m_accountStatusHelper->requestedGlobalPresence().statusMessage.isEmpty())) {
0134                 m_parsers[QLatin1String("GlobalPresence")]->parseStatusMessage(m_accountStatusHelper->requestedGlobalPresence().statusMessage);
0135             }
0136         }
0137 
0138         setPresence(accountUID);
0139     });
0140 
0141     connect(m_enabledAccounts.data(), &Tp::AccountSet::accountAdded, [=] (const Tp::AccountPtr &account) {
0142         addAccount(account);
0143     });
0144 
0145     connect(m_enabledAccounts.data(), &Tp::AccountSet::accountRemoved, [=] (const Tp::AccountPtr &account) {
0146         disconnect(account.data(), &Tp::Account::requestedPresenceChanged, account.data(), Q_NULLPTR);
0147         disconnect(m_parsers[account->uniqueIdentifier()], &StatusMessageParser::statusMessageChanged, m_parsers[account->uniqueIdentifier()], Q_NULLPTR);
0148         m_parsers.remove(account->uniqueIdentifier());
0149         parkAccount(account);
0150     });
0151 }
0152 
0153 StatusHandler::~StatusHandler()
0154 {
0155     QDBusConnection::sessionBus().unregisterObject(QLatin1String("/StatusHandler"), QDBusConnection::UnregisterTree);
0156 
0157     for (const Tp::AccountPtr &account : KTp::accountManager()->onlineAccounts()->accounts()) {
0158         disconnect(account.data(), &Tp::Account::requestedPresenceChanged, account.data(), Q_NULLPTR);
0159         parkAccount(account);
0160     }
0161 }
0162 
0163 void StatusHandler::setPresence(const QString &accountUID)
0164 {
0165     const QString &globalParsedMessage = m_parsers[QLatin1String("GlobalPresence")]->statusMessage();
0166     const QString &pluginParsedMessage = m_parsers[QLatin1String("PluginPresence")]->statusMessage();
0167     const QHash<QString, QString> &pluginTokens = m_parsers[QLatin1String("PluginPresence")]->tokens();
0168 
0169     auto accountPresence = [&] (const QString &accountUID) {
0170         Tp::Presence presence = Tp::Presence(qvariant_cast<Tp::SimplePresence>(m_accountStatusHelper->requestedAccountPresences().value(accountUID)));
0171         QHash<QString, QString> tokens;
0172 
0173         if ((presence.type() == Tp::ConnectionPresenceTypeUnset)
0174             || (m_accountStatusHelper->requestedGlobalPresence().type == Tp::Presence::offline().type())) {
0175             tokens = m_parsers[QLatin1String("GlobalPresence")]->tokens();
0176             presence = Tp::Presence(m_accountStatusHelper->requestedGlobalPresence());
0177             presence.setStatusMessage(globalParsedMessage);
0178         } else {
0179             tokens = m_parsers[accountUID]->tokens();
0180 
0181             if (tokens.contains((QLatin1String("%um"))) && tokens[(QLatin1String("%um"))] == QLatin1String("g")) {
0182                 presence.setStatusMessage(globalParsedMessage);
0183             } else {
0184                 presence.setStatusMessage(m_parsers[accountUID]->statusMessage());
0185             }
0186         }
0187 
0188         bool sourcePluginQueue = (presence.type() != Tp::ConnectionPresenceTypeHidden)
0189           && (presence.type() != Tp::ConnectionPresenceTypeOffline)
0190           && (m_pluginPresence.type() != Tp::ConnectionPresenceTypeUnset);
0191 
0192         if (sourcePluginQueue) {
0193             if (KTp::Presence::sortPriority(presence.type()) < KTp::Presence::sortPriority(m_pluginPresence.type())) {
0194                 presence = Tp::Presence(m_pluginPresence.type(), m_pluginPresence.status(), QString());
0195             }
0196 
0197             if (!pluginTokens.contains(QLatin1String("%um")) && !tokens.contains(QLatin1String("%um"))) {
0198                 presence.setStatusMessage(pluginParsedMessage);
0199             } else if (tokens.contains((QLatin1String("%um"))) && tokens[(QLatin1String("%um"))] == QLatin1String("g")) {
0200                 presence.setStatusMessage(globalParsedMessage);
0201             }
0202         }
0203 
0204         return presence;
0205     };
0206 
0207     for (const Tp::AccountPtr &account : m_enabledAccounts->accounts()) {
0208         if (!accountUID.isEmpty() && (accountUID != account->uniqueIdentifier())) {
0209             continue;
0210         }
0211 
0212         const Tp::Presence presence = accountPresence(account->uniqueIdentifier());
0213         connect(account->setRequestedPresence(presence), &Tp::PendingOperation::finished, [=] (Tp::PendingOperation *op) {
0214             if (!op->isError()) {
0215                 qCDebug(KTP_KDED_MODULE) << account->uniqueIdentifier() << "requested presence change to" << presence.status() << "with status message" << presence.statusMessage();
0216             } else {
0217                 qCWarning(KTP_KDED_MODULE()) << account->uniqueIdentifier() << "requested presence change error:" << op->errorMessage();
0218             }
0219         });
0220     }
0221 }
0222 
0223 void StatusHandler::parkAccount(const Tp::AccountPtr &account)
0224 {
0225     Tp::SimplePresence accountPresence = qvariant_cast<Tp::SimplePresence>(m_accountStatusHelper->requestedAccountPresences().value(account->uniqueIdentifier()));
0226     if (accountPresence.type == Tp::ConnectionPresenceTypeUnset) {
0227         accountPresence = m_accountStatusHelper->requestedGlobalPresence();
0228     }
0229     accountPresence.statusMessage = QLatin1String();
0230 
0231     account->setRequestedPresence(Tp::Presence(accountPresence));
0232 }