diff --git a/src/kpeoplevcard.cpp b/src/kpeoplevcard.cpp index 071a2db..8aea25b 100644 --- a/src/kpeoplevcard.cpp +++ b/src/kpeoplevcard.cpp @@ -1,209 +1,245 @@ /* Copyright (C) 2015 Aleix Pol Gonzalez Copyright (C) 2015 Martin Klapetek 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 "kpeoplevcard.h" #include #include #include #include #include #include #include +#include #include #include #include +#include using namespace KPeople; Q_GLOBAL_STATIC_WITH_ARGS(QString, vcardsLocation, (QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + ("/kpeoplevcard"))) +Q_GLOBAL_STATIC_WITH_ARGS(QString, vcardsWriteLocation, (QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + ("/kpeoplevcard/own/"))) -class VCardContact : public AbstractContact +class VCardContact : public AbstractEditableContact { public: VCardContact() {} - VCardContact(const KContacts::Addressee& addr) : m_addressee(addr) {} + VCardContact(const KContacts::Addressee& addr, const QUrl &location) : m_addressee(addr), m_location(location) {} void setAddressee(const KContacts::Addressee& addr) { m_addressee = addr; } + void setUrl(const QUrl &url) { m_location = url; } QVariant customProperty(const QString & key) const override { QVariant ret; if (key == NameProperty) { const QString name = m_addressee.realName(); if (!name.isEmpty()) { return name; } // If both first and last name are set combine them to a full name if (!m_addressee.givenName().isEmpty() && !m_addressee.familyName().isEmpty()) return i18nc("given-name family-name", "%1 %2", m_addressee.givenName(), m_addressee.familyName()); // If only one of them is set just return what we know if (!m_addressee.givenName().isEmpty()) return m_addressee.givenName(); if (!m_addressee.familyName().isEmpty()) return m_addressee.familyName(); // Fall back to other identifiers if (!m_addressee.preferredEmail().isEmpty()) { return m_addressee.preferredEmail(); } if (!m_addressee.phoneNumbers().isEmpty()) { return m_addressee.phoneNumbers().at(0).number(); } return QVariant(); } else if (key == EmailProperty) return m_addressee.preferredEmail(); else if (key == AllEmailsProperty) return m_addressee.emails(); else if (key == PictureProperty) return m_addressee.photo().data(); else if (key == AllPhoneNumbersProperty) { const auto phoneNumbers = m_addressee.phoneNumbers(); QVariantList numbers; for (const KContacts::PhoneNumber &phoneNumber : phoneNumbers) { // convert from KContacts specific format to QString numbers << phoneNumber.number(); } return numbers; } else if (key == PhoneNumberProperty) { return m_addressee.phoneNumbers().isEmpty() ? QVariant() : m_addressee.phoneNumbers().at(0).number(); + } else if (key == VCardProperty) { + KContacts::VCardConverter converter; + return converter.createVCard(m_addressee); } return ret; } + bool setCustomProperty(const QString & key, const QVariant & value) override { + if (key == VCardProperty) { + QFile f(m_location.toLocalFile()); + if (!f.open(QIODevice::WriteOnly)) + return false; + f.write(value.toByteArray()); + return true; + } + return false; + } + static QString createUri(const QString& path) { return QStringLiteral("vcard:/") + path; } private: KContacts::Addressee m_addressee; + QUrl m_location; }; -class VCardDataSource : public KPeople::BasePersonsDataSource +class VCardDataSource : public KPeople::BasePersonsDataSourceV2 { public: VCardDataSource(QObject *parent, const QVariantList &data); ~VCardDataSource() override; QString sourcePluginId() const override; KPeople::AllContactsMonitor* createAllContactsMonitor() override; + bool addContact(const QVariantMap & properties) override { + if (!properties.contains("vcard")) + return false; + + if (!QDir().mkpath(*vcardsWriteLocation)) + return false; + + QFile f(*vcardsWriteLocation + KFileUtils::suggestName(QUrl::fromLocalFile(*vcardsWriteLocation), QStringLiteral("contact.vcard"))); + if (!f.open(QFile::WriteOnly)) { + qWarning() << "could not open file to write" << f.fileName(); + return false; + } + + f.write(properties.value("vcard").toByteArray()); + return true; + } }; KPeopleVCard::KPeopleVCard() : KPeople::AllContactsMonitor() , m_fs(new KDirWatch(this)) { QDir().mkpath(*vcardsLocation); QDir dir(*vcardsLocation); const QStringList subdirs = dir.entryList(QDir::AllDirs | QDir::NoDotDot); // includes '.', ie. vcards from no subdir QStringList entries; for (const QString &subdirName : subdirs) { QDir subdir(dir.absoluteFilePath(subdirName)); const QFileInfoList subdirVcards = subdir.entryInfoList({"*.vcard", "*.vcf"}); for (const QFileInfo &vcardFile : subdirVcards) { entries << vcardFile.absoluteFilePath(); } } for (const QString& entry : qAsConst(entries)) { processVCard(entry); } m_fs->addDir(dir.absolutePath(), KDirWatch::WatchDirOnly | KDirWatch::WatchSubDirs); connect(m_fs, &KDirWatch::dirty, this, [this](const QString& path){ if (QFileInfo(path).isFile()) processVCard(path); }); connect(m_fs, &KDirWatch::created, this, &KPeopleVCard::processVCard); connect(m_fs, &KDirWatch::deleted, this, &KPeopleVCard::deleteVCard); } KPeopleVCard::~KPeopleVCard() {} QMap KPeopleVCard::contacts() { return m_contactForUri; } void KPeopleVCard::processVCard(const QString &path) { m_fs->addFile(path); QFile f(path); bool b = f.open(QIODevice::ReadOnly); if (!b) { qWarning() << "error: couldn't open:" << path; return; } KContacts::VCardConverter conv; const KContacts::Addressee addressee = conv.parseVCard(f.readAll()); QString uri = VCardContact::createUri(path); auto it = m_contactForUri.find(uri); if (it != m_contactForUri.end()) { static_cast(it->data())->setAddressee(addressee); + static_cast(it->data())->setUrl(QUrl::fromLocalFile(path)); Q_EMIT contactChanged(uri, *it); } else { - KPeople::AbstractContact::Ptr contact(new VCardContact(addressee)); + KPeople::AbstractContact::Ptr contact(new VCardContact(addressee, QUrl::fromLocalFile(path))); m_contactForUri.insert(uri, contact); Q_EMIT contactAdded(uri, contact); } } void KPeopleVCard::deleteVCard(const QString &path) { if (QFile::exists(path)) return; QString uri = VCardContact::createUri(path); int r = m_contactForUri.remove(uri); Q_ASSERT(r); Q_EMIT contactRemoved(uri); } QString KPeopleVCard::contactsVCardPath() { return *vcardsLocation; } VCardDataSource::VCardDataSource(QObject *parent, const QVariantList &args) -: BasePersonsDataSource(parent) + : BasePersonsDataSourceV2(parent) { Q_UNUSED(args); } VCardDataSource::~VCardDataSource() { } QString VCardDataSource::sourcePluginId() const { return QStringLiteral("vcard"); } AllContactsMonitor* VCardDataSource::createAllContactsMonitor() { return new KPeopleVCard(); } K_PLUGIN_FACTORY_WITH_JSON( VCardDataSourceFactory, "kpeoplevcard.json", registerPlugin(); ) K_EXPORT_PLUGIN( VCardDataSourceFactory("kpeoplevcard") ) #include "kpeoplevcard.moc"