[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