[Merge] lp:~renatofilho/buteo-sync-plugins-contacts/new-code into lp:buteo-sync-plugins-contacts
Michael Sheldon
michael.sheldon at canonical.com
Mon Jul 20 11:52:06 UTC 2015
Review: Needs Fixing
It is correct to say that these files are part of buteo-gcontact-plugins in the copyright statements, or is this effectively a new project derived from buteo-gcontact-plugins?
I've also added a number of small things in the diff comments (mostly just typos, but also a couple of questions about some TODOs and an unused variable).
(I've only reviewed the first 1000 lines of the diff so far, so there'll be more to come)
Diff comments:
>
> === added file 'buteo-contact-client/UAbstractRemoteSource.h'
> --- buteo-contact-client/UAbstractRemoteSource.h 1970-01-01 00:00:00 +0000
> +++ buteo-contact-client/UAbstractRemoteSource.h 2015-07-19 21:39:03 +0000
> @@ -0,0 +1,119 @@
> +/*
> + * This file is part of buteo-gcontact-plugins package
> + *
> + * Copyright (C) 2015 Canonical Ltd
> + *
> + * Contributors: Renato Araujo Oliveira Filho <renato.filho at canonical.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License
> + * version 2.1 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef UABSTRACTREMOTESOURCE_H
> +#define UABSTRACTREMOTESOURCE_H
> +
> +#include <QObject>
> +#include <QDateTime>
> +#include <QVariantMap>
> +
> +#include <QtContacts/QContact>
> +
> +#include <SyncCommonDefs.h>
> +
> +class UAbstractRemoteSourcePrivate;
> +
> +class UAbstractRemoteSource : public QObject
> +{
> + Q_OBJECT
> + Q_DECLARE_PRIVATE(UAbstractRemoteSource)
> +
> +public:
> +
> + UAbstractRemoteSource(QObject *parent = 0);
> + ~UAbstractRemoteSource();
> +
> + virtual void abort() = 0;
> + virtual bool init(const QVariantMap &properties) = 0;
> + virtual void fetchContacts(const QDateTime &since, bool includeDeleted, bool fetchAvatar = true) = 0;
> +
> + /*!
> + * \brief Begins a transaction on the remote database.
> + */
> + void transaction();
> +
> + /*!
> + * \brief Commits a transaction to the remote database.
> + */
> + bool commit();
> +
> + /*!
> + * \brief Rolls back a transaction on the remote database.
> + */
> + bool rollback();
> +
> + virtual void saveContacts(const QList<QtContacts::QContact> &contacts);
> + virtual void removeContacts(const QList<QtContacts::QContact> &contacts);
> +
> +signals:
> + void contactsFetched(const QList<QtContacts::QContact> &contacts, Sync::SyncStatus status);
> +
> + /*!
> + * \brief This signal is emitted, when a remote contact is created
> + * \param contacts A list of created contacts
> + * \param status The operation status
> + */
> + void contactsCreated(const QList<QtContacts::QContact> &contacts, Sync::SyncStatus status);
> +
> + /*!
> + * \brief This signal is emitted, when a remote contact is changed
> + * \param contacts A list of changed contacts
> + * \param status The operation status
> + */
> + void contactsChanged(const QList<QtContacts::QContact> &contacts, Sync::SyncStatus status);
> +
> + /*!
> + * \brief This signal is emitted, when a remote contact is remove
Small typo, should be "removed"
> + * \param ids A list with remoteId of removed contacts
> + * \param status The operation status
> + */
> + void contactsRemoved(const QStringList &ids, Sync::SyncStatus status);
> +
> + /*!
> + * \brief This signal is emitted, when a batch operation finish
finish -> finishes
> + * \param createdContacts A list of created contacts
> + * \param updatedContacts A list of updated contacts
> + * \param removedContacts A list with remoteId of removed contacts
> + * \param status The operation status
> + */
> + void transactionCommited(const QList<QtContacts::QContact> &createdContacts,
> + const QList<QtContacts::QContact> &updatedContacts,
> + const QStringList &removedContacts,
> + Sync::SyncStatus status);
> +
> +protected:
> + virtual void batch(const QList<QtContacts::QContact> &contactsToCreate,
> + const QList<QtContacts::QContact> &contactsToUpdate,
> + const QList<QtContacts::QContact> &contactsToRemove) = 0;
> +
> + virtual void saveContactsNonBatch(const QList<QtContacts::QContact> contacts) = 0;
> + virtual void removeContactsNonBatch(const QList<QtContacts::QContact> contacts) = 0;
> +
> +private:
> + QScopedPointer<UAbstractRemoteSourcePrivate> d_ptr;
> +};
> +
> +Q_DECLARE_METATYPE(QList<QtContacts::QContact>)
> +
> +#endif
Would be good to include details of what this #endif refers to (i.e. // UABSTRACTREMOTESOURCE_H)
>
> === added file 'buteo-contact-client/UAuth.cpp'
> --- buteo-contact-client/UAuth.cpp 1970-01-01 00:00:00 +0000
> +++ buteo-contact-client/UAuth.cpp 2015-07-19 21:39:03 +0000
> @@ -0,0 +1,185 @@
> +/*
> + * This file is part of buteo-gcontact-plugins package
> + *
> + * Copyright (C) 2013 Jolla Ltd. and/or its subsidiary(-ies).
> + * 2015 Canonical Ltd
> + *
> + * Contributors: Sateesh Kavuri <sateesh.kavuri at gmail.com>
> + * Mani Chandrasekar <maninc at gmail.com>
> + * Renato Araujo Oliveira Filho <renato.filho at canonical.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License
> + * version 2.1 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#include "config.h"
> +#include "UAuth.h"
> +
> +#include <QVariantMap>
> +#include <QTextStream>
> +#include <QFile>
> +#include <QStringList>
> +#include <QDebug>
> +
> +#include <Accounts/AccountService>
> +
> +#include <ProfileEngineDefs.h>
> +#include <LogMacros.h>
> +
> +using namespace Accounts;
> +using namespace SignOn;
> +
> +const QString SYNC_SERVICE ("google-contacts2");
This doesn't appear to be used anywhere?
> +
> +class UAuthPrivate
> +{
> +public:
> + UAuthPrivate() {}
> + ~UAuthPrivate() {}
> +
> + QPointer<Accounts::Manager> mAccountManager;
> + QPointer<SignOn::Identity> mIdentity;
> + QPointer<SignOn::AuthSession> mSession;
> + QPointer<Accounts::Account> mAccount;
> + QString mServiceName;
> +};
> +
> +UAuth::UAuth(QObject *parent)
> + : QObject(parent),
> + d_ptr(new UAuthPrivate)
> +{
> +}
> +
> +UAuth::~UAuth()
> +{
> +}
> +
> +bool
> +UAuth::init(const quint32 accountId, const QString serviceName)
> +{
> + Q_D(UAuth);
> +
> + d->mServiceName = serviceName;
> + if (d->mAccountManager && d_ptr->mAccount) {
> + LOG_DEBUG("GAuth already initialized");
> + return false;
> + }
> +
> + if (!d->mAccountManager) {
> + d->mAccountManager = new Accounts::Manager();
> + if (d->mAccountManager == NULL) {
> + LOG_DEBUG("Account manager is not created... Cannot authenticate");
> + return false;
> + }
> + }
> +
> + if (!d->mAccount) {
> + d->mAccount = Accounts::Account::fromId(d->mAccountManager.data(), accountId, this);
> + if (d->mAccount == NULL) {
> + LOG_DEBUG("Account is not created... Cannot authenticate");
> + return false;
> + }
> + mDisplayName = d->mAccount->displayName();
> + }
> +
> + return true;
> +}
> +
> +void
> +UAuth::sessionResponse(const SessionData &sessionData)
> +{
> + SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession*>(sender());
> + Q_ASSERT(session);
> + session->disconnect(this);
> +
> + mToken = sessionData.getProperty(QStringLiteral("AccessToken")).toString();
> + LOG_DEBUG("Authenticated !!!");
> +
> + emit success();
> +}
> +
> +bool
> +UAuth::authenticate()
> +{
> + Q_D(UAuth);
> + if (d->mSession) {
> + LOG_WARNING(QString("error: Account %1 Authenticate already requested")
> + .arg(d->mAccount->displayName()));
> + return true;
> + }
> +
> + Accounts::Service srv(d->mAccountManager->service(d->mServiceName));
> + if (!srv.isValid()) {
> + LOG_WARNING(QString("error: Service [%1] not found for account [%2].")
> + .arg(d->mServiceName)
> + .arg(d->mAccount->displayName()));
> + return false;
> + }
> + d->mAccount->selectService(srv);
> +
> + Accounts::AccountService *accSrv = new Accounts::AccountService(d->mAccount, srv);
> + if (!accSrv) {
> + LOG_WARNING(QString("error: Aaccount %1 has no valid account service")
Aaccount -> Account
> + .arg(d->mAccount->displayName()));
> + return false;
> + }
> + if (!accSrv->isEnabled()) {
> + LOG_WARNING(QString("error: Service %1 not enable for account %2.")
enable -> enabled
> + .arg(d->mServiceName)
> + .arg(d->mAccount->displayName()));
> + return false;
> + }
> +
> + AuthData authData = accSrv->authData();
> + d->mIdentity = SignOn::Identity::existingIdentity(authData.credentialsId());
> + if (!d->mIdentity) {
> + LOG_WARNING(QString("error: Account %1 has no valid credentials")
> + .arg(d->mAccount->displayName()));
> + return false;
> + }
> +
> + d->mSession = d->mIdentity->createSession(authData.method());
> + if (!d->mSession) {
> + LOG_WARNING(QString("error: could not create signon session for Google account %1")
> + .arg(d->mAccount->displayName()));
> + accSrv->deleteLater();
> + return false;
> + }
> + connect(d->mSession.data(),SIGNAL(response(SignOn::SessionData)),
> + SLOT(sessionResponse(SignOn::SessionData)), Qt::QueuedConnection);
> + connect(d->mSession.data(), SIGNAL(error(SignOn::Error)),
> + SLOT(error(SignOn::Error)), Qt::QueuedConnection);
> + accSrv->deleteLater();
> +
> + QVariantMap signonSessionData = authData.parameters();
> + signonSessionData.insert("ClientId", GOOGLE_CONTACTS_CLIENT_ID);
> + signonSessionData.insert("ClientSecret", GOOGLE_CONTACTS_CLIENT_SECRET);
> + signonSessionData.insert("UiPolicy", SignOn::NoUserInteractionPolicy);
> + d->mSession->process(signonSessionData, authData.mechanism());
> + return true;
> +}
> +
> +void UAuth::credentialsStored(const quint32 id)
> +{
> + Q_D(UAuth);
> + d->mAccount->setCredentialsId(id);
> + d->mAccount->sync();
> +}
> +
> +void UAuth::error(const SignOn::Error & error)
> +{
> + LOG_WARNING("LOGIN ERROR:" << error.message());
> + emit failed();
> +}
>
> === added file 'buteo-contact-client/UAuth.h'
> --- buteo-contact-client/UAuth.h 1970-01-01 00:00:00 +0000
> +++ buteo-contact-client/UAuth.h 2015-07-19 21:39:03 +0000
> @@ -0,0 +1,72 @@
> +/*
> + * This file is part of buteo-gcontact-plugins package
> + *
> + * Copyright (C) 2013 Jolla Ltd. and/or its subsidiary(-ies).
> + * 2015 Canonical Ltd
> + *
> + * Contributors: Sateesh Kavuri <sateesh.kavuri at gmail.com>
> + * Mani Chandrasekar <maninc at gmail.com>
> + * Renato Araujo Oliveira Filho <renato.filho at canonical.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License
> + * version 2.1 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef UAUTH_H
> +#define UAUTH_H
> +
> +#include <QObject>
> +#include <QScopedPointer>
> +
> +#include <SignOn/AuthService>
> +#include <SignOn/Identity>
> +
> +#include <Accounts/Account>
> +#include <Accounts/Manager>
> +
> +class UAuthPrivate;
> +
> +class UAuth : public QObject
> +{
> + Q_OBJECT
> + Q_DECLARE_PRIVATE(UAuth)
> +public:
> + explicit UAuth(QObject *parent = 0);
> + ~UAuth();
> +
> + virtual bool authenticate();
> + virtual bool init(const quint32 accountId, const QString serviceName);
> +
> + inline QString accountDisplayName() const { return mDisplayName; }
> + inline QString token() const { return mToken; }
> +
> +signals:
> + void success();
> + void failed();
> +
> +protected:
> + QString mToken;
> + QString mDisplayName;
> +
> +private:
> + QScopedPointer<UAuthPrivate> d_ptr;
> +
> +private slots:
> + void credentialsStored(const quint32);
> + void error(const SignOn::Error &);
> + void sessionResponse(const SignOn::SessionData &);
> +};
> +
> +#endif // GAUTH_H
GAUTH_H -> UAUTH_H
>
> === added file 'buteo-contact-client/UContactsBackend.cpp'
> --- buteo-contact-client/UContactsBackend.cpp 1970-01-01 00:00:00 +0000
> +++ buteo-contact-client/UContactsBackend.cpp 2015-07-19 21:39:03 +0000
> @@ -0,0 +1,560 @@
> +/*
> + * This file is part of buteo-gcontact-plugins package
> + *
> + * Copyright (C) 2013 Jolla Ltd. and/or its subsidiary(-ies).
> + * 2015 Canonical Ltd
> + *
> + * Contributors: Sateesh Kavuri <sateesh.kavuri at gmail.com>
> + * Mani Chandrasekar <maninc at gmail.com>
> + * Renato Araujo Oliveira Filho <renato.filho at canonical.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License
> + * version 2.1 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#include "config.h"
> +#include "UContactsBackend.h"
> +#include "UContactsCustomDetail.h"
> +
> +#include <LogMacros.h>
> +
> +#include <QContactTimestamp>
> +#include <QContactIdFilter>
> +#include <QContactIntersectionFilter>
> +#include <QContactSyncTarget>
> +#include <QContactDetailFilter>
> +#include <QContactGuid>
> +#include <QContactDisplayLabel>
> +#include <QContactExtendedDetail>
> +#include <QContactSyncTarget>
> +
> +#include <QBuffer>
> +#include <QSet>
> +#include <QHash>
> +
> +#include <QDBusInterface>
> +#include <QDBusReply>
> +
> +static const QString CPIM_SERVICE_NAME ("com.canonical.pim");
> +static const QString CPIM_ADDRESSBOOK_OBJECT_PATH ("/com/canonical/pim/AddressBook");
> +static const QString CPIM_ADDRESSBOOK_IFACE_NAME ("com.canonical.pim.AddressBook");
> +
> +UContactsBackend::UContactsBackend(const QString &managerName, QObject* parent)
> + : QObject (parent),
> + iMgr(new QContactManager(managerName))
> +{
> + FUNCTION_CALL_TRACE;
> +}
> +
> +UContactsBackend::~UContactsBackend()
> +{
> + FUNCTION_CALL_TRACE;
> +
> + delete iMgr;
> + iMgr = NULL;
> +}
> +
> +bool
> +UContactsBackend::init(uint syncAccount, const QString &syncTarget)
> +{
> + FUNCTION_CALL_TRACE;
> +
> + // create address book it it does not exists
> + // check if the source already exists
> + QContactDetailFilter filter;
> + filter.setDetailType(QContactDetail::TypeType, QContactType::FieldType);
> + filter.setValue(QContactType::TypeGroup);
> +
> + QList<QContact> sources = iMgr->contacts(filter);
> + Q_FOREACH(const QContact &contact, sources) {
> + QContactExtendedDetail exd = UContactsCustomDetail::getCustomField(contact,
> + "ACCOUNT-ID");
> + if (!exd.isEmpty() && (exd.data().toUInt() == syncAccount)) {
> + mSyncTargetId = contact.detail<QContactGuid>().guid();
> + return true;
> + }
> + }
> +
> + // memory/mock manager does not support syncTarget
> + if (iMgr->managerName() != "mock") {
> + // create a new source if necessary
> + QContact contact;
> + contact.setType(QContactType::TypeGroup);
> +
> + QContactDisplayLabel label;
> + label.setLabel(syncTarget);
> + contact.saveDetail(&label);
> +
> + // set the new source as default
> + QContactExtendedDetail isDefault;
> + isDefault.setName("IS-PRIMARY");
> + isDefault.setData(true);
> + contact.saveDetail(&isDefault);
> +
> + // Link source with account
> + QContactExtendedDetail accountId;
> + accountId.setName("ACCOUNT-ID");
> + accountId.setData(syncAccount);
> + contact.saveDetail(&accountId);
> +
> + if (!iMgr->saveContact(&contact)) {
> + qWarning() << "Fail to create contact source:" << syncTarget;
> + return false;
> + }
> +
> + mSyncTargetId = contact.detail<QContactGuid>().guid();
> + }
> +
> + return true;
> +}
> +
> +bool
> +UContactsBackend::uninit()
> +{
> + FUNCTION_CALL_TRACE;
> +
> + return true;
> +}
> +
> +QList<QContactId>
> +UContactsBackend::getAllContactIds()
> +{
> + FUNCTION_CALL_TRACE;
> + Q_ASSERT (iMgr);
> + return iMgr->contactIds(getSyncTargetFilter());
> +}
> +
> +RemoteToLocalIdMap
> +UContactsBackend::getAllNewContactIds(const QDateTime &aTimeStamp)
> +{
> + FUNCTION_CALL_TRACE;
> + LOG_DEBUG("Retrieve New Contacts Since " << aTimeStamp);
> +
> + RemoteToLocalIdMap idList;
> + const QContactChangeLogFilter::EventType eventType =
> + QContactChangeLogFilter::EventAdded;
> +
> + getSpecifiedContactIds(eventType, aTimeStamp, &idList);
> +
> + return idList;
> +}
> +
> +RemoteToLocalIdMap
> +UContactsBackend::getAllModifiedContactIds(const QDateTime &aTimeStamp)
> +{
> +
> + FUNCTION_CALL_TRACE;
> +
> + LOG_DEBUG("Retrieve Modified Contacts Since " << aTimeStamp);
> +
> + RemoteToLocalIdMap idList;
> + const QContactChangeLogFilter::EventType eventType =
> + QContactChangeLogFilter::EventChanged;
> +
> + getSpecifiedContactIds(eventType, aTimeStamp, &idList);
> +
> + return idList;
> +}
> +
> +RemoteToLocalIdMap
> +UContactsBackend::getAllDeletedContactIds(const QDateTime &aTimeStamp)
> +{
> + FUNCTION_CALL_TRACE;
> + LOG_DEBUG("Retrieve Deleted Contacts Since " << aTimeStamp);
> +
> + RemoteToLocalIdMap idList;
> + const QContactChangeLogFilter::EventType eventType =
> + QContactChangeLogFilter::EventRemoved;
> +
> + getSpecifiedContactIds(eventType, aTimeStamp, &idList);
> +
> + return idList;
> +}
> +
> +bool
> +UContactsBackend::addContacts(QList<QContact>& aContactList,
> + QMap<int, UContactsStatus> *aStatusMap)
> +{
> + FUNCTION_CALL_TRACE;
> + Q_ASSERT(iMgr);
> + Q_ASSERT(aStatusMap);
> +
> + QMap<int, QContactManager::Error> errorMap;
> +
> + // Check if contact already exists if it exists set the contact id
> + // to cause an update instead of create a new one
> + for(int i=0; i < aContactList.size(); i++) {
> + QContact &c = aContactList[i];
> + QString remoteId = getRemoteId(c);
> + QContactId id = entryExists(remoteId);
> + if (!id.isNull()) {
> + c.setId(id);
> + } else {
> + // make sure that all contacts retrieved is saved on the correct sync target
is -> are
> + QContactSyncTarget syncTarget = c.detail<QContactSyncTarget>();
> + syncTarget.setSyncTarget(syncTargetId());
> + c.saveDetail(&syncTarget);
> + }
> +
> + // remove guid field if it exists
> + QContactGuid guid = c.detail<QContactGuid>();
> + if (!guid.isEmpty()) {
> + c.removeDetail(&guid);
> + }
> + }
> +
> + bool retVal = iMgr->saveContacts(&aContactList, &errorMap);
> + if (!retVal) {
> + LOG_WARNING( "Errors reported while saving contacts:" << iMgr->error() );
> + }
> +
> + // QContactManager will populate errorMap only for errors, but we use this as a status map,
> + // so populate NoError if there's no error.
> + // TODO QContactManager populates indices from the qContactList, but we populate keys, is this OK?
Should this assumption be verified before merging?
> + for (int i = 0; i < aContactList.size(); i++)
> + {
> + UContactsStatus status;
> + status.id = i;
> + if (!errorMap.contains(i)) {
> + status.errorCode = QContactManager::NoError;
> + } else {
> + qDebug() << "Contact with id " << aContactList.at(i).id() << " and index " << i <<" is in error";
> + status.errorCode = errorMap.value(i);
> + }
> + aStatusMap->insert(i, status);
> + }
> +
> + return retVal;
> +}
> +
> +QMap<int,UContactsStatus>
> +UContactsBackend::modifyContacts(QList<QContact> *aContactList)
> +{
> + FUNCTION_CALL_TRACE;
> +
> + Q_ASSERT (iMgr);
> + UContactsStatus status;
> +
> + QMap<int,QContactManager::Error> errors;
> + QMap<int,UContactsStatus> statusMap;
> +
> + // WORKAROUND: Our backend uses GUid as contact id due problems with contact id serialization
> + // we can not use this field
> + for (int i = 0; i < aContactList->size(); i++) {
> + QContact &newContact = (*aContactList)[i];
> + QString remoteId = getRemoteId(newContact);
> +
> + // if the contact was created the remoteId will not exists on local database
> + QContactId localId = entryExists(remoteId);
> +
> + // int this case we should use the guid stored on contact
int -> in
> + QContactGuid guid = newContact.detail<QContactGuid>();
> +
> + if (localId.isNull() && !guid.isEmpty()) {
> + // try the guid (should contains the local id) field
contains -> contain
> + localId = QContactId::fromString(guid.guid());
> + }
> + newContact.setId(localId);
> + newContact.removeDetail(&guid);
> + }
> +
> + if(iMgr->saveContacts(aContactList , &errors)) {
> + LOG_DEBUG("Batch Modification of Contacts Succeeded");
> + } else {
> + LOG_DEBUG("Batch Modification of Contacts Failed");
> + }
> +
> + // QContactManager will populate errorMap only for errors, but we use this as a status map,
> + // so populate NoError if there's no error.
> + // TODO QContactManager populates indices from the aContactList, but we populate keys, is this OK?
Same question as previous TODO, does this need confirming?
> + for (int i = 0; i < aContactList->size(); i++) {
> + QContactId contactId = aContactList->at(i).id();
> + if( !errors.contains(i) ) {
> + LOG_DEBUG("No error for contact with id " << contactId << " and index " << i);
> + status.errorCode = QContactManager::NoError;
> + statusMap.insert(i, status);
> + } else {
> + LOG_DEBUG("contact with id " << contactId << " and index " << i <<" is in error");
> + QContactManager::Error errorCode = errors.value(i);
> + status.errorCode = errorCode;
> + statusMap.insert(i, status);
> + }
> + }
> + return statusMap;
> +}
> +
> +QMap<int, UContactsStatus>
> +UContactsBackend::deleteContacts(const QStringList &aContactIDList)
> +{
> + FUNCTION_CALL_TRACE;
> +
> + QList<QContactId> qContactIdList;
> + foreach (QString id, aContactIDList) {
> + qContactIdList.append(QContactId::fromString(id));
> + }
> +
> + return deleteContacts(qContactIdList);
> +}
> +
> +QMap<int, UContactsStatus>
> +UContactsBackend::deleteContacts(const QList<QContactId> &aContactIDList) {
> + FUNCTION_CALL_TRACE;
> +
> + Q_ASSERT (iMgr);
> + UContactsStatus status;
> + QMap<int, QContactManager::Error> errors;
> + QMap<int, UContactsStatus> statusMap;
> +
> + qDebug() << "WILL REMOVE CONTACTS:" << aContactIDList;
> + if(iMgr->removeContacts(aContactIDList , &errors)) {
> + LOG_DEBUG("Successfully Removed all contacts ");
> + }
> + else {
> + LOG_WARNING("Failed Removing Contacts");
> + }
> +
> + // QContactManager will populate errorMap only for errors, but we use this as a status map,
> + // so populate NoError if there's no error.
> + // TODO QContactManager populates indices from the qContactList, but we populate keys, is this OK?
> + for (int i = 0; i < aContactIDList.size(); i++) {
> + QContactId contactId = aContactIDList.value(i);
> + if( !errors.contains(i) )
> + {
> + LOG_DEBUG("No error for contact with id " << contactId << " and index " << i);
> + status.errorCode = QContactManager::NoError;
> + statusMap.insert(i, status);
> + }
> + else
> + {
> + LOG_DEBUG("contact with id " << contactId << " and index " << i <<" is in error");
> + QContactManager::Error errorCode = errors.value(i);
> + status.errorCode = errorCode;
> + statusMap.insert(i, status);
> + }
> + }
> +
> + return statusMap;
> +}
> +
> +
> +void
> +UContactsBackend::getSpecifiedContactIds(const QContactChangeLogFilter::EventType aEventType,
> + const QDateTime& aTimeStamp,
> + RemoteToLocalIdMap *aIdList)
> +{
> + FUNCTION_CALL_TRACE;
> + Q_ASSERT(aIdList);
> +
> + QList<QContactId> localIdList;
> + QContactChangeLogFilter filter(aEventType);
> + filter.setSince(aTimeStamp);
> +
> + localIdList = iMgr->contactIds(filter & getSyncTargetFilter());
> + LOG_DEBUG("Local ID added = " << localIdList.size() << " Datetime from when this " << aTimeStamp.toString());
> + // Filter out ids for items that were added after the specified time.
> + if (aEventType != QContactChangeLogFilter::EventAdded)
> + {
> + filter.setEventType(QContactChangeLogFilter::EventAdded);
> + QList<QContactId> addedList = iMgr->contactIds(filter & getSyncTargetFilter());
> + foreach (const QContactId &id, addedList)
> + {
> + localIdList.removeAll(id);
> + }
> + }
> +
> + // This is a defensive procedure to prevent duplicate items being sent.
> + // QSet does not allow duplicates, thus transforming QList to QSet and back
> + // again will remove any duplicate items in the original QList.
> + int originalIdCount = localIdList.size();
> + QSet<QContactId> idSet = localIdList.toSet();
> + int idCountAfterDupRemoval = idSet.size();
> +
> + LOG_DEBUG("Item IDs found (returned / incl. duplicates): " << idCountAfterDupRemoval << "/" << originalIdCount);
> + if (originalIdCount != idCountAfterDupRemoval) {
> + LOG_WARNING("Contacts backend returned duplicate items for requested list");
> + LOG_WARNING("Duplicate item IDs have been removed");
> + } // no else
> +
> + localIdList = idSet.toList();
> +
> + QContactFetchHint remoteIdHint;
> + QList <QContactDetail::DetailType> detailTypes;
> + detailTypes << QContactExtendedDetail::Type;
> + remoteIdHint.setDetailTypesHint(detailTypes);
> +
> + QList<QContact> contacts = iMgr->contacts(localIdList, remoteIdHint);
> + foreach (const QContact &contact, contacts) {
> + QString rid = getRemoteId(contact);
> + aIdList->insertMulti(rid, contact.id());
> + }
> +}
> +
> +/*!
> + \fn GContactsBackend::getContact(QContactId aContactId)
> + */
> +QContact
> +UContactsBackend::getContact(const QContactId& aContactId)
> +{
> + FUNCTION_CALL_TRACE;
> + Q_ASSERT (iMgr);
> + QList<QContact> returnedContacts;
> +
> + LOG_DEBUG("Contact ID to be retreived = " << aContactId.toString());
> + returnedContacts = iMgr->contacts(QList<QContactId>() << aContactId);
> +
> + LOG_DEBUG("Contacts retreived from Contact manager = " << returnedContacts.count());
> + return returnedContacts.value(0, QContact());
> +}
> +
> +QContact
> +UContactsBackend::getContact(const QString& remoteId)
> +{
> + FUNCTION_CALL_TRACE;
> + Q_ASSERT (iMgr);
> + LOG_DEBUG("Remote id to be searched for = " << remoteId);
> +
> + //FIXME: use guid field when supported by address-book-service
> + QContactIntersectionFilter remoteIdFilter = getRemoteIdFilter(remoteId);
> + QList<QContact> contactList = iMgr->contacts(remoteIdFilter & getSyncTargetFilter());
> + if (contactList.size() > 0) {
> + return contactList.at(0);
> + }
> + return QContact();
> +}
> +
> +QContactId
> +UContactsBackend::entryExists(const QString remoteId)
> +{
> + if (remoteId.isEmpty()) {
> + return QContactId();
> + }
> +
> + QContactFilter ridFilter = getRemoteIdFilter(remoteId);
> + QList<QContactId> idList = iMgr->contactIds(ridFilter & getSyncTargetFilter());
> + if (idList.size () > 0)
> + return idList.first ();
> + else
> + return QContactId();
> +}
> +
> +QString
> +UContactsBackend::syncTargetId() const
> +{
> + return mSyncTargetId;
> +}
> +
> +const QStringList
> +UContactsBackend::localIds(const QStringList remoteIds)
> +{
> + QStringList localIdList;
> + foreach (QString guid , remoteIds) {
> + QString localId = entryExists(guid).toString();
> + if (!localId.isEmpty()) {
> + localIdList << localId;
> + }
> + }
> + Q_ASSERT(localIdList.count() == remoteIds.count());
> + return localIdList;
> +}
> +
> +QContactFilter
> +UContactsBackend::getRemoteIdFilter(const QString &remoteId) const
> +{
> + QContactIntersectionFilter remoteFilter;
> +
> + QContactDetailFilter xDetailNameFilter;
> + xDetailNameFilter.setDetailType(QContactExtendedDetail::Type,
> + QContactExtendedDetail::FieldName);
> + xDetailNameFilter.setValue(UContactsCustomDetail::FieldRemoteId);
> +
> + QContactDetailFilter xDetailValueFilter;
> + xDetailValueFilter.setDetailType(QContactExtendedDetail::Type,
> + QContactExtendedDetail::FieldData);
> + xDetailValueFilter.setValue(remoteId);
> +
> + remoteFilter << xDetailNameFilter
> + << xDetailValueFilter;
> + return remoteFilter;
> +}
> +
> +QString
> +UContactsBackend::getRemoteId(const QContact &contact)
> +{
> + return UContactsCustomDetail::getCustomField(contact, UContactsCustomDetail::FieldRemoteId).data().toString();
> +}
> +
> +void UContactsBackend::setRemoteId(QContact &contact, const QString &remoteId)
> +{
> + UContactsCustomDetail::setCustomField(contact, UContactsCustomDetail::FieldRemoteId, QVariant(remoteId));
> +}
> +
> +QString UContactsBackend::getLocalId(const QContact &contact)
> +{
> + QContactGuid guid = contact.detail<QContactGuid>();
> + return guid.guid();
> +}
> +
> +void UContactsBackend::setLocalId(QContact &contact, const QString &localId)
> +{
> + QContactGuid guid = contact.detail<QContactGuid>();
> + guid.setGuid(localId);
> + contact.saveDetail(&guid);
> +}
> +
> +bool UContactsBackend::deleted(const QContact &contact)
> +{
> + QString deletedAt = UContactsCustomDetail::getCustomField(contact, UContactsCustomDetail::FieldDeletedAt).data().toString();
> + return !deletedAt.isEmpty();
> +}
> +
> +void
> +UContactsBackend::purgecontacts()
> +{
> + QDBusInterface iface(CPIM_SERVICE_NAME,
> + CPIM_ADDRESSBOOK_OBJECT_PATH,
> + CPIM_ADDRESSBOOK_IFACE_NAME);
> + QDBusReply<void> reply = iface.call("purgeContacts", QString(""), mSyncTargetId);
> + if (reply.error().isValid()) {
> + LOG_WARNING("Fail to purge contacts" << reply.error());
> + } else {
> + LOG_DEBUG("Purged backend contacts");
> + }
> +}
> +
> +QContactFilter
> +UContactsBackend::getSyncTargetFilter() const
> +{
> + // user enterred contacts, i.e. all other contacts that are not sourcing
> + // from restricted backends or instant messaging service
> + static QContactDetailFilter detailFilterDefaultSyncTarget;
> +
> + if (!mSyncTargetId.isEmpty() &&
> + detailFilterDefaultSyncTarget.value().isNull()) {
> + detailFilterDefaultSyncTarget.setDetailType(QContactSyncTarget::Type,
> + QContactSyncTarget::FieldSyncTarget + 1);
> + detailFilterDefaultSyncTarget.setValue(mSyncTargetId);
> + } else if (mSyncTargetId.isEmpty()) {
> + return QContactFilter();
> + }
> +
> + // return the union
> + return detailFilterDefaultSyncTarget;
> +}
> +
> +
> +QtContacts::QContactManager *UContactsBackend::manager() const
> +{
> + return iMgr;
> +}
--
https://code.launchpad.net/~renatofilho/buteo-sync-plugins-contacts/new-code/+merge/264335
Your team Ubuntu Phablet Team is subscribed to branch lp:buteo-sync-plugins-contacts.
More information about the Ubuntu-reviews
mailing list