diff --git a/plugins/contacts/contactsplugin.cpp b/plugins/contacts/contactsplugin.cpp index 0f0ee7a5..1137c6a9 100644 --- a/plugins/contacts/contactsplugin.cpp +++ b/plugins/contacts/contactsplugin.cpp @@ -1,226 +1,228 @@ /** * Copyright 2018 Simon Redman * * 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 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_contacts.json", registerPlugin< ContactsPlugin >(); ) Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_CONTACTS, "kdeconnect.plugin.contacts") ContactsPlugin::ContactsPlugin(QObject* parent, const QVariantList& args) : KdeConnectPlugin(parent, args) { vcardsPath = QString(*vcardsLocation).append("/kdeconnect-").append(device()->id()); // Create the storage directory if it doesn't exist if (! QDir().mkpath(vcardsPath)) { qCWarning(KDECONNECT_PLUGIN_CONTACTS) << "handleResponseVCards:" << "Unable to create VCard directory"; } + this->synchronizeRemoteWithLocal(); + qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "Contacts constructor for device " << device()->name(); } ContactsPlugin::~ContactsPlugin() { QDBusConnection::sessionBus().unregisterObject(dbusPath(), QDBusConnection::UnregisterTree); // qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "Contacts plugin destructor for device" << device()->name(); } bool ContactsPlugin::receivePacket(const NetworkPacket& np) { qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "Packet Received for device " << device()->name(); qCDebug(KDECONNECT_PLUGIN_CONTACTS) << np.body(); if (np.type() == PACKAGE_TYPE_CONTACTS_RESPONSE_UIDS_TIMESTAMPS) { return this->handleResponseUIDsTimestamps(np); } else if (np.type() == PACKET_TYPE_CONTACTS_RESPONSE_VCARDS) { return this->handleResponseVCards(np); } else { // Is this check necessary? qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "Unknown package type received from device: " << device()->name() << ". Maybe you need to upgrade KDE Connect?"; return false; } } void ContactsPlugin::synchronizeRemoteWithLocal() { this->sendRequest(PACKET_TYPE_CONTACTS_REQUEST_ALL_UIDS_TIMESTAMP); } bool ContactsPlugin::handleResponseUIDsTimestamps(const NetworkPacket& np) { if (!np.has("uids")) { qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "handleResponseUIDsTimestamps:" << "Malformed packet does not have uids key"; return false; } uIDList_t uIDsToUpdate; QDir vcardsDir(vcardsPath); // Get a list of all file info in this directory // Clean out IDs returned from the remote. Anything leftover should be deleted QFileInfoList localVCards = vcardsDir.entryInfoList({"*.vcard", "*.vcf"}); QStringList uIDs = np.get("uids"); // Check local storage for the contacts: // If the contact is not found in local storage, request its vcard be sent // If the contact is in local storage but not reported, delete it // If the contact is in local storage, compare its timestamp. If different, request the contact for (QString ID : uIDs) { QString filename = vcardsDir.filePath(ID + VCARD_EXTENSION); QFile vcardFile(filename); if (!QFile().exists(filename)) { // We do not have a vcard for this contact. Request it. uIDsToUpdate.push_back(ID.toLongLong()); continue; } // Remove this file from the list of known files QFileInfo fileInfo(vcardFile); bool success = localVCards.removeOne(fileInfo); // TODO: Test // Check if the vcard needs to be updated if (!vcardFile.open(QIODevice::ReadOnly)) { qCWarning(KDECONNECT_PLUGIN_CONTACTS) << "handleResponseUIDsTimestamps:" << "Unable to open" << filename << "to read even though it was reported to exist"; continue; } QTextStream fileReadStream(&vcardFile); QString line; while (!fileReadStream.atEnd()) { fileReadStream >> line; // TODO: Check that the saved ID is the same as the one we were expecting if (!line.startsWith("X-KDECONNECT-TIMESTAMP:")) { continue; } QStringList parts = line.split(":"); QString timestamp = parts[1]; qint32 remoteTimestamp = np.get(ID); qint32 localTimestamp = timestamp.toInt(); if (!(localTimestamp == remoteTimestamp)) { uIDsToUpdate.push_back(ID.toLongLong()); } } } // Delete all locally-known files which were not reported by the remote device for (QFileInfo unknownFile : localVCards) { QFile toDelete(unknownFile.filePath()); toDelete.remove(); } this->sendRequestWithIDs(PACKET_TYPE_CONTACTS_REQUEST_VCARDS_BY_UIDS, uIDsToUpdate); return true; } bool ContactsPlugin::handleResponseVCards(const NetworkPacket& np) { if (!np.has("uids")) { qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "handleResponseVCards:" << "Malformed packet does not have uids key"; return false; } QDir vcardsDir(vcardsPath); QStringList uIDs = np.get("uids"); // Loop over all IDs, extract the VCard from the packet and write the file for (auto ID : uIDs) { qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "Got VCard:" << np.get(ID); QString filename = vcardsDir.filePath(ID + VCARD_EXTENSION); QFile vcardFile(filename); bool vcardFileOpened = vcardFile.open(QIODevice::WriteOnly); // Want to smash anything that might have already been there if (!vcardFileOpened) { qCWarning(KDECONNECT_PLUGIN_CONTACTS) << "handleResponseVCards:" << "Unable to open" << filename; continue; } QTextStream fileWriteStream(&vcardFile); fileWriteStream << np.get(ID); } qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "handleResponseVCards:" << "Got" << uIDs.size() << "VCards"; return true; } bool ContactsPlugin::sendRequest(QString packageType) { NetworkPacket np(packageType); bool success = sendPacket(np); qCDebug(KDECONNECT_PLUGIN_CONTACTS) << "sendRequest: Sending " << packageType << success; return success; } bool ContactsPlugin::sendRequestWithIDs(QString packageType, uIDList_t uIDs) { NetworkPacket np(packageType); // Convert IDs to strings QStringList uIDsAsStrings; for (auto uID : uIDs) { uIDsAsStrings.append(QString::number(uID)); } np.set("uids", uIDsAsStrings); bool success = sendPacket(np); return success; } QString ContactsPlugin::dbusPath() const { return "/modules/kdeconnect/devices/" + device()->id() + "/contacts"; } #include "contactsplugin.moc"