File indexing completed on 2023-11-26 04:55:46

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 }