diff --git a/CMakeLists.txt b/CMakeLists.txt index f0c0721dba0338e829adacaad11e77eae961e0e5..3aebcfba698d8e1a68e61d7f0b0b43459d562034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,7 @@ SET( libringclient_LIB_SRCS src/transitionalpersonbackend.cpp src/collectioninterface.cpp src/collectioneditor.cpp + src/fallbackpersoncollection.cpp #Communication src/dbus/configurationmanager.cpp @@ -300,6 +301,7 @@ SET( libringclient_LIB_HDRS src/collectionmediator.hpp src/collectioneditor.h src/collectioneditor.hpp + src/fallbackpersoncollection.h ) SET(libringclient_video_LIB_HDRS diff --git a/src/collectioneditor.h b/src/collectioneditor.h index 65011fc335f003d00297c51626d6eb98e77c732d..776c8c58b6c621f49b02af5b7c13c6596c5355d2 100644 --- a/src/collectioneditor.h +++ b/src/collectioneditor.h @@ -63,9 +63,13 @@ public: ///Edit 'item', the implementation may be a GUI or something else virtual bool edit ( T* item ) = 0; + ///Add a new item to the backend virtual bool addNew ( T* item ) = 0; + ///Add an existing item to the collection + virtual bool addExisting( T* item ) = 0; + ///Add a new phone number to an existing item virtual bool addContactMethod( T* item , ContactMethod* number ); diff --git a/src/collectionmediator.hpp b/src/collectionmediator.hpp index 3dc33b5e3e446c1bfe23b60b0b0b24b911f568c8..f97732a97b6b0b5fd73930e16a43786c0ec01ba8 100644 --- a/src/collectionmediator.hpp +++ b/src/collectionmediator.hpp @@ -16,6 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ +#include <collectionmanagerinterface.h> + template<class T> class CollectionMediatorPrivate { diff --git a/src/contactproxymodel.cpp b/src/contactproxymodel.cpp index b617f2ad5a6854271df6c5833c4005c9c09f401d..65a8a82d380d1a134d4235085c137fc67f452796 100644 --- a/src/contactproxymodel.cpp +++ b/src/contactproxymodel.cpp @@ -190,8 +190,12 @@ ContactProxyModel::ContactProxyModel(int role) : QAbstractItemModel(QCoreApplica d_ptr->m_Role = role; d_ptr->m_lCategoryCounter.reserve(32); d_ptr->m_lMimes << RingMimes::PLAIN_TEXT << RingMimes::PHONENUMBER; + connect(PersonModel::instance(),SIGNAL(reloaded()),d_ptr.data(),SLOT(reloadCategories())); - connect(PersonModel::instance(),SIGNAL(newContactAdded(Person*)),d_ptr.data(),SLOT(slotContactAdded(Person*))); + connect(PersonModel::instance(),SIGNAL(newPersonAdded(Person*)),d_ptr.data(),SLOT(slotContactAdded(Person*))); + for (Person* p : PersonModel::instance()->contacts()) { + d_ptr->slotContactAdded(p); + } } ContactProxyModel::~ContactProxyModel() diff --git a/src/delegates/pixmapmanipulationdelegate.cpp b/src/delegates/pixmapmanipulationdelegate.cpp index 0b376defae43932d8002f9a111c78af6d6a43484..d94aa9e255a3756bb4f8cf0c301c45a78ddbaeda 100644 --- a/src/delegates/pixmapmanipulationdelegate.cpp +++ b/src/delegates/pixmapmanipulationdelegate.cpp @@ -77,7 +77,7 @@ QByteArray PixmapManipulationDelegate::toByteArray(const QVariant& pxm) return QByteArray(); } -QVariant PixmapManipulationDelegate::profilePhoto(const QByteArray& data) +QVariant PixmapManipulationDelegate::profilePhoto(const QByteArray& data, const QString& type) { Q_UNUSED(data) return QVariant(); diff --git a/src/delegates/pixmapmanipulationdelegate.h b/src/delegates/pixmapmanipulationdelegate.h index 36ef5fe0880f08cfbabe8340b3d58af12664e770..af14e8f4b07d49b6b2df4d7229dcafe27161d116 100644 --- a/src/delegates/pixmapmanipulationdelegate.h +++ b/src/delegates/pixmapmanipulationdelegate.h @@ -49,7 +49,7 @@ public: virtual QVariant numberCategoryIcon(const QVariant& p, const QSize& size, bool displayPresence = false, bool isPresent = false); virtual QVariant serurityIssueIcon(const QModelIndex& index); virtual QByteArray toByteArray(const QVariant& pxm); - virtual QVariant profilePhoto(const QByteArray& data); + virtual QVariant profilePhoto(const QByteArray& data, const QString& type = "PNG"); /** * Return the icons associated with the action and its state diff --git a/src/fallbackpersoncollection.cpp b/src/fallbackpersoncollection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55fe7b3d0fdc308b899fdb07dbefa6bab29007d6 --- /dev/null +++ b/src/fallbackpersoncollection.cpp @@ -0,0 +1,178 @@ +/************************************************************************************ + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***********************************************************************************/ +#include "fallbackpersoncollection.h" + +//Qt +#include <QtCore/QFile> +#include <QtCore/QDir> +#include <QtCore/QHash> +#include <QtCore/QUrl> +#include <QtWidgets/QApplication> +#include <QtCore/QStandardPaths> + +//Ring +#include "person.h" +#include "vcardutils.h" +#include "contactmethod.h" +#include "collectioneditor.h" + + +class FallbackPersonBackendEditor : public CollectionEditor<Person> +{ +public: + FallbackPersonBackendEditor(CollectionMediator<Person>* m) : CollectionEditor<Person>(m) {} + virtual bool save ( const Person* item ) override; + virtual bool append ( const Person* item ) override; + virtual bool remove ( Person* item ) override; + virtual bool edit ( Person* item ) override; + virtual bool addNew ( Person* item ) override; + virtual bool addExisting( Person* item ) override; + + QVector<Person*> m_lItems; + +private: + virtual QVector<Person*> items() const override; +}; + +class FallbackPersonCollectionPrivate +{ +public: + FallbackPersonCollectionPrivate(CollectionMediator<Person>* mediator); + CollectionMediator<Person>* m_pMediator; +}; + +FallbackPersonCollectionPrivate::FallbackPersonCollectionPrivate(CollectionMediator<Person>* mediator) : m_pMediator(mediator) +{ + +} + +FallbackPersonCollection::FallbackPersonCollection(CollectionMediator<Person>* mediator) : +CollectionInterface(new FallbackPersonBackendEditor(mediator)),d_ptr(new FallbackPersonCollectionPrivate(mediator)) +{ +} + +FallbackPersonCollection::~FallbackPersonCollection() +{ + +} + +bool FallbackPersonBackendEditor::save(const Person* item) +{ + QFile file("/tmp/vcard/"+item->uid()+".vcf"); + file.open(QIODevice::WriteOnly); + file.write(item->toVCard({})); + file.close(); + return true; +} + +bool FallbackPersonBackendEditor::append(const Person* item) +{ + Q_UNUSED(item) + return false; +} + +bool FallbackPersonBackendEditor::remove(Person* item) +{ + Q_UNUSED(item) + return false; +} + +bool FallbackPersonBackendEditor::edit( Person* item) +{ + Q_UNUSED(item) + return false; +} + +bool FallbackPersonBackendEditor::addNew( Person* item) +{ + Q_UNUSED(item) + return false; +} + +bool FallbackPersonBackendEditor::addExisting( Person* item) +{ + Q_UNUSED(item) + + m_lItems << item; + mediator()->addItem(item); + return true; +} + +QVector<Person*> FallbackPersonBackendEditor::items() const +{ + return m_lItems; +} + +QString FallbackPersonCollection::name () const +{ + return QObject::tr("vCard backend"); +} + +QString FallbackPersonCollection::category () const +{ + return QObject::tr("Contacts"); +} + +QVariant FallbackPersonCollection::icon() const +{ + return QVariant(); +} + +bool FallbackPersonCollection::isEnabled() const +{ + return true; +} + +bool FallbackPersonCollection::load() +{ + bool ok; + QList< Person* > ret = VCardUtils::loadDir(QUrl("/tmp/vcard"),ok); + for(Person* p : ret) { + editor<Person>()->addExisting(p); + } + return true; +} + +bool FallbackPersonCollection::reload() +{ + return false; +} + +CollectionInterface::SupportedFeatures FallbackPersonCollection::supportedFeatures() const +{ + return (CollectionInterface::SupportedFeatures) ( + CollectionInterface::SupportedFeatures::NONE | + CollectionInterface::SupportedFeatures::LOAD | + CollectionInterface::SupportedFeatures::CLEAR | +// CollectionInterface::SupportedFeatures::REMOVE| + CollectionInterface::SupportedFeatures::ADD ); +} + +bool FallbackPersonCollection::clear() +{ + QDir dir("/tmp/vcard"); + for (const QString& file : dir.entryList({"*.vcf"},QDir::Files)) + dir.remove(file); + return true; +} + +QByteArray FallbackPersonCollection::id() const +{ + return "fpc2"; +} diff --git a/src/fallbackpersoncollection.h b/src/fallbackpersoncollection.h new file mode 100644 index 0000000000000000000000000000000000000000..047370efb8a71dab09d8e36046bbf2c2dab93af1 --- /dev/null +++ b/src/fallbackpersoncollection.h @@ -0,0 +1,61 @@ +/************************************************************************************ + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***********************************************************************************/ +#ifndef FALLBACKPERSONCOLLECTION_H +#define FALLBACKPERSONCOLLECTION_H + +#include <collectioninterface.h> +#include <typedefs.h> + +class Call; +class Person; +class FallbackPersonCollectionPrivate; + +template<typename T> class CollectionMediator; + +/** + * This class is used when no other Person collections are available. It will + * provide a basic collection to add and use Persons/Contacts. It is also + * necessary as some metadata required for elements such as auto completion are + * provided by the Person collections. + */ +class LIB_EXPORT FallbackPersonCollection : public CollectionInterface +{ +public: + explicit FallbackPersonCollection(CollectionMediator<Person>* mediator); + virtual ~FallbackPersonCollection(); + + virtual bool load () override; + virtual bool reload() override; + virtual bool clear () override; + + virtual QString name () const override; + virtual QString category () const override; + virtual QVariant icon () const override; + virtual bool isEnabled() const override; + virtual QByteArray id () const override; + + virtual SupportedFeatures supportedFeatures() const override; + +private: + FallbackPersonCollectionPrivate* d_ptr; + Q_DECLARE_PRIVATE(FallbackPersonCollection) +}; +Q_DECLARE_METATYPE(FallbackPersonCollection*) + +#endif diff --git a/src/personmodel.cpp b/src/personmodel.cpp index ccac3685849e411a88febc9193e5482268f7cf91..009ba075cc1302e02c6a90e026446768c9baa219 100644 --- a/src/personmodel.cpp +++ b/src/personmodel.cpp @@ -70,6 +70,7 @@ m_pBackendModel(nullptr) PersonModel::PersonModel(QObject* par) : QAbstractItemModel(par?par:QCoreApplication::instance()), CollectionManagerInterface<Person>(this), d_ptr(new PersonModelPrivate(this)) { + setObjectName("PersonModel"); } ///Destructor @@ -280,9 +281,12 @@ void PersonModel::backendAddedCallback(CollectionInterface* backend) bool PersonModel::addItemCallback(Person* c) { - beginInsertRows(QModelIndex(),d_ptr->m_lPersons.size()-1,d_ptr->m_lPersons.size()); + //Add to the model + beginInsertRows(QModelIndex(),d_ptr->m_lPersons.size(),d_ptr->m_lPersons.size()); d_ptr->m_lPersons << c; d_ptr->m_hPersonsByUid[c->uid()] = c; + endInsertRows(); + emit newPersonAdded(c); //Deprecate the placeholder if (d_ptr->m_hPlaceholders.contains(c->uid())) { @@ -292,9 +296,6 @@ bool PersonModel::addItemCallback(Person* c) d_ptr->m_hPlaceholders[c->uid()] = nullptr; } } - endInsertRows(); - emit layoutChanged(); - emit newPersonAdded(c); return true; } @@ -345,8 +346,10 @@ const PersonList PersonModel::contacts() const bool PersonModel::addNewPerson(Person* c, CollectionInterface* backend) { - Q_UNUSED(backend); - return backends()[0]->editor<Person>()->addNew(c); + if ((!backend) || (!backends().size())) + return false; + + return (backend?backend:backends()[0])->editor<Person>()->addNew(c); } diff --git a/src/profilemodel.cpp b/src/profilemodel.cpp index 6f39ea56a5a5e84077c0d3eef5222034e6449095..40f68ccbd62b59e6cbfc97faa5a605fef4cc04de 100644 --- a/src/profilemodel.cpp +++ b/src/profilemodel.cpp @@ -20,6 +20,7 @@ //Qt #include <QtCore/QTimer> #include <QtCore/QObject> +#include <QtCore/QUrl> #include <QMimeData> #include <QtCore/QCoreApplication> #include <QtCore/QPointer> @@ -44,94 +45,6 @@ class Person; class Account; struct Node; -typedef void (VCardMapper:: *mapToProperty)(Person*, const QByteArray&); - -struct VCardMapper { - - QHash<QByteArray, mapToProperty> m_hHash; - - VCardMapper() { - m_hHash[VCardUtils::Property::UID] = &VCardMapper::setUid; - m_hHash[VCardUtils::Property::NAME] = &VCardMapper::setNames; - m_hHash[VCardUtils::Property::FORMATTED_NAME] = &VCardMapper::setFormattedName; - m_hHash[VCardUtils::Property::EMAIL] = &VCardMapper::setEmail; - m_hHash[VCardUtils::Property::ORGANIZATION] = &VCardMapper::setOrganization; - } - - void setFormattedName(Person* c, const QByteArray& fn) { - c->setFormattedName(QString::fromUtf8(fn)); - } - - void setNames(Person* c, const QByteArray& fn) { - QList<QByteArray> splitted = fn.split(';'); - c->setFamilyName(splitted[0].trimmed()); - c->setFirstName(splitted[1].trimmed()); - } - - void setUid(Person* c, const QByteArray& fn) { - c->setUid(fn); - } - - void setEmail(Person* c, const QByteArray& fn) { - c->setPreferredEmail(fn); - } - - void setOrganization(Person* c, const QByteArray& fn) { - c->setOrganization(QString::fromUtf8(fn)); - } - - void setPhoto(Person* c, const QByteArray& fn) { - qDebug() << fn; - QVariant photo = PixmapManipulationDelegate::instance()->profilePhoto(fn); - c->setPhoto(photo); - } - - void addContactMethod(Person* c, const QString& key, const QByteArray& fn) { - Q_UNUSED(c) - Q_UNUSED(key) - qDebug() << fn; - } - - void addAddress(Person* c, const QString& key, const QByteArray& fn) { - Person::Address* addr = new Person::Address(); - QList<QByteArray> fields = fn.split(VCardUtils::Delimiter::SEPARATOR_TOKEN[0]); - - addr->setType (key.split(VCardUtils::Delimiter::SEPARATOR_TOKEN)[1] ); - addr->setAddressLine (QString::fromUtf8(fields[2]) ); - addr->setCity (QString::fromUtf8(fields[3]) ); - addr->setState (QString::fromUtf8(fields[4]) ); - addr->setZipCode (QString::fromUtf8(fields[5]) ); - addr->setCountry (QString::fromUtf8(fields[6]) ); - - c->addAddress(addr); - } - - bool metacall(Person* c, const QByteArray& key, const QByteArray& value) { - if (!m_hHash[key]) { - if(key.contains(VCardUtils::Property::PHOTO)) { - //key must contain additionnal attributes, we don't need them right now (ENCODING, TYPE...) - setPhoto(c, value); - return true; - } - - if(key.contains(VCardUtils::Property::ADDRESS)) { - addAddress(c, key, value); - return true; - } - - if(key.contains(VCardUtils::Property::TELEPHONE)) { - addContactMethod(c, key, value); - return true; - } - - return false; - } - (this->*(m_hHash[key]))(c,value); - return true; - } -}; -static VCardMapper* vc_mapper = new VCardMapper; - class ProfileEditor : public CollectionEditor<Person> { public: @@ -142,6 +55,7 @@ public: virtual bool remove ( Person* item ) override; virtual bool edit ( Person* item ) override; virtual bool addNew ( Person* item ) override; + virtual bool addExisting( Person* item ) override; Node* getProfileById(const QByteArray& id); QList<Account*> getAccountsForProfile(const QString& id); @@ -259,6 +173,13 @@ bool ProfileEditor::addNew( Person* contact) return true; } +bool ProfileEditor::addExisting( Person* contact) +{ + m_lProfilePersons << contact; + mediator()->addItem(contact); + return true; +} + QVector<Person*> ProfileEditor::items() const { return m_lProfilePersons; @@ -373,7 +294,7 @@ void ProfileContentBackend::setupDefaultProfile() if (orphans.size() && (!m_pDefault)) { qDebug() << "No profile found, creating one"; Person* profile = new Person(this); - PersonModel::instance()->addPerson(profile); + m_pEditor->addNew(profile); profile->setFormattedName(tr("Default")); m_pDefault = new Node ; @@ -417,18 +338,9 @@ void ProfileContentBackend::loadProfiles() qDebug() << "Loading vcf from:" << profilesDir; - QStringList extensions = QStringList(); - extensions << "*.vcf"; - - QStringList entries = profilesDir.entryList(extensions, QDir::Files); + QStringList entries = profilesDir.entryList({"*.vcf"}, QDir::Files); foreach (const QString& item , entries) { - qDebug() << "Loading profile: " << item; - QFile file(profilesDir.absolutePath()+"/"+item); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "Error opening vcard: " << item; - continue; - } Person* profile = new Person(this); @@ -437,33 +349,10 @@ void ProfileContentBackend::loadProfiles() pro->contact = profile ; pro->m_Index = m_pEditor->m_lProfiles.size() ; - const QByteArray all = file.readAll(); - - bool propertyInserted = false; - - for (const QByteArray& property : all.split('\n')){ - qDebug() << "property: " << property; - const QList<QByteArray> splitted = property.split(':'); - if(splitted.size() < 2){ - qDebug() << "Property malformed!"; - continue; - } - propertyInserted = vc_mapper->metacall(profile,splitted[0],splitted[1].trimmed()); - if(!propertyInserted) - qDebug() << "Could not extract: " << splitted[0]; - - //Link with accounts - if(splitted[0] == VCardUtils::Property::X_RINGACCOUNT) { - Account* acc = AccountModel::instance()->getById(splitted[1].trimmed(),true); - if(!acc) { - qDebug() << "Could not find account: " << splitted[1].trimmed(); - continue; - } - - addAccount(pro,acc); - - } - } + Account* acc = nullptr; + VCardUtils::mapToPerson(profile,QUrl(item),&acc); + if (acc) + addAccount(pro,acc); ProfileModel::instance()->beginInsertRows(QModelIndex(), m_pEditor->m_lProfiles.size(), m_pEditor->m_lProfiles.size()); m_pEditor->m_lProfiles << pro; diff --git a/src/transitionalpersonbackend.cpp b/src/transitionalpersonbackend.cpp index 7f540eb215628d3ff9ae1077b6eb27243c412630..95b933e530220407352b23f7b80989957f66aca3 100644 --- a/src/transitionalpersonbackend.cpp +++ b/src/transitionalpersonbackend.cpp @@ -34,6 +34,7 @@ public: virtual bool remove ( Person* item ) override; virtual bool edit ( Person* item ) override; virtual bool addNew ( Person* item ) override; + virtual bool addExisting( Person* item ) override; private: virtual QVector<Person*> items() const override; @@ -69,6 +70,13 @@ bool TransitionalPersonEditor::addNew( Person* item) return false; } +bool TransitionalPersonEditor::addExisting( Person* item) +{ + Q_UNUSED(item) + return false; +} + + QVector<Person*> TransitionalPersonEditor::items() const { return QVector<Person*>(); diff --git a/src/vcardutils.cpp b/src/vcardutils.cpp index 520d66a43d20a4379253da56ae91250ab9eec100..7e057e1c70198f2ca56df1d52feec34870331894 100644 --- a/src/vcardutils.cpp +++ b/src/vcardutils.cpp @@ -17,7 +17,23 @@ ***************************************************************************/ #include "vcardutils.h" -#include <QBuffer> + +//Qt +#include <QtCore/QBuffer> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QUrl> + +//Ring +#include "phonedirectorymodel.h" +#include "contactmethod.h" +#include "accountmodel.h" +#include "delegates/pixmapmanipulationdelegate.h" + +/* https://www.ietf.org/rfc/rfc2045.txt + * https://www.ietf.org/rfc/rfc2047.txt + * https://www.ietf.org/rfc/rfc2426.txt + */ //BEGIN:VCARD //VERSION:3.0 @@ -36,6 +52,118 @@ //REV:20080424T195243Z //END:VCARD +struct VCardMapper; + +typedef void (VCardMapper:: *mapToProperty)(Person*, const QByteArray&); + +struct VCardMapper { + + QHash<QByteArray, mapToProperty> m_hHash; + + VCardMapper() { + m_hHash[VCardUtils::Property::UID] = &VCardMapper::setUid; + m_hHash[VCardUtils::Property::NAME] = &VCardMapper::setNames; + m_hHash[VCardUtils::Property::FORMATTED_NAME] = &VCardMapper::setFormattedName; + m_hHash[VCardUtils::Property::EMAIL] = &VCardMapper::setEmail; + m_hHash[VCardUtils::Property::ORGANIZATION] = &VCardMapper::setOrganization; + } + + void setFormattedName(Person* c, const QByteArray& fn) { + c->setFormattedName(QString::fromUtf8(fn)); + } + + void setNames(Person* c, const QByteArray& fn) { + QList<QByteArray> splitted = fn.split(';'); + c->setFamilyName(splitted[0].trimmed()); + c->setFirstName(splitted[1].trimmed()); + } + + void setUid(Person* c, const QByteArray& fn) { + c->setUid(fn); + } + + void setEmail(Person* c, const QByteArray& fn) { + c->setPreferredEmail(fn); + } + + void setOrganization(Person* c, const QByteArray& fn) { + c->setOrganization(QString::fromUtf8(fn)); + } + + void setPhoto(Person* c, const QByteArray& fn, const QByteArray& key) { + QByteArray type = "PNG"; + + QRegExp rx("TYPE=([A-Za-z]*)"); + + while ((rx.indexIn(key, 0)) != -1) { + type = rx.cap(1).toLatin1(); + break; + } + + QVariant photo = PixmapManipulationDelegate::instance()->profilePhoto(fn,type); + c->setPhoto(photo); + } + + void addContactMethod(Person* c, const QString& key, const QByteArray& fn) { + Q_UNUSED(c) + Q_UNUSED(key) + QByteArray type; + + QRegExp rx("TYPE=([A-Za-z,]*)"); + + while ((rx.indexIn(key, 0)) != -1) { + type = rx.cap(1).toLatin1(); + break; + } + + 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); + } + + void addAddress(Person* c, const QString& key, const QByteArray& fn) { + Person::Address* addr = new Person::Address(); + QList<QByteArray> fields = fn.split(VCardUtils::Delimiter::SEPARATOR_TOKEN[0]); + + addr->setType (key.split(VCardUtils::Delimiter::SEPARATOR_TOKEN)[1] ); + addr->setAddressLine (QString::fromUtf8(fields[2]) ); + addr->setCity (QString::fromUtf8(fields[3]) ); + addr->setState (QString::fromUtf8(fields[4]) ); + addr->setZipCode (QString::fromUtf8(fields[5]) ); + addr->setCountry (QString::fromUtf8(fields[6]) ); + + c->addAddress(addr); + } + + bool metacall(Person* c, const QByteArray& key, const QByteArray& value) { + if (!m_hHash[key]) { + if(key.contains(VCardUtils::Property::PHOTO)) { + //key must contain additionnal attributes, we don't need them right now (ENCODING, TYPE...) + setPhoto(c, value, key); + return true; + } + + if(key.contains(VCardUtils::Property::ADDRESS)) { + addAddress(c, key, value); + return true; + } + + if(key.contains(VCardUtils::Property::TELEPHONE)) { + addContactMethod(c, key, value); + return true; + } + + return false; + } + (this->*(m_hHash[key]))(c,value); + return true; + } +}; +static VCardMapper* vc_mapper = new VCardMapper; + VCardUtils::VCardUtils() { @@ -115,3 +243,82 @@ const QByteArray VCardUtils::endVCard() const QString result = m_vCard.join(QString::fromUtf8(Delimiter::END_LINE_TOKEN)); return result.toUtf8(); } + +QList< Person* > VCardUtils::loadDir (const QUrl& path, bool& ok) +{ + QList< Person* > ret; + + QDir dir(path.toString()); + if (!dir.exists()) + ok = false; + else { + ok = true; + for (const QString& file : dir.entryList({"*.vcf"},QDir::Files)) { + Person* p = new Person(); + mapToPerson(p,QUrl(dir.absoluteFilePath(file))); + ret << p; + } + } + + return ret; +} + +bool VCardUtils::mapToPerson(Person* p, const QUrl& path, Account** a) +{ + + qDebug() << "file" << path.toString(); + + QFile file(path.toString()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << "Error opening vcard: " << path; + return false; + } + + const QByteArray all = file.readAll(); + +// bool propertyInserted = false; + QByteArray previousKey,previousValue; + for (const QByteArray& property : all.split('\n')) { + + //Ignore empty lines + if (property.size()) { + + //Some properties are over multiple lines + if (property[0] == ' ' && previousKey.size()) { + 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; + } + + const QList<QByteArray> splitted = property.split(':'); + if(splitted.size() < 2){ + qDebug() << "Malformed vCard property!" << splitted[0] << property[0] << (property[0] == ' '); + continue; + } + + + //Link with accounts + if(splitted[0] == VCardUtils::Property::X_RINGACCOUNT) { + if (a) { + *a = AccountModel::instance()->getById(splitted[1].trimmed(),true); + if(!*a) { + qDebug() << "Could not find account: " << splitted[1].trimmed(); + continue; + } + } + } + + previousKey = splitted[0]; + previousValue = splitted[1]; + } + + } + + } + return true; +} diff --git a/src/vcardutils.h b/src/vcardutils.h index e6a11905484da943e4d56ef03f694a628d518876..ff64f662821dc741f1fdef6d7717e179e7ddd17c 100644 --- a/src/vcardutils.h +++ b/src/vcardutils.h @@ -78,6 +78,12 @@ public: void addPhoto(const QByteArray img); const QByteArray endVCard(); + //Loading + static QList<Person*> loadDir(const QUrl& path, bool& ok); + + //Mapping + static bool mapToPerson(Person* p, const QUrl& url, Account** a = nullptr); + private: //Attributes