File indexing completed on 2024-05-26 05:13:54
0001 /*************************************************************************** 0002 * SPDX-FileCopyrightText: 2019 Daniel Vrátil <dvratil@kde.org> * 0003 * * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later * 0005 ***************************************************************************/ 0006 0007 #include "accountsintegration.h" 0008 #include "accountsinterface.h" 0009 #include "agentmanager.h" 0010 #include "akonadicontrol_debug.h" 0011 0012 #include "private/dbus_p.h" 0013 0014 #include <QDBusConnection> 0015 #include <QTimer> 0016 0017 #include <Accounts/Account> 0018 #include <Accounts/Service> 0019 0020 using namespace Akonadi; 0021 using namespace std::chrono_literals; 0022 0023 namespace 0024 { 0025 const auto akonadiAgentType = QStringLiteral("akonadi/agentType"); 0026 0027 } 0028 0029 AccountsIntegration::AccountsIntegration(AgentManager &agentManager) 0030 : mAgentManager(agentManager) 0031 { 0032 connect(&mAccountsManager, &Accounts::Manager::accountCreated, this, &AccountsIntegration::onAccountAdded); 0033 connect(&mAccountsManager, &Accounts::Manager::accountRemoved, this, &AccountsIntegration::onAccountRemoved); 0034 0035 const auto accounts = mAccountsManager.accountList(); 0036 for (const auto account : accounts) { 0037 connect(mAccountsManager.account(account), &Accounts::Account::enabledChanged, this, &AccountsIntegration::onAccountServiceEnabled); 0038 } 0039 } 0040 0041 std::optional<QString> AccountsIntegration::agentForAccount(const QString &agentType, Accounts::AccountId accountId) const 0042 { 0043 const auto instances = mAgentManager.agentInstances(); 0044 for (const auto &identifier : instances) { 0045 if (mAgentManager.agentInstanceType(identifier) == agentType) { 0046 const auto serviceName = Akonadi::DBus::agentServiceName(identifier, Akonadi::DBus::Resource); 0047 org::kde::Akonadi::Accounts accountsIface(serviceName, QStringLiteral("/Accounts"), QDBusConnection::sessionBus()); 0048 if (!accountsIface.isValid()) { 0049 continue; 0050 } 0051 0052 if (accountsIface.getAccountId() == accountId) { 0053 return identifier; 0054 } 0055 } 0056 } 0057 return std::nullopt; 0058 } 0059 0060 void AccountsIntegration::configureAgentInstance(const QString &identifier, Accounts::AccountId accountId, int attempt) 0061 { 0062 const auto serviceName = Akonadi::DBus::agentServiceName(identifier, Akonadi::DBus::Resource); 0063 org::kde::Akonadi::Accounts accountsIface(serviceName, QStringLiteral("/Accounts"), QDBusConnection::sessionBus()); 0064 if (!accountsIface.isValid()) { 0065 if (attempt >= 3) { 0066 qCWarning(AKONADICONTROL_LOG) << "The resource" << identifier << "does not provide the Accounts DBus interface. Will remove the agent"; 0067 mAgentManager.removeAgentInstance(identifier); 0068 } else { 0069 QTimer::singleShot(2s, this, [this, identifier, accountId, attempt]() { 0070 configureAgentInstance(identifier, accountId, attempt + 1); 0071 }); 0072 } 0073 return; 0074 } 0075 0076 accountsIface.setAccountId(accountId); 0077 qCDebug(AKONADICONTROL_LOG) << "Configured resource" << identifier << "for account" << accountId; 0078 } 0079 0080 void AccountsIntegration::createAgent(const QString &agentType, Accounts::AccountId accountId) 0081 { 0082 const auto identifier = mAgentManager.createAgentInstance(agentType); 0083 qCDebug(AKONADICONTROL_LOG) << "Created resource" << identifier << "for account" << accountId; 0084 configureAgentInstance(identifier, accountId); 0085 } 0086 0087 void AccountsIntegration::removeAgentInstance(const QString &identifier) 0088 { 0089 mAgentManager.removeAgentInstance(identifier); 0090 } 0091 0092 void AccountsIntegration::onAccountAdded(Accounts::AccountId accId) 0093 { 0094 qCDebug(AKONADICONTROL_LOG) << "Online account ID" << accId << "added."; 0095 auto account = mAccountsManager.account(accId); 0096 if (!account || !account->isEnabled()) { 0097 return; 0098 } 0099 0100 const auto enabledServices = account->enabledServices(); 0101 for (const auto &service : enabledServices) { 0102 account->selectService(service); 0103 const auto agentType = account->valueAsString(akonadiAgentType); 0104 if (agentType.isEmpty()) { 0105 continue; // doesn't support Akonadi :-( 0106 } 0107 const auto agent = agentForAccount(agentType, accId); 0108 if (!agent.has_value()) { 0109 createAgent(agentType, account->id()); 0110 } 0111 // Always go through all services, there may be more! 0112 } 0113 account->selectService(); 0114 0115 connect(account, &Accounts::Account::enabledChanged, this, &AccountsIntegration::onAccountServiceEnabled); 0116 } 0117 0118 void AccountsIntegration::onAccountRemoved(Accounts::AccountId accId) 0119 { 0120 qCDebug(AKONADICONTROL_LOG) << "Online account ID" << accId << "removed."; 0121 0122 const auto instances = mAgentManager.agentInstances(); 0123 for (const auto &instance : instances) { 0124 const auto serviceName = DBus::agentServiceName(instance, DBus::Resource); 0125 org::kde::Akonadi::Accounts accountIface(serviceName, QStringLiteral("/Accounts"), QDBusConnection::sessionBus()); 0126 if (!accountIface.isValid()) { 0127 continue; 0128 } 0129 0130 if (accountIface.getAccountId() == accId) { 0131 removeAgentInstance(instance); 0132 } 0133 } 0134 } 0135 0136 void AccountsIntegration::onAccountServiceEnabled(const QString &serviceType, bool enabled) 0137 { 0138 if (serviceType.isEmpty()) { 0139 return; 0140 } 0141 0142 auto account = qobject_cast<Accounts::Account *>(sender()); 0143 qCDebug(AKONADICONTROL_LOG) << "Online account ID" << account->id() << "service" << serviceType << "has been" << (enabled ? "enabled" : "disabled"); 0144 0145 const auto service = mAccountsManager.service(serviceType); 0146 account->selectService(service); 0147 const auto agentType = account->valueAsString(akonadiAgentType); 0148 account->selectService(); 0149 if (agentType.isEmpty()) { 0150 return; // this service does not support Akonadi (yet -;) 0151 } 0152 0153 const auto identifier = agentForAccount(agentType, account->id()); 0154 if (enabled && !identifier.has_value()) { 0155 createAgent(agentType, account->id()); 0156 } else if (!enabled && identifier.has_value()) { 0157 removeAgentInstance(identifier.value()); 0158 } 0159 } 0160 0161 #include "moc_accountsintegration.cpp"