diff --git a/src/private/vcardutils.cpp b/src/private/vcardutils.cpp index ac905dbb289078a94bf040ac7be63ce5632c6e1f..9125f3458c9265668276064ce242d99f7c773248 100644 --- a/src/private/vcardutils.cpp +++ b/src/private/vcardutils.cpp @@ -24,6 +24,7 @@ #include <QtCore/QFile> #include <QtCore/QUrl> #include <QtCore/QMimeData> +#include <QtCore/QMutex> //Ring #include "phonedirectorymodel.h" @@ -58,10 +59,20 @@ struct VCardMapper; typedef void (VCardMapper:: *mapToProperty)(Person*, const QString&, const QByteArray&); -struct VCardMapper { +struct VCardMapper final { QHash<QByteArray, mapToProperty> m_hHash; + // Calling getNumber before the Contact is finalized will create duplicates + struct GetNumberFuture { + QByteArray uri; + Person* c; + QString category; + }; + + QHash<Person*, QList<GetNumberFuture> > m_hDelayedCMInserts; + static QMutex* m_pMutex; + VCardMapper() { m_hHash[VCardUtils::Property::UID] = &VCardMapper::setUid; m_hHash[VCardUtils::Property::NAME] = &VCardMapper::setNames; @@ -73,6 +84,27 @@ struct VCardMapper { m_hHash[VCardUtils::Property::PHOTO] = &VCardMapper::setPhoto; } + void apply() { + // Finalize the transaction, set the ContactsMethods + // it is done at the end to make sure UID has been set and all CMs + // are there at once not to mess PhoneDirectoryModel detection + + QMutexLocker locker(m_pMutex); + + for (QHash<Person*, QList<GetNumberFuture>>::iterator i = m_hDelayedCMInserts.begin(); i != m_hDelayedCMInserts.end(); ++i) { + Person::ContactMethods m = i.key()->phoneNumbers(); + + foreach(const GetNumberFuture& v, i.value()) { + ContactMethod* cm = PhoneDirectoryModel::instance().getNumber(v.uri,v.c,nullptr,v.category); + + m << cm; + } + i.key()->setContactMethods(m); + } + + m_hDelayedCMInserts.clear(); + } + void setFormattedName(Person* c, const QString&, const QByteArray& fn) { c->setFormattedName(QString::fromUtf8(fn)); } @@ -100,7 +132,7 @@ struct VCardMapper { void setPhoto(Person* c, const QString& key, const QByteArray& fn) { QByteArray type = "PNG"; - QRegExp rx("TYPE=([A-Za-z]*)"); + QRegExp rx(QStringLiteral("TYPE=([A-Za-z]*)")); while ((rx.indexIn(key, 0)) != -1) { type = rx.cap(1).toLatin1(); @@ -114,7 +146,7 @@ struct VCardMapper { void addContactMethod(Person* c, const QString& key, const QByteArray& fn) { QByteArray type; - QRegExp rx("TYPE=([A-Za-z,]*)"); + QRegExp rx(QStringLiteral("TYPE=([A-Za-z,]*)")); //VCard spec: it is RECOMMENDED that property and parameter names // be upper-case on output. @@ -128,10 +160,11 @@ struct VCardMapper { // TODO: Currently we only support one type (the first on the line) TYPE=WORK,VOICE: <number> const QStringList categories = QString(type).split(','); - ContactMethod* cm = PhoneDirectoryModel::instance().getNumber(fn,c,nullptr,categories.size()?categories[0]:QString()); - Person::ContactMethods m = c->phoneNumbers(); - m << cm; - c->setContactMethods(m); + m_hDelayedCMInserts[c] << GetNumberFuture { + fn, + c, + categories.size()?categories[0]:QString() + }; } void addAddress(Person* c, const QString& key, const QByteArray& fn) { @@ -182,6 +215,8 @@ struct VCardMapper { return true; } }; + +QMutex* VCardMapper::m_pMutex = new QMutex(); static VCardMapper* vc_mapper = new VCardMapper; VCardUtils::VCardUtils() @@ -283,7 +318,12 @@ bool VCardUtils::mapToPerson(Person* p, const QByteArray& all, QList<Account*>* { // bool propertyInserted = false; QByteArray previousKey,previousValue; - for (const QByteArray& property : all.split('\n')) { + + const QList<QByteArray> lines = all.split('\n'); + + QHash<QByteArray,QByteArray> fields; + + foreach (const QByteArray& property, lines) { //Ignore empty lines if (property.size()) { @@ -293,12 +333,8 @@ bool VCardUtils::mapToPerson(Person* p, const QByteArray& all, QList<Account*>* previousValue += property.right(property.size()-1); } else { - if (previousKey.size()) { - /*propertyInserted = */vc_mapper->metacall(p,previousKey,previousValue.trimmed()); - -// if(!propertyInserted) -// qDebug() << "Could not extract: " << previousKey; - } + if (previousKey.size()) + vc_mapper->metacall(p,previousKey,previousValue.trimmed()); //Do not use split, URIs can have : in them const int dblptPos = property.indexOf(':'); @@ -324,6 +360,9 @@ bool VCardUtils::mapToPerson(Person* p, const QByteArray& all, QList<Account*>* } } + + vc_mapper->apply(); + return true; }