Akonadi

akonadicontrol/accountsintegration.cpp
1 /***************************************************************************
2  * SPDX-FileCopyrightText: 2019 Daniel Vr├ítil <[email protected]> *
3  * *
4  * SPDX-License-Identifier: LGPL-2.0-or-later *
5  ***************************************************************************/
6 
7 #include "accountsintegration.h"
8 #include "accountsinterface.h"
9 #include "agentmanager.h"
10 #include "akonadicontrol_debug.h"
11 
12 #include <private/dbus_p.h>
13 
14 #include <QDBusConnection>
15 #include <QTimer>
16 
17 #include <Accounts/Account>
18 #include <Accounts/Service>
19 
20 using namespace Akonadi;
21 using namespace std::chrono_literals;
22 
23 namespace
24 {
25 const auto akonadiAgentType = QStringLiteral("akonadi/agentType");
26 
27 }
28 
29 AccountsIntegration::AccountsIntegration(AgentManager &agentManager)
30  : mAgentManager(agentManager)
31 {
32  connect(&mAccountsManager, &Accounts::Manager::accountCreated, this, &AccountsIntegration::onAccountAdded);
33  connect(&mAccountsManager, &Accounts::Manager::accountRemoved, this, &AccountsIntegration::onAccountRemoved);
34 
35  const auto accounts = mAccountsManager.accountList();
36  for (const auto account : accounts) {
37  connect(mAccountsManager.account(account), &Accounts::Account::enabledChanged, this, &AccountsIntegration::onAccountServiceEnabled);
38  }
39 }
40 
41 std::optional<QString> AccountsIntegration::agentForAccount(const QString &agentType, Accounts::AccountId accountId) const
42 {
43  const auto instances = mAgentManager.agentInstances();
44  for (const auto &identifier : instances) {
45  if (mAgentManager.agentInstanceType(identifier) == agentType) {
46  const auto serviceName = Akonadi::DBus::agentServiceName(identifier, Akonadi::DBus::Resource);
47  org::kde::Akonadi::Accounts accountsIface(serviceName, QStringLiteral("/Accounts"), QDBusConnection::sessionBus());
48  if (!accountsIface.isValid()) {
49  continue;
50  }
51 
52  if (accountsIface.getAccountId() == accountId) {
53  return identifier;
54  }
55  }
56  }
57  return std::nullopt;
58 }
59 
60 void AccountsIntegration::configureAgentInstance(const QString &identifier, Accounts::AccountId accountId, int attempt)
61 {
62  const auto serviceName = Akonadi::DBus::agentServiceName(identifier, Akonadi::DBus::Resource);
63  org::kde::Akonadi::Accounts accountsIface(serviceName, QStringLiteral("/Accounts"), QDBusConnection::sessionBus());
64  if (!accountsIface.isValid()) {
65  if (attempt >= 3) {
66  qCWarning(AKONADICONTROL_LOG) << "The resource" << identifier << "does not provide the Accounts DBus interface. Will remove the agent";
67  mAgentManager.removeAgentInstance(identifier);
68  } else {
69  QTimer::singleShot(2s, this, [this, identifier, accountId, attempt]() {
70  configureAgentInstance(identifier, accountId, attempt + 1);
71  });
72  }
73  return;
74  }
75 
76  accountsIface.setAccountId(accountId);
77  qCDebug(AKONADICONTROL_LOG) << "Configured resource" << identifier << "for account" << accountId;
78 }
79 
80 void AccountsIntegration::createAgent(const QString &agentType, Accounts::AccountId accountId)
81 {
82  const auto identifier = mAgentManager.createAgentInstance(agentType);
83  qCDebug(AKONADICONTROL_LOG) << "Created resource" << identifier << "for account" << accountId;
84  configureAgentInstance(identifier, accountId);
85 }
86 
87 void AccountsIntegration::removeAgentInstance(const QString &identifier)
88 {
89  mAgentManager.removeAgentInstance(identifier);
90 }
91 
92 void AccountsIntegration::onAccountAdded(Accounts::AccountId accId)
93 {
94  qCDebug(AKONADICONTROL_LOG) << "Online account ID" << accId << "added.";
95  auto account = mAccountsManager.account(accId);
96  if (!account || !account->isEnabled()) {
97  return;
98  }
99 
100  const auto enabledServices = account->enabledServices();
101  for (const auto &service : enabledServices) {
102  account->selectService(service);
103  const auto agentType = account->valueAsString(akonadiAgentType);
104  if (agentType.isEmpty()) {
105  continue; // doesn't support Akonadi :-(
106  }
107  const auto agent = agentForAccount(agentType, accId);
108  if (!agent.has_value()) {
109  createAgent(agentType, account->id());
110  }
111  // Always go through all services, there may be more!
112  }
113  account->selectService();
114 
115  connect(account, &Accounts::Account::enabledChanged, this, &AccountsIntegration::onAccountServiceEnabled);
116 }
117 
118 void AccountsIntegration::onAccountRemoved(Accounts::AccountId accId)
119 {
120  qCDebug(AKONADICONTROL_LOG) << "Online account ID" << accId << "removed.";
121 
122  const auto instances = mAgentManager.agentInstances();
123  for (const auto &instance : instances) {
124  const auto serviceName = DBus::agentServiceName(instance, DBus::Resource);
125  org::kde::Akonadi::Accounts accountIface(serviceName, QStringLiteral("/Accounts"), QDBusConnection::sessionBus());
126  if (!accountIface.isValid()) {
127  continue;
128  }
129 
130  if (accountIface.getAccountId() == accId) {
131  removeAgentInstance(instance);
132  }
133  }
134 }
135 
136 void AccountsIntegration::onAccountServiceEnabled(const QString &serviceType, bool enabled)
137 {
138  if (serviceType.isEmpty()) {
139  return;
140  }
141 
142  auto account = qobject_cast<Accounts::Account *>(sender());
143  qCDebug(AKONADICONTROL_LOG) << "Online account ID" << account->id() << "service" << serviceType << "has been" << (enabled ? "enabled" : "disabled");
144 
145  const auto service = mAccountsManager.service(serviceType);
146  account->selectService(service);
147  const auto agentType = account->valueAsString(akonadiAgentType);
148  account->selectService();
149  if (agentType.isEmpty()) {
150  return; // this service does not support Akonadi (yet -;)
151  }
152 
153  const auto identifier = agentForAccount(agentType, account->id());
154  if (enabled && !identifier.has_value()) {
155  createAgent(agentType, account->id());
156  } else if (!enabled && identifier.has_value()) {
157  removeAgentInstance(identifier.value());
158  }
159 }
Provides an interface to retrieve agent types and manage agent instances.
QDBusConnection sessionBus()
bool isEmpty() const const
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jul 2 2022 06:41:46 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.