[Merge] lp:~boiko/telephony-service/support_non_phone_accounts into lp:telephony-service

Tiago Salem Herrmann tiago.herrmann at canonical.com
Thu Mar 26 20:34:54 UTC 2015


Review: Needs Information



Diff comments:

> === modified file 'Ubuntu/Telephony/contactwatcher.cpp'
> --- Ubuntu/Telephony/contactwatcher.cpp	2014-09-02 17:42:20 +0000
> +++ Ubuntu/Telephony/contactwatcher.cpp	2015-03-25 22:11:52 +0000
> @@ -1,7 +1,8 @@
>  /*
> - * Copyright (C) 2013 Canonical, Ltd.
> + * Copyright (C) 2013-2015 Canonical, Ltd.
>   *
>   * Authors:
> + *  Gustavo Pichorim Boiko <gustavo.boiko at canonical.com>
>   *  Tiago Salem Herrmann <tiago.herrmann at canonical.com>
>   *
>   * This file is part of telephony-service.
> @@ -22,12 +23,17 @@
>  #include "contactwatcher.h"
>  #include "contactutils.h"
>  #include "phoneutils.h"
> +#include "accountentry.h"
> +#include "telepathyhelper.h"
>  #include <QContactManager>
>  #include <QContactFetchByIdRequest>
>  #include <QContactFetchRequest>
>  #include <QContactAvatar>
> +#include <QContactExtendedDetail>
> +#include <QContactPhoneNumber>
>  #include <QContactDetailFilter>
> -#include <QContactPhoneNumber>
> +#include <QContactIntersectionFilter>
> +#include <QContactUnionFilter>
>  
>  namespace C {
>  #include <libintl.h>
> @@ -36,6 +42,8 @@
>  ContactWatcher::ContactWatcher(QObject *parent) :
>      QObject(parent), mRequest(0), mInteractive(false), mCompleted(false)
>  {
> +    // addressable VCard fields defaults to "tel" only
> +    mAddressableFields << "tel";
>      connect(ContactUtils::sharedManager(),
>              SIGNAL(contactsAdded(QList<QContactId>)),
>              SLOT(onContactsAdded(QList<QContactId>)));
> @@ -55,10 +63,10 @@
>      }
>  }
>  
> -void ContactWatcher::searchByPhoneNumber(const QString &phoneNumber)
> +void ContactWatcher::startSearching()
>  {
> -    if (!mCompleted) {
> -        // componenty is not ready yet
> +    if (!mCompleted || mIdentifier.isEmpty()) {
> +        // componenty is not ready yet or no identifier given
>          return;
>      }
>  
> @@ -68,15 +76,60 @@
>          mRequest->deleteLater();
>      }
>  
> +    // FIXME: search for all the fields
>      mRequest = new QContactFetchRequest(this);
> -    mRequest->setFilter(QContactPhoneNumber::match(phoneNumber));
> +
> +    QContactUnionFilter topLevelFilter;
> +    Q_FOREACH(const QString &field, mAddressableFields) {
> +        if (field == "tel") {
> +            topLevelFilter.append(QContactPhoneNumber::match(mIdentifier));
> +        } else {
> +            // FIXME: handle more fields
> +            // rely on a generic field filter
> +            QContactDetailFilter nameFilter = QContactDetailFilter();
> +            nameFilter.setDetailType(QContactExtendedDetail::Type, QContactExtendedDetail::FieldName);
> +            nameFilter.setMatchFlags(QContactFilter::MatchExactly);
> +            nameFilter.setValue(field);
> +
> +            QContactDetailFilter valueFilter = QContactDetailFilter();
> +            valueFilter.setDetailType(QContactExtendedDetail::Type, QContactExtendedDetail::FieldData);
> +            valueFilter.setMatchFlags(QContactFilter::MatchExactly);
> +            valueFilter.setValue(mIdentifier);
> +
> +            QContactIntersectionFilter intersectionFilter;
> +            intersectionFilter.append(nameFilter);
> +            intersectionFilter.append(valueFilter);
> +
> +            topLevelFilter.append(intersectionFilter);
> +        }
> +    }
> +
> +    mRequest->setFilter(topLevelFilter);
>      connect(mRequest, SIGNAL(stateChanged(QContactAbstractRequest::State)),
>                        SLOT(onRequestStateChanged(QContactAbstractRequest::State)));
> -    connect(mRequest, SIGNAL(resultsAvailable()), SLOT(resultsAvailable()));
> +    connect(mRequest, SIGNAL(resultsAvailable()), SLOT(onResultsAvailable()));
>      mRequest->setManager(ContactUtils::sharedManager());
>      mRequest->start();
>  }
>  
> +QVariantList ContactWatcher::wrapIntList(const QList<int> &list)
> +{
> +    QVariantList resultList;
> +    Q_FOREACH(int value, list) {
> +        resultList << value;
> +    }
> +    return resultList;
> +}
> +
> +QList<int> ContactWatcher::unwrapIntList(const QVariantList &list)
> +{
> +    QList<int> resultList;
> +    Q_FOREACH(const QVariant &value, list) {
> +        resultList << value.toInt();
> +    }
> +    return resultList;
> +}
> +
>  QString ContactWatcher::contactId() const
>  {
>      QString id = mContactId.toString();
> @@ -97,40 +150,30 @@
>      return mAlias;
>  }
>  
> -QString ContactWatcher::phoneNumber() const
> -{
> -    return mPhoneNumber;
> -}
> -
> -QList<int> ContactWatcher::phoneNumberSubTypes() const
> -{
> -    return mPhoneNumberSubTypes;
> -}
> -
> -QList<int> ContactWatcher::phoneNumberContexts() const
> -{
> -    return mPhoneNumberContexts;
> -}
> -
> -void ContactWatcher::setPhoneNumber(const QString &phoneNumber)
> -{
> -    if (mPhoneNumber == phoneNumber) {
> +QString ContactWatcher::identifier() const
> +{
> +    return mIdentifier;
> +}
> +
> +void ContactWatcher::setIdentifier(const QString &identifier)
> +{
> +    if (mIdentifier == identifier) {
>          return;
>      }
>  
> -    const bool isPrivate = phoneNumber.startsWith("x-ofono-private");
> -    const bool isUnknown = phoneNumber.startsWith("x-ofono-unknown");
> -    const bool isInteractive = !phoneNumber.isEmpty() && !isPrivate && !isUnknown;
> -
> -    mPhoneNumber = phoneNumber;
> -    Q_EMIT phoneNumberChanged();
> -
> -    if (mPhoneNumber.isEmpty() || isPrivate || isUnknown) {
> +    // FIXME: ofono stuff, maybe move somewhere else?
> +    const bool isPrivate = identifier.startsWith("x-ofono-private");
> +    const bool isUnknown = identifier.startsWith("x-ofono-unknown");
> +    const bool isInteractive = !identifier.isEmpty() && !isPrivate && !isUnknown;
> +
> +    mIdentifier = identifier;
> +    Q_EMIT identifierChanged();
> +
> +    if (mIdentifier.isEmpty() || isPrivate || isUnknown) {
>          mAlias.clear();
>          mContactId = QContactId();
>          mAvatar.clear();
> -        mPhoneNumberSubTypes.clear();
> -        mPhoneNumberContexts.clear();
> +        mDetailProperties.clear();
>  
>          if (isPrivate) {
>              mAlias = C::gettext("Private Number");
> @@ -141,11 +184,10 @@
>          Q_EMIT contactIdChanged();
>          Q_EMIT avatarChanged();
>          Q_EMIT aliasChanged();
> -        Q_EMIT phoneNumberSubTypesChanged();
> -        Q_EMIT phoneNumberContextsChanged();
> +        Q_EMIT detailPropertiesChanged();
>          Q_EMIT isUnknownChanged();
>      } else {
> -        searchByPhoneNumber(mPhoneNumber);
> +        startSearching();
>      }
>  
>      if (isInteractive != mInteractive) {
> @@ -154,6 +196,11 @@
>      }
>  }
>  
> +QVariantMap ContactWatcher::detailProperties() const
> +{
> +    return mDetailProperties;
> +}
> +
>  bool ContactWatcher::isUnknown() const
>  {
>      return mContactId.isNull();
> @@ -164,6 +211,19 @@
>      return mInteractive;
>  }
>  
> +QStringList ContactWatcher::addressableFields() const
> +{
> +    return mAddressableFields;
> +}
> +
> +void ContactWatcher::setAddressableFields(const QStringList &fields)
> +{
> +    mAddressableFields = fields;
> +    Q_EMIT addressableFieldsChanged();
> +
> +    startSearching();
> +}
> +
>  void ContactWatcher::classBegin()
>  {
>  }
> @@ -171,30 +231,25 @@
>  void ContactWatcher::componentComplete()
>  {
>      mCompleted = true;
> -    // query for phone if the phone number was initialized
> -    if (!mPhoneNumber.isEmpty()) {
> -        searchByPhoneNumber(mPhoneNumber);
> -    }
> +    startSearching();
>  }
>  
>  void ContactWatcher::onContactsAdded(QList<QContactId> ids)
>  {
>      // ignore this signal if we have a contact already
>      // or if we have no phone number set
> -    if (!mContactId.isNull() || mPhoneNumber.isEmpty()) {
> +    if (!mContactId.isNull() || mIdentifier.isEmpty()) {
>          return;
>      }
>  
> -    searchByPhoneNumber(mPhoneNumber);
> +    startSearching();
>  }
>  
>  void ContactWatcher::onContactsChanged(QList<QContactId> ids)
>  {
>      // check for changes even if we have this contact already,
>      // as the number might have changed, thus invalidating the current contact
> -    if (!mPhoneNumber.isEmpty() || ids.contains(mContactId)) {
> -        searchByPhoneNumber(mPhoneNumber);
> -    }
> +    startSearching();
>  }
>  
>  void ContactWatcher::onContactsRemoved(QList<QContactId> ids)
> @@ -204,22 +259,18 @@
>          mAlias.clear();
>          mContactId = QContactId();
>          mAvatar.clear();
> -        mPhoneNumberSubTypes.clear();
> -        mPhoneNumberContexts.clear();
> +        mDetailProperties.clear();
>          Q_EMIT contactIdChanged();
>          Q_EMIT avatarChanged();
>          Q_EMIT aliasChanged();
> -        Q_EMIT phoneNumberSubTypesChanged();
> -        Q_EMIT phoneNumberContextsChanged();
> +        Q_EMIT detailPropertiesChanged();
>          Q_EMIT isUnknownChanged();
>  
> -        if (!mPhoneNumber.isEmpty()) {
> -            searchByPhoneNumber(mPhoneNumber);
> -        }
> +        startSearching();
>      }
>  }
>  
> -void ContactWatcher::resultsAvailable()
> +void ContactWatcher::onResultsAvailable()
>  {
>      QContactFetchRequest *request = qobject_cast<QContactFetchRequest*>(sender());
>      if (request && request->contacts().size() > 0) {
> @@ -243,18 +294,19 @@
>              Q_EMIT isUnknownChanged();
>          }
>  
> -        Q_FOREACH(const QContactPhoneNumber phoneNumber, contact.details(QContactDetail::TypePhoneNumber)) {
> -            if (PhoneUtils::comparePhoneNumbers(phoneNumber.number(), mPhoneNumber)) {
> -                QList<int> newSubTypes = phoneNumber.subTypes();
> -                if (newSubTypes != mPhoneNumberSubTypes) {
> -                    mPhoneNumberSubTypes = phoneNumber.subTypes();
> -                    Q_EMIT phoneNumberSubTypesChanged();
> -                }
> -                QList<int> newContexts = phoneNumber.contexts();
> -                if (newContexts != mPhoneNumberContexts) {
> -                    mPhoneNumberContexts =  newContexts;
> -                    Q_EMIT phoneNumberContextsChanged();
> -                }
> +        Q_FOREACH(const QString &field, mAddressableFields) {
> +            if (field == "tel") {
> +                Q_FOREACH(const QContactPhoneNumber phoneNumber, contact.details(QContactDetail::TypePhoneNumber)) {
> +                    if (PhoneUtils::comparePhoneNumbers(phoneNumber.number(), mIdentifier)) {
> +                        mDetailProperties["type"] = (int)QContactDetail::TypePhoneNumber;
> +                        mDetailProperties["phoneNumberSubTypes"] = wrapIntList(phoneNumber.subTypes());
> +                        mDetailProperties["phoneNumberContexts"] = wrapIntList(phoneNumber.contexts());
> +                        Q_EMIT detailPropertiesChanged();
> +                        break;
> +                    }
> +                }
> +            } else {
> +                // FIXME: add proper support for more fields
>              }
>          }
>      }
> @@ -272,14 +324,12 @@
>              mAlias.clear();
>              mContactId = QContactId();
>              mAvatar.clear();
> -            mPhoneNumberSubTypes.clear();
> -            mPhoneNumberContexts.clear();
> +            mDetailProperties.clear();
>  
>              Q_EMIT contactIdChanged();
>              Q_EMIT avatarChanged();
>              Q_EMIT aliasChanged();
> -            Q_EMIT phoneNumberSubTypesChanged();
> -            Q_EMIT phoneNumberContextsChanged();
> +            Q_EMIT detailPropertiesChanged();
>              Q_EMIT isUnknownChanged();
>          }
>      }
> 
> === modified file 'Ubuntu/Telephony/contactwatcher.h'
> --- Ubuntu/Telephony/contactwatcher.h	2014-09-02 17:42:20 +0000
> +++ Ubuntu/Telephony/contactwatcher.h	2015-03-25 22:11:52 +0000
> @@ -1,7 +1,8 @@
>  /*
> - * Copyright (C) 2013 Canonical, Ltd.
> + * Copyright (C) 2013-2015 Canonical, Ltd.
>   *
>   * Authors:
> + *  Gustavo Pichorim Boiko <gustavo.boiko at canonical.com>
>   *  Tiago Salem Herrmann <tiago.herrmann at canonical.com>
>   *
>   * This file is part of telephony-service.
> @@ -38,11 +39,15 @@
>      Q_PROPERTY(QString contactId READ contactId NOTIFY contactIdChanged)
>      Q_PROPERTY(QString avatar READ avatar NOTIFY avatarChanged)
>      Q_PROPERTY(QString alias READ alias NOTIFY aliasChanged)
> -    Q_PROPERTY(QString phoneNumber READ phoneNumber WRITE setPhoneNumber NOTIFY phoneNumberChanged)
> -    Q_PROPERTY(QList<int> phoneNumberSubTypes READ phoneNumberSubTypes NOTIFY phoneNumberSubTypesChanged)
> -    Q_PROPERTY(QList<int> phoneNumberContexts READ phoneNumberContexts NOTIFY phoneNumberContextsChanged)
> +    Q_PROPERTY(QString identifier READ identifier WRITE setIdentifier NOTIFY identifierChanged)
> +    Q_PROPERTY(QString phoneNumber READ identifier WRITE setIdentifier NOTIFY identifierChanged)
> +    // The details property changes according to the detail type.
> +    // One property is always present on the map though, the "detailType" property.
> +    Q_PROPERTY(QVariantMap detailProperties READ detailProperties NOTIFY detailPropertiesChanged)
>      Q_PROPERTY(bool isUnknown READ isUnknown NOTIFY isUnknownChanged)
>      Q_PROPERTY(bool interactive READ interactive NOTIFY interactiveChanged)
> +    Q_PROPERTY(QStringList addressableFields READ addressableFields WRITE setAddressableFields NOTIFY addressableFieldsChanged)
> +
>  public:
>      explicit ContactWatcher(QObject *parent = 0);
>      ~ContactWatcher();
> @@ -50,46 +55,52 @@
>      QString contactId() const;
>      QString avatar() const;
>      QString alias() const;
> -    QString phoneNumber() const;
> -    void setPhoneNumber(const QString &phoneNumber);
> -    QList<int> phoneNumberSubTypes() const;
> -    QList<int> phoneNumberContexts() const;
> +    QString identifier() const;
> +    void setIdentifier(const QString &identifier);
> +    QVariantMap detailProperties() const;
>      bool isUnknown() const;
>      bool interactive() const;
>  
> +    // defaults to only phone number searching
> +    QStringList addressableFields() const;
> +    void setAddressableFields(const QStringList &fields);
> +
>      void classBegin();
>      void componentComplete();
>  
> +    // helpers
> +    Q_INVOKABLE QVariantList wrapIntList(const QList<int> &list);
> +    Q_INVOKABLE QList<int> unwrapIntList(const QVariantList &list);
> +
>  Q_SIGNALS:
>      void contactIdChanged();
>      void avatarChanged();
>      void aliasChanged();
> -    void phoneNumberChanged();
> -    void phoneNumberSubTypesChanged();
> -    void phoneNumberContextsChanged();
> +    void identifierChanged();
> +    void detailPropertiesChanged();
>      void isUnknownChanged();
>      void interactiveChanged();
> +    void addressableFieldsChanged();
>  
>  protected Q_SLOTS:
>      void onContactsAdded(QList<QContactId> ids);
>      void onContactsChanged(QList<QContactId> ids);
>      void onContactsRemoved(QList<QContactId> ids);
> -    void resultsAvailable();
> +    void onResultsAvailable();
>      void onRequestStateChanged(QContactAbstractRequest::State state);
>  
>  private:
> -    void searchByPhoneNumber(const QString &phoneNumber);
> +    void startSearching();
>  
>      QContactFetchRequest *mRequest;
>      QContactId mContactId;
>      QString mAvatar;
>      QString mAlias;
> -    QString mPhoneNumber;
> -    QList<int> mPhoneNumberSubTypes;
> -    QList<int> mPhoneNumberContexts;
> +    QString mIdentifier;
> +    QVariantMap mDetailProperties;
>      bool mInteractive;
>      bool mCompleted;
> -
> +    QStringList mAddressableFields;
>  };
>  
>  #endif // CONTACTWATCHER_H
> 
> === modified file 'Ubuntu/Telephony/tests/ContactWatcherTest.cpp'
> --- Ubuntu/Telephony/tests/ContactWatcherTest.cpp	2014-09-02 17:42:20 +0000
> +++ Ubuntu/Telephony/tests/ContactWatcherTest.cpp	2015-03-25 22:11:52 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (C) 2013 Canonical, Ltd.
> + * Copyright (C) 2013-2015 Canonical, Ltd.
>   *
>   * This file is part of telephony-service.
>   *
> @@ -24,6 +24,7 @@
>  #include <QContactName>
>  #include <QContactAvatar>
>  #include <QContactPhoneNumber>
> +#include <QContactExtendedDetail>
>  
>  QTCONTACTS_USE_NAMESPACE
>  
> @@ -33,7 +34,7 @@
>  
>  private Q_SLOTS:
>      void initTestCase();
> -    void testPhoneNumber();
> +    void testIdentifier();
>      void testMatchExistingContact();
>      void testMatchNewContact();
>      void testMatchContactChanged();
> @@ -43,6 +44,8 @@
>      void testInteractiveProperty_data();
>      void testInteractiveProperty();
>      void testLateSearch();
> +    void testAddressableFields();
> +    void testExtendedFieldMatch();
>  
>  private:
>      QContact createContact(const QString &firstName,
> @@ -61,24 +64,24 @@
>      mManager = ContactUtils::sharedManager("memory");
>  }
>  
> -void ContactWatcherTest::testPhoneNumber()
> +void ContactWatcherTest::testIdentifier()
>  {
> -    QString phoneNumber("123456");
> +    QString identifier("123456");
>      ContactWatcher watcher;
> -    QSignalSpy spy(&watcher, SIGNAL(phoneNumberChanged()));
> -    watcher.setPhoneNumber(phoneNumber);
> +    QSignalSpy spy(&watcher, SIGNAL(identifierChanged()));
> +    watcher.setIdentifier(identifier);
>  
>      QCOMPARE(spy.count(), 1);
> -    QCOMPARE(watcher.phoneNumber(), phoneNumber);
> +    QCOMPARE(watcher.identifier(), identifier);
>  }
>  
>  void ContactWatcherTest::testMatchExistingContact()
>  {
> -    QString phoneNumber("12345");
> +    QString identifier("12345");
>      QContact contact = createContact("FirstName",
>                                       "LastName",
>                                       "file://some_file",
> -                                     QStringList() << phoneNumber,
> +                                     QStringList() << identifier,
>                                       QList<int>() << 0 << 1 << 2,
>                                       QList<int>() << 3 << 4 << 5);
>      ContactWatcher watcher;
> @@ -86,12 +89,11 @@
>      QSignalSpy contactIdSpy(&watcher, SIGNAL(contactIdChanged()));
>      QSignalSpy aliasSpy(&watcher, SIGNAL(aliasChanged()));
>      QSignalSpy avatarSpy(&watcher, SIGNAL(avatarChanged()));
> -    QSignalSpy contextsSpy(&watcher, SIGNAL(phoneNumberContextsChanged()));
> -    QSignalSpy subTypesSpy(&watcher, SIGNAL(phoneNumberSubTypesChanged()));
> +    QSignalSpy detailPropertiesSpy(&watcher, SIGNAL(detailPropertiesChanged()));
>      QSignalSpy unknownSpy(&watcher, SIGNAL(isUnknownChanged()));
>  
>      // set the phone number and wait for the match to happen
> -    watcher.setPhoneNumber(phoneNumber);
> +    watcher.setIdentifier(identifier);
>  
>  
>      // contact fetching is asynchronous so use QTRY_COMPARE for the first signal spy
> @@ -99,16 +101,15 @@
>      QTRY_COMPARE(contactIdSpy.count(), 1);
>      QCOMPARE(aliasSpy.count(), 1);
>      QCOMPARE(avatarSpy.count(), 1);
> -    QCOMPARE(contextsSpy.count(), 1);
> -    QCOMPARE(subTypesSpy.count(), 1);
> +    QCOMPARE(detailPropertiesSpy.count(), 1);
>      QCOMPARE(unknownSpy.count(), 1);
>  
>      // and verify that the values are properly set
>      QCOMPARE(watcher.contactId(), contact.id().toString());
>      QCOMPARE(watcher.alias(), ContactUtils::formatContactName(contact));
>      QCOMPARE(watcher.avatar(), contact.detail<QContactAvatar>().imageUrl().toString());
> -    QCOMPARE(watcher.phoneNumberContexts(), contact.detail<QContactPhoneNumber>().contexts());
> -    QCOMPARE(watcher.phoneNumberSubTypes(), contact.detail<QContactPhoneNumber>().subTypes());
> +    QCOMPARE(watcher.unwrapIntList(watcher.detailProperties()["phoneNumberContexts"].toList()), contact.detail<QContactPhoneNumber>().contexts());
> +    QCOMPARE(watcher.unwrapIntList(watcher.detailProperties()["phoneNumberSubTypes"].toList()), contact.detail<QContactPhoneNumber>().subTypes());
>      QCOMPARE(watcher.isUnknown(), false);
>  
>      clearManager();
> @@ -116,24 +117,23 @@
>  
>  void ContactWatcherTest::testMatchNewContact()
>  {
> -    QString phoneNumber("1234567");
> +    QString identifier("1234567");
>      ContactWatcher watcher;
>      watcher.componentComplete();
>      QSignalSpy contactIdSpy(&watcher, SIGNAL(contactIdChanged()));
>      QSignalSpy aliasSpy(&watcher, SIGNAL(aliasChanged()));
>      QSignalSpy avatarSpy(&watcher, SIGNAL(avatarChanged()));
> -    QSignalSpy contextsSpy(&watcher, SIGNAL(phoneNumberContextsChanged()));
> -    QSignalSpy subTypesSpy(&watcher, SIGNAL(phoneNumberSubTypesChanged()));
> +    QSignalSpy detailPropertiesSpy(&watcher, SIGNAL(detailPropertiesChanged()));
>      QSignalSpy unknownSpy(&watcher, SIGNAL(isUnknownChanged()));
>  
> -    watcher.setPhoneNumber(phoneNumber);
> +    watcher.setIdentifier(identifier);
>  
>      // now create the contact and wait to see if it gets matched
>      QContact contact = createContact("FirstName",
>                                       "LastName",
>                                       "file://some_file",
>                                       // just to make it a little more complicated, use a prefixed phone number
> -                                     QStringList() << phoneNumber.prepend("+1"),
> +                                     QStringList() << identifier.prepend("+1"),
>                                       QList<int>() << 0 << 1 << 2,
>                                       QList<int>() << 3 << 4 << 5);
>  
> @@ -142,16 +142,15 @@
>      QTRY_COMPARE(contactIdSpy.count(), 1);
>      QCOMPARE(aliasSpy.count(), 1);
>      QCOMPARE(avatarSpy.count(), 1);
> -    QCOMPARE(contextsSpy.count(), 1);
> -    QCOMPARE(subTypesSpy.count(), 1);
> +    QCOMPARE(detailPropertiesSpy.count(), 1);
>      QCOMPARE(unknownSpy.count(), 1);
>  
>      // and verify that the values are properly set
>      QCOMPARE(watcher.contactId(), contact.id().toString());
>      QCOMPARE(watcher.alias(), ContactUtils::formatContactName(contact));
>      QCOMPARE(watcher.avatar(), contact.detail<QContactAvatar>().imageUrl().toString());
> -    QCOMPARE(watcher.phoneNumberContexts(), contact.detail<QContactPhoneNumber>().contexts());
> -    QCOMPARE(watcher.phoneNumberSubTypes(), contact.detail<QContactPhoneNumber>().subTypes());
> +    QCOMPARE(watcher.unwrapIntList(watcher.detailProperties()["phoneNumberContexts"].toList()), contact.detail<QContactPhoneNumber>().contexts());
> +    QCOMPARE(watcher.unwrapIntList(watcher.detailProperties()["phoneNumberSubTypes"].toList()), contact.detail<QContactPhoneNumber>().subTypes());
>      QCOMPARE(watcher.isUnknown(), false);
>  
>      clearManager();
> @@ -159,7 +158,7 @@
>  
>  void ContactWatcherTest::testMatchContactChanged()
>  {
> -    QString phoneNumber("12345");
> +    QString identifier("12345");
>      QContact contact = createContact("FirstName",
>                                       "LastName",
>                                       "file://some_file",
> @@ -168,18 +167,17 @@
>                                       QList<int>() << 3 << 4 << 5);
>      ContactWatcher watcher;
>      watcher.componentComplete();
> -    watcher.setPhoneNumber(phoneNumber);
> +    watcher.setIdentifier(identifier);
>  
>      QSignalSpy contactIdSpy(&watcher, SIGNAL(contactIdChanged()));
>      QSignalSpy aliasSpy(&watcher, SIGNAL(aliasChanged()));
>      QSignalSpy avatarSpy(&watcher, SIGNAL(avatarChanged()));
> -    QSignalSpy contextsSpy(&watcher, SIGNAL(phoneNumberContextsChanged()));
> -    QSignalSpy subTypesSpy(&watcher, SIGNAL(phoneNumberSubTypesChanged()));
> +    QSignalSpy detailPropertiesSpy(&watcher, SIGNAL(detailPropertiesChanged()));
>      QSignalSpy unknownSpy(&watcher, SIGNAL(isUnknownChanged()));
>  
>      // now modify the contact´s phone number so that it matches
>      QContactPhoneNumber number = contact.detail<QContactPhoneNumber>();
> -    number.setNumber(phoneNumber);
> +    number.setNumber(identifier);
>      contact.saveDetail(&number);
>      mManager->saveContact(&contact);
>  
> @@ -188,16 +186,15 @@
>      QTRY_COMPARE(contactIdSpy.count(), 1);
>      QCOMPARE(aliasSpy.count(), 1);
>      QCOMPARE(avatarSpy.count(), 1);
> -    QCOMPARE(contextsSpy.count(), 1);
> -    QCOMPARE(subTypesSpy.count(), 1);
> +    QCOMPARE(detailPropertiesSpy.count(), 1);
>      QCOMPARE(unknownSpy.count(), 1);
>  
>      // and verify that the values are properly set
>      QCOMPARE(watcher.contactId(), contact.id().toString());
>      QCOMPARE(watcher.alias(), ContactUtils::formatContactName(contact));
>      QCOMPARE(watcher.avatar(), contact.detail<QContactAvatar>().imageUrl().toString());
> -    QCOMPARE(watcher.phoneNumberContexts(), contact.detail<QContactPhoneNumber>().contexts());
> -    QCOMPARE(watcher.phoneNumberSubTypes(), contact.detail<QContactPhoneNumber>().subTypes());
> +    QCOMPARE(watcher.unwrapIntList(watcher.detailProperties()["phoneNumberContexts"].toList()), contact.detail<QContactPhoneNumber>().contexts());
> +    QCOMPARE(watcher.unwrapIntList(watcher.detailProperties()["phoneNumberSubTypes"].toList()), contact.detail<QContactPhoneNumber>().subTypes());
>      QCOMPARE(watcher.isUnknown(), false);
>  
>      clearManager();
> @@ -207,11 +204,11 @@
>  {
>      // after modifying a contact, if the phone number doesn´t match anymore, the data should be cleared
>      // verify that this happens, but first we need to make sure the match actually happened
> -    QString phoneNumber("12345");
> +    QString identifier("12345");
>      QContact contact = createContact("FirstName",
>                                       "LastName",
>                                       "file://some_file",
> -                                     QStringList() << phoneNumber,
> +                                     QStringList() << identifier,
>                                       QList<int>() << 0 << 1 << 2,
>                                       QList<int>() << 3 << 4 << 5);
>      ContactWatcher watcher;
> @@ -219,7 +216,7 @@
>      QSignalSpy contactIdSpy(&watcher, SIGNAL(contactIdChanged()));
>  
>      // set the phone number and wait for the match to happen
> -    watcher.setPhoneNumber(phoneNumber);
> +    watcher.setIdentifier(identifier);
>  
>      // at this point we just need to make sure the contactId is correct, the other fields
>      // are tested in a separate test
> @@ -229,8 +226,7 @@
>  
>      QSignalSpy aliasSpy(&watcher, SIGNAL(aliasChanged()));
>      QSignalSpy avatarSpy(&watcher, SIGNAL(avatarChanged()));
> -    QSignalSpy contextsSpy(&watcher, SIGNAL(phoneNumberContextsChanged()));
> -    QSignalSpy subTypesSpy(&watcher, SIGNAL(phoneNumberSubTypesChanged()));
> +    QSignalSpy detailPropertiesSpy(&watcher, SIGNAL(detailPropertiesChanged()));
>      QSignalSpy unknownSpy(&watcher, SIGNAL(isUnknownChanged()));
>  
>      // now modify the contact´s phone number so that it doesn´t match anymore
> @@ -242,17 +238,15 @@
>      QTRY_COMPARE(contactIdSpy.count(), 1);
>      QCOMPARE(aliasSpy.count(), 1);
>      QCOMPARE(avatarSpy.count(), 1);
> -    QCOMPARE(contextsSpy.count(), 1);
> -    QCOMPARE(subTypesSpy.count(), 1);
> +    QCOMPARE(detailPropertiesSpy.count(), 1);
>      QCOMPARE(unknownSpy.count(), 1);
>  
>      // and verify that the values are properly cleared
> -    QCOMPARE(watcher.contactId(), QString(""));
> -    QCOMPARE(watcher.alias(), QString(""));
> -    QCOMPARE(watcher.avatar(), QString(""));
> -    QCOMPARE(watcher.phoneNumberContexts().count(), 0);
> -    QCOMPARE(watcher.phoneNumberSubTypes().count(), 0);
> -    QCOMPARE(watcher.isUnknown(), true);
> +    QVERIFY(watcher.contactId().isEmpty());
> +    QVERIFY(watcher.alias().isEmpty());
> +    QVERIFY(watcher.avatar().isEmpty());
> +    QVERIFY(watcher.detailProperties().isEmpty());
> +    QVERIFY(watcher.isUnknown());
>  
>      clearManager();
>  }
> @@ -261,11 +255,11 @@
>  {
>      // after removing a contact, the contact match should be cleared
>      // verify that this happens, but first we need to make sure the match actually happened
> -    QString phoneNumber("12345");
> +    QString identifier("12345");
>      QContact contact = createContact("FirstName",
>                                       "LastName",
>                                       "file://some_file",
> -                                     QStringList() << phoneNumber,
> +                                     QStringList() << identifier,
>                                       QList<int>() << 0 << 1 << 2,
>                                       QList<int>() << 3 << 4 << 5);
>      ContactWatcher watcher;
> @@ -273,7 +267,7 @@
>      QSignalSpy contactIdSpy(&watcher, SIGNAL(contactIdChanged()));
>  
>      // set the phone number and wait for the match to happen
> -    watcher.setPhoneNumber(phoneNumber);
> +    watcher.setIdentifier(identifier);
>  
>      // at this point we just need to make sure the contactId is correct, the other fields
>      // are tested in a separate test
> @@ -283,8 +277,7 @@
>  
>      QSignalSpy aliasSpy(&watcher, SIGNAL(aliasChanged()));
>      QSignalSpy avatarSpy(&watcher, SIGNAL(avatarChanged()));
> -    QSignalSpy contextsSpy(&watcher, SIGNAL(phoneNumberContextsChanged()));
> -    QSignalSpy subTypesSpy(&watcher, SIGNAL(phoneNumberSubTypesChanged()));
> +    QSignalSpy detailPropertiesSpy(&watcher, SIGNAL(detailPropertiesChanged()));
>      QSignalSpy unknownSpy(&watcher, SIGNAL(isUnknownChanged()));
>  
>      // now remove the contact
> @@ -293,17 +286,15 @@
>      QTRY_COMPARE(contactIdSpy.count(), 1);
>      QCOMPARE(aliasSpy.count(), 1);
>      QCOMPARE(avatarSpy.count(), 1);
> -    QCOMPARE(contextsSpy.count(), 1);
> -    QCOMPARE(subTypesSpy.count(), 1);
> +    QCOMPARE(detailPropertiesSpy.count(), 1);
>      QCOMPARE(unknownSpy.count(), 1);
>  
>      // and verify that the values are properly cleared
> -    QCOMPARE(watcher.contactId(), QString(""));
> -    QCOMPARE(watcher.alias(), QString(""));
> -    QCOMPARE(watcher.avatar(), QString(""));
> -    QCOMPARE(watcher.phoneNumberContexts().count(), 0);
> -    QCOMPARE(watcher.phoneNumberSubTypes().count(), 0);
> -    QCOMPARE(watcher.isUnknown(), true);
> +    QVERIFY(watcher.contactId().isEmpty());
> +    QVERIFY(watcher.alias().isEmpty());
> +    QVERIFY(watcher.avatar().isEmpty());
> +    QVERIFY(watcher.detailProperties().isEmpty());
> +    QVERIFY(watcher.isUnknown());
>  
>      clearManager();
>  }
> @@ -313,11 +304,11 @@
>      // clearing a phone number should trigger the contact data to be cleared too
>      // after removing a contact, the contact match should be cleared
>      // verify that this happens, but first we need to make sure the match actually happened
> -    QString phoneNumber("12345");
> +    QString identifier("12345");
>      QContact contact = createContact("FirstName",
>                                       "LastName",
>                                       "file://some_file",
> -                                     QStringList() << phoneNumber,
> +                                     QStringList() << identifier,
>                                       QList<int>() << 0 << 1 << 2,
>                                       QList<int>() << 3 << 4 << 5);
>      ContactWatcher watcher;
> @@ -325,7 +316,7 @@
>      QSignalSpy contactIdSpy(&watcher, SIGNAL(contactIdChanged()));
>  
>      // set the phone number and wait for the match to happen
> -    watcher.setPhoneNumber(phoneNumber);
> +    watcher.setIdentifier(identifier);
>  
>      // at this point we just need to make sure the contactId is correct, the other fields
>      // are tested in a separate test
> @@ -335,34 +326,31 @@
>  
>      QSignalSpy aliasSpy(&watcher, SIGNAL(aliasChanged()));
>      QSignalSpy avatarSpy(&watcher, SIGNAL(avatarChanged()));
> -    QSignalSpy contextsSpy(&watcher, SIGNAL(phoneNumberContextsChanged()));
> -    QSignalSpy subTypesSpy(&watcher, SIGNAL(phoneNumberSubTypesChanged()));
> +    QSignalSpy detailPropertiesSpy(&watcher, SIGNAL(detailPropertiesChanged()));
>      QSignalSpy unknownSpy(&watcher, SIGNAL(isUnknownChanged()));
>  
>      // now clear the phone number
> -    watcher.setPhoneNumber("");
> +    watcher.setIdentifier("");
>  
>      QCOMPARE(contactIdSpy.count(), 1);
>      QCOMPARE(aliasSpy.count(), 1);
>      QCOMPARE(avatarSpy.count(), 1);
> -    QCOMPARE(contextsSpy.count(), 1);
> -    QCOMPARE(subTypesSpy.count(), 1);
> +    QCOMPARE(detailPropertiesSpy.count(), 1);
>      QCOMPARE(unknownSpy.count(), 1);
>  
>      // and verify that the values are properly cleared
> -    QCOMPARE(watcher.contactId(), QString(""));
> -    QCOMPARE(watcher.alias(), QString(""));
> -    QCOMPARE(watcher.avatar(), QString(""));
> -    QCOMPARE(watcher.phoneNumberContexts().count(), 0);
> -    QCOMPARE(watcher.phoneNumberSubTypes().count(), 0);
> -    QCOMPARE(watcher.isUnknown(), true);
> +    QVERIFY(watcher.contactId().isEmpty());
> +    QVERIFY(watcher.alias().isEmpty());
> +    QVERIFY(watcher.avatar().isEmpty());
> +    QVERIFY(watcher.detailProperties().isEmpty());
> +    QVERIFY(watcher.isUnknown());
>  
>      clearManager();
>  }
>  
>  void ContactWatcherTest::testInteractiveProperty_data()
>  {
> -    QTest::addColumn<QString>("phoneNumber");
> +    QTest::addColumn<QString>("identifier");
>      QTest::addColumn<int>("signalCount");
>      QTest::addColumn<bool>("interactive");
>  
> @@ -374,7 +362,7 @@
>  
>  void ContactWatcherTest::testInteractiveProperty()
>  {
> -    QFETCH(QString, phoneNumber);
> +    QFETCH(QString, identifier);
>      QFETCH(int, signalCount);
>      QFETCH(bool, interactive);
>  
> @@ -382,7 +370,7 @@
>      watcher.componentComplete();
>      QSignalSpy spy(&watcher, SIGNAL(interactiveChanged()));
>  
> -    watcher.setPhoneNumber(phoneNumber);
> +    watcher.setIdentifier(identifier);
>      // the initial interactive value is false it will not change in case of invalid phones
>      QTRY_COMPARE(spy.count(), signalCount);
>      QCOMPARE(watcher.interactive(), interactive);
> @@ -391,30 +379,28 @@
>  
>  void ContactWatcherTest::testLateSearch()
>  {
> -    QString phoneNumber("12345");
> +    QString identifier("12345");
>      QContact contact = createContact("FirstName",
>                                       "LastName",
>                                       "file://some_file",
> -                                     QStringList() << phoneNumber,
> +                                     QStringList() << identifier,
>                                       QList<int>() << 0 << 1 << 2,
>                                       QList<int>() << 3 << 4 << 5);
>      ContactWatcher watcher;
>      QSignalSpy contactIdSpy(&watcher, SIGNAL(contactIdChanged()));
>      QSignalSpy aliasSpy(&watcher, SIGNAL(aliasChanged()));
>      QSignalSpy avatarSpy(&watcher, SIGNAL(avatarChanged()));
> -    QSignalSpy contextsSpy(&watcher, SIGNAL(phoneNumberContextsChanged()));
> -    QSignalSpy subTypesSpy(&watcher, SIGNAL(phoneNumberSubTypesChanged()));
> +    QSignalSpy detailPropertiesSpy(&watcher, SIGNAL(detailPropertiesChanged()));
>      QSignalSpy unknownSpy(&watcher, SIGNAL(isUnknownChanged()));
>  
>      // set the phone number and wait for the match to happen
> -    watcher.setPhoneNumber(phoneNumber);
> +    watcher.setIdentifier(identifier);
>  
>      // component not complete yet
>      QTRY_COMPARE(contactIdSpy.count(), 0);
>      QCOMPARE(aliasSpy.count(), 0);
>      QCOMPARE(avatarSpy.count(), 0);
> -    QCOMPARE(contextsSpy.count(), 0);
> -    QCOMPARE(subTypesSpy.count(), 0);
> +    QCOMPARE(detailPropertiesSpy.count(), 0);
>      QCOMPARE(unknownSpy.count(), 0);
>  
>      // mark as complete
> @@ -424,21 +410,65 @@
>      QTRY_COMPARE(contactIdSpy.count(), 1);
>      QCOMPARE(aliasSpy.count(), 1);
>      QCOMPARE(avatarSpy.count(), 1);
> -    QCOMPARE(contextsSpy.count(), 1);
> -    QCOMPARE(subTypesSpy.count(), 1);
> +    QCOMPARE(detailPropertiesSpy.count(), 1);
>      QCOMPARE(unknownSpy.count(), 1);
>  
>      // and verify that the values are properly set
>      QCOMPARE(watcher.contactId(), contact.id().toString());
>      QCOMPARE(watcher.alias(), ContactUtils::formatContactName(contact));
>      QCOMPARE(watcher.avatar(), contact.detail<QContactAvatar>().imageUrl().toString());
> -    QCOMPARE(watcher.phoneNumberContexts(), contact.detail<QContactPhoneNumber>().contexts());
> -    QCOMPARE(watcher.phoneNumberSubTypes(), contact.detail<QContactPhoneNumber>().subTypes());
> +    QCOMPARE(watcher.unwrapIntList(watcher.detailProperties()["phoneNumberContexts"].toList()), contact.detail<QContactPhoneNumber>().contexts());
> +    QCOMPARE(watcher.unwrapIntList(watcher.detailProperties()["phoneNumberSubTypes"].toList()), contact.detail<QContactPhoneNumber>().subTypes());
>      QCOMPARE(watcher.isUnknown(), false);
>  
>      clearManager();
>  }
>  
> +void ContactWatcherTest::testAddressableFields()
> +{
> +    ContactWatcher watcher;
> +
> +    // check that addressable fields contains "tel" by default
> +    QCOMPARE(watcher.addressableFields().count(), 1);
> +    QCOMPARE(watcher.addressableFields()[0], QString("tel"));
> +
> +    QSignalSpy addressableFieldsSpy(&watcher, SIGNAL(addressableFieldsChanged()));
> +    QStringList addressableFields;
> +    addressableFields << "x-jabber" << "tel" << "x-sip";
> +    watcher.setAddressableFields(addressableFields);
> +    QCOMPARE(addressableFieldsSpy.count(), 1);
> +    QCOMPARE(watcher.addressableFields(), addressableFields);
> +}
> +
> +void ContactWatcherTest::testExtendedFieldMatch()
> +{
> +    QString field("x-jabber");
> +    QString identifier("foo.bar at someserver.jabber");
> +    QContact contact = createContact("FirstName",
> +                                     "LastName",
> +                                     "file://some_file",
> +                                     QStringList() << "12345",
> +                                     QList<int>() << 0 << 1 << 2,
> +                                     QList<int>() << 3 << 4 << 5);
> +
> +    // now add the extended info to the contact
> +    QContactExtendedDetail detail;
> +    detail.setName(field);
> +    detail.setData(identifier);
> +    contact.appendDetail(detail);
> +    mManager->saveContact(&contact);
> +
> +    // now create the watcher and check that it matches this field
> +    ContactWatcher watcher;
> +    QSignalSpy contactIdSpy(&watcher, SIGNAL(contactIdChanged()));
> +    watcher.setIdentifier(identifier);
> +    watcher.setAddressableFields(QStringList() << field);
> +    watcher.componentComplete();
> +
> +    QTRY_COMPARE(contactIdSpy.count(), 1);
> +    QCOMPARE(watcher.contactId(), contact.id().toString());
> +}
> +
>  QContact ContactWatcherTest::createContact(const QString &firstName,
>                                             const QString &lastName,
>                                             const QString &avatarUrl,
> 
> === modified file 'approver/approver.cpp'
> --- approver/approver.cpp	2015-02-09 20:32:32 +0000
> +++ approver/approver.cpp	2015-03-25 22:11:52 +0000
> @@ -33,6 +33,7 @@
>  #include "callentry.h"
>  #include "tonegenerator.h"
>  #include "telepathyhelper.h"
> +#include "accountentry.h"
>  
>  #include <QContactAvatar>
>  #include <QContactDisplayLabel>
> @@ -321,6 +322,12 @@
>          showSnapDecision(dispatchOp, channel);
>          GreeterContacts::instance()->setContactFilter(QContactPhoneNumber::match(contact->id()));
>      } else {
> +        AccountEntry *account = TelepathyHelper::instance()->accountForConnection(callChannel->connection());
> +        if (!account) {
> +            qCritical() << "Call exists with no account for connection";
> +            return;
> +        }
> +
>          // try to match the contact info
>          QContactFetchRequest *request = new QContactFetchRequest(this);
>          request->setFilter(QContactPhoneNumber::match(contact->id()));
> @@ -345,8 +352,14 @@
>              showSnapDecision(dispatchOp, channel, contact);
>          });
>  
> -        request->setManager(ContactUtils::sharedManager());
> -        request->start();
> +        // FIXME: For accounts not based on phone numbers, don't try to match contacts for now
> +        if (account->type() == AccountEntry::PhoneAccount) {
> +            request->setManager(ContactUtils::sharedManager());
> +            request->start();
> +        } else {
> +            // just emit the signal to pretend we did a contact search
> +            Q_EMIT request->stateChanged(QContactAbstractRequest::FinishedState);
> +        }
>      }
>  }
>  
> @@ -397,8 +410,8 @@
>  void Approver::onRejectMessage(Tp::ChannelDispatchOperationPtr dispatchOp, const char *action)
>  {
>      if (mRejectActions.contains(action)) {
> -        QString phoneNumber = dispatchOp->channels().first()->targetContact()->id();
> -        ChatManager::instance()->sendMessage(QStringList() << phoneNumber, mRejectActions[action],
> +        QString targetId = dispatchOp->channels().first()->targetContact()->id();
> +        ChatManager::instance()->sendMessage(QStringList() << targetId, mRejectActions[action],
>                                               dispatchOp->account()->uniqueIdentifier());
>      }
>  
> 
> === modified file 'handler/callhandler.cpp'
> --- handler/callhandler.cpp	2015-02-17 17:01:36 +0000
> +++ handler/callhandler.cpp	2015-03-25 22:11:52 +0000
> @@ -92,7 +92,7 @@
>  {
>  }
>  
> -void CallHandler::startCall(const QString &phoneNumber, const QString &accountId)
> +void CallHandler::startCall(const QString &targetId, const QString &accountId)
>  {
>      // Request the contact to start audio call
>      AccountEntry *accountEntry = TelepathyHelper::instance()->accountForId(accountId);
> @@ -105,7 +105,7 @@
>          return;
>      }
>  
> -    connect(connection->contactManager()->contactsForIdentifiers(QStringList() << phoneNumber),
> +    connect(connection->contactManager()->contactsForIdentifiers(QStringList() << targetId),
>              SIGNAL(finished(Tp::PendingOperation*)),
>              SLOT(onContactsAvailable(Tp::PendingOperation*)));
>  }
> @@ -354,7 +354,7 @@
>      }
>  }
>  
> -Tp::CallChannelPtr CallHandler::existingCall(const QString &phoneNumber)
> +Tp::CallChannelPtr CallHandler::existingCall(const QString &targetId)
>  {
>      Tp::CallChannelPtr channel;
>      Q_FOREACH(const Tp::CallChannelPtr &ch, mCallChannels) {
> @@ -362,7 +362,12 @@
>              continue;
>          }
>  
> -        if (PhoneUtils::comparePhoneNumbers(ch->targetContact()->id(), phoneNumber)) {
> +        AccountEntry *account = TelepathyHelper::instance()->accountForConnection(ch->connection());
> +        if (!account) {
> +            continue;
> +        }
> +
> +        if (account->compareIds(ch->targetContact()->id(), targetId)) {
>              channel = ch;
>              break;
>          }
> 
> === modified file 'handler/callhandler.h'
> --- handler/callhandler.h	2015-02-17 17:01:36 +0000
> +++ handler/callhandler.h	2015-03-25 22:11:52 +0000
> @@ -40,7 +40,7 @@
>  
>  public Q_SLOTS:
>      void onCallChannelAvailable(Tp::CallChannelPtr channel);
> -    void startCall(const QString &phoneNumber, const QString &accountId);
> +    void startCall(const QString &targetId, const QString &accountId);
>      void hangUpCall(const QString &objectPath);
>      void setHold(const QString &objectPath, bool hold);
>      void setMuted(const QString &objectPath, bool muted);
> @@ -58,7 +58,7 @@
>      void callHoldingFailed(const QString &objectPath);
>  
>  protected:
> -    Tp::CallChannelPtr existingCall(const QString &phoneNumber);
> +    Tp::CallChannelPtr existingCall(const QString &targetId);
>      Tp::CallChannelPtr callFromObjectPath(const QString &objectPath);
>  
>  protected Q_SLOTS:
> 
> === modified file 'handler/texthandler.cpp'
> --- handler/texthandler.cpp	2015-01-15 15:52:44 +0000
> +++ handler/texthandler.cpp	2015-03-25 22:11:52 +0000
> @@ -77,20 +77,20 @@
>          
>          if (mPendingMessages.contains(accountId)) {
>              // create text channels to send the pending messages
> -            Q_FOREACH(const QStringList& phoneNumbers, mPendingMessages[accountId].keys()) {
> -                startChat(phoneNumbers, accountId);
> +            Q_FOREACH(const QStringList& recipients, mPendingMessages[accountId].keys()) {
> +                startChat(recipients, accountId);
>              }
>          }
>          if (mPendingMMSs.contains(accountId)) {
>              // create text channels to send the pending MMSs
> -            Q_FOREACH(const QStringList& phoneNumbers, mPendingMMSs[accountId].keys()) {
> -                startChat(phoneNumbers, accountId);
> +            Q_FOREACH(const QStringList& recipients, mPendingMMSs[accountId].keys()) {
> +                startChat(recipients, accountId);
>              }
>          }
>          if (mPendingSilentMessages.contains(accountId)) {
>              // create text channels to send the pending silent messages
> -            Q_FOREACH(const QStringList& phoneNumbers, mPendingSilentMessages[accountId].keys()) {
> -                startChat(phoneNumbers, accountId);
> +            Q_FOREACH(const QStringList& recipients, mPendingSilentMessages[accountId].keys()) {
> +                startChat(recipients, accountId);
>              }
>          }
>  
> @@ -103,7 +103,7 @@
>      return handler;
>  }
>  
> -void TextHandler::startChat(const QStringList &phoneNumbers, const QString &accountId)
> +void TextHandler::startChat(const QStringList &recipients, const QString &accountId)
>  {
>      // Request the contact to start chatting to
>      // FIXME: make it possible to select which account to use, for now, pick the first one
> @@ -113,7 +113,7 @@
>          return;
>      }
>  
> -    connect(account->account()->connection()->contactManager()->contactsForIdentifiers(phoneNumbers),
> +    connect(account->account()->connection()->contactManager()->contactsForIdentifiers(recipients),
>              SIGNAL(finished(Tp::PendingOperation*)),
>              SLOT(onContactsAvailable(Tp::PendingOperation*)));
>  }
> @@ -205,21 +205,21 @@
>      return message;
>  }
>  
> -void TextHandler::sendMMS(const QStringList &phoneNumbers, const AttachmentList &attachments, const QString &accountId) {
> +void TextHandler::sendMMS(const QStringList &recipients, const AttachmentList &attachments, const QString &accountId) {
>      AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
>      if (!account) {
>          // account does not exist
>          return;
>      }
>      if (!account->connected()) {
> -        mPendingMMSs[accountId][phoneNumbers].append(attachments);
> +        mPendingMMSs[accountId][recipients].append(attachments);
>          return;
>      }
>  
> -    Tp::TextChannelPtr channel = existingChat(phoneNumbers, accountId);
> +    Tp::TextChannelPtr channel = existingChat(recipients, accountId);
>      if (channel.isNull()) {
> -        mPendingMMSs[accountId][phoneNumbers].append(attachments);
> -        startChat(phoneNumbers, accountId);
> +        mPendingMMSs[accountId][recipients].append(attachments);
> +        startChat(recipients, accountId);
>          return;
>      }
>  
> @@ -230,7 +230,7 @@
>              SLOT(onMessageSent(Tp::PendingOperation*)));
>  }
>  
> -void TextHandler::sendSilentMessage(const QStringList &phoneNumbers, const QString &message, const QString &accountId)
> +void TextHandler::sendSilentMessage(const QStringList &recipients, const QString &message, const QString &accountId)
>  {
>      AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
>      if (!account) {
> @@ -238,13 +238,13 @@
>          return;
>      }
>      if (!account->connected()) {
> -        mPendingSilentMessages[accountId][phoneNumbers].append(message);
> +        mPendingSilentMessages[accountId][recipients].append(message);
>          return;
>      }
> -    Tp::TextChannelPtr channel = existingChat(phoneNumbers, accountId);
> +    Tp::TextChannelPtr channel = existingChat(recipients, accountId);
>      if (channel.isNull()) {
> -        mPendingSilentMessages[accountId][phoneNumbers].append(message);
> -        startChat(phoneNumbers, accountId);
> +        mPendingSilentMessages[accountId][recipients].append(message);
> +        startChat(recipients, accountId);
>          return;
>      }
>  
> @@ -263,7 +263,7 @@
>              SLOT(onMessageSent(Tp::PendingOperation*)));
>  }
>  
> -void TextHandler::sendMessage(const QStringList &phoneNumbers, const QString &message, const QString &accountId)
> +void TextHandler::sendMessage(const QStringList &recipients, const QString &message, const QString &accountId)
>  {
>      AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
>      if (!account) {
> @@ -271,14 +271,14 @@
>          return;
>      }
>      if (!account->connected()) {
> -        mPendingMessages[accountId][phoneNumbers].append(message);
> +        mPendingMessages[accountId][recipients].append(message);
>          return;
>      }
>  
> -    Tp::TextChannelPtr channel = existingChat(phoneNumbers, accountId);
> +    Tp::TextChannelPtr channel = existingChat(recipients, accountId);
>      if (channel.isNull()) {
> -        mPendingMessages[accountId][phoneNumbers].append(message);
> -        startChat(phoneNumbers, accountId);
> +        mPendingMessages[accountId][recipients].append(message);
> +        startChat(recipients, accountId);
>          return;
>      }
>  
> @@ -287,9 +287,9 @@
>              SLOT(onMessageSent(Tp::PendingOperation*)));
>  }
>  
> -void TextHandler::acknowledgeMessages(const QStringList &phoneNumbers, const QStringList &messageIds, const QString &accountId)
> +void TextHandler::acknowledgeMessages(const QStringList &recipients, const QStringList &messageIds, const QString &accountId)
>  {
> -    Tp::TextChannelPtr channel = existingChat(phoneNumbers, accountId);
> +    Tp::TextChannelPtr channel = existingChat(recipients, accountId);
>      if (channel.isNull()) {
>          return;
>      }
> @@ -321,8 +321,8 @@
>          return;
>      }
>  
> -    Q_FOREACH(const Tp::ContactPtr &phoneNumberOld, channel->groupContacts(false)) {
> -        recipients << phoneNumberOld->id();
> +    Q_FOREACH(const Tp::ContactPtr &channelContact, channel->groupContacts(false)) {
> +        recipients << channelContact->id();
>      }
>  
>      QMap<QStringList, QStringList> &pendingMessages = mPendingMessages[accountId];
> @@ -377,25 +377,25 @@
>      }
>  }
>  
> -Tp::TextChannelPtr TextHandler::existingChat(const QStringList &phoneNumbers, const QString &accountId)
> +Tp::TextChannelPtr TextHandler::existingChat(const QStringList &targetIds, const QString &accountId)
>  {
>      Tp::TextChannelPtr channel;
>  
>      Q_FOREACH(const Tp::TextChannelPtr &channel, mChannels) {
>          int count = 0;
>          AccountEntry *channelAccount = TelepathyHelper::instance()->accountForConnection(channel->connection());
> -        if (!channelAccount || channel->groupContacts(false).size() != phoneNumbers.size()
> +        if (!channelAccount || channel->groupContacts(false).size() != targetIds.size()
>              || channelAccount->accountId() != accountId) {
>              continue;
>          }
> -        Q_FOREACH(const QString &phoneNumberNew, phoneNumbers) {
> -            Q_FOREACH(const Tp::ContactPtr &phoneNumberOld, channel->groupContacts(false)) {
> -                if (PhoneUtils::comparePhoneNumbers(phoneNumberOld->id(), phoneNumberNew)) {
> +        Q_FOREACH(const QString &targetId, targetIds) {
> +            Q_FOREACH(const Tp::ContactPtr &channelContact, channel->groupContacts(false)) {
> +                if (channelAccount->compareIds(channelContact->id(), targetId)) {
>                      count++;
>                  }
>              }
>          }
> -        if (count == phoneNumbers.size()) {
> +        if (count == targetIds.size()) {
>              return channel;
>          }
>      }
> 
> === modified file 'handler/texthandler.h'
> --- handler/texthandler.h	2014-09-10 04:27:25 +0000
> +++ handler/texthandler.h	2015-03-25 22:11:52 +0000
> @@ -33,14 +33,14 @@
>      Q_OBJECT
>  public:
>      static TextHandler *instance();
> -    void startChat(const QStringList &phoneNumber, const QString &accountId);
> +    void startChat(const QStringList &recipients, const QString &accountId);
>      void startChat(const Tp::AccountPtr &account, const Tp::Contacts &contacts);
>  
>  public Q_SLOTS:
> -    void sendMessage(const QStringList &phoneNumber, const QString &message, const QString &accountId);
> -    void sendSilentMessage(const QStringList &phoneNumber, const QString &message, const QString &accountId);
> -    void sendMMS(const QStringList &phoneNumbers, const AttachmentList &attachments, const QString &accountId);
> -    void acknowledgeMessages(const QStringList &phoneNumber, const QStringList &messageIds, const QString &accountId);
> +    void sendMessage(const QStringList &recipients, const QString &message, const QString &accountId);
> +    void sendSilentMessage(const QStringList &recipients, const QString &message, const QString &accountId);
> +    void sendMMS(const QStringList &recipients, const AttachmentList &attachments, const QString &accountId);
> +    void acknowledgeMessages(const QStringList &recipients, const QStringList &messageIds, const QString &accountId);
>  
>  protected Q_SLOTS:
>      void onTextChannelAvailable(Tp::TextChannelPtr channel);
> @@ -49,7 +49,7 @@
>      void onConnectedChanged();
>  
>  protected:
> -    Tp::TextChannelPtr existingChat(const QStringList &phoneNumber, const QString &accountId);
> +    Tp::TextChannelPtr existingChat(const QStringList &targetIds, const QString &accountId);
>  
>  private:
>      explicit TextHandler(QObject *parent = 0);
> 
> === modified file 'indicator/messagingmenu.cpp'
> --- indicator/messagingmenu.cpp	2015-02-04 20:42:14 +0000
> +++ indicator/messagingmenu.cpp	2015-03-25 22:11:52 +0000
> @@ -27,6 +27,7 @@
>  #include "messagingmenu.h"
>  #include "telepathyhelper.h"
>  #include "accountentry.h"
> +#include "ofonoaccountentry.h"
>  #include <QContactAvatar>
>  #include <QContactFetchRequest>
>  #include <QContactFilter>
> @@ -110,6 +111,14 @@
>      QUrl iconPath = QUrl::fromLocalFile(telephonyServiceDir() + "/assets/avatar-default at 18.png");
>      QString contactAlias = senderId;
>  
> +    AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
> +    if (!account) {
> +        return;
> +    }
> +
> +    // FIXME: for accounts not based on phone number, we need to match other fields.
> +    // Right now we don't even bother trying to match contact data
> +
>      // try to match the contact info
>      QContactFetchRequest *request = new QContactFetchRequest(this);
>      request->setFilter(QContactPhoneNumber::match(senderId));
> @@ -182,8 +191,14 @@
>          g_object_unref(message);
>      });
>  
> -    request->setManager(ContactUtils::sharedManager());
> -    request->start();
> +    // FIXME: For accounts not based on phone numbers, don't try to match contacts for now
> +    if (account->type() == AccountEntry::PhoneAccount) {
> +        request->setManager(ContactUtils::sharedManager());
> +        request->start();
> +    } else {
> +        // just emit the signal to pretend we did a contact search
> +        Q_EMIT request->stateChanged(QContactAbstractRequest::FinishedState);
> +    }
>  }
>  
>  void MessagingMenu::removeMessage(const QString &messageId)
> @@ -201,7 +216,7 @@
>      GVariant *messages = NULL;
>      GFile *file = g_file_new_for_uri(call.contactIcon.toString().toUtf8().data());
>      GIcon *icon = g_file_icon_new(file);
> -    MessagingMenuMessage *message = messaging_menu_message_new(call.number.toUtf8().data(),
> +    MessagingMenuMessage *message = messaging_menu_message_new(call.targetId.toUtf8().data(),
>                                                                 icon,
>                                                                 call.contactAlias.toUtf8().data(),
>                                                                 NULL,
> @@ -209,7 +224,7 @@
>                                                                 call.timestamp.toMSecsSinceEpoch() * 1000);  // the value is expected to be in microseconds
>  
>      call.messageId = messaging_menu_message_get_id(message);
> -    if (call.number != "x-ofono-private" && call.number != "x-ofono-unknown") {
> +    if (call.targetId != "x-ofono-private" && call.targetId != "x-ofono-unknown") {
>          messaging_menu_message_add_action(message,
>                                            "callBack",
>                                            C::gettext("Call back"), // label
> @@ -242,12 +257,18 @@
>      g_object_unref(message);
>  }
>  
> -void MessagingMenu::addCall(const QString &phoneNumber, const QString &accountId, const QDateTime &timestamp)
> +void MessagingMenu::addCall(const QString &targetId, const QString &accountId, const QDateTime &timestamp)
>  {
>      Call call;
>      bool found = false;
> +    AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
> +    if (!account) {
> +        return;
> +    }
> +
>      Q_FOREACH(Call callMessage, mCalls) {
> -        if (PhoneUtils::comparePhoneNumbers(callMessage.number, phoneNumber)) {
> +        // FIXME: we need a better strategy to group calls from different accounts
> +        if (account->compareIds(callMessage.targetId, targetId)) {
>              call = callMessage;
>              found = true;
>              mCalls.removeOne(callMessage);
> @@ -259,10 +280,10 @@
>      }
>  
>      if (!found) {
> -        call.contactAlias = phoneNumber;
> +        call.contactAlias = targetId;
>          call.accountId = accountId;
>          call.contactIcon = QUrl::fromLocalFile(telephonyServiceDir() + "/assets/avatar-default at 18.png");
> -        call.number = phoneNumber;
> +        call.targetId = targetId;
>          call.count = 0;
>      }
>  
> @@ -272,19 +293,22 @@
>      QString text;
>      text = QString::fromUtf8(C::ngettext("%1 missed call", "%1 missed calls", call.count)).arg(call.count);
>  
> -    if (phoneNumber.startsWith("x-ofono-private")) {
> +    if (targetId.startsWith("x-ofono-private")) {
>          call.contactAlias = C::gettext("Private number");
>          addCallToMessagingMenu(call, text);
>          return;
> -    } else if (phoneNumber.startsWith("x-ofono-unknown")) {
> +    } else if (targetId.startsWith("x-ofono-unknown")) {
>          call.contactAlias = C::gettext("Unknown number");
>          addCallToMessagingMenu(call, text);
>          return;
>      }
>  
> +    // FIXME: we need to match other fields for accounts not based on phone numbers.
> +    // For now we are not even trying to match contact data
> +
>      // try to match the contact info
>      QContactFetchRequest *request = new QContactFetchRequest(this);
> -    request->setFilter(QContactPhoneNumber::match(phoneNumber));
> +    request->setFilter(QContactPhoneNumber::match(targetId));
>  
>      // place the messaging-menu item only after the contact fetch request is finished, as we can´t simply update
>      QObject::connect(request, &QContactAbstractRequest::stateChanged, [request, call, text, this]() {
> @@ -310,17 +334,28 @@
>          addCallToMessagingMenu(newCall, text);
>      });
>  
> -    request->setManager(ContactUtils::sharedManager());
> -    request->start();
> +    // FIXME: For accounts not based on phone numbers, don't try to match contacts for now
> +    if (account->type() == AccountEntry::PhoneAccount) {
> +        request->setManager(ContactUtils::sharedManager());
> +        request->start();
> +    } else {
> +        // just emit the signal to pretend we did a contact search
> +        Q_EMIT request->stateChanged(QContactAbstractRequest::FinishedState);
> +    }
>  }
>  
>  void MessagingMenu::showVoicemailEntry(AccountEntry *account)
>  {
> +    OfonoAccountEntry *ofonoAccount = qobject_cast<OfonoAccountEntry*>(account);

Sip accounts can also show voicemail. This is not specific to ofono, but not sure how to proceed in such case.

> +    if (!ofonoAccount) {
> +        return;
> +    }
> +
>      messaging_menu_app_remove_message_by_id(mCallsApp, account->accountId().toUtf8().data());
>      mVoicemailIds.removeAll(account->accountId());
>  
>      QString messageBody = C::gettext("Voicemail messages");
> -    uint count = account->voicemailCount();
> +    uint count = ofonoAccount->voicemailCount();
>      if (count != 0) {
>          messageBody = QString::fromUtf8(C::ngettext("%1 voicemail message", "%1 voicemail messages", count)).arg(count);
>      }
> @@ -340,7 +375,7 @@
>                                                                 QDateTime::currentDateTime().toMSecsSinceEpoch() * 1000); // the value is expected to be in microseconds
>      g_signal_connect(message, "activate", G_CALLBACK(&MessagingMenu::callsActivateCallback), this);
>      messaging_menu_app_append_message(mCallsApp, message, SOURCE_ID, true);
> -    mVoicemailIds.append(account->accountId());
> +    mVoicemailIds.append(ofonoAccount->accountId());
>  
>      g_object_unref(icon);
>      g_object_unref(message);
> @@ -411,10 +446,13 @@
>  void MessagingMenu::saveFlashMessage(const QString &messageId)
>  {
>      QVariantMap details = mMessages[messageId];
> +    AccountEntry *account = TelepathyHelper::instance()->accountForId(details["accountId"].toString());
> +    bool phoneNumberBased = account && (account->type() == AccountEntry::PhoneAccount);
>      History::Thread thread = History::Manager::instance()->threadForParticipants(details["accountId"].toString(),
>                                                                                   History::EventTypeText,
>                                                                                   QStringList() << details["senderId"].toString(),
> -                                                                                 History::MatchPhoneNumber,
> +                                                                                 phoneNumberBased ? History::MatchPhoneNumber :
> +                                                                                                    History::MatchCaseSensitive,
>                                                                                   true);
>      History::TextEvent textEvent(details["accountId"].toString(),
>                                   thread.threadId(), 
> @@ -447,30 +485,37 @@
>  
>  void MessagingMenu::callBack(const QString &messageId)
>  {
> -    QString phoneNumber = callFromMessageId(messageId).number;
> -    qDebug() << "TelephonyService/MessagingMenu: Calling back" << phoneNumber;
> -    ApplicationUtils::openUrl(QString("tel:///%1").arg(QString(QUrl::toPercentEncoding(phoneNumber))));
> +    Call call = callFromMessageId(messageId);
> +    AccountEntry *account = TelepathyHelper::instance()->accountForId(call.accountId);
> +    if (!account) {
> +        qWarning() << "Could not find the account originating the call";
> +    }
> +    qDebug() << "TelephonyService/MessagingMenu: Calling back" << call.targetId;
> +    // FIXME: support accounts not based on phone numbers
> +    if (account->type() == AccountEntry::PhoneAccount) {
> +        ApplicationUtils::openUrl(QString("tel:///%1").arg(QString(QUrl::toPercentEncoding(call.targetId))));
> +    }
>  }
>  
>  void MessagingMenu::replyWithMessage(const QString &messageId, const QString &reply)
>  {
>      Call call = callFromMessageId(messageId);
> -    qDebug() << "TelephonyService/MessagingMenu: Replying to call" << call.number << "with text" << reply;
> -    Q_EMIT replyReceived(QStringList() << call.number, call.accountId, reply);
> +    qDebug() << "TelephonyService/MessagingMenu: Replying to call" << call.targetId << "with text" << reply;
> +    Q_EMIT replyReceived(QStringList() << call.targetId, call.accountId, reply);
>  }
>  
>  void MessagingMenu::callVoicemail(const QString &messageId)
>  {
>      QString voicemailNumber;
> -    Q_FOREACH(AccountEntry *accountEntry, TelepathyHelper::instance()->accounts()) {
> -        if (!accountEntry->voicemailNumber().isEmpty() && messageId == accountEntry->accountId()) {
> -            voicemailNumber = accountEntry->voicemailNumber();
> -            break;
> -        }
> +    // get the corresponding account
> +    OfonoAccountEntry *ofonoAccount = qobject_cast<OfonoAccountEntry*>(TelepathyHelper::instance()->accountForId(messageId));

Same here. We can also call voicemail on sip accounts.

> +    if (ofonoAccount) {
> +        voicemailNumber = ofonoAccount->voicemailNumber();
>      }
>  
>      qDebug() << "TelephonyService/MessagingMenu: Calling voicemail for messageId" << messageId;
>      if (!voicemailNumber.isEmpty()) {
> +        // FIXME: we need to specify which account to use
>          ApplicationUtils::openUrl(QUrl(QString("tel:///%1").arg(voicemailNumber)));
>      }
>  }
> 
> === modified file 'indicator/messagingmenu.h'
> --- indicator/messagingmenu.h	2014-11-19 21:45:35 +0000
> +++ indicator/messagingmenu.h	2015-03-25 22:11:52 +0000
> @@ -32,7 +32,7 @@
>  {
>  public:
>      Call() : count(0) { }
> -    QString number;
> +    QString targetId;
>      int count;
>      QString contactAlias;
>      QUrl contactIcon;
> @@ -41,7 +41,7 @@
>      QDateTime timestamp;
>  
>      bool operator==(const Call &other) {
> -        return other.number == number;
> +        return other.targetId == targetId;
>      }
>  };
>  
> @@ -56,7 +56,7 @@
>      void addFlashMessage(const QString &senderId, const QString &accountId, const QString &messageId, const QDateTime &timestamp, const QString &text);
>      void removeMessage(const QString &messageId);
>  
> -    void addCall(const QString &phoneNumber, const QString &accountId, const QDateTime &timestamp);
> +    void addCall(const QString &targetId, const QString &accountId, const QDateTime &timestamp);
>      void addCallToMessagingMenu(Call call, const QString &text);
>  
>      static void flashMessageActivateCallback(MessagingMenuMessage *message, const char *actionId, GVariant *param, MessagingMenu *instance);
> @@ -68,7 +68,7 @@
>  
>  Q_SIGNALS:
>      void replyReceived(const QStringList &recipients, const QString &accountId, const QString &reply);
> -    void messageRead(const QStringList &phoneNumber, const QString &accountId, const QString &messageId);
> +    void messageRead(const QStringList &recipients, const QString &accountId, const QString &messageId);
>  
>  private Q_SLOTS:
>      void sendMessageReply(const QString &messageId, const QString &reply);
> 
> === modified file 'indicator/textchannelobserver.cpp'
> --- indicator/textchannelobserver.cpp	2015-02-20 20:51:48 +0000
> +++ indicator/textchannelobserver.cpp	2015-03-25 22:11:52 +0000
> @@ -32,6 +32,7 @@
>  #include "telepathyhelper.h"
>  #include "phoneutils.h"
>  #include "accountentry.h"
> +#include "ofonoaccountentry.h"
>  #include <TelepathyQt/AvatarData>
>  #include <TelepathyQt/TextChannel>
>  #include <TelepathyQt/ReceivedMessage>
> @@ -88,12 +89,15 @@
>      if (action == QLatin1String("notification_save_action")) {
>          NotificationData *notificationData = (NotificationData*) data;
>          if (notificationData != NULL) {
> +            AccountEntry *account = TelepathyHelper::instance()->accountForId(notificationData->accountId);
> +            bool phoneNumberBased = account && (account->type() == AccountEntry::PhoneAccount);
>              QStringList recipients;
>              recipients << notificationData->senderId << notificationData->participantIds;
>              History::Thread thread = History::Manager::instance()->threadForParticipants(notificationData->accountId,
>                                                                                           History::EventTypeText,
>                                                                                           recipients,
> -                                                                                         History::MatchPhoneNumber,
> +                                                                                         phoneNumberBased ? History::MatchPhoneNumber :
> +                                                                                                            History::MatchCaseSensitive,
>                                                                                           true);
>              History::TextEvent textEvent(notificationData->accountId,
>                                           thread.threadId(), 
> @@ -191,10 +195,12 @@
>  
>      // check if the account is available
>      if (!account->connected()) {
> +        bool phoneNumberBased = account->type() == AccountEntry::PhoneAccount;
>          History::Thread thread = History::Manager::instance()->threadForParticipants(account->accountId(),
>                                                                                       History::EventTypeText,
>                                                                                       recipients,
> -                                                                                     History::MatchPhoneNumber,
> +                                                                                     phoneNumberBased ? History::MatchPhoneNumber :
> +                                                                                                        History::MatchCaseSensitive,
>                                                                                       true);
>          History::TextEvent textEvent(account->accountId(),
>                                       thread.threadId(),
> @@ -211,7 +217,10 @@
>          History::Manager::instance()->writeEvents(events);
>  
>          QString failureMessage;
> -        if (account->simLocked()) {
> +        OfonoAccountEntry *ofonoAccount = qobject_cast<OfonoAccountEntry*>(account);
> +        bool simLocked = (ofonoAccount && ofonoAccount->simLocked());
> +
> +        if (simLocked) {
>              failureMessage = C::gettext("Unlock your sim card and try again from the messaging application.");
>          } else if (TelepathyHelper::instance()->flightMode()) {

we have to check if this is an ofono account here as well. We might be in flight mode but manually enable wifi and try to reply to an IM message.

>              failureMessage = C::gettext("Deactivate flight mode and try again from the messaging application.");
> @@ -319,6 +328,11 @@
>          // in greeter mode we show the notification right away as the contact data might not be received
>          showNotificationForMessage(message, accountId, participantIds);
>      } else {
> +        AccountEntry *account = TelepathyHelper::instance()->accountForId(accountId);
> +        if (!account) {
> +            return;
> +        }
> +
>          // try to match the contact info
>          QContactFetchRequest *request = new QContactFetchRequest(this);
>          request->setFilter(QContactPhoneNumber::match(contact->id()));
> @@ -341,8 +355,14 @@
>              showNotificationForMessage(message, accountId, participantIds, contact);
>          });
>  
> -        request->setManager(ContactUtils::sharedManager());
> -        request->start();
> +        // FIXME: For accounts not based on phone numbers, don't try to match contacts for now
> +        if (account->type() == AccountEntry::PhoneAccount) {
> +            request->setManager(ContactUtils::sharedManager());
> +            request->start();
> +        } else {
> +            // just emit the signal to pretend we did a contact search
> +            Q_EMIT request->stateChanged(QContactAbstractRequest::FinishedState);
> +        }
>      }
>  
>  }
> @@ -458,6 +478,13 @@
>      while (i != mNotifications.constEnd()) {
>          NotifyNotification *notification = i.key();
>          NotificationData *data = i.value();
> +
> +        AccountEntry *account = TelepathyHelper::instance()->accountForId(data->accountId);
> +        if (!account || account->type() != AccountEntry::PhoneAccount) {
> +            return;
> +        }
> +
> +        // FIXME: add support for contact matching for non phone number based accounts
>          Q_FOREACH(const QContactPhoneNumber phoneNumber, contact.details(QContactDetail::TypePhoneNumber)) {
>              if (PhoneUtils::comparePhoneNumbers(data->senderId, phoneNumber.number())) {
>                  QString displayLabel = contact.detail<QContactDisplayLabel>().label();
> 
> === modified file 'indicator/textchannelobserver.h'
> --- indicator/textchannelobserver.h	2014-11-24 15:07:19 +0000
> +++ indicator/textchannelobserver.h	2015-03-25 22:11:52 +0000
> @@ -41,7 +41,7 @@
>  
>  public Q_SLOTS:
>      void onTextChannelAvailable(Tp::TextChannelPtr textChannel);
> -    void sendMessage(const QStringList &phoneNumbers, const QString &text, const QString &accountId);
> +    void sendMessage(const QStringList &recipients, const QString &text, const QString &accountId);
>  
>  protected:
>      void showNotificationForFlashMessage(const Tp::ReceivedMessage &message, const QString &accountId);
> 
> === modified file 'indicator/voicemailindicator.cpp'
> --- indicator/voicemailindicator.cpp	2014-09-16 15:35:04 +0000
> +++ indicator/voicemailindicator.cpp	2015-03-25 22:11:52 +0000
> @@ -23,6 +23,7 @@
>  #include "telepathyhelper.h"
>  #include "messagingmenu.h"
>  #include "accountentry.h"
> +#include "ofonoaccountentry.h"
>  #include <QDebug>
>  #include <QDBusReply>
>  
> @@ -37,13 +38,17 @@
>  void VoiceMailIndicator::onAccountReady()
>  {
>      Q_FOREACH(AccountEntry *account, TelepathyHelper::instance()->accounts()) {
> +        OfonoAccountEntry *ofonoAccount = qobject_cast<OfonoAccountEntry*>(account);
> +        if (!ofonoAccount) {
> +            continue;
> +        }
>          // disconnect previous signals if any
> -        disconnect(account, SIGNAL(voicemailIndicatorChanged()), this, SLOT(onVoicemailIndicatorChanged()));
> -        disconnect(account, SIGNAL(voicemailCountChanged()), this, SLOT(onVoicemailIndicatorChanged()));
> +        disconnect(ofonoAccount, SIGNAL(voicemailIndicatorChanged()), this, SLOT(onVoicemailIndicatorChanged()));
> +        disconnect(ofonoAccount, SIGNAL(voicemailCountChanged()), this, SLOT(onVoicemailIndicatorChanged()));
>   
> -        connect(account, SIGNAL(voicemailIndicatorChanged()), this, SLOT(onVoicemailIndicatorChanged()));
> -        connect(account, SIGNAL(voicemailCountChanged()), this, SLOT(onVoicemailIndicatorChanged()));
> -        if (account->voicemailIndicator()) {
> +        connect(ofonoAccount, SIGNAL(voicemailIndicatorChanged()), this, SLOT(onVoicemailIndicatorChanged()));
> +        connect(ofonoAccount, SIGNAL(voicemailCountChanged()), this, SLOT(onVoicemailIndicatorChanged()));
> +        if (ofonoAccount->voicemailIndicator()) {
>              MessagingMenu::instance()->showVoicemailEntry(account);
>          } else {
>              MessagingMenu::instance()->hideVoicemailEntry(account);
> @@ -53,14 +58,14 @@
>  
>  void VoiceMailIndicator::onVoicemailIndicatorChanged()
>  {
> -    AccountEntry *account = qobject_cast<AccountEntry*>(sender());
> -    if (!account) {
> +    OfonoAccountEntry *ofonoAccount = qobject_cast<OfonoAccountEntry*>(sender());
> +    if (!ofonoAccount) {
>          return;
>      }
>  
> -    if (account->voicemailIndicator()) {
> -        MessagingMenu::instance()->showVoicemailEntry(account);
> +    if (ofonoAccount->voicemailIndicator()) {
> +        MessagingMenu::instance()->showVoicemailEntry(ofonoAccount);
>      } else {
> -        MessagingMenu::instance()->hideVoicemailEntry(account);
> +        MessagingMenu::instance()->hideVoicemailEntry(ofonoAccount);
>      }
>  }
> 
> === modified file 'libtelephonyservice/CMakeLists.txt'
> --- libtelephonyservice/CMakeLists.txt	2014-08-25 14:49:53 +0000
> +++ libtelephonyservice/CMakeLists.txt	2015-03-25 22:11:52 +0000
> @@ -1,5 +1,6 @@
>  set(library_SRCS
>      accountentry.cpp
> +    accountentryfactory.cpp
>      audiooutput.cpp
>      applicationutils.cpp
>      callentry.cpp
> @@ -9,6 +10,7 @@
>      chatmanager.cpp
>      contactutils.cpp
>      greetercontacts.cpp
> +    ofonoaccountentry.cpp
>      phoneutils.cpp
>      ringtone.cpp
>      telepathyhelper.cpp
> 
> === modified file 'libtelephonyservice/accountentry.cpp'
> --- libtelephonyservice/accountentry.cpp	2015-02-20 18:46:14 +0000
> +++ libtelephonyservice/accountentry.cpp	2015-03-25 22:11:52 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (C) 2013 Canonical, Ltd.
> + * Copyright (C) 2013-2015 Canonical, Ltd.
>   *
>   * Authors:
>   *  Gustavo Pichorim Boiko <gustavo.boiko at canonical.com>
> @@ -25,7 +25,7 @@
>  #include "telepathyhelper.h"
>  
>  AccountEntry::AccountEntry(const Tp::AccountPtr &account, QObject *parent) :
> -    QObject(parent), mAccount(account), mVoicemailCount(0), mVoicemailIndicator(false)
> +    QObject(parent), mAccount(account)
>  {
>      initialize();
>  }
> @@ -55,6 +55,27 @@
>      return mAccount->displayName();
>  }
>  
> +QString AccountEntry::status() const
> +{
> +    if (mAccount.isNull() || mAccount->connection().isNull() || mAccount->connection()->selfContact().isNull()) {
> +        return QString::null;
> +    }
> +    Tp::Presence presence = mAccount->connection()->selfContact()->presence();
> +    return presence.status();
> +}
> +
> +QString AccountEntry::statusMessage() const
> +{
> +    if (mAccount.isNull() || mAccount->connection().isNull() || mAccount->connection()->selfContact().isNull()) {
> +        return QString::null;
> +    }
> +    Tp::Presence presence = mAccount->connection()->selfContact()->presence();
> +    if (presence.type() == Tp::ConnectionPresenceTypeAvailable) {
> +        return presence.statusMessage();
> +    }
> +    return QString::null;
> +}
> +
>  QString AccountEntry::selfContactId() const
>  {
>      if (!mAccount.isNull() && !mAccount->connection().isNull() &&
> @@ -64,27 +85,6 @@
>      return QString();
>  }
>  
> -QString AccountEntry::networkName() const
> -{
> -    if (mAccount.isNull() || mAccount->connection().isNull() || mAccount->connection()->selfContact().isNull()) {
> -        return QString::null;
> -    }
> -    Tp::Presence presence = mAccount->connection()->selfContact()->presence();
> -    if (presence.type() == Tp::ConnectionPresenceTypeAvailable) {
> -        return presence.statusMessage();
> -    }
> -    return QString::null;
> -}
> -
> -bool AccountEntry::simLocked() const
> -{
> -    if (mAccount.isNull() || mAccount->connection().isNull() || mAccount->connection()->selfContact().isNull()) {
> -        return false;
> -    }
> -    Tp::Presence presence = mAccount->connection()->selfContact()->presence();
> -    return (presence.type() == Tp::ConnectionPresenceTypeAway && presence.status() == "simlocked");
> -}
> -
>  void AccountEntry::setDisplayName(const QString &name)
>  {
>      if (mAccount.isNull()) {
> @@ -100,44 +100,24 @@
>              mAccount->connection()->selfContact()->presence().type() == Tp::ConnectionPresenceTypeAvailable;
>  }
>  
> -QStringList AccountEntry::emergencyNumbers() const
> -{
> -    return mEmergencyNumbers;
> -}
> -
> -QString AccountEntry::voicemailNumber() const
> -{
> -    return mVoicemailNumber;
> -}
> -
> -bool AccountEntry::voicemailIndicator() const
> -{
> -    return mVoicemailIndicator;
> -}
> -
> -uint AccountEntry::voicemailCount() const
> -{
> -    return mVoicemailCount;
> -}
> -
>  Tp::AccountPtr AccountEntry::account() const
>  {
>      return mAccount;
>  }
>  
> -bool AccountEntry::emergencyCallsAvailable() const
> -{
> -    if (mAccount.isNull() || mAccount->connection().isNull() || mAccount->connection()->selfContact().isNull()) {
> -        return false;
> -    }
> -
> -    QString status = mAccount->connection()->selfContact()->presence().status();
> -    return status != "flightmode" && status != "nomodem" && status != "";
> -}
> -
> -QString AccountEntry::serial() const
> -{
> -    return mSerial;
> +AccountEntry::AccountType AccountEntry::type() const
> +{
> +    return GenericAccount;
> +}
> +
> +QStringList AccountEntry::addressableVCardFields() const
> +{
> +    return mAccount->protocolInfo().addressableVCardFields();
> +}
> +
> +bool AccountEntry::compareIds(const QString &first, const QString &second) const
> +{
> +    return first == second;
>  }
>  
>  void AccountEntry::initialize()
> @@ -208,36 +188,28 @@
>              SIGNAL(connectedChanged()));
>      connect(mAccount->connection()->selfContact().data(),
>              SIGNAL(presenceChanged(Tp::Presence)),
> -            SIGNAL(networkNameChanged()));
> -    connect(mAccount->connection()->selfContact().data(),
> -            SIGNAL(presenceChanged(Tp::Presence)),
> -            SIGNAL(emergencyCallsAvailableChanged()));
> -    connect(mAccount->connection()->selfContact().data(),
> -            SIGNAL(presenceChanged(Tp::Presence)),
> -            SIGNAL(simLockedChanged()));
> +            SIGNAL(statusMessageChanged()));
> +    connect(mAccount->connection()->selfContact().data(),
> +            SIGNAL(presenceChanged(Tp::Presence)),
> +            SIGNAL(statusChanged()));
>  }
>  
>  void AccountEntry::onSelfHandleChanged(uint handle)
>  {
> +    Q_UNUSED(handle)
>      watchSelfContactPresence();
>  
> -    Q_EMIT networkNameChanged();
> +    Q_EMIT statusChanged();
> +    Q_EMIT statusMessageChanged();
>      Q_EMIT connectedChanged();
> -    Q_EMIT simLockedChanged();
>      Q_EMIT selfContactIdChanged();
>      Q_EMIT activeChanged();
>  }
>  
>  void AccountEntry::onConnectionChanged()
>  {
> -    QDBusConnection dbusConnection = QDBusConnection::sessionBus();
>      if (!mAccount->connection()) {
> -        // disconnect any previous dbus connections
> -        if (!mConnectionInfo.objectPath.isEmpty()) {
> -            dbusConnection.disconnect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> -                                      CANONICAL_TELEPHONY_EMERGENCYMODE_IFACE, "EmergencyNumbersChanged",
> -                                      this, SLOT(onEmergencyNumbersChanged(QStringList)));
> -        }
> +
>  
>          // and ensure the account gets connected
>          ensureConnected();
> @@ -245,91 +217,14 @@
>          mConnectionInfo.busName = mAccount->connection()->busName();
>          mConnectionInfo.objectPath = mAccount->connection()->objectPath();
>  
> -        // connect the emergency numbers changed signal
> -        dbusConnection.connect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> -                               CANONICAL_TELEPHONY_EMERGENCYMODE_IFACE, "EmergencyNumbersChanged",
> -                               this, SLOT(onEmergencyNumbersChanged(QStringList)));
> -
> -        // and get the current value of the emergency numbers
> -        QDBusInterface connIface(mConnectionInfo.busName, mConnectionInfo.objectPath, CANONICAL_TELEPHONY_EMERGENCYMODE_IFACE);
> -        QDBusReply<QStringList> replyNumbers = connIface.call("EmergencyNumbers");
> -        if (replyNumbers.isValid()) {
> -            mEmergencyNumbers = replyNumbers.value();
> -            Q_EMIT emergencyNumbersChanged();
> -        }
> -
> -        // connect the voicemail number changed signal
> -        dbusConnection.connect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> -                               CANONICAL_TELEPHONY_VOICEMAIL_IFACE, "VoicemailNumberChanged",
> -                               this, SLOT(onVoicemailNumberChanged(QString)));
> -
> -        QDBusInterface voicemailIface(mConnectionInfo.busName, mConnectionInfo.objectPath, CANONICAL_TELEPHONY_VOICEMAIL_IFACE);
> -        QDBusReply<QString> replyNumber = voicemailIface.call("VoicemailNumber");
> -        if (replyNumber.isValid()) {
> -            mVoicemailNumber = replyNumber.value();
> -            Q_EMIT voicemailNumberChanged();
> -        }
> -
> -        // connect the voicemail count changed signal
> -        dbusConnection.connect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> -                               CANONICAL_TELEPHONY_VOICEMAIL_IFACE, "VoicemailCountChanged",
> -                               this, SLOT(onVoicemailCountChanged(uint)));
> -
> -        QDBusReply<uint> replyCount = voicemailIface.call("VoicemailCount");
> -        if (replyCount.isValid()) {
> -            mVoicemailCount = replyCount.value();
> -            Q_EMIT voicemailCountChanged();
> -        }
> -
> -        // connect the voicemail indicator changed signal
> -        dbusConnection.connect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> -                               CANONICAL_TELEPHONY_VOICEMAIL_IFACE, "VoicemailIndicatorChanged",
> -                               this, SLOT(onVoicemailIndicatorChanged(bool)));
> -
> -        QDBusReply<bool> replyIndicator = voicemailIface.call("VoicemailIndicator");
> -        if (replyIndicator.isValid()) {
> -            mVoicemailIndicator = replyIndicator.value();
> -            Q_EMIT voicemailIndicatorChanged();
> -        }
> -
>          connect(mAccount->connection().data(),
>                  SIGNAL(selfHandleChanged(uint)),
>                  SLOT(onSelfHandleChanged(uint)));
> -        // and get the serial
> -        QDBusInterface ussdIface(mConnectionInfo.busName, mConnectionInfo.objectPath, CANONICAL_TELEPHONY_USSD_IFACE);
> -        mSerial = ussdIface.property("Serial").toString();
>  
>          watchSelfContactPresence();
>      }
>  
> -    Q_EMIT networkNameChanged();
>      Q_EMIT connectedChanged();
> -    Q_EMIT simLockedChanged();
>      Q_EMIT selfContactIdChanged();
> -    Q_EMIT serialChanged();
>      Q_EMIT activeChanged();
>  }
> -
> -void AccountEntry::onEmergencyNumbersChanged(const QStringList &numbers)
> -{
> -    mEmergencyNumbers = numbers;
> -    Q_EMIT emergencyNumbersChanged();
> -}
> -
> -void AccountEntry::onVoicemailNumberChanged(const QString &number)
> -{
> -    mVoicemailNumber = number;
> -    Q_EMIT voicemailNumberChanged();
> -}
> -
> -void AccountEntry::onVoicemailCountChanged(uint count)
> -{
> -    mVoicemailCount = count;
> -    Q_EMIT voicemailCountChanged();
> -}
> -
> -void AccountEntry::onVoicemailIndicatorChanged(bool visible)
> -{
> -    mVoicemailIndicator = visible;
> -    Q_EMIT voicemailIndicatorChanged();
> -}
> 
> === modified file 'libtelephonyservice/accountentry.h'
> --- libtelephonyservice/accountentry.h	2015-02-20 18:46:14 +0000
> +++ libtelephonyservice/accountentry.h	2015-03-25 22:11:52 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (C) 2013 Canonical, Ltd.
> + * Copyright (C) 2013-2015 Canonical, Ltd.
>   *
>   * Authors:
>   *  Gustavo Pichorim Boiko <gustavo.boiko at canonical.com>
> @@ -25,7 +25,6 @@
>  #include <QObject>
>  #include <TelepathyQt/Account>
>  
> -
>  typedef struct {
>      QString busName;
>      QString objectPath;
> @@ -37,74 +36,59 @@
>      Q_PROPERTY(QString accountId READ accountId NOTIFY accountIdChanged)
>      Q_PROPERTY(bool active READ active NOTIFY activeChanged)
>      Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName NOTIFY displayNameChanged)
> +    Q_PROPERTY(QString status READ status NOTIFY statusChanged)
> +    Q_PROPERTY(QString statusMessage READ statusMessage NOTIFY statusMessageChanged)
>      Q_PROPERTY(QString selfContactId READ selfContactId NOTIFY selfContactIdChanged)
>      Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
> -    Q_PROPERTY(QStringList emergencyNumbers READ emergencyNumbers NOTIFY emergencyNumbersChanged)
> -    Q_PROPERTY(QString voicemailNumber READ voicemailNumber NOTIFY voicemailNumberChanged)
> -    Q_PROPERTY(uint voicemailCount READ voicemailCount NOTIFY voicemailCountChanged)
> -    Q_PROPERTY(bool voicemailIndicator READ voicemailIndicator NOTIFY voicemailIndicatorChanged)
> -    Q_PROPERTY(QString networkName READ networkName NOTIFY networkNameChanged)
> -    Q_PROPERTY(bool emergencyCallsAvailable READ emergencyCallsAvailable NOTIFY emergencyCallsAvailableChanged)
> -    Q_PROPERTY(bool simLocked READ simLocked NOTIFY simLockedChanged)
> -    Q_PROPERTY(QString serial READ serial NOTIFY serialChanged)
> +    Q_PROPERTY(QStringList addressableVCardFields READ addressableVCardFields NOTIFY addressableVCardFieldsChanged)
> +    Q_ENUMS(AccountType)
> +    friend class AccountEntryFactory;
>  
>  public:
> -    explicit AccountEntry(const Tp::AccountPtr &account, QObject *parent = 0);
> +    enum AccountType {
> +        PhoneAccount,
> +        GenericAccount
> +    };
> +
>      QString accountId() const;
>      bool active() const;
>      QString displayName() const;
> +    QString status() const;
> +    QString statusMessage() const;
>      QString selfContactId() const;
> -    QString networkName() const;
> -    bool simLocked() const;
>      void setDisplayName(const QString &name);
> -    bool connected() const;
> -    QStringList emergencyNumbers() const;
> -    QString voicemailNumber() const;
> -    uint voicemailCount() const;
> -    bool voicemailIndicator() const;
> +    virtual bool connected() const;
>      Tp::AccountPtr account() const;
> -    bool emergencyCallsAvailable() const;
> -    QString serial() const;
> +    virtual AccountType type() const;
> +    virtual QStringList addressableVCardFields() const;
> +
> +    virtual bool compareIds(const QString &first, const QString &second) const;
>  
>  Q_SIGNALS:
>      void accountReady();
>      void accountIdChanged();
>      void activeChanged();
>      void displayNameChanged();
> +    void statusChanged();
> +    void statusMessageChanged();
>      void selfContactIdChanged();
> -    void networkNameChanged();
> -    void simLockedChanged();
>      void connectedChanged();
> -    void emergencyNumbersChanged();
> -    void voicemailNumberChanged();
> -    void voicemailCountChanged();
> -    void voicemailIndicatorChanged();
> -    void emergencyCallsAvailableChanged();
> -    void serialChanged();
> +    void addressableVCardFieldsChanged();
>      void removed();
>  
>  protected Q_SLOTS:
> -    void initialize();
> -    void ensureEnabled();
> -    void ensureConnected();
> -    void watchSelfContactPresence();
> -
> -private Q_SLOTS:
> -    void onConnectionChanged();
> -    void onEmergencyNumbersChanged(const QStringList &numbers);
> -    void onVoicemailNumberChanged(const QString &number);
> -    void onVoicemailCountChanged(uint count);
> -    void onVoicemailIndicatorChanged(bool visible);
> -    void onSelfHandleChanged(uint handle);
> -
> -private:
> +    virtual void initialize();
> +    virtual void ensureEnabled();
> +    virtual void ensureConnected();
> +    virtual void watchSelfContactPresence();
> +    virtual void onConnectionChanged();
> +    virtual void onSelfHandleChanged(uint handle);
> +
> +protected:
> +    explicit AccountEntry(const Tp::AccountPtr &account, QObject *parent = 0);
> +
>      Tp::AccountPtr mAccount;
> -    QStringList mEmergencyNumbers;
> -    QString mVoicemailNumber;
> -    uint mVoicemailCount;
> -    bool mVoicemailIndicator;
>      ConnectionInfo mConnectionInfo;
> -    QString mSerial;
>  };
>  
>  #endif // ACCOUNTENTRY_H
> 
> === added file 'libtelephonyservice/accountentryfactory.cpp'
> --- libtelephonyservice/accountentryfactory.cpp	1970-01-01 00:00:00 +0000
> +++ libtelephonyservice/accountentryfactory.cpp	2015-03-25 22:11:52 +0000
> @@ -0,0 +1,40 @@
> +/*
> + * Copyright (C) 2015 Canonical, Ltd.
> + *
> + * Authors:
> + *  Gustavo Pichorim Boiko <gustavo.boiko at canonical.com>
> + *
> + * This file is part of telephony-service.
> + *
> + * telephony-service is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * telephony-service 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 General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "accountentryfactory.h"
> +#include "accountentry.h"
> +#include "ofonoaccountentry.h"
> +
> +AccountEntry *AccountEntryFactory::createEntry(const Tp::AccountPtr &account, QObject *parent)
> +{
> +    QString protocol = account->protocolName();
> +
> +    // FIXME: check what other accounts need extra properties/methods
> +    if (protocol == "ofono") {
> +        return new OfonoAccountEntry(account, parent);
> +    }
> +
> +    return new AccountEntry(account, parent);
> +}
> +
> +AccountEntryFactory::AccountEntryFactory()
> +{
> +}
> 
> === added file 'libtelephonyservice/accountentryfactory.h'
> --- libtelephonyservice/accountentryfactory.h	1970-01-01 00:00:00 +0000
> +++ libtelephonyservice/accountentryfactory.h	2015-03-25 22:11:52 +0000
> @@ -0,0 +1,38 @@
> +/*
> + * Copyright (C) 2015 Canonical, Ltd.
> + *
> + * Authors:
> + *  Gustavo Pichorim Boiko <gustavo.boiko at canonical.com>
> + *
> + * This file is part of telephony-service.
> + *
> + * telephony-service is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * telephony-service 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 General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef ACCOUNTENTRYFACTORY_H
> +#define ACCOUNTENTRYFACTORY_H
> +
> +#include <TelepathyQt/Account>
> +
> +class AccountEntry;
> +
> +class AccountEntryFactory
> +{
> +public:
> +    static AccountEntry *createEntry(const Tp::AccountPtr &account, QObject *parent = 0);
> +
> +private:
> +    explicit AccountEntryFactory();
> +};
> +
> +#endif // ACCOUNTENTRYFACTORY_H
> 
> === modified file 'libtelephonyservice/callentry.cpp'
> --- libtelephonyservice/callentry.cpp	2015-01-19 21:14:26 +0000
> +++ libtelephonyservice/callentry.cpp	2015-03-25 22:11:52 +0000
> @@ -24,6 +24,7 @@
>  #include "callmanager.h"
>  #include "telepathyhelper.h"
>  #include "accountentry.h"
> +#include "ofonoaccountentry.h"
>  
>  #include <QDBusReply>
>  #include <QTime>
> @@ -76,8 +77,10 @@
>              SIGNAL(CallHoldingFailed(QString)),
>              SLOT(onCallHoldingFailed(QString)));
>  
> -    if (mAccount && !mAccount->voicemailNumber().isEmpty()) {
> -        setVoicemail(phoneNumber() == mAccount->voicemailNumber());
> +    // in case the account is an ofono account, we can check the voicemail number
> +    OfonoAccountEntry *ofonoAccount = qobject_cast<OfonoAccountEntry*>(mAccount);
> +    if (ofonoAccount && ofonoAccount->voicemailNumber().isEmpty()) {
> +        setVoicemail(phoneNumber() == ofonoAccount->voicemailNumber());
>      }
>  
>      Q_EMIT incomingChanged();
> 
> === modified file 'libtelephonyservice/callentry.h'
> --- libtelephonyservice/callentry.h	2015-01-19 21:14:26 +0000
> +++ libtelephonyservice/callentry.h	2015-03-25 22:11:52 +0000
> @@ -48,6 +48,7 @@
>                 NOTIFY voicemailChanged)
>      Q_PROPERTY(AccountEntry *account READ account)
>  
> +    // FIXME: replace this by a more generic identifier to support accounts not based on phone numbers
>      // this property is only filled for 1-1 calls
>      Q_PROPERTY(QString phoneNumber
>                 READ phoneNumber
> 
> === modified file 'libtelephonyservice/chatmanager.cpp'
> --- libtelephonyservice/chatmanager.cpp	2015-02-04 21:01:09 +0000
> +++ libtelephonyservice/chatmanager.cpp	2015-03-25 22:11:52 +0000
> @@ -146,13 +146,7 @@
>      connect(channel.data(),
>              SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
>              SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
> -    connect(channel.data(),
> -            SIGNAL(pendingMessageRemoved(const Tp::ReceivedMessage&)),
> -            SLOT(onPendingMessageRemoved(const Tp::ReceivedMessage&)));
>  
> -    if (!channel->targetContact().isNull()){
> -        Q_EMIT unreadMessagesChanged(channel->targetContact()->id());
> -    }
>      Q_FOREACH(const Tp::ReceivedMessage &message, channel->messageQueue()) {
>          onMessageReceived(message);
>      }
> @@ -167,13 +161,6 @@
>      }
>  
>      Q_EMIT messageReceived(message.sender()->id(), message.text(), message.received(), message.messageToken(), true);
> -    Q_EMIT unreadMessagesChanged(message.sender()->id());
> -}
> -
> -void ChatManager::onPendingMessageRemoved(const Tp::ReceivedMessage &message)
> -{
> -    // emit the signal saying the unread messages for a specific number has changed
> -    Q_EMIT unreadMessagesChanged(message.sender()->id());
>  }
>  
>  void ChatManager::onMessageSent(const Tp::Message &sentMessage, const Tp::MessageSendingFlags flags, const QString &message)
> @@ -191,33 +178,6 @@
>      }
>  }
>  
> -Tp::TextChannelPtr ChatManager::existingChat(const QStringList &recipients, const QString &accountId)
> -{
> -    Tp::TextChannelPtr channel;
> -
> -    Q_FOREACH(const Tp::TextChannelPtr &channel, mChannels) {
> -        AccountEntry *channelAccount = TelepathyHelper::instance()->accountForConnection(channel->connection());
> -        int count = 0;
> -        if (!channelAccount || channelAccount->accountId() != accountId
> -                || channel->groupContacts(false).size() != recipients.size()) {
> -            continue;
> -        }
> -        Q_FOREACH(const QString &recipientNew, recipients) {
> -            Q_FOREACH(const Tp::ContactPtr &recipientOld, channel->groupContacts(false)) {
> -                if (PhoneUtils::comparePhoneNumbers(recipientOld->id(), recipientNew)) {
> -                    count++;
> -                }
> -            }
> -        }
> -        if (count == recipients.size()) {
> -            return channel;
> -        }
> -
> -    }
> -
> -    return channel;
> -}
> -
>  void ChatManager::acknowledgeMessage(const QStringList &recipients, const QString &messageId, const QString &accountId)
>  {
>      AccountEntry *account = NULL;
> 
> === modified file 'libtelephonyservice/chatmanager.h'
> --- libtelephonyservice/chatmanager.h	2015-02-04 21:01:09 +0000
> +++ libtelephonyservice/chatmanager.h	2015-03-25 22:11:52 +0000
> @@ -40,20 +40,15 @@
>  Q_SIGNALS:
>      void messageReceived(const QString &recipient, const QString &message, const QDateTime &timestamp, const QString &messageId, bool unread);
>      void messageSent(const QString &recipient, const QString &message);
> -    void unreadMessagesChanged(const QString &recipient);
>  
>  public Q_SLOTS:
>      void onTextChannelAvailable(Tp::TextChannelPtr channel);
>      void onConnectedChanged();
>      void onMessageReceived(const Tp::ReceivedMessage &message);
> -    void onPendingMessageRemoved(const Tp::ReceivedMessage &message);
>      void onMessageSent(const Tp::Message &sentMessage, const Tp::MessageSendingFlags flags, const QString &message);
>  
>      void acknowledgeMessage(const QStringList &recipients, const QString &messageId, const QString &accountId = QString::null);
>  
> -protected:
> -    Tp::TextChannelPtr existingChat(const QStringList &recipients, const QString &accountId);
> -
>  protected Q_SLOTS:
>      void onAckTimerTriggered();
>  
> 
> === added file 'libtelephonyservice/ofonoaccountentry.cpp'
> --- libtelephonyservice/ofonoaccountentry.cpp	1970-01-01 00:00:00 +0000
> +++ libtelephonyservice/ofonoaccountentry.cpp	2015-03-25 22:11:52 +0000
> @@ -0,0 +1,208 @@
> +/*
> + * Copyright (C) 2013-2015 Canonical, Ltd.
> + *
> + * Authors:
> + *  Gustavo Pichorim Boiko <gustavo.boiko at canonical.com>
> + *
> + * This file is part of telephony-service.
> + *
> + * telephony-service is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * telephony-service 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 General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "ofonoaccountentry.h"
> +#include "telepathyhelper.h"
> +#include "phoneutils.h"
> +
> +OfonoAccountEntry::OfonoAccountEntry(const Tp::AccountPtr &account, QObject *parent) :
> +    AccountEntry(account, parent), mVoicemailCount(0), mVoicemailIndicator(false)
> +{
> +    // the sim lock detection is based on the status message, so whenever it
> +    // changes, it might mean the sim lock state changed too
> +    connect(this,
> +            SIGNAL(statusChanged()),
> +            SIGNAL(simLockedChanged()));
> +    connect(this,
> +            SIGNAL(statusMessageChanged()),
> +            SIGNAL(networkNameChanged()));
> +    connect(this,
> +            SIGNAL(statusMessageChanged()),
> +            SIGNAL(emergencyCallsAvailableChanged()));
> +}
> +
> +QStringList OfonoAccountEntry::emergencyNumbers() const
> +{
> +    return mEmergencyNumbers;
> +}
> +
> +QString OfonoAccountEntry::voicemailNumber() const
> +{
> +    return mVoicemailNumber;
> +}
> +
> +uint OfonoAccountEntry::voicemailCount() const
> +{
> +    return mVoicemailCount;
> +}
> +
> +bool OfonoAccountEntry::voicemailIndicator() const
> +{
> +    return mVoicemailIndicator;
> +}
> +
> +QString OfonoAccountEntry::networkName() const
> +{
> +    // FIXME: maybe it is safer to reimplement here, but for ofono accounts the status message really is the
> +    // network name
> +    return statusMessage();
> +}
> +
> +bool OfonoAccountEntry::emergencyCallsAvailable() const
> +{
> +    if (mAccount.isNull() || mAccount->connection().isNull() || mAccount->connection()->selfContact().isNull()) {
> +        return false;
> +    }
> +
> +    QString status = mAccount->connection()->selfContact()->presence().status();
> +    return status != "flightmode" && status != "nomodem" && status != "";
> +}
> +
> +bool OfonoAccountEntry::simLocked() const
> +{
> +    if (mAccount.isNull() || mAccount->connection().isNull() || mAccount->connection()->selfContact().isNull()) {
> +        return false;
> +    }
> +    Tp::Presence presence = mAccount->connection()->selfContact()->presence();
> +    return (presence.type() == Tp::ConnectionPresenceTypeAway && presence.status() == "simlocked");
> +}
> +
> +QString OfonoAccountEntry::serial() const
> +{
> +    return mSerial;
> +}
> +
> +AccountEntry::AccountType OfonoAccountEntry::type() const
> +{
> +    return AccountEntry::PhoneAccount;
> +}
> +
> +bool OfonoAccountEntry::connected() const
> +{
> +    return !mAccount.isNull() && !mAccount->connection().isNull() &&
> +           !mAccount->connection()->selfContact().isNull() &&
> +            mAccount->connection()->selfContact()->presence().type() == Tp::ConnectionPresenceTypeAvailable;
> +}
> +
> +bool OfonoAccountEntry::compareIds(const QString &first, const QString &second) const
> +{
> +    return PhoneUtils::comparePhoneNumbers(first, second);
> +}
> +
> +QStringList OfonoAccountEntry::addressableVCardFields()
> +{
> +    return mAccount->protocolInfo().addressableVCardFields();
> +}
> +
> +void OfonoAccountEntry::onEmergencyNumbersChanged(const QStringList &numbers)
> +{
> +    mEmergencyNumbers = numbers;
> +    Q_EMIT emergencyNumbersChanged();
> +}
> +
> +void OfonoAccountEntry::onVoicemailNumberChanged(const QString &number)
> +{
> +    mVoicemailNumber = number;
> +    Q_EMIT voicemailNumberChanged();
> +}
> +
> +void OfonoAccountEntry::onVoicemailCountChanged(uint count)
> +{
> +    mVoicemailCount = count;
> +    Q_EMIT voicemailCountChanged();
> +}
> +
> +void OfonoAccountEntry::onVoicemailIndicatorChanged(bool visible)
> +{
> +    mVoicemailIndicator = visible;
> +    Q_EMIT voicemailIndicatorChanged();
> +}
> +
> +void OfonoAccountEntry::onConnectionChanged()
> +{
> +    // make sure the generic code is also run
> +    AccountEntry::onConnectionChanged();
> +
> +    QDBusConnection dbusConnection = QDBusConnection::sessionBus();
> +
> +    if (!mAccount->connection()) {
> +        // disconnect any previous dbus connections
> +        if (!mConnectionInfo.objectPath.isEmpty()) {
> +            dbusConnection.disconnect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> +                                      CANONICAL_TELEPHONY_EMERGENCYMODE_IFACE, "EmergencyNumbersChanged",
> +                                      this, SLOT(onEmergencyNumbersChanged(QStringList)));
> +        }
> +    } else {
> +        // connect the emergency numbers changed signal
> +        dbusConnection.connect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> +                               CANONICAL_TELEPHONY_EMERGENCYMODE_IFACE, "EmergencyNumbersChanged",
> +                               this, SLOT(onEmergencyNumbersChanged(QStringList)));
> +
> +        // and get the current value of the emergency numbers
> +        QDBusInterface connIface(mConnectionInfo.busName, mConnectionInfo.objectPath, CANONICAL_TELEPHONY_EMERGENCYMODE_IFACE);
> +        QDBusReply<QStringList> replyNumbers = connIface.call("EmergencyNumbers");
> +        if (replyNumbers.isValid()) {
> +            mEmergencyNumbers = replyNumbers.value();
> +            Q_EMIT emergencyNumbersChanged();
> +        }
> +
> +        // connect the voicemail number changed signal
> +        dbusConnection.connect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> +                               CANONICAL_TELEPHONY_VOICEMAIL_IFACE, "VoicemailNumberChanged",
> +                               this, SLOT(onVoicemailNumberChanged(QString)));
> +
> +        QDBusInterface voicemailIface(mConnectionInfo.busName, mConnectionInfo.objectPath, CANONICAL_TELEPHONY_VOICEMAIL_IFACE);
> +        QDBusReply<QString> replyNumber = voicemailIface.call("VoicemailNumber");
> +        if (replyNumber.isValid()) {
> +            mVoicemailNumber = replyNumber.value();
> +            Q_EMIT voicemailNumberChanged();
> +        }
> +
> +        // connect the voicemail count changed signal
> +        dbusConnection.connect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> +                               CANONICAL_TELEPHONY_VOICEMAIL_IFACE, "VoicemailCountChanged",
> +                               this, SLOT(onVoicemailCountChanged(uint)));
> +
> +        QDBusReply<uint> replyCount = voicemailIface.call("VoicemailCount");
> +        if (replyCount.isValid()) {
> +            mVoicemailCount = replyCount.value();
> +            Q_EMIT voicemailCountChanged();
> +        }
> +
> +        // connect the voicemail indicator changed signal
> +        dbusConnection.connect(mConnectionInfo.busName, mConnectionInfo.objectPath,
> +                               CANONICAL_TELEPHONY_VOICEMAIL_IFACE, "VoicemailIndicatorChanged",
> +                               this, SLOT(onVoicemailIndicatorChanged(bool)));
> +
> +        QDBusReply<bool> replyIndicator = voicemailIface.call("VoicemailIndicator");
> +        if (replyIndicator.isValid()) {
> +            mVoicemailIndicator = replyIndicator.value();
> +            Q_EMIT voicemailIndicatorChanged();
> +        }
> +
> +        // and get the serial
> +        QDBusInterface ussdIface(mConnectionInfo.busName, mConnectionInfo.objectPath, CANONICAL_TELEPHONY_USSD_IFACE);
> +        mSerial = ussdIface.property("Serial").toString();
> +    }
> +
> +    Q_EMIT simLockedChanged();
> +    Q_EMIT serialChanged();
> +}
> 
> === added file 'libtelephonyservice/ofonoaccountentry.h'
> --- libtelephonyservice/ofonoaccountentry.h	1970-01-01 00:00:00 +0000
> +++ libtelephonyservice/ofonoaccountentry.h	2015-03-25 22:11:52 +0000
> @@ -0,0 +1,86 @@
> +/*
> + * Copyright (C) 2013-2015 Canonical, Ltd.
> + *
> + * Authors:
> + *  Gustavo Pichorim Boiko <gustavo.boiko at canonical.com>
> + *
> + * This file is part of telephony-service.
> + *
> + * telephony-service is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * telephony-service 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 General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef OFONOACCOUNTENTRY_H
> +#define OFONOACCOUNTENTRY_H
> +
> +#include "accountentry.h"
> +
> +class OfonoAccountEntry : public AccountEntry
> +{
> +    Q_OBJECT
> +    Q_PROPERTY(QStringList emergencyNumbers READ emergencyNumbers NOTIFY emergencyNumbersChanged)
> +    Q_PROPERTY(QString voicemailNumber READ voicemailNumber NOTIFY voicemailNumberChanged)
> +    Q_PROPERTY(uint voicemailCount READ voicemailCount NOTIFY voicemailCountChanged)
> +    Q_PROPERTY(bool voicemailIndicator READ voicemailIndicator NOTIFY voicemailIndicatorChanged)
> +    Q_PROPERTY(QString networkName READ networkName NOTIFY networkNameChanged)
> +    Q_PROPERTY(bool emergencyCallsAvailable READ emergencyCallsAvailable NOTIFY emergencyCallsAvailableChanged)
> +    Q_PROPERTY(bool simLocked READ simLocked NOTIFY simLockedChanged)
> +    Q_PROPERTY(QString serial READ serial NOTIFY serialChanged)
> +    friend class AccountEntryFactory;
> +
> +public:
> +    QStringList emergencyNumbers() const;
> +    QString voicemailNumber() const;
> +    uint voicemailCount() const;
> +    bool voicemailIndicator() const;
> +    QString networkName() const;
> +    bool emergencyCallsAvailable() const;
> +    bool simLocked() const;
> +    QString serial() const;
> +
> +    // reimplemented from AccountEntry
> +    virtual AccountEntry::AccountType type() const;
> +    virtual bool connected() const;
> +    virtual bool compareIds(const QString &first, const QString &second) const;
> +    virtual QStringList addressableVCardFields();
> +
> +Q_SIGNALS:
> +    void emergencyNumbersChanged();
> +    void voicemailNumberChanged();
> +    void voicemailCountChanged();
> +    void voicemailIndicatorChanged();
> +    void networkNameChanged();
> +    void emergencyCallsAvailableChanged();
> +    void simLockedChanged();
> +    void serialChanged();
> +
> +private Q_SLOTS:
> +    void onEmergencyNumbersChanged(const QStringList &numbers);
> +    void onVoicemailNumberChanged(const QString &number);
> +    void onVoicemailCountChanged(uint count);
> +    void onVoicemailIndicatorChanged(bool visible);
> +
> +    // reimplemented from AccountEntry
> +    void onConnectionChanged();
> +
> +protected:
> +    explicit OfonoAccountEntry(const Tp::AccountPtr &account, QObject *parent = 0);
> +
> +private:
> +    QStringList mEmergencyNumbers;
> +    QString mVoicemailNumber;
> +    uint mVoicemailCount;
> +    bool mVoicemailIndicator;
> +    QString mSerial;
> +};
> +
> +#endif // OFONOACCOUNTENTRY_H
> 
> === modified file 'libtelephonyservice/telepathyhelper.cpp'
> --- libtelephonyservice/telepathyhelper.cpp	2015-02-20 18:46:14 +0000
> +++ libtelephonyservice/telepathyhelper.cpp	2015-03-25 22:11:52 +0000
> @@ -22,6 +22,8 @@
>  
>  #include "telepathyhelper.h"
>  #include "accountentry.h"
> +#include "ofonoaccountentry.h"
> +#include "accountentryfactory.h"
>  #include "chatmanager.h"
>  #include "callmanager.h"
>  #include "config.h"
> @@ -269,11 +271,21 @@
>              SIGNAL(connectedChanged()),
>              SLOT(updateConnectedStatus()));
>      connect(entry,
> +            SIGNAL(connectedChanged()),
> +            SIGNAL(activeAccountsChanged()));
> +    connect(entry,
>              SIGNAL(accountReady()),
>              SLOT(onAccountReady()));
>      connect(entry,
>              SIGNAL(removed()),
>              SLOT(onAccountRemoved()));
> +
> +    OfonoAccountEntry *ofonoAccount = qobject_cast<OfonoAccountEntry*>(entry);
> +    if (ofonoAccount) {
> +        connect(ofonoAccount,
> +                SIGNAL(emergencyCallsAvailableChanged()),
> +                SIGNAL(emergencyCallsAvailableChanged()));
> +    }
>  }
>  
>  bool TelepathyHelper::registerClient(Tp::AbstractClient *client, QString name)
> @@ -379,15 +391,8 @@
>  
>  void TelepathyHelper::onNewAccount(const Tp::AccountPtr &account)
>  {
> -    AccountEntry *accountEntry = new AccountEntry(account, this);
> -    connect(accountEntry,
> -            SIGNAL(connectedChanged()),
> -            SIGNAL(activeAccountsChanged()));
> -    connect(accountEntry,
> -            SIGNAL(emergencyCallsAvailableChanged()),
> -            SIGNAL(emergencyCallsAvailableChanged()));
> +    AccountEntry *accountEntry = AccountEntryFactory::createEntry(account, this);
>      setupAccountEntry(accountEntry);
> -
>      mAccounts.append(accountEntry);
>  
>      QMap<QString, AccountEntry *> sortedOfonoAccounts;
> @@ -501,8 +506,10 @@
>  
>  bool TelepathyHelper::emergencyCallsAvailable() const
>  {
> +    // FIXME: this is really ofono specific, so maybe move somewhere else?
>      Q_FOREACH(const AccountEntry *account, mAccounts) {
> -        if (account->emergencyCallsAvailable()) {
> +        const OfonoAccountEntry *ofonoAccount = qobject_cast<const OfonoAccountEntry*>(account);
> +        if (ofonoAccount && ofonoAccount->emergencyCallsAvailable()) {
>              return true;
>          }
>      }
> 


-- 
https://code.launchpad.net/~boiko/telephony-service/support_non_phone_accounts/+merge/251796
Your team Ubuntu Phablet Team is subscribed to branch lp:telephony-service.



More information about the Ubuntu-reviews mailing list