File indexing completed on 2023-10-01 08:41:44
0001 /* 0002 * This file is part of telepathy-common-internals 0003 * 0004 * Copyright (C) 2012 David Edmundson <kde@davidedmundson.co.uk> 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 St, Fifth Floor, Boston, MA 02110-1301 USA 0019 */ 0020 0021 #include "global-contact-manager.h" 0022 0023 #include <TelepathyQt/AccountManager> 0024 #include <TelepathyQt/Account> 0025 #include <TelepathyQt/ContactManager> 0026 #include <TelepathyQt/PendingReady> 0027 0028 #include "KTp/types.h" 0029 0030 #include "ktp-debug.h" 0031 0032 0033 namespace KTp { 0034 class GlobalContactManagerPrivate { 0035 public: 0036 Tp::AccountManagerPtr accountManager; 0037 }; 0038 } 0039 0040 using namespace KTp; 0041 0042 GlobalContactManager::GlobalContactManager(const Tp::AccountManagerPtr &accountManager, QObject *parent) : 0043 QObject(parent), 0044 d(new GlobalContactManagerPrivate()) 0045 { 0046 d->accountManager = accountManager; 0047 connect(d->accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountManagerReady(Tp::PendingOperation*))); 0048 } 0049 0050 GlobalContactManager::~GlobalContactManager() 0051 { 0052 delete d; 0053 } 0054 0055 Tp::Contacts GlobalContactManager::allKnownContacts() const 0056 { 0057 Tp::Contacts allContacts; 0058 if (d->accountManager.isNull()) { 0059 return allContacts; 0060 } 0061 0062 Q_FOREACH(const Tp::AccountPtr &account, d->accountManager->allAccounts()) { 0063 if (!account->connection().isNull() && account->connection()->contactManager()->state() == Tp::ContactListStateSuccess) { 0064 allContacts.unite(account->connection()->contactManager()->allKnownContacts()); 0065 } 0066 } 0067 return allContacts; 0068 } 0069 0070 void GlobalContactManager::onAccountManagerReady(Tp::PendingOperation *op) 0071 { 0072 if (op->isError()) { 0073 qCWarning(KTP_COMMONINTERNALS) << "Account Manager becomeReady failed"; 0074 } 0075 0076 Q_FOREACH(const Tp::AccountPtr &account, d->accountManager->allAccounts()) { 0077 onNewAccount(account); 0078 } 0079 connect(d->accountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)), SLOT(onNewAccount(Tp::AccountPtr))); 0080 0081 } 0082 0083 void GlobalContactManager::onNewAccount(const Tp::AccountPtr &account) 0084 { 0085 if (account->isValidAccount()) { 0086 onConnectionChanged(account->connection()); 0087 connect(account.data(), SIGNAL(connectionChanged(Tp::ConnectionPtr)), SLOT(onConnectionChanged(Tp::ConnectionPtr))); 0088 } 0089 } 0090 0091 0092 void GlobalContactManager::onConnectionChanged(const Tp::ConnectionPtr &connection) 0093 { 0094 if (connection.isNull()) { 0095 return; 0096 } 0097 0098 //fetch the roster 0099 //only request roster groups if we support it. Otherwise it can error and not finish becoming ready 0100 //this is needed to fetch contacts from Salut which do not support groups 0101 Tp::Features connectionFeatures; 0102 connectionFeatures << Tp::Connection::FeatureRoster; 0103 0104 if (connection->hasInterface(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS)) { 0105 connectionFeatures << Tp::Connection::FeatureRosterGroups; 0106 } 0107 Tp::PendingReady *op = connection->becomeReady(connectionFeatures); 0108 op->setProperty("connection", QVariant::fromValue<Tp::ConnectionPtr>(connection)); 0109 connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onConnectionReady(Tp::PendingOperation*))); 0110 } 0111 0112 void GlobalContactManager::onConnectionReady(Tp::PendingOperation *op) 0113 { 0114 Tp::ConnectionPtr connection = op->property("connection").value<Tp::ConnectionPtr>(); 0115 if (!connection) { 0116 return; 0117 } 0118 0119 onContactManagerStateChanged(connection->contactManager(), connection->contactManager()->state()); 0120 connect(connection->contactManager().data(), SIGNAL(stateChanged(Tp::ContactListState)), SLOT(onContactManagerStateChanged(Tp::ContactListState))); 0121 } 0122 0123 void GlobalContactManager::onContactManagerStateChanged(Tp::ContactListState state) 0124 { 0125 Tp::ContactManager* contactManager = qobject_cast<Tp::ContactManager*>(sender()); 0126 Q_ASSERT(contactManager); 0127 onContactManagerStateChanged(Tp::ContactManagerPtr(contactManager), state); 0128 } 0129 0130 void GlobalContactManager::onContactManagerStateChanged(const Tp::ContactManagerPtr &contactManager, Tp::ContactListState state) 0131 { 0132 //contact manager still isn't ready. Do nothing. 0133 if (state != Tp::ContactListStateSuccess) { 0134 return; 0135 } 0136 0137 //contact manager connected, inform everyone of potential new contacts 0138 Q_EMIT allKnownContactsChanged(contactManager->allKnownContacts(), Tp::Contacts()); 0139 0140 connect(contactManager.data(), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts,Tp::Channel::GroupMemberChangeDetails)), SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts))); 0141 } 0142 0143 Tp::AccountPtr GlobalContactManager::accountForContact(const Tp::ContactPtr &contact) const 0144 { 0145 if (!contact || !contact->manager()) { 0146 qCWarning(KTP_COMMONINTERNALS) << "Null contact or contact manager!"; 0147 return Tp::AccountPtr(); 0148 } 0149 return accountForConnection(contact->manager()->connection()); 0150 } 0151 0152 Tp::AccountPtr GlobalContactManager::accountForConnection(const Tp::ConnectionPtr &connection) const 0153 { 0154 //loop through all accounts looking for a matching connection. 0155 //arguably inneficient, but no. of accounts is normally very low, and it's not called very often. 0156 Q_FOREACH(const Tp::AccountPtr &account, d->accountManager->allAccounts()) { 0157 if (account->connection() == connection) { 0158 return account; 0159 } 0160 } 0161 0162 return Tp::AccountPtr(); 0163 } 0164 0165 Tp::AccountPtr GlobalContactManager::accountForAccountId(const QString &accountId) const 0166 { 0167 if (!d->accountManager.isNull() && d->accountManager->isReady()) { 0168 Q_FOREACH(const Tp::AccountPtr &account, d->accountManager->allAccounts()) { 0169 if (account->uniqueIdentifier() == accountId) { 0170 return account; 0171 } 0172 } 0173 } 0174 0175 return Tp::AccountPtr(); 0176 } 0177 0178 Tp::AccountPtr GlobalContactManager::accountForAccountPath(const QString &accountPath) const 0179 { 0180 if (!d->accountManager.isNull() && d->accountManager->isReady()) { 0181 return d->accountManager->accountForObjectPath(accountPath); 0182 } 0183 0184 return Tp::AccountPtr(); 0185 } 0186 0187 KTp::ContactPtr GlobalContactManager::contactForContactId(const QString &accountPath, const QString &contactId) 0188 { 0189 Q_ASSERT(!accountPath.isEmpty()); 0190 if (!d->accountManager || accountPath.isEmpty()) { 0191 qWarning() << "Account manager unavailable"; 0192 return KTp::ContactPtr(); 0193 } 0194 0195 Tp::AccountPtr account = d->accountManager->accountForObjectPath(accountPath); 0196 if (!account) { 0197 qWarning() << "account not found" << accountPath; 0198 } 0199 0200 if (account && account->connection() && account->connection()->contactManager() && account->connection()->isReady(Tp::Connection::FeatureRoster)) { 0201 Tp::Contacts contactSet = account->connection()->contactManager()->allKnownContacts(); 0202 Q_FOREACH (const Tp::ContactPtr &contact, contactSet) { 0203 if (contact->id() == contactId) { 0204 return KTp::ContactPtr::qObjectCast(contact); 0205 } 0206 } 0207 } 0208 // qDebug() << "Couldn't find a contact for" << contactId; 0209 0210 return KTp::ContactPtr(); 0211 }