From 59e3cd180313c81b6607c52a67546c22cea61d9f Mon Sep 17 00:00:00 2001 From: Nicolas Jager <nicolas.jager@savoirfairelinux.com> Date: Thu, 27 Apr 2017 09:53:08 -0400 Subject: [PATCH] add vcard from contact request - mapToPersonFromIncomingContactRequest : this function creates a Person from a vCard stored by the daemon; we make sure to ignore any ContactMethods which might be contained in the vCard and only use the CM from which we receive it. - PendingContactRequestModel::data now can return : * PEER_ID : get the username if possible or ring Id if not. * FORMATTED_NAME : get the profile name stored in the vCard. * COUNT__ : used to get the number of elements in the enum. - ContactRequest now store a person. This person matches the vCard. - PeerProfileCollection updates the CM(s) of the vCards it stores with the last modified date of the vCard in to get the date at which the contact request was accepted. [SS: update commit message] [SS: change how we restore the ContactRequest accept date] Change-Id: I3bafda5b38d5e2332e095cd5f1f1d0b101847f86 Signed-off-by: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com> Reviewed-by: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com> --- src/account.cpp | 14 ++++++++++---- src/accountmodel.cpp | 9 +++++++-- src/contactrequest.cpp | 24 +++++++++++++++++++++++- src/contactrequest.h | 7 ++++++- src/peerprofilecollection.cpp | 15 ++++++++++++++- src/pendingcontactrequestmodel.cpp | 27 ++++++++++++++++++--------- src/pendingcontactrequestmodel.h | 7 +++++++ src/private/vcardutils.cpp | 29 +++++++++++++++++++++++++++++ src/private/vcardutils.h | 1 + src/recentmodel.cpp | 18 ------------------ 10 files changed, 115 insertions(+), 36 deletions(-) diff --git a/src/account.cpp b/src/account.cpp index 500abdcd..081e5298 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -143,9 +143,14 @@ Account* Account::buildExistingAccountFromId(const QByteArray& _accountId) //Load the pending trust requests if (a->protocol() == Account::Protocol::RING) { - const VectorMapStringString& pending_tr {ConfigurationManager::instance().getTrustRequests(a->id())}; - for (const auto& tr_info : pending_tr) { - a->pendingContactRequestModel()->d_ptr->addRequest(new ContactRequest(a, tr_info["from"], 0)); + const VectorMapStringString& pending_tr {ConfigurationManager::instance().getTrustRequests(a->id())}; + for (const auto& tr_info : pending_tr) { + auto payload = tr_info["payload"]; + auto peer = VCardUtils::mapToPersonFromIncomingContactRequest(VCardUtils::toHashMap(payload.toUtf8()), + tr_info["from"]); + + a->pendingContactRequestModel()->d_ptr->addRequest(new ContactRequest(a, peer, tr_info["from"], + tr_info["received"].toInt())); } } @@ -155,7 +160,8 @@ Account* Account::buildExistingAccountFromId(const QByteArray& _accountId) }); // Load the contacts associated from the daemon and create the cms. - const auto account_contacts = static_cast<QVector<QMap<QString, QString>>>(ConfigurationManager::instance().getContacts(a->id().data())); + const auto account_contacts = static_cast<QVector<QMap<QString, QString>>>(ConfigurationManager::instance() + .getContacts(a->id().data())); if (a->protocol() == Account::Protocol::RING) { for (auto contact_info : account_contacts) { diff --git a/src/accountmodel.cpp b/src/accountmodel.cpp index 62cd2df3..604a5aaa 100644 --- a/src/accountmodel.cpp +++ b/src/accountmodel.cpp @@ -50,6 +50,8 @@ #include "dbus/instancemanager.h" #include "codecmodel.h" #include "private/pendingcontactrequestmodel_p.h" +#include "person.h" +#include "private/vcardutils.h" QHash<QByteArray,AccountPlaceHolder*> AccountModelPrivate::m_hsPlaceHolder; @@ -459,7 +461,7 @@ void AccountModelPrivate::slotVolatileAccountDetailsChange(const QString& accoun void AccountModelPrivate::slotIncomingContactRequest(const QString& accountId, const QString& hash, const QByteArray& payload, time_t time) { Q_UNUSED(payload); - qDebug() << "INCOMING REQUEST" << accountId << hash << time; + Account* a = q_ptr->getById(accountId.toLatin1()); if (!a) { @@ -467,7 +469,10 @@ void AccountModelPrivate::slotIncomingContactRequest(const QString& accountId, c return; } - ContactRequest* r = new ContactRequest(a, hash, time); + auto peer = VCardUtils::mapToPersonFromIncomingContactRequest(VCardUtils::toHashMap(payload), hash); + + ContactRequest* r = new ContactRequest(a, peer, hash, time); + a->pendingContactRequestModel()->d_ptr->addRequest(r); } diff --git a/src/contactrequest.cpp b/src/contactrequest.cpp index 3d5941af..448b05ad 100644 --- a/src/contactrequest.cpp +++ b/src/contactrequest.cpp @@ -25,6 +25,7 @@ #include <certificate.h> #include <certificatemodel.h> #include "itembase.h" +#include "personmodel.h" //DRing #include "dbus/configurationmanager.h" @@ -36,11 +37,13 @@ public: QDateTime m_Time ; Certificate* m_pCertificate; Account* m_pAccount ; + Person* m_pPeer ; }; -ContactRequest::ContactRequest(Account* a, const QString& id, time_t time) : QObject(a), d_ptr(new ContactRequestPrivate) +ContactRequest::ContactRequest(Account* a, Person* p, const QString& id, time_t time) : QObject(a), d_ptr(new ContactRequestPrivate) { d_ptr->m_pAccount = a; + d_ptr->m_pPeer = p; d_ptr->m_Time = QDateTime::fromTime_t(time); d_ptr->m_pCertificate = CertificateModel::instance().getCertificateFromId(id, a); } @@ -65,9 +68,28 @@ Account* ContactRequest::account() const return d_ptr->m_pAccount; } +/** + * get the person associated to the contact request. + */ +Person* +ContactRequest::peer() const +{ + return d_ptr->m_pPeer; +} + +/** + * set the person associated to the contact request. + */ +void +ContactRequest::setPeer(Person* person) +{ + d_ptr->m_pPeer = person; +} + bool ContactRequest::accept() { if (ConfigurationManager::instance().acceptTrustRequest(d_ptr->m_pAccount->id(), d_ptr->m_pCertificate->remoteId())) { + PersonModel::instance().addPeerProfile(peer()); emit requestAccepted(); return true; } diff --git a/src/contactrequest.h b/src/contactrequest.h index f2950b68..f9e1427d 100644 --- a/src/contactrequest.h +++ b/src/contactrequest.h @@ -26,6 +26,7 @@ class AccountModelPrivate; class Certificate; class Account; class AccountPrivate; +class Person; class LIB_EXPORT ContactRequest : public QObject { @@ -42,6 +43,10 @@ public: QDateTime date () const; Account* account () const; Q_INVOKABLE QVariant roleData (int role) const; + Person* peer() const; + + // Setter + void setPeer(Person* person); //Mutator Q_INVOKABLE bool accept (); @@ -52,7 +57,7 @@ public: bool operator==(const ContactRequest& another) const; private: - explicit ContactRequest(Account* a, const QString& id, time_t time); + explicit ContactRequest(Account* a, Person* p, const QString& id = QString(), time_t time = -1); virtual ~ContactRequest(); ContactRequestPrivate* d_ptr; diff --git a/src/peerprofilecollection.cpp b/src/peerprofilecollection.cpp index 2b74ef78..e09b5a82 100644 --- a/src/peerprofilecollection.cpp +++ b/src/peerprofilecollection.cpp @@ -25,12 +25,14 @@ #include <QtCore/QStandardPaths> #include <QtCore/QUrl> #include <QtCore/QVector> +#include <QtCore/QDateTime> //Ring #include "private/vcardutils.h" #include "account.h" #include "accountmodel.h" #include "person.h" +#include "contactmethod.h" class PeerProfileEditor final : public CollectionEditor<Person> { @@ -161,10 +163,21 @@ bool PeerProfileCollection::load() const QStringList entries = profilesDir.entryList({QStringLiteral("*.vcf")}, QDir::Files); foreach (const QString& item , entries) { + auto filePath = profilesDir.path() + '/' + item; + + // create Person auto personProfile = new Person(this); QList<Account*> accs; - VCardUtils::mapToPerson(personProfile,QUrl(profilesDir.path()+'/'+item),&accs); + VCardUtils::mapToPerson(personProfile, QUrl(filePath), &accs); editor<Person>()->addExisting(personProfile); + + // set last used time based on last modified of vCard file; this is in case there has been + // no other interactions with these CMs + auto lastUsed = QFileInfo(filePath).lastModified(); + for (auto cm : personProfile->phoneNumbers()) { + qDebug() << "ppc setting last used" << personProfile << cm << lastUsed; + cm->setLastUsed(lastUsed.toTime_t()); + } } return true; diff --git a/src/pendingcontactrequestmodel.cpp b/src/pendingcontactrequestmodel.cpp index ef3a689e..c8f5603c 100644 --- a/src/pendingcontactrequestmodel.cpp +++ b/src/pendingcontactrequestmodel.cpp @@ -25,11 +25,8 @@ #include <certificate.h> #include <account.h> #include "private/pendingcontactrequestmodel_p.h" - -enum Columns { - HASH, - TIME -}; +#include "person.h" +#include "contactmethod.h" PendingContactRequestModelPrivate::PendingContactRequestModelPrivate(PendingContactRequestModel* p) : q_ptr(p) {} @@ -51,10 +48,10 @@ QVariant PendingContactRequestModel::data( const QModelIndex& index, int role ) return QVariant(); switch(index.column()) { - case Columns::HASH: + case Columns::PEER_ID: switch(role) { case Qt::DisplayRole: - return d_ptr->m_lRequests[index.row()]->certificate()->remoteId(); + return d_ptr->m_lRequests[index.row()]->peer()->phoneNumbers()[0]->getBestId(); } break; case Columns::TIME: @@ -63,6 +60,18 @@ QVariant PendingContactRequestModel::data( const QModelIndex& index, int role ) return d_ptr->m_lRequests[index.row()]->date(); } break; + case Columns::FORMATTED_NAME: + switch(role) { + case Qt::DisplayRole: + return d_ptr->m_lRequests[index.row()]->peer()->formattedName(); + } + break; + case Columns::COUNT__: + switch(role) { + case Qt::DisplayRole: + return static_cast<int>(PendingContactRequestModel::Columns::COUNT__); + } + break; } return QVariant::fromValue(d_ptr->m_lRequests[index.row()]->roleData(role)); @@ -75,7 +84,7 @@ int PendingContactRequestModel::rowCount( const QModelIndex& parent ) const int PendingContactRequestModel::columnCount( const QModelIndex& parent ) const { - return parent.isValid()? 0 : 2; + return parent.isValid()? 0 : static_cast<int>(PendingContactRequestModel::Columns::COUNT__); } Qt::ItemFlags PendingContactRequestModel::flags( const QModelIndex& index ) const @@ -138,7 +147,7 @@ void PendingContactRequestModelPrivate::addRequest(ContactRequest* r) removeRequest(r); }); - emit q_ptr->requestAdded(r); + emit q_ptr->requestAdded(r); } void PendingContactRequestModelPrivate::removeRequest(ContactRequest* r) diff --git a/src/pendingcontactrequestmodel.h b/src/pendingcontactrequestmodel.h index 8e811e75..2e90173f 100644 --- a/src/pendingcontactrequestmodel.h +++ b/src/pendingcontactrequestmodel.h @@ -36,6 +36,13 @@ class LIB_EXPORT PendingContactRequestModel : public QAbstractTableModel friend class AccountModelPrivate; public: + enum Columns { + PEER_ID, + TIME, + FORMATTED_NAME, + COUNT__ + }; + //Model functions virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; diff --git a/src/private/vcardutils.cpp b/src/private/vcardutils.cpp index 07fd2bba..c73fbf5e 100644 --- a/src/private/vcardutils.cpp +++ b/src/private/vcardutils.cpp @@ -400,6 +400,35 @@ Person* VCardUtils::mapToPerson(const QHash<QByteArray, QByteArray>& vCard, QLis return personMapped; } +/** + * create a Person object from a vcard and a ringId, to use when loading and receiving a contact request. + * + * @param vCard, the vcard. Ring ids inside a vcard should be discarded. + * @param ringId, this ring id should always used to identify the peer. + */ +Person* VCardUtils::mapToPersonFromIncomingContactRequest(const QHash<QByteArray, QByteArray>& vCard, const QString& ringId) +{ + auto personMapped = new Person(); + + QHashIterator<QByteArray, QByteArray> it(vCard); + while (it.hasNext()) { + it.next(); + + if (it.key() == VCardUtils::Property::TELEPHONE) { + // Do not trust a ringid from an incoming vcard, it could have been falsified. + continue; + } + + vc_mapper->metacall(personMapped, it.key(), it.value().trimmed()); + } + + // Add the ringid + vc_mapper->metacall(personMapped, VCardUtils::Property::TELEPHONE, ringId.toLatin1()); + vc_mapper->apply(); + + return personMapped; +} + QHash<QByteArray, QByteArray> VCardUtils::toHashMap(const QByteArray& content) { QHash<QByteArray, QByteArray> vCard; diff --git a/src/private/vcardutils.h b/src/private/vcardutils.h index bd15d1ce..604dbc4e 100644 --- a/src/private/vcardutils.h +++ b/src/private/vcardutils.h @@ -83,6 +83,7 @@ public: static bool mapToPerson(Person* p, const QUrl& url, QList<Account*>* accounts = nullptr); static bool mapToPerson(Person* p, const QByteArray& content, QList<Account*>* accounts = nullptr); static Person* mapToPerson(const QHash<QByteArray, QByteArray>& vCard, QList<Account*>* accounts = nullptr); + static Person* mapToPersonFromIncomingContactRequest(const QHash<QByteArray, QByteArray>& vCard, const QString& hash); static QHash<QByteArray, QByteArray> toHashMap(const QByteArray& content); //Serialization diff --git a/src/recentmodel.cpp b/src/recentmodel.cpp index b6c658f2..9899e4f7 100644 --- a/src/recentmodel.cpp +++ b/src/recentmodel.cpp @@ -216,24 +216,6 @@ RecentModel::RecentModel(QObject* parent) : QAbstractItemModel(parent), d_ptr(ne connect(&CallModel::instance() , &CallModel::conferenceChanged , d_ptr, &RecentModelPrivate::slotConferenceChanged ); connect(CallModel::instance().selectionModel(), &QItemSelectionModel::currentChanged, d_ptr, &RecentModelPrivate::slotCurrentCallChanged); - // Fill contacts from daemon source - for (int i = 0; i < AccountModel::instance().rowCount(); i++) { - auto account = qvariant_cast<Account*>(AccountModel::instance().data(AccountModel::instance().index(i,0), - static_cast<int>(Account::Role::Object))); - - for (auto cm : account->getContacts()) - d_ptr->slotLastUsedChanged(cm, cm->lastUsed()); - } - - // Called when a contact was added to the daemon list (e.g when the user as accepted a request) - connect(&AccountModel::instance(), &AccountModel::accountContactAdded, [this] (Account* a, const ContactRequest* r) { - auto cm = r->certificate()->contactMethod(); - if (!cm) - cm = PhoneDirectoryModel::instance().getNumber(r->certificate()->remoteId(), a); - - d_ptr->slotLastUsedChanged(cm, cm->lastUsed()); - }); - //Fill the contacts for (int i=0; i < PersonModel::instance().rowCount(); i++) { auto person = qvariant_cast<Person*>(PersonModel::instance().data( -- GitLab