[Merge] lp:~renatofilho/address-book-service/changes-necessary-to-work-with-buteo into lp:address-book-service

Michael Sheldon michael.sheldon at canonical.com
Tue Sep 29 11:39:43 UTC 2015


Review: Needs Fixing

Added in line diffs up to line 5000 (max launchpad can show), will continue with normal comments for the remaining lines.

Diff comments:

> 
> === modified file 'common/filter.cpp'
> --- common/filter.cpp	2015-08-07 14:27:25 +0000
> +++ common/filter.cpp	2015-09-24 17:48:11 +0000
> @@ -236,6 +278,105 @@
>      return checkIsEmpty(QList<QContactFilter>() << m_filter);
>  }
>  
> +bool Filter::includeRemoved() const
> +{
> +    // Only return removed contacts if the filter type is ChangeLogFilter
> +    return (m_filter.type() == QContactFilter::ChangeLogFilter);
> +}
> +
> +QString Filter::phoneNumberToFilter() const
> +{
> +    return phoneNumberToFilter(m_filter);
> +}
> +
> +QStringList Filter::idsToFilter() const
> +{
> +    return idsToFilter(m_filter);
> +}
> +
> +QString Filter::phoneNumberToFilter(const QtContacts::QContactFilter &filter)
> +{
> +    switch (filter.type()) {
> +    case QContactFilter::ContactDetailFilter:
> +    {
> +        const QContactDetailFilter cdf(filter);
> +        if (cdf.matchFlags() & QContactFilter::MatchPhoneNumber) {
> +            return cdf.value().toString();
> +        }
> +        break;
> +    }
> +    case QContactFilter::UnionFilter:
> +    {
> +        // if the union contains only the phone filter we still able to optimize

we -> we're

> +        const QContactUnionFilter uf(filter);
> +        if (uf.filters().size() == 1) {
> +            return phoneNumberToFilter(uf.filters().first());
> +        }
> +        break;
> +    }
> +    case QContactFilter::IntersectionFilter:
> +    {
> +        const QContactIntersectionFilter cif(filter);
> +        Q_FOREACH(const QContactFilter &f, cif.filters()) {
> +            QString phoneToFilter = phoneNumberToFilter(f);
> +            if (!phoneToFilter.isEmpty()) {
> +                return phoneToFilter;
> +            }
> +        }
> +        break;
> +    }
> +    default:
> +        break;
> +    }
> +    return QString();
> +}
> +
> +QStringList Filter::idsToFilter(const QtContacts::QContactFilter &filter)
> +{
> +    QStringList result;
> +
> +    switch (filter.type()) {
> +    case QContactFilter::ContactDetailFilter:
> +    {
> +        const QContactDetailFilter cdf(filter);
> +        if ((cdf.detailType() == QContactDetail::TypeGuid) &&
> +            (cdf.detailField() == QContactGuid::FieldGuid) &&
> +            cdf.matchFlags().testFlag(QContactFilter::MatchExactly)) {
> +            result << cdf.value().toString();
> +        }
> +        break;
> +    }
> +    case QContactFilter::IdFilter:
> +    {
> +
> +        const QContactIdFilter idf(filter);
> +        Q_FOREACH(const QContactId &id, idf.ids()) {
> +            result << id.toString();
> +        }
> +        break;
> +    }
> +    case QContactFilter::UnionFilter:
> +    {
> +        const QContactUnionFilter uf(filter);
> +        Q_FOREACH(const QContactFilter &f, uf.filters()) {
> +            result.append(idsToFilter(f));
> +        }
> +        break;
> +    }
> +    case QContactFilter::IntersectionFilter:
> +    {
> +        const QContactIntersectionFilter cif(filter);
> +        Q_FOREACH(const QContactFilter &f, cif.filters()) {
> +            result.append(idsToFilter(f));
> +        }
> +        break;
> +    }
> +    default:
> +        break;
> +    }
> +    return result;
> +}
> +
>  QString Filter::toString(const QtContacts::QContactFilter &filter)
>  {
>      QByteArray filterArray;
> 
> === modified file 'common/filter.h'
> --- common/filter.h	2015-07-29 21:02:56 +0000
> +++ common/filter.h	2015-09-24 17:48:11 +0000
> @@ -45,7 +51,10 @@
>  
>      bool checkIsEmpty(const QList<QtContacts::QContactFilter> filters) const;
>      bool checkIsValid(const QList<QtContacts::QContactFilter> filters) const;
> +    //bool test(const QtContacts::QContactFilter &filter, const QtContacts::QContact &contact, const QDateTime &deletedDate) const;

Why is this commented out instead of simply removed?

>  
> +    static QString phoneNumberToFilter(const QtContacts::QContactFilter &filter);
> +    static QStringList idsToFilter(const QtContacts::QContactFilter &filter);
>      static QString toString(const QtContacts::QContactFilter &filter);
>      static QtContacts::QContactFilter buildFilter(const QString &filter);
>  
> 
> === modified file 'common/vcard-parser.cpp'
> --- common/vcard-parser.cpp	2014-08-11 21:22:02 +0000
> +++ common/vcard-parser.cpp	2015-09-24 17:48:11 +0000
> @@ -116,102 +128,137 @@
>  
>          virtual void contactProcessed(const QContact& contact, QVersitDocument* document)
>          {
> +            if (!contact.id().isNull() &&
> +                contact.details<QContactGuid>().isEmpty()) {
> +                // translate contact id to uid vcard
> +                QVersitProperty prop;
> +                prop.setName("UID");
> +                prop.setValue(contact.id().toString().split("::").last());
> +                document->addProperty(prop);
> +            }
>              Q_UNUSED(contact);
>              document->removeProperties("X-QTPROJECT-EXTENDED-DETAIL");
>          }
>      };
>  
>  
> -    class  ContactImporterPropertyHandler : public QVersitContactImporterPropertyHandlerV2
> -    {
> -    public:
> -        virtual void propertyProcessed(const QVersitDocument& document,
> -                                       const QVersitProperty& property,
> -                                       const QContact& contact,
> -                                       bool *alreadyProcessed,
> -                                       QList<QContactDetail>* updatedDetails)
> -        {
> -            Q_UNUSED(document);
> -            Q_UNUSED(contact);
> -
> -            if (!*alreadyProcessed && (property.name() == galera::VCardParser::PidMapFieldName)) {
> -                QContactSyncTarget target;
> -                target.setSyncTarget(property.value<QString>());
> -                *updatedDetails  << target;
> -                *alreadyProcessed = true;
> -            }
> -
> -            if (!*alreadyProcessed) {
> -                return;
> -            }
> -
> -            QString pid = property.parameters().value(galera::VCardParser::PidFieldName);
> -            if (!pid.isEmpty()) {
> -                QContactDetail &det = updatedDetails->last();
> -                det.setDetailUri(pid);
> -            }
> -
> -            bool ro = (property.parameters().value(galera::VCardParser::ReadOnlyFieldName, "NO") == "YES");
> -            bool irremovable = (property.parameters().value(galera::VCardParser::IrremovableFieldName, "NO") == "YES");
> -            if (ro && irremovable) {
> -                QContactDetail &det = updatedDetails->last();
> -                QContactManagerEngine::setDetailAccessConstraints(&det,
> -                                                                  QContactDetail::ReadOnly |
> -                                                                  QContactDetail::Irremovable);
> -            } else if (ro) {
> -                QContactDetail &det = updatedDetails->last();
> -                QContactManagerEngine::setDetailAccessConstraints(&det,
> -                                                                  QContactDetail::ReadOnly);
> -            } else if (irremovable) {
> -                QContactDetail &det = updatedDetails->last();
> -                QContactManagerEngine::setDetailAccessConstraints(&det,
> -                                                                  QContactDetail::Irremovable);
> -            }
> -
> -            if (updatedDetails->size() == 0) {
> -                return;
> -            }
> -
> -            // Remove empty phone and address subtypes
> -            QContactDetail &det = updatedDetails->last();
> -            switch (det.type()) {
> -                case QContactDetail::TypePhoneNumber:
> -                {
> -                    QContactPhoneNumber phone = static_cast<QContactPhoneNumber>(det);
> -                    if (phone.subTypes().isEmpty()) {
> -                        det.setValue(QContactPhoneNumber::FieldSubTypes, QVariant());
> -                    }
> -                    if (property.parameters().contains(galera::VCardParser::PrefParamName)) {
> -                        m_prefferedPhone = phone;
> -                    }
> -                    break;
> -                }
> -                case QContactDetail::TypeAvatar:
> -                {
> -                    QString value = property.parameters().value("VALUE");
> -                    if (value == "URL") {
> -                        det.setValue(QContactAvatar::FieldImageUrl, QUrl(property.value()));
> -                    }
> -                    break;
> -                }
> -                default:
> -                    break;
> -            }
> -        }
> -
> -        virtual void documentProcessed(const QVersitDocument& document, QContact* contact)
> -        {
> -            Q_UNUSED(document);
> -            Q_UNUSED(contact);
> -            if (!m_prefferedPhone.isEmpty()) {
> -                contact->setPreferredDetail(galera::VCardParser::PreferredActionNames[QContactDetail::TypePhoneNumber],
> -                                            m_prefferedPhone);
> -                m_prefferedPhone = QContactDetail();
> -            }
> -        }
> -    private:
> -        QContactDetail m_prefferedPhone;
> -    };
> +class  ContactImporterPropertyHandler : public QVersitContactImporterPropertyHandlerV2

Why has the indentation been changed for this class? It's still part of the same namespace as ContactExporterDetailHandler so I'd have thought it should have the same level of indentation.

> +{
> +public:
> +    virtual void propertyProcessed(const QVersitDocument& document,
> +                                   const QVersitProperty& property,
> +                                   const QContact& contact,
> +                                   bool *alreadyProcessed,
> +                                   QList<QContactDetail>* updatedDetails)
> +    {
> +        Q_UNUSED(document);
> +        Q_UNUSED(contact);
> +
> +        if (!*alreadyProcessed && (property.name() == galera::VCardParser::PidMapFieldName)) {
> +            QContactSyncTarget target;
> +            QStringList values = property.value().split(QStringLiteral(";"));
> +            target.setSyncTarget(values.value(0));
> +            target.setValue(QContactSyncTarget::FieldSyncTarget + 1, values.value(1));
> +            *updatedDetails  << target;
> +            *alreadyProcessed = true;
> +        }
> +
> +        if (!*alreadyProcessed && (property.name().startsWith("X-"))) {
> +            QContactExtendedDetail xDet;
> +            xDet.setName(property.name());
> +            xDet.setData(property.value<QString>());
> +            *updatedDetails  << xDet;
> +            *alreadyProcessed = true;
> +        }
> +
> +        if (!*alreadyProcessed) {
> +            return;
> +        }
> +
> +        QString pid = property.parameters().value(galera::VCardParser::PidFieldName);
> +        if (!pid.isEmpty()) {
> +            QContactDetail &det = updatedDetails->last();
> +            det.setDetailUri(pid);
> +        }
> +
> +        bool ro = (property.parameters().value(galera::VCardParser::ReadOnlyFieldName, "NO") == "YES");
> +        bool irremovable = (property.parameters().value(galera::VCardParser::IrremovableFieldName, "NO") == "YES");
> +        if (ro && irremovable) {
> +            QContactDetail &det = updatedDetails->last();
> +            QContactManagerEngine::setDetailAccessConstraints(&det,
> +                                                              QContactDetail::ReadOnly |
> +                                                              QContactDetail::Irremovable);
> +        } else if (ro) {
> +            QContactDetail &det = updatedDetails->last();
> +            QContactManagerEngine::setDetailAccessConstraints(&det,
> +                                                              QContactDetail::ReadOnly);
> +        } else if (irremovable) {
> +            QContactDetail &det = updatedDetails->last();
> +            QContactManagerEngine::setDetailAccessConstraints(&det,
> +                                                              QContactDetail::Irremovable);
> +        }
> +
> +        if (updatedDetails->size() == 0) {
> +            return;
> +        }
> +
> +        // Remove empty phone and address subtypes
> +        QContactDetail &det = updatedDetails->last();
> +        switch (det.type()) {
> +            case QContactDetail::TypePhoneNumber:
> +            {
> +                QContactPhoneNumber phone = static_cast<QContactPhoneNumber>(det);
> +                if (phone.subTypes().isEmpty()) {
> +                    det.setValue(QContactPhoneNumber::FieldSubTypes, QVariant());
> +                }
> +                if (property.parameters().contains(galera::VCardParser::PrefParamName)) {
> +                    m_prefferedPhone = phone;
> +                }
> +                break;
> +            }
> +            case QContactDetail::TypeAvatar:
> +            {
> +                QString value = property.parameters().value("VALUE");
> +                if (value == "URL") {
> +                    det.setValue(QContactAvatar::FieldImageUrl, QUrl(property.value()));
> +                }
> +                break;
> +            }
> +            default:
> +                break;
> +        }
> +    }
> +
> +    virtual void documentProcessed(const QVersitDocument& document, QContact* contact)
> +    {
> +        if (!m_prefferedPhone.isEmpty()) {
> +            contact->setPreferredDetail(galera::VCardParser::PreferredActionNames[QContactDetail::TypePhoneNumber],
> +                                        m_prefferedPhone);
> +            m_prefferedPhone = QContactDetail();
> +        }
> +
> +        if (contact->id().isNull() &&
> +            !contact->detail<QContactGuid>().isEmpty()) {
> +            QContactId id = QContactId::fromString(
> +                        QString("qtcontacts:galera::%1").arg(contact->detail<QContactGuid>().guid()));
> +            contact->setId(id);
> +        }
> +
> +        //update contact timestamp with X-CREATED-AT
> +        QContactTimestamp timestamp = contact->detail<QContactTimestamp>();
> +        QDateTime createdAt = timestamp.lastModified();
> +        Q_FOREACH(const QVersitProperty &prop, document.properties()) {
> +            if (prop.name() == "X-CREATED-AT") {
> +                createdAt = QDateTime::fromString(prop.value(), Qt::ISODate).toUTC();
> +                break;
> +            }
> +        }
> +        timestamp.setCreated(createdAt);
> +        contact->saveDetail(&timestamp);
> +    }
> +private:
> +    QContactDetail m_prefferedPhone;
> +};
>  }
>  
>  
> 
> === added file 'eds-extension/module-ubuntu-sources.c'
> --- eds-extension/module-ubuntu-sources.c	1970-01-01 00:00:00 +0000
> +++ eds-extension/module-ubuntu-sources.c	2015-09-24 17:48:11 +0000
> @@ -0,0 +1,400 @@
> +/*
> + * Copyright (C) 2015 Canonical Ltd
> + *
> + * This library is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License 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 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, see <http://www.gnu.org/licenses/>.
> + *
> + * Authors: Renato Araujo Oliveira Filho <renato.filho at canonical.com>
> + *
> + */
> +
> +#include "e-source-ubuntu.h"
> +
> +#include <libebackend/libebackend.h>
> +#include <libaccounts-glib/accounts-glib.h>
> +
> +#define E_AG_SERVICE_TYPE_CALENDAR "calendar"
> +#define E_AG_SERVICE_TYPE_CONTACTS "contacts"
> +
> +/* Standard GObject macros */
> +#define E_TYPE_UBUNTU_SOURCES \
> +    (e_ubuntu_sources_get_type ())
> +#define E_UBUNTU_SOURCES(obj) \
> +    (G_TYPE_CHECK_INSTANCE_CAST \
> +    ((obj), E_TYPE_UBUNTU_SOURCES, EUbuntuSources))
> +
> +
> +typedef struct _EUbuntuSources EUbuntuSources;
> +typedef struct _EUbuntuSourcesClass EUbuntuSourcesClass;
> +
> +struct _EUbuntuSources {
> +    EExtension parent;
> +
> +    AgManager *ag_manager;
> +    /* AgAccountId -> ESource UID */
> +    GHashTable *uoa_to_eds;
> +
> +};
> +
> +struct _EUbuntuSourcesClass {
> +    EExtensionClass parent_class;
> +};
> +
> +
> +/* Module Entry Points */
> +void e_module_load (GTypeModule *type_module);
> +void e_module_unload (GTypeModule *type_module);
> +
> +/* Forward Declarations */
> +GType e_ubuntu_sources_get_type (void);
> +
> +G_DEFINE_TYPE (
> +    EUbuntuSources,
> +    e_ubuntu_sources,
> +    E_TYPE_EXTENSION)
> +
> +static ESourceRegistryServer *
> +ubuntu_sources_get_server (EUbuntuSources *extension)
> +{
> +    EExtensible *extensible;
> +
> +    extensible = e_extension_get_extensible (E_EXTENSION (extension));
> +
> +    return E_SOURCE_REGISTRY_SERVER (extensible);
> +}
> +
> +static void
> +ubuntu_sources_remove_collection (EUbuntuSources *extension,
> +                                  ESource *source)
> +{
> +    GError *local_error = NULL;
> +    ESourceUbuntu *ubuntu_ext;
> +
> +    ubuntu_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_UBUNTU);
> +    if (e_source_ubuntu_get_autoremove (ubuntu_ext)) {
> +        /* This removes the entire subtree rooted at source.
> +         * Deletes the corresponding on-disk key files too. */
> +        e_source_remove_sync (source, NULL, &local_error);
> +
> +        if (local_error != NULL) {
> +            g_warning ("%s: %s", G_STRFUNC, local_error->message);
> +            g_error_free (local_error);
> +        }
> +    }
> +}
> +
> +static void
> +ubuntu_sources_config_source (EUbuntuSources *extension,
> +                              ESource *source,
> +                              AgAccount *ag_account)
> +{
> +    ESourceExtension *source_extension;
> +    g_debug("CONFIGURE SOURCE: %s,%s", e_source_get_display_name(source),
> +            e_source_get_uid(source));
> +
> +    g_object_bind_property (
> +        ag_account, "display-name",
> +        source, "display-name",
> +        G_BINDING_SYNC_CREATE);
> +
> +    g_object_bind_property (
> +        ag_account, "enabled",
> +        source, "enabled",
> +        G_BINDING_SYNC_CREATE);
> +
> +    source_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_UBUNTU);
> +
> +    g_object_bind_property (
> +        ag_account, "id",
> +        source_extension, "account-id",
> +        G_BINDING_SYNC_CREATE);
> +}
> +
> +static void
> +ubuntu_sources_account_deleted_cb (AgManager *ag_manager,
> +                                   AgAccountId ag_account_id,
> +                                   EUbuntuSources *extension)
> +{
> +    ESource *source = NULL;
> +    ESourceRegistryServer *server;
> +    GSList *eds_id_list;
> +    GSList *link;
> +
> +    server = ubuntu_sources_get_server (extension);
> +
> +    eds_id_list = g_hash_table_lookup (extension->uoa_to_eds,
> +                                       GUINT_TO_POINTER (ag_account_id));
> +
> +    g_debug("Sources registered for account: %d", g_slist_length (eds_id_list));
> +
> +    for (link = eds_id_list; link != NULL; link = g_slist_next (link)) {
> +        const gchar *source_uid = link->data;
> +
> +        source = e_source_registry_server_ref_source (server, source_uid);
> +        if (source != NULL) {
> +            ubuntu_sources_remove_collection (extension, source);
> +            g_object_unref (source);
> +        }
> +    }
> +
> +    g_hash_table_remove (extension->uoa_to_eds,
> +                         GUINT_TO_POINTER (ag_account_id));
> +}
> +
> +static gboolean
> +ubuntu_sources_register_source (EUbuntuSources *extension,
> +                                ESource *source)
> +{
> +    ESourceUbuntu *ubuntu_ext;
> +    AgAccountId ag_account_id;
> +    AgAccount *ag_account;
> +
> +    g_debug("REgister new source: %s/%s", e_source_get_display_name(source),

REgister -> Register

> +            e_source_get_uid(source));
> +
> +    if (!e_source_has_extension (source, E_SOURCE_EXTENSION_UBUNTU)) {
> +        return FALSE;
> +    }
> +
> +    ubuntu_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_UBUNTU);
> +    ag_account_id = e_source_ubuntu_get_account_id (ubuntu_ext);
> +    ag_account = ag_manager_get_account (extension->ag_manager,
> +                                         ag_account_id);
> +
> +    if (ag_account) {
> +        GSList *eds_id_list;
> +        GSList *match;
> +        const gchar *source_uid;
> +
> +        eds_id_list = g_hash_table_lookup (extension->uoa_to_eds,
> +                                           GUINT_TO_POINTER (ag_account_id));
> +
> +        source_uid = e_source_get_uid (source);
> +        match = g_slist_find(eds_id_list, source_uid);
> +        if (match) {
> +            g_object_unref (ag_account);
> +            g_debug ("Source Already registered");
> +            return FALSE;
> +        }
> +
> +
> +        eds_id_list = g_slist_append (eds_id_list, g_strdup (source_uid));
> +        g_hash_table_insert (extension->uoa_to_eds,
> +                             GUINT_TO_POINTER (ag_account_id),
> +                             eds_id_list);
> +
> +        ubuntu_sources_config_source (extension, source, ag_account);
> +
> +        g_object_unref (ag_account);
> +
> +        g_debug("Source %s, linked with account %d", source_uid, ag_account_id);
> +        return TRUE;
> +    }
> +
> +    return FALSE;
> +}
> +
> +static void
> +ubuntu_sources_populate_accounts_table (EUbuntuSources *extension)
> +{
> +    ESourceRegistryServer *server;
> +    GQueue trash = G_QUEUE_INIT;
> +    GList *list, *link;
> +
> +    server = ubuntu_sources_get_server (extension);
> +    list = e_source_registry_server_list_sources (server,
> +                                                  E_SOURCE_EXTENSION_UBUNTU);
> +
> +    g_debug ("Found %d ubuntu accounts.", g_list_length(list));
> +    for (link = list; link != NULL; link = g_list_next (link)) {
> +        ESource *source;
> +        source = E_SOURCE (link->data);
> +
> +        /* If a matching AgAccountId was found, add it
> +         * to our accounts hash table.  Otherwise remove
> +         * the ESource after we finish looping. */
> +        if (!ubuntu_sources_register_source (extension, source)) {
> +            g_debug ("Account not found we will remove the source: %s",
> +                     e_source_get_display_name (source));
> +
> +            g_queue_push_tail (&trash, source);
> +        }
> +    }
> +
> +    /* Empty the trash. */
> +    while (!g_queue_is_empty (&trash)) {
> +        ESource *source = g_queue_pop_head (&trash);
> +        ubuntu_sources_remove_collection (extension, source);
> +    }
> +
> +    g_list_free_full (list, (GDestroyNotify) g_object_unref);
> +    g_debug("ubuntu_sources_populate_accounts_table:END");
> +}
> +
> +static void
> +ubuntu_source_source_added_cb (ESourceRegistryServer *server,
> +                               ESource *source,
> +                               EUbuntuSources *extension)
> +{
> +    ubuntu_sources_register_source (extension, source);
> +}
> +
> +static void
> +ubuntu_source_source_removed_cb (ESourceRegistryServer *server,
> +                                 ESource *source,
> +                                 EUbuntuSources *extension)
> +{
> +    GHashTableIter iter;
> +    gpointer key, value;
> +
> +    const gchar *source_uid = e_source_get_uid(source);
> +
> +    g_hash_table_iter_init (&iter, extension->uoa_to_eds);
> +    while (g_hash_table_iter_next (&iter, &key, &value)) {
> +        GSList *sources = (GSList*) value;
> +        gint index = g_slist_index (sources, source_uid);
> +        if (index > -1) {
> +            g_debug ("Remove source :%s for account %lu", source_uid, (gulong) value);
> +            sources = g_slist_remove (sources, source_uid);
> +        }
> +    }
> +}
> +
> +static void
> +ubuntu_sources_bus_acquired_cb (EDBusServer *server,
> +                                GDBusConnection *connection,
> +                                EUbuntuSources *extension)
> +{
> +    g_debug("loading ubuntu sources");
> +
> +    extension->ag_manager = ag_manager_new ();
> +
> +    /* This populates a hash table of UOA ID -> ESource UID strings by
> +     * searching through available data sources for ones with a "Ubuntu
> +     * Source" extension.  If such an extension is found, but
> +     * no corresponding AgAccount (presumably meaning the UOA account
> +     * was somehow deleted between E-D-S sessions) then the ESource in
> +     * which the extension was found gets deleted. */
> +    ubuntu_sources_populate_accounts_table (extension);
> +
> +    /* Listen for Online Account changes. */
> +    g_signal_connect (extension->ag_manager, "account-deleted",
> +                      G_CALLBACK (ubuntu_sources_account_deleted_cb),
> +                      extension);
> +
> +    ESourceRegistryServer *registry_server;
> +    registry_server = ubuntu_sources_get_server (extension);
> +    g_signal_connect (registry_server, "source_added",
> +                      G_CALLBACK (ubuntu_source_source_added_cb),
> +                      extension);
> +    g_signal_connect (registry_server, "source_removed",
> +                      G_CALLBACK (ubuntu_source_source_removed_cb),
> +                      extension);
> +}
> +
> +static void
> +ubuntu_sources_dispose (GObject *object)
> +{
> +    EUbuntuSources *extension;
> +
> +    extension = E_UBUNTU_SOURCES (object);
> +
> +    if (extension->ag_manager != NULL) {
> +        g_signal_handlers_disconnect_matched (
> +            extension->ag_manager,
> +            G_SIGNAL_MATCH_DATA,
> +            0, 0, NULL, NULL, object);
> +        g_object_unref (extension->ag_manager);
> +        extension->ag_manager = NULL;
> +    }
> +
> +    /* Chain up to parent's dispose() method. */
> +    G_OBJECT_CLASS (e_ubuntu_sources_parent_class)->dispose (object);
> +}
> +
> +static void
> +ubuntu_sources_finalize (GObject *object)
> +{
> +    EUbuntuSources *extension;
> +
> +    extension = E_UBUNTU_SOURCES (object);
> +
> +    g_hash_table_destroy (extension->uoa_to_eds);
> +
> +    /* Chain up to parent's finalize() method. */
> +    G_OBJECT_CLASS (e_ubuntu_sources_parent_class)->finalize (object);
> +}
> +
> +static void
> +ubuntu_sources_constructed (GObject *object)
> +{
> +    EExtension *extension;
> +    EExtensible *extensible;
> +
> +    extension = E_EXTENSION (object);
> +    extensible = e_extension_get_extensible (extension);
> +
> +    /* Wait for the registry service to acquire its well-known
> +     * bus name so we don't do anything destructive beforehand.
> +     * Run last so that all the sources get loaded first. */
> +
> +    g_signal_connect_after (
> +        extensible, "bus-acquired",
> +        G_CALLBACK (ubuntu_sources_bus_acquired_cb),
> +        extension);
> +
> +    /* Chain up to parent's constructed() method. */
> +    G_OBJECT_CLASS (e_ubuntu_sources_parent_class)->constructed (object);
> +}
> +
> +static void
> +e_ubuntu_sources_class_init (EUbuntuSourcesClass *klass)
> +{
> +    GObjectClass *object_class;
> +    EExtensionClass *extension_class;
> +
> +    object_class = G_OBJECT_CLASS (klass);
> +    object_class->dispose = ubuntu_sources_dispose;
> +    object_class->finalize = ubuntu_sources_finalize;
> +    object_class->constructed = ubuntu_sources_constructed;
> +
> +    extension_class = E_EXTENSION_CLASS (klass);
> +    extension_class->extensible_type = E_TYPE_SOURCE_REGISTRY_SERVER;
> +}
> +
> +static void
> +e_ubuntu_sources_destroy_eds_id_slist (GSList *eds_id_list)
> +{
> +    g_slist_free_full (eds_id_list, g_free);
> +}
> +
> +static void
> +e_ubuntu_sources_init (EUbuntuSources *extension)
> +{
> +    extension->uoa_to_eds = g_hash_table_new_full (
> +        (GHashFunc) g_direct_hash,
> +        (GEqualFunc) g_direct_equal,
> +        (GDestroyNotify) NULL,
> +        (GDestroyNotify) e_ubuntu_sources_destroy_eds_id_slist);
> +}
> +
> +G_MODULE_EXPORT void
> +e_module_load (GTypeModule *type_module)
> +{
> +    g_type_ensure (E_TYPE_SOURCE_UBUNTU);
> +    g_type_ensure (E_TYPE_UBUNTU_SOURCES);
> +}
> +
> +G_MODULE_EXPORT void
> +e_module_unload (GTypeModule *type_module)
> +{
> +}
> 
> === modified file 'lib/addressbook.cpp'
> --- lib/addressbook.cpp	2015-07-21 19:34:05 +0000
> +++ lib/addressbook.cpp	2015-09-24 17:48:11 +0000
> @@ -533,6 +619,65 @@
>      self->prepareFolks();
>  }
>  
> +void AddressBook::onSafeModeMessageActivated(MessagingMenuMessage *message,
> +                                             const char *actionId,
> +                                             GVariant *param,
> +                                             AddressBook *self)
> +{
> +    if (self->m_messagingMenu) {
> +        if (self->m_messagingMenuMessage) {
> +             messaging_menu_app_remove_message(self->m_messagingMenu, self->m_messagingMenuMessage);
> +             g_object_unref(self->m_messagingMenuMessage);
> +             self->m_messagingMenuMessage = 0;
> +        }
> +
> +        messaging_menu_app_unregister(self->m_messagingMenu);
> +        g_object_unref(self->m_messagingMenu);
> +        self->m_messagingMenu = 0;
> +    }
> +
> +    qDebug() << "mesage clicked launching address-book-app";

mesage -> message

> +    url_dispatch_send("application:///address-book-app.desktop", NULL, NULL);
> +}
> +
> +bool AddressBook::isSafeMode()
> +{
> +    QByteArray envSafeMode = qgetenv(ADDRESS_BOOK_SAFE_MODE);
> +    if (!envSafeMode.isEmpty()) {
> +        return (envSafeMode.toLower() == "on" ? true : false);
> +    } else {
> +        return m_settings.value(SETTINGS_SAFE_MODE_KEY, false).toBool();
> +    }
> +}
> +
> +void AddressBook::setSafeMode(bool flag)
> +{
> +    QByteArray envSafeMode = qgetenv(ADDRESS_BOOK_SAFE_MODE);
> +    if (!envSafeMode.isEmpty()) {
> +        return;
> +    }
> +
> +    if (m_settings.value(SETTINGS_SAFE_MODE_KEY, false).toBool() != flag) {
> +        m_settings.setValue(SETTINGS_SAFE_MODE_KEY, flag);
> +        if (!flag) {
> +            // make all contacts visible
> +            Q_FOREACH(ContactEntry *entry, m_contacts->values()) {
> +                QIndividual *i = entry->individual();
> +                if (!i->isVisible()) {
> +                    i->setVisible(true);
> +                }
> +            }
> +            // clear invisible sources list
> +            m_settings.setValue(SETTINGS_INVISIBLE_SOURCES, QStringList());
> +        }
> +        m_settings.sync();
> +        // avoid send a ton of signals since the service will be reseted after the
> +        // 'safeModeChanged' signal
> +        m_notifyContactUpdate->clear();
> +        Q_EMIT safeModeChanged();
> +    }
> +}
> +
>  void AddressBook::createSourceDone(GObject *source,
>                                     GAsyncResult *res,
>                                     void *data)
> @@ -788,6 +972,44 @@
>      }
>  }
>  
> +void AddressBook::onSafeModeChanged()
> +{
> +    GIcon *icon = g_themed_icon_new("address-book-app");
> +    bool showUpdateComplete = false;
> +
> +    if (m_messagingMenu == 0) {
> +        m_messagingMenu = messaging_menu_app_new("address-book-app.desktop");
> +        messaging_menu_app_register(m_messagingMenu);
> +        messaging_menu_app_append_source(m_messagingMenu, MESSAGING_MENU_SOURCE_ID, icon, C::gettext("Address book service"));
> +    }
> +
> +    if (m_messagingMenuMessage) {
> +        messaging_menu_app_remove_message(m_messagingMenu, m_messagingMenuMessage);
> +        g_object_unref (m_messagingMenuMessage);
> +        m_messagingMenuMessage = 0;
> +    }
> +
> +    if (isSafeMode()) {
> +        m_messagingMenuMessage = messaging_menu_message_new("address-book-service-safe-mode",
> +                                                            icon,
> +                                                            C::gettext("Update required"),
> +                                                            NULL,
> +                                                            C::gettext("Your Contacts app needs to be upgraded. Only local contacts will be editable until upgrade is complete"),
> +                                                            QDateTime::currentMSecsSinceEpoch() * 1000); // the value is expected to be in microseconds
> +    } else {
> +        m_messagingMenuMessage = messaging_menu_message_new("address-book-service-safe-mode",
> +                                                            icon,
> +                                                            C::gettext("Update complete"),
> +                                                            NULL,
> +                                                            C::gettext("Your Contacts app upldate is complete."),

upldate -> update
^ This will result in a translatable string change.

> +                                                            QDateTime::currentMSecsSinceEpoch() * 1000); // the value is expected to be in microseconds
> +    }
> +
> +    g_signal_connect(m_messagingMenuMessage, "activate", G_CALLBACK(&AddressBook::onSafeModeMessageActivated), this);
> +    messaging_menu_app_append_message(m_messagingMenu, m_messagingMenuMessage, MESSAGING_MENU_SOURCE_ID, true);
> +    g_object_unref(icon);
> +}
> +
>  int AddressBook::removeContacts(const QStringList &contactIds, const QDBusMessage &message)
>  {
>      RemoveContactsData *data = new RemoveContactsData;
> 
> === modified file 'lib/contacts-map.h'
> --- lib/contacts-map.h	2014-09-05 20:58:28 +0000
> +++ lib/contacts-map.h	2015-09-24 17:48:11 +0000
> @@ -84,10 +89,16 @@
>  
>  private:
>      QHash<QString, ContactEntry*> m_idToEntry;
> +    QMultiMap<QString, ContactEntry*> m_phoneToEntry;
>      // sorted contacts
>      QList<ContactEntry*> m_contacts;
>      SortClause m_sortClause;
> -    QMutex m_mutex;
> +    QReadWriteLock m_mutex;
> +
> +    void removeData(ContactEntry *entry, bool del);
> +    void insertData(ContactEntry *entry);
> +    void insertdata(const QList<QtContacts::QContactPhoneNumber> &numbers, ContactEntry *entry);

Is it intentional that one of these methods is insertData and the other is insertdata (no captial D)?

> +    QString minimalNumber(const QString &phone) const;
>  };
>  
>  } //namespace


-- 
https://code.launchpad.net/~renatofilho/address-book-service/changes-necessary-to-work-with-buteo/+merge/264295
Your team Ubuntu Phablet Team is subscribed to branch lp:address-book-service.



More information about the Ubuntu-reviews mailing list