Skip to content
Snippets Groups Projects
Select Git revision
  • 5e9090175fa2e6e96fa208cea8c50b4549e1b7e5
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/201911
  • release/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • release/201811
  • release/201808
  • releases/beta1
  • packaging
  • native
  • release-0.2.x
  • 1.0.0
  • 0.2.0
  • 0.1.1
  • 0.1.0
25 results

newwizardwidget.h

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    windowscontactbackend.cpp 13.91 KiB
    /***************************************************************************
     * Copyright (C) 2015-2016 by Savoir-faire Linux                                *
     * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
     *                                                                         *
     * This program 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; either version 3 of the License, or       *
     * (at your option) any later version.                                     *
     *                                                                         *
     * This program 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 "windowscontactbackend.h"
    
    #include <QtXml>
    #include <QPainter>
    
    #include "personmodel.h"
    #include "categorizedcontactmodel.h"
    
    #include "utils.h"
    
    WindowsContactEditor::WindowsContactEditor(CollectionMediator<Person> *m
                                               , WindowsContactBackend *parent)
        : CollectionEditor<Person>(m),collection_(parent)
    {
    
    }
    
    WindowsContactEditor::~WindowsContactEditor()
    {
    
    }
    
    bool
    WindowsContactEditor::save(const Person *item)
    {
        QFile file(QStandardPaths::writableLocation
                   (QStandardPaths::HomeLocation) + "/Contacts/"
                   + item->formattedName() + ".contact");
        if (!file.open(QIODevice::ReadWrite)) {
            file.close();
            qDebug() << "Cannot open contact file";
            return false;
        }
    
        QDomDocument doc;
        doc.setContent(&file);
    
        auto root = doc.elementsByTagName("c:contact").at(0);
        auto nodes = doc.elementsByTagName("c:PhoneNumberCollection");
    
        //if PhoneNumberCollection already exists
        QVector<QString> nodeNumberVector;
        if (nodes.length()) {
            auto phoneNumberCollection = nodes.at(0);
            auto phoneNumbers = doc.elementsByTagName("c:Number");
            auto virtualPhoneNumber = item->phoneNumbers();
            for (int i = 0; i < phoneNumbers.length(); i++) {
                auto node = phoneNumbers.at(i).toElement();
                nodeNumberVector.append(node.text());
            }
            for (auto elem : virtualPhoneNumber) {
                if (not nodeNumberVector.contains(elem->uri())) {
                    auto phoneNumber = doc.createElement("c:PhoneNumber");
                    phoneNumberCollection.appendChild(phoneNumber);
                    phoneNumber.setAttribute("c:ElementID", Utils::GenGUID());
                    auto numberNode = doc.createElement("c:Number");
                    phoneNumber.appendChild(numberNode);
                    auto numberValue = doc.createTextNode(elem->uri());
                    numberNode.appendChild(numberValue);
                }
            }
        } else {
            auto phoneNumberCollection = doc.createElement("c:PhoneNumberCollection");
            root.appendChild(phoneNumberCollection);
            auto phoneNumber = doc.createElement("c:PhoneNumber");
            phoneNumberCollection.appendChild(phoneNumber);
            phoneNumber.setAttribute("c:ElementID", Utils::GenGUID());
            auto numberNode = doc.createElement("c:Number");
            phoneNumber.appendChild(numberNode);
            auto numberValue = doc.createTextNode(item->phoneNumbers().at(0)->uri());
            numberNode.appendChild(numberValue);
        }
        file.resize(0);
        file.write(doc.toByteArray());
        file.close();
        return true;
    }
    
    bool
    WindowsContactEditor::remove(const Person *item)
    {
        items_.removeOne(const_cast<Person*>(item));
        mediator()->removeItem(item);
        return true;
    }
    
    bool
    WindowsContactEditor::edit(Person *item)
    {
        Q_UNUSED(item)
        return false;
    }
    
    bool
    WindowsContactEditor::addNew(Person *item)
    {
        QDomDocument doc;
        QFile file(QStandardPaths::writableLocation
                   (QStandardPaths::HomeLocation) + "/Contacts/"
                   + item->formattedName()+".contact");
        if (file.exists())
            return false;
        if (!file.open(QIODevice::ReadWrite)) {
            file.close();
            qDebug() << "Cannot create contact file";
            return false;
        }
        doc.appendChild(
                    doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""));
    
        //Create root
        auto root = doc.createElement("c:contact");
        root.setAttribute("c:Version", "1");
        root.setAttribute("xmlns:c", "http://schemas.microsoft.com/Contact");
        root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
        root.setAttribute("xmlns:MSP2P","http://schemas.microsoft.com/Contact/Extended/MSP2P");
        doc.appendChild(root);
    
        auto date = Utils::GetISODate();
    
        //Create creation date
        auto creationDateNode = doc.createElement("c:CreationDate");
        auto creationDateValue = doc.createTextNode(date);
        creationDateNode.appendChild(creationDateValue);
        root.appendChild(creationDateNode);
    
        //Create extended node
        auto extendedNode = doc.createElement("c:Extended");
        extendedNode.setAttribute("xsi:nil", "true");
        root.appendChild(extendedNode);
    
        //Create contactID collection
        auto contactIDCol = doc.createElement("c:ContactIDCollection");
        root.appendChild(contactIDCol);
        auto contactID = doc.createElement("c:ContactID");
        contactID.setAttribute("c:ElementID", Utils::GenGUID());
        auto contactValue = doc.createElement("c:Value");
        auto value = doc.createTextNode(item->uid());
        contactValue.appendChild(value);
        contactID.appendChild(contactValue);
        contactIDCol.appendChild(contactID);
    
        //Create NameCollection
        auto nameCollection = doc.createElement("c:NameCollection");
        root.appendChild(nameCollection);
        auto name = doc.createElement("c:Name");
        nameCollection.appendChild(name);
        name.setAttribute("c:ElementID", Utils::GenGUID());
        auto formattedName = doc.createElement("c:FormattedName");
        name.appendChild(formattedName);
        auto formattedNameValue = doc.createTextNode(item->formattedName());
        formattedName.appendChild(formattedNameValue);
    
        //Create PhoneNumberCollection
        auto phoneNumberCollection = doc.createElement("c:PhoneNumberCollection");
        root.appendChild(phoneNumberCollection);
        auto phoneNumber = doc.createElement("c:PhoneNumber");
        phoneNumberCollection.appendChild(phoneNumber);
        phoneNumber.setAttribute("c:ElementID", Utils::GenGUID());
        auto numberNode = doc.createElement("c:Number");
        phoneNumber.appendChild(numberNode);
        auto numberValue = doc.createTextNode(item->phoneNumbers().at(0)->uri());
        numberNode.appendChild(numberValue);
    
        //Write to file
        file.write(doc.toByteArray());
        file.close();
    
        return true;
    }
    
    bool
    WindowsContactEditor::addExisting(const Person *item)
    {
        items_ << const_cast<Person*>(item);
        mediator()->addItem(item);
        return true;
    }
    
    QVector<Person*>
    WindowsContactEditor::items() const
    {
        return items_;
    }
    
    WindowsContactBackend::WindowsContactBackend(CollectionMediator<Person>* mediator,
                                                 CollectionInterface* parent)
        : CollectionInterface(new WindowsContactEditor(mediator,this), parent)
        , mediator_(mediator), watcher_(new QFileSystemWatcher())
    {
    
    }
    
    WindowsContactBackend::~WindowsContactBackend()
    {
        delete watcher_;
    }
    
    bool
    WindowsContactBackend::load()
    {
        QtConcurrent::run(this, &WindowsContactBackend::loadRun);
        watcher_->addPath(QStandardPaths::writableLocation
                          (QStandardPaths::HomeLocation) + "/Contacts");
    
        QObject::connect(watcher_, &QFileSystemWatcher::directoryChanged, [=](QString path) {
            Q_UNUSED(path)
            QtConcurrent::run(this, &WindowsContactBackend::loadRun);
        });
        return true;
    }
    
    bool
    WindowsContactBackend::loadRun()
    {
        QDir contactDir(QStandardPaths::writableLocation
                        (QStandardPaths::HomeLocation) + "/Contacts");
        QStringList filesList = contactDir.entryList(QStringList("*.contact"));
        auto ret = true;
        for(auto contactFileName : filesList) {
            if (not getPersonFromContactFile(contactDir, contactFileName))
                ret = false;
        }
        return ret;
    }
    
    bool
    WindowsContactBackend::getPersonFromContactFile(const QDir& contactDir,
                                                    const QString &contactFileName)
    {
        QString contactFilePath
                (contactDir.absolutePath() + "/" +  contactFileName);
        QFile contactFile(contactFilePath);
        if (contactFile.open(QIODevice::ReadOnly)) {
            QXmlStreamReader reader;
            Person *p = new Person(this);
            QVector<ContactMethod*> contactMethod;
            reader.setDevice(&contactFile);
            while (!reader.atEnd()) {
                reader.readNext();
                if (reader.isStartElement()) {
                    QString name = reader.name().toString();
                    if (name == "FormattedName")
                        p->setFormattedName(reader.readElementText());
                    else if (name == "NickName")
                        p->setNickName(reader.readElementText());
                    else if (name == "GivenName")
                        p->setFirstName(reader.readElementText());
                    else if (name == "FamilyName")
                        p->setFamilyName(reader.readElementText());
                    else if (name == "Company")
                        p->setOrganization(reader.readElementText());
                    else if (name == "Department")
                        p->setDepartment(reader.readElementText());
                    else if (name == "Number") {
                        QString number = reader.readElementText();
                        if (not number.isEmpty()) {
                            ContactMethod *contact =
                                    PhoneDirectoryModel::instance().getNumber(number,p);
                            contactMethod.append(contact);
                        }
                    } else if (name == "ContactID") {
                        while (reader.name().toString() != "Value")
                            reader.readNext();
                        p->setUid(reader.readElementText().toUtf8());
                    }
                    else if (name == "Photo") {
                        //FIXME: It seems to be possible to have multiple photo...
                        reader.readNext();
                        if (reader.name().toString() == "Url") {
                            QString photoValue = reader.readElementText();
                            QImage photo;
                            photo.load(photoValue);
                            if (not photo.isNull())
                                p->setPhoto(Utils::getCirclePhoto(photo, sizePhoto_));
                        }
                    }
                    else if (name == "EmailAddress") {
                        QString address;
                        bool isPreferred = false;
                        reader.readNext();
                        while (reader.name().toString() != "EmailAddress"
                               && !reader.atEnd()) {
                            if (reader.isStartElement()) {
                                QString tag = reader.name().toString();
                                if (tag == "Address")
                                    address = reader.readElementText();
                                else if (tag == "Label")
                                    if (reader.readElementText() == "Preferred")
                                        isPreferred = true;
                            }
                            reader.readNext();
                        }
                        if (isPreferred)
                            p->setPreferredEmail(address);
                    }
                }
            }
            if (reader.hasError()) {
                qDebug() << reader.errorString();
                contactFile.close();
                return false;
            } else {
                Person* existing = PersonModel::instance().getPersonByUid(p->uid());
                if (existing) {
                    if (contactMethod.size() > 0)
                        existing->setContactMethods ( contactMethod   );
                    existing->setNickName       ( p->nickName()       );
                    existing->setFirstName      ( p->firstName()      );
                    existing->setFamilyName     ( p->secondName()     );
                    existing->setFormattedName  ( p->formattedName()  );
                    existing->setOrganization   ( p->organization()   );
                    existing->setPreferredEmail ( p->preferredEmail() );
                    existing->setGroup          ( p->group()          );
                    existing->setDepartment     ( p->department()     );
                    existing->setPhoto          ( p->photo()          );
                    delete p;
                } else {
                    p->setContactMethods(contactMethod);
                    editor<Person>()->addExisting(p);
                }
                return true;
            }
        } else {
            qDebug() << "Error Opening contact file : " << contactFileName;
            return false;
        }
    }
    
    bool
    WindowsContactBackend::reload()
    {
        return false;
    }
    
    bool
    WindowsContactBackend::clear()
    {
        return false;
    }
    
    QString
    WindowsContactBackend::name() const
    {
        return "Windows Contact Backend";
    }
    
    QString
    WindowsContactBackend::category() const
    {
        return "Contacts";
    }
    
    bool
    WindowsContactBackend::isEnabled() const
    {
        return true;
    }
    
    QByteArray
    WindowsContactBackend::id() const
    {
        return "wincb";
    }
    
    FlagPack<CollectionInterface::SupportedFeatures> WindowsContactBackend::supportedFeatures() const
    {
        return (
                    CollectionInterface::SupportedFeatures::NONE |
                    CollectionInterface::SupportedFeatures::LOAD |
                    CollectionInterface::SupportedFeatures::SAVE |
                    CollectionInterface::SupportedFeatures::REMOVE |
                    CollectionInterface::SupportedFeatures::ADD);
    }