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