diff --git a/src/common.pri b/src/common.pri index 6cb92b8..63f2852 100644 --- a/src/common.pri +++ b/src/common.pri @@ -6,6 +6,7 @@ PKGCONFIG += \ accounts-qt5 \ buteosyncfw5 \ socialcache +LIBS += -lssu QT += \ network \ @@ -30,12 +31,14 @@ DEFINES += 'SOCIALD_SYNC_DATABASE_NAME=\'\"sociald.db\"\'' INCLUDEPATH += . $$PWD/common/ HEADERS += \ + $$PWD/common/backuprestoreoptions_p.h \ $$PWD/common/buteosyncfw_p.h \ $$PWD/common/socialdbuteoplugin.h \ $$PWD/common/socialnetworksyncadaptor.h \ $$PWD/common/trace.h SOURCES += \ + $$PWD/common/backuprestoreoptions.cpp \ $$PWD/common/socialdbuteoplugin.cpp \ $$PWD/common/socialnetworksyncadaptor.cpp diff --git a/src/common/backuprestoreoptions.cpp b/src/common/backuprestoreoptions.cpp new file mode 100644 index 0000000..69eacb8 --- /dev/null +++ b/src/common/backuprestoreoptions.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** + ** + ** Copyright (C) 2019 Open Mobile Platform LLC + ** + ** This program/library is free software; you can redistribute it and/or + ** modify it under the terms of the GNU Lesser General Public License + ** version 2.1 as published by the Free Software Foundation. + ** + ** This program/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 program/library; if not, write to the Free + ** Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + ** 02110-1301 USA + ** + ****************************************************************************/ + +#include "backuprestoreoptions_p.h" +#include "trace.h" + +#include + +// nemo +#include + +// buteo-syncfw +#include + +bool BackupRestoreOptions::copyToProfile(Buteo::SyncProfile *syncProfile) +{ + if (!syncProfile) { + qWarning() << "Invalid profile!"; + return false; + } + + Buteo::Profile *clientProfile = syncProfile->clientProfile(); + if (!clientProfile) { + qWarning() << "Cannot find client profile in sync profile:" << syncProfile->name(); + return false; + } + + QString operationValue; + switch (operation) { + case DirectoryListing: + operationValue = "dir-listing"; + break; + case Upload: + operationValue = "upload"; + break; + case Download: + operationValue = "download"; + break; + }; + + clientProfile->setKey("sfos-operation", operationValue); + clientProfile->setKey("sfos-dir-local", localDirPath); + clientProfile->setKey("sfos-dir-remote", remoteDirPath); + clientProfile->setKey("sfos-filename", fileName); + + return true; +} + +BackupRestoreOptions BackupRestoreOptions::fromProfile(Buteo::SyncProfile *syncProfile, bool *ok) +{ + if (!syncProfile) { + qWarning() << "Invalid sync profile!"; + return BackupRestoreOptions(); + } + + Buteo::Profile *clientProfile = syncProfile->clientProfile(); + if (!clientProfile) { + qWarning() << "Cannot find client profile in sync profile:" << syncProfile->name(); + return BackupRestoreOptions(); + } + + BackupRestoreOptions options; + QString operation = clientProfile->key("sfos-operation"); + options.localDirPath = clientProfile->key("sfos-dir-local"); + options.remoteDirPath = clientProfile->key("sfos-dir-remote"); + options.fileName = clientProfile->key("sfos-filename"); + + if (operation == "dir-listing") { + options.operation = BackupRestoreOptions::DirectoryListing; + } else if (operation == "upload") { + options.operation = BackupRestoreOptions::Upload; + } else if (operation == "download") { + options.operation = BackupRestoreOptions::Download; + } else { + qWarning() << "Backup/restore options for sync profile" << syncProfile->name() + << "has invalid operation type:" << operation; + return BackupRestoreOptions(); + } + + if (options.localDirPath.isEmpty()) { + qWarning() << "Backup/restore options for sync profile" << syncProfile->name() + << "do not specify a local directory!"; + return BackupRestoreOptions(); + } + + if (options.operation == BackupRestoreOptions::DirectoryListing && options.fileName.isEmpty()) { + qWarning() << "Backup/restore options for sync profile" << syncProfile->name() + << "do not specify a file name for directory listing!"; + return BackupRestoreOptions(); + } + + if (ok) { + *ok = true; + } + return options; +} + +QString BackupRestoreOptions::backupDeviceName() +{ + SsuDeviceInfo deviceInfo; + const QString deviceId = deviceInfo.deviceUid(); + const QByteArray hashedDeviceId = QCryptographicHash::hash(deviceId.toUtf8(), QCryptographicHash::Sha256); + const QString encodedDeviceId = QString::fromUtf8(hashedDeviceId.toBase64(QByteArray::Base64UrlEncoding)).mid(0,12); + if (deviceId.isEmpty()) { + qWarning() << "Could not determine device identifier for backup directory name!"; + return QString(); + } + + QString deviceDisplayNamePrefix = deviceInfo.displayName(Ssu::DeviceModel); + if (!deviceDisplayNamePrefix.isEmpty()) { + deviceDisplayNamePrefix = deviceDisplayNamePrefix.replace(' ', '-') + '_'; + } + + return deviceDisplayNamePrefix + encodedDeviceId; +} diff --git a/src/common/backuprestoreoptions_p.h b/src/common/backuprestoreoptions_p.h new file mode 100644 index 0000000..e46be4d --- /dev/null +++ b/src/common/backuprestoreoptions_p.h @@ -0,0 +1,52 @@ +/**************************************************************************** + ** + ** Copyright (C) 2019 Open Mobile Platform LLC + ** + ** This program/library is free software; you can redistribute it and/or + ** modify it under the terms of the GNU Lesser General Public License + ** version 2.1 as published by the Free Software Foundation. + ** + ** This program/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 program/library; if not, write to the Free + ** Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + ** 02110-1301 USA + ** + ****************************************************************************/ + +#ifndef BACKUPRESTOREOPTIONS_H +#define BACKUPRESTOREOPTIONS_H + +#include + +namespace Buteo { + class SyncProfile; +} + +// Basically a mirror of AccountSyncManager::BackupRestoreOptions. +class BackupRestoreOptions +{ +public: + enum Operation { + DirectoryListing, + Upload, + Download + }; + + Operation operation = DirectoryListing; + QString localDirPath; + QString remoteDirPath; + QString fileName; + + bool copyToProfile(Buteo::SyncProfile *syncProfile); + + static BackupRestoreOptions fromProfile(Buteo::SyncProfile *syncProfile, bool *ok); + + static QString backupDeviceName(); +}; + +#endif // BACKUPRESTOREOPTIONS_H diff --git a/src/dropbox/dropbox-backup/dropbox-backup.pri b/src/dropbox/dropbox-backup/dropbox-backup.pri index 3836671..ccec271 100644 --- a/src/dropbox/dropbox-backup/dropbox-backup.pri +++ b/src/dropbox/dropbox-backup/dropbox-backup.pri @@ -1,7 +1,3 @@ -CONFIG += link_pkgconfig -PKGCONFIG += mlite5 -LIBS += -lssu - SOURCES += $$PWD/dropboxbackupsyncadaptor.cpp HEADERS += $$PWD/dropboxbackupsyncadaptor.h INCLUDEPATH += $$PWD diff --git a/src/dropbox/dropbox-backup/dropboxbackupplugin.cpp b/src/dropbox/dropbox-backup/dropboxbackupplugin.cpp index 59a6742..c9a6e2d 100644 --- a/src/dropbox/dropbox-backup/dropboxbackupplugin.cpp +++ b/src/dropbox/dropbox-backup/dropboxbackupplugin.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** - ** Copyright (C) 2015 Jolla Ltd. + ** Copyright (C) 2015-2019 Jolla Ltd. + ** Copyright (C) 2019 Open Mobile Platform LLC ** Contact: Chris Adams ** ** This program/library is free software; you can redistribute it and/or @@ -50,5 +51,5 @@ DropboxBackupPlugin::~DropboxBackupPlugin() SocialNetworkSyncAdaptor *DropboxBackupPlugin::createSocialNetworkSyncAdaptor() { - return new DropboxBackupSyncAdaptor(this); + return new DropboxBackupSyncAdaptor(profile().name(), this); } diff --git a/src/dropbox/dropbox-backup/dropboxbackupsyncadaptor.cpp b/src/dropbox/dropbox-backup/dropboxbackupsyncadaptor.cpp index 2076b1c..3567849 100644 --- a/src/dropbox/dropbox-backup/dropboxbackupsyncadaptor.cpp +++ b/src/dropbox/dropbox-backup/dropboxbackupsyncadaptor.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** - ** Copyright (C) 2015 Jolla Ltd. - ** Contact: Chris Adams + ** Copyright (C) 2015-2019 Jolla Ltd. + ** Copyright (C) 2019 Open Mobile Platform LLC ** ** This program/library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public License @@ -27,14 +27,13 @@ #include #include #include -#include #include #include -#include - -#include +// buteo +#include +#include static void debugDumpResponse(const QByteArray &data) { @@ -44,14 +43,17 @@ static void debugDumpResponse(const QByteArray &data) } } -DropboxBackupSyncAdaptor::DropboxBackupSyncAdaptor(QObject *parent) +DropboxBackupSyncAdaptor::DropboxBackupSyncAdaptor(const QString &profileName, QObject *parent) : DropboxDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Backup, parent) + , m_profileManager(new Buteo::ProfileManager) + , m_profileName(profileName) { setInitialActive(true); } DropboxBackupSyncAdaptor::~DropboxBackupSyncAdaptor() { + delete m_profileManager; } QString DropboxBackupSyncAdaptor::syncServiceName() const @@ -71,87 +73,74 @@ void DropboxBackupSyncAdaptor::purgeDataForOldAccount(int oldId, SocialNetworkSy void DropboxBackupSyncAdaptor::beginSync(int accountId, const QString &accessToken) { - SsuDeviceInfo deviceInfo; - QString deviceId = deviceInfo.deviceUid(); - QByteArray hashedDeviceId = QCryptographicHash::hash(deviceId.toUtf8(), QCryptographicHash::Sha256); - QString encodedDeviceId = QString::fromUtf8(hashedDeviceId.toBase64(QByteArray::Base64UrlEncoding)).mid(0,12); - if (deviceId.isEmpty()) { - SOCIALD_LOG_ERROR("Could not determine device identifier; cannot create remote per-device backup directory!"); + bool backupRestoreOptionsLoaded = false; + Buteo::SyncProfile *syncProfile = m_profileManager->syncProfile(m_profileName); + BackupRestoreOptions backupRestoreOptions = + BackupRestoreOptions::fromProfile(syncProfile, &backupRestoreOptionsLoaded); + if (!backupRestoreOptionsLoaded) { + SOCIALD_LOG_ERROR("Could not load backup/restore options for" << m_profileName); setStatus(SocialNetworkSyncAdaptor::Error); return; } - QString deviceDisplayNamePrefix = deviceInfo.displayName(Ssu::DeviceModel); - if (!deviceDisplayNamePrefix.isEmpty()) { - deviceDisplayNamePrefix = deviceDisplayNamePrefix.replace(' ', '-') + '_'; + // Immediately unset the backup/restore to ensure that future scheduled + // or manually triggered syncs fail, until the options are set again. + BackupRestoreOptions emptyOptions; + if (!emptyOptions.copyToProfile(syncProfile) + || m_profileManager->updateProfile(*syncProfile).isEmpty()) { + SOCIALD_LOG_ERROR("Warning: failed to reset backup/restore options for profile: " + m_profileName); } - MGConfItem operationTypeConf("/SailfishOS/vault/Dropbox/operationType"); - QString operationType = operationTypeConf.value(QString()).toString(); - - MGConfItem remotePathConf("/SailfishOS/vault/Dropbox/remotePath"); - QString remotePath = remotePathConf.value(QString()).toString(); - if (remotePath.isEmpty()) { - remotePath = QString::fromLatin1("/Backups/%1%2").arg(deviceDisplayNamePrefix).arg(encodedDeviceId); + if (backupRestoreOptions.remoteDirPath.isEmpty()) { + QString backupDeviceName = BackupRestoreOptions::backupDeviceName(); + if (backupDeviceName.isEmpty()) { + SOCIALD_LOG_ERROR("backupDeviceName() returned empty string!"); + setStatus(SocialNetworkSyncAdaptor::Error); + return; + } + backupRestoreOptions.remoteDirPath = QString::fromLatin1("/Backups/%1").arg(backupDeviceName); } - // Immediately unset the keys to ensure that future scheduled - // or manually triggered syncs fail, until the keys are set. - remotePathConf.set(QString()); - operationTypeConf.set(QString()); - - if (operationType == QStringLiteral("list")) { - beginListOperation(accountId, accessToken, remotePath); - } else if (operationType == QStringLiteral("sync")) { - beginSyncOperation(accountId, accessToken, remotePath); - } else { - SOCIALD_LOG_ERROR("Unrecognized sync operation: " + operationType); + switch (backupRestoreOptions.operation) { + case BackupRestoreOptions::DirectoryListing: + beginListOperation(accountId, accessToken, backupRestoreOptions); + break; + case BackupRestoreOptions::Upload: + case BackupRestoreOptions::Download: + beginSyncOperation(accountId, accessToken, backupRestoreOptions); + break; + default: + SOCIALD_LOG_ERROR("Unrecognized sync operation: " + backupRestoreOptions.operation); setStatus(SocialNetworkSyncAdaptor::Error); - return; + break; } } -void DropboxBackupSyncAdaptor::beginListOperation(int accountId, const QString &accessToken, const QString &remotePath) +void DropboxBackupSyncAdaptor::beginListOperation(int accountId, const QString &accessToken, const BackupRestoreOptions &options) { - MGConfItem listResultLocalPathConf("/SailfishOS/vault/Dropbox/listResultLocalPath"); - QString listResultPath = listResultLocalPathConf.value().toString(); - if (listResultPath.isEmpty()) { - SOCIALD_LOG_ERROR("Cannot fetch directory listing, no local results file path set in" << listResultLocalPathConf.key()); + if (options.localDirPath.isEmpty() || options.fileName.isEmpty()) { + SOCIALD_LOG_ERROR("Cannot fetch directory listing, no local results file path set!"); setStatus(SocialNetworkSyncAdaptor::Error); return; } - listResultLocalPathConf.set(QString()); QVariantMap properties = { - { QStringLiteral("listResultPath"), listResultPath }, + { QStringLiteral("listResultPath"), options.localDirPath + '/' + options.fileName }, }; - requestList(accountId, accessToken, QStringLiteral("list"), remotePath, QString(), properties); + requestList(accountId, accessToken, options.operation, options.remoteDirPath, QString(), properties); } -void DropboxBackupSyncAdaptor::beginSyncOperation(int accountId, const QString &accessToken, const QString &remotePath) +void DropboxBackupSyncAdaptor::beginSyncOperation(int accountId, const QString &accessToken, const BackupRestoreOptions &options) { - // read from dconf some key values, which determine the direction of sync etc. - MGConfItem localPathConf("/SailfishOS/vault/Dropbox/localPath"); - MGConfItem remoteFileConf("/SailfishOS/vault/Dropbox/remoteFile"); - MGConfItem directionConf("/SailfishOS/vault/Dropbox/direction"); - QString localPath = localPathConf.value(QString()).toString(); - QString remoteFile = remoteFileConf.value(QString()).toString(); - QString direction = directionConf.value(QString()).toString(); - - // Immediately unset the keys to ensure that future scheduled - // or manually triggered syncs fail, until the keys are set. - // Specifically, the value of the direction key is important. - localPathConf.set(QString()); - remoteFileConf.set(QString()); - directionConf.set(QString()); - // set defaults if required. + QString localPath = options.localDirPath; if (localPath.isEmpty()) { localPath = QString::fromLatin1("%1/Backups/").arg(QString::fromLatin1(PRIVILEGED_DATA_DIR)); } + QString remoteFile = options.fileName; if (!remoteFile.isEmpty()) { // dropbox requestData() function takes remoteFile param which has a fully specified path. - remoteFile = QStringLiteral("%1/%2").arg(remotePath).arg(remoteFile); + remoteFile = QStringLiteral("%1/%2").arg(options.remoteDirPath).arg(remoteFile); } // create local directory if it doesn't exist @@ -163,16 +152,16 @@ void DropboxBackupSyncAdaptor::beginSyncOperation(int accountId, const QString & } // either upsync or downsync as required. - if (direction == Buteo::VALUE_TO_REMOTE) { - uploadData(accountId, accessToken, localPath, remotePath); - } else if (direction == Buteo::VALUE_FROM_REMOTE) { + if (options.operation == BackupRestoreOptions::Upload) { + uploadData(accountId, accessToken, localPath, options.remoteDirPath); + } else if (options.operation == BackupRestoreOptions::Download) { // step one: get the remote path and its children metadata. // step two: for each (non-folder) child in metadata, download it. QVariantMap properties = { { QStringLiteral("localPath"), localPath }, { QStringLiteral("remoteFile"), remoteFile }, }; - requestList(accountId, accessToken, QStringLiteral("sync"), remotePath, QString(), properties); + requestList(accountId, accessToken, options.operation, options.remoteDirPath, QString(), properties); } else { SOCIALD_LOG_ERROR("No direction set for Dropbox Backup sync with account:" << accountId); setStatus(SocialNetworkSyncAdaptor::Error); @@ -182,7 +171,7 @@ void DropboxBackupSyncAdaptor::beginSyncOperation(int accountId, const QString & void DropboxBackupSyncAdaptor::requestList(int accountId, const QString &accessToken, - const QString &operationType, + int operationType, const QString &remotePath, const QString &continuationCursor, const QVariantMap &extraProperties) @@ -245,7 +234,7 @@ void DropboxBackupSyncAdaptor::remotePathFinishedHandler() QByteArray data = reply->readAll(); int accountId = reply->property("accountId").toInt(); QString accessToken = reply->property("accessToken").toString(); - QString operationType = reply->property("operationType").toString(); + int operationType = reply->property("operationType").toInt(); QString remotePath = reply->property("remotePath").toString(); int httpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); bool isError = reply->property("isError").toBool(); @@ -311,7 +300,9 @@ void DropboxBackupSyncAdaptor::remotePathFinishedHandler() SOCIALD_LOG_DEBUG("Parsed dir listing entries:" << entries); } - if (operationType == QStringLiteral("list")) { + switch (operationType) { + case BackupRestoreOptions::DirectoryListing: + { QString listResultPath = reply->property("listResultPath").toString(); if (listResultPath.isEmpty()) { SOCIALD_LOG_ERROR("Cannot save directory listing, no local results file path set"); @@ -343,7 +334,11 @@ void DropboxBackupSyncAdaptor::remotePathFinishedHandler() file.close(); SOCIALD_LOG_DEBUG("Wrote directory listing to" << file.fileName()); } - } else if (operationType == QStringLiteral("sync")) { + break; + } + case BackupRestoreOptions::Upload: + case BackupRestoreOptions::Download: + { QString localPath = reply->property("localPath").toString(); QString remoteFile = reply->property("remoteFile").toString(); if (hasMore) { @@ -357,8 +352,10 @@ void DropboxBackupSyncAdaptor::remotePathFinishedHandler() requestData(accountId, accessToken, localPath, remotePath, *it); } } - } else { - SOCIALD_LOG_ERROR("Unrecognized sync operation: " + operationType); + break; + } + default: + SOCIALD_LOG_ERROR("Unrecognized sync operation: " << operationType); setStatus(SocialNetworkSyncAdaptor::Error); decrementSemaphore(accountId); return; diff --git a/src/dropbox/dropbox-backup/dropboxbackupsyncadaptor.h b/src/dropbox/dropbox-backup/dropboxbackupsyncadaptor.h index eb4b898..b496c93 100644 --- a/src/dropbox/dropbox-backup/dropboxbackupsyncadaptor.h +++ b/src/dropbox/dropbox-backup/dropboxbackupsyncadaptor.h @@ -1,7 +1,7 @@ /**************************************************************************** ** - ** Copyright (C) 2015 Jolla Ltd. - ** Contact: Chris Adams + ** Copyright (C) 2015-2019 Jolla Ltd. + ** Copyright (C) 2019 Open Mobile Platform LLC ** ** This program/library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public License @@ -23,6 +23,7 @@ #define DROPBOXBACKUPSYNCADAPTOR_H #include "dropboxdatatypesyncadaptor.h" +#include "backuprestoreoptions_p.h" #include #include @@ -35,12 +36,16 @@ #include #include +namespace Buteo { + class ProfileManager; +} + class DropboxBackupSyncAdaptor : public DropboxDataTypeSyncAdaptor { Q_OBJECT public: - DropboxBackupSyncAdaptor(QObject *parent); + DropboxBackupSyncAdaptor(const QString &profileName, QObject *parent); ~DropboxBackupSyncAdaptor(); QString syncServiceName() const; @@ -55,7 +60,7 @@ class DropboxBackupSyncAdaptor : public DropboxDataTypeSyncAdaptor private: void requestList(int accountId, const QString &accessToken, - const QString &operationType, + int operationType, const QString &remotePath, const QString &continuationCursor, const QVariantMap &extraProperties); @@ -67,8 +72,8 @@ class DropboxBackupSyncAdaptor : public DropboxDataTypeSyncAdaptor const QString &localFile = QString()); void purgeAccount(int accountId); - void beginListOperation(int accountId, const QString &accessToken, const QString &remotePath); - void beginSyncOperation(int accountId, const QString &accessToken, const QString &remotePath); + void beginListOperation(int accountId, const QString &accessToken, const BackupRestoreOptions &options); + void beginSyncOperation(int accountId, const QString &accessToken, const BackupRestoreOptions &options); private Q_SLOTS: void remotePathFinishedHandler(); @@ -79,7 +84,10 @@ private Q_SLOTS: void uploadProgressHandler(qint64 bytesSent, qint64 bytesTotal); private: + Buteo::ProfileManager *m_profileManager; + QSet m_backupFiles; + QString m_profileName; }; #endif // DROPBOXBACKUPSYNCADAPTOR_H diff --git a/src/onedrive/onedrive-backup/onedrive-backup.pri b/src/onedrive/onedrive-backup/onedrive-backup.pri index 679a7b3..3ed85df 100644 --- a/src/onedrive/onedrive-backup/onedrive-backup.pri +++ b/src/onedrive/onedrive-backup/onedrive-backup.pri @@ -1,7 +1,3 @@ -CONFIG += link_pkgconfig -PKGCONFIG += mlite5 -LIBS += -lssu - SOURCES += $$PWD/onedrivebackupsyncadaptor.cpp HEADERS += $$PWD/onedrivebackupsyncadaptor.h INCLUDEPATH += $$PWD diff --git a/src/onedrive/onedrive-backup/onedrivebackupplugin.cpp b/src/onedrive/onedrive-backup/onedrivebackupplugin.cpp index ea8ff8d..3af8260 100644 --- a/src/onedrive/onedrive-backup/onedrivebackupplugin.cpp +++ b/src/onedrive/onedrive-backup/onedrivebackupplugin.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** - ** Copyright (C) 2015 Jolla Ltd. + ** Copyright (C) 2015-2019 Jolla Ltd. + ** Copyright (C) 2019 Open Mobile Platform LLC ** Contact: Chris Adams ** ** This program/library is free software; you can redistribute it and/or @@ -50,5 +51,5 @@ OneDriveBackupPlugin::~OneDriveBackupPlugin() SocialNetworkSyncAdaptor *OneDriveBackupPlugin::createSocialNetworkSyncAdaptor() { - return new OneDriveBackupSyncAdaptor(this); + return new OneDriveBackupSyncAdaptor(profile().name(), this); } diff --git a/src/onedrive/onedrive-backup/onedrivebackupsyncadaptor.cpp b/src/onedrive/onedrive-backup/onedrivebackupsyncadaptor.cpp index 51d48dc..2827c17 100644 --- a/src/onedrive/onedrive-backup/onedrivebackupsyncadaptor.cpp +++ b/src/onedrive/onedrive-backup/onedrivebackupsyncadaptor.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** - ** Copyright (C) 2015 Jolla Ltd. - ** Contact: Chris Adams + ** Copyright (C) 2015-2019 Jolla Ltd. + ** Copyright (C) 2019 Open Mobile Platform LLC ** ** This program/library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public License @@ -32,9 +32,9 @@ #include #include -#include - -#include +// buteo +#include +#include static void debugDumpResponse(const QByteArray &data) { @@ -77,8 +77,10 @@ static void debugDumpJsonResponse(const QByteArray &data) debugDumpResponse(output.toUtf8()); } -OneDriveBackupSyncAdaptor::OneDriveBackupSyncAdaptor(QObject *parent) +OneDriveBackupSyncAdaptor::OneDriveBackupSyncAdaptor(const QString &profileName, QObject *parent) : OneDriveDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Backup, parent) + , m_profileManager(new Buteo::ProfileManager) + , m_profileName(profileName) , m_remoteAppDir(QStringLiteral("drive/special/approot")) { setInitialActive(true); @@ -86,6 +88,7 @@ OneDriveBackupSyncAdaptor::OneDriveBackupSyncAdaptor(QObject *parent) OneDriveBackupSyncAdaptor::~OneDriveBackupSyncAdaptor() { + delete m_profileManager; } QString OneDriveBackupSyncAdaptor::syncServiceName() const @@ -105,59 +108,58 @@ void OneDriveBackupSyncAdaptor::purgeDataForOldAccount(int oldId, SocialNetworkS void OneDriveBackupSyncAdaptor::beginSync(int accountId, const QString &accessToken) { - SsuDeviceInfo deviceInfo; - QString deviceId = deviceInfo.deviceUid(); - QByteArray hashedDeviceId = QCryptographicHash::hash(deviceId.toUtf8(), QCryptographicHash::Sha256); - QString encodedDeviceId = QString::fromUtf8(hashedDeviceId.toBase64(QByteArray::Base64UrlEncoding)).mid(0,12); - if (deviceId.isEmpty()) { - SOCIALD_LOG_ERROR("Could not determine device identifier; cannot create remote per-device backup directory!"); + bool backupRestoreOptionsLoaded = false; + Buteo::SyncProfile *syncProfile = m_profileManager->syncProfile(m_profileName); + BackupRestoreOptions backupRestoreOptions = + BackupRestoreOptions::fromProfile(syncProfile, &backupRestoreOptionsLoaded); + if (!backupRestoreOptionsLoaded) { + SOCIALD_LOG_ERROR("Could not load backup/restore options for" << m_profileName); setStatus(SocialNetworkSyncAdaptor::Error); return; } - QString deviceDisplayNamePrefix = deviceInfo.displayName(Ssu::DeviceModel); - if (!deviceDisplayNamePrefix.isEmpty()) { - deviceDisplayNamePrefix = deviceDisplayNamePrefix.replace(' ', '-') + '_'; - } - - MGConfItem operationTypeConf("/SailfishOS/vault/OneDrive/operationType"); - QString operationType = operationTypeConf.value(QString()).toString(); - - MGConfItem remotePathConf("/SailfishOS/vault/OneDrive/remotePath"); - QString remotePath = remotePathConf.value(QString()).toString(); - if (remotePath.isEmpty()) { - remotePath = QString::fromLatin1("Backups/%1%2").arg(deviceDisplayNamePrefix).arg(encodedDeviceId); + // Immediately unset the backup/restore to ensure that future scheduled + // or manually triggered syncs fail, until the options are set again. + BackupRestoreOptions emptyOptions; + if (!emptyOptions.copyToProfile(syncProfile) + || m_profileManager->updateProfile(*syncProfile).isEmpty()) { + SOCIALD_LOG_ERROR("Warning: failed to reset backup/restore options for profile: " + m_profileName); } - // Immediately unset the keys to ensure that future scheduled - // or manually triggered syncs fail, until the keys are set. - remotePathConf.set(QString()); - operationTypeConf.set(QString()); - - if (operationType == QStringLiteral("list")) { - beginListOperation(accountId, accessToken, remotePath); - } else if (operationType == QStringLiteral("sync")) { - beginSyncOperation(accountId, accessToken, remotePath); - } else { - SOCIALD_LOG_ERROR("Unrecognized sync operation: " + operationType); + if (backupRestoreOptions.remoteDirPath.isEmpty()) { + QString backupDeviceName = BackupRestoreOptions::backupDeviceName(); + if (backupDeviceName.isEmpty()) { + SOCIALD_LOG_ERROR("backupDeviceName() returned empty string!"); + setStatus(SocialNetworkSyncAdaptor::Error); + return; + } + backupRestoreOptions.remoteDirPath = "Backups/" + backupDeviceName; + } + + switch (backupRestoreOptions.operation) { + case BackupRestoreOptions::DirectoryListing: + beginListOperation(accountId, accessToken, backupRestoreOptions); + break; + case BackupRestoreOptions::Upload: + case BackupRestoreOptions::Download: + beginSyncOperation(accountId, accessToken, backupRestoreOptions); + break; + default: + SOCIALD_LOG_ERROR("Unrecognized sync operation: " + backupRestoreOptions.operation); setStatus(SocialNetworkSyncAdaptor::Error); - return; + break; } } -void OneDriveBackupSyncAdaptor::beginListOperation(int accountId, const QString &accessToken, const QString &remotePath) +void OneDriveBackupSyncAdaptor::beginListOperation(int accountId, const QString &accessToken, const BackupRestoreOptions &options) { - MGConfItem listResultLocalPathConf("/SailfishOS/vault/OneDrive/listResultLocalPath"); - QString listResultPath = listResultLocalPathConf.value().toString(); - if (listResultPath.isEmpty()) { - SOCIALD_LOG_ERROR("Cannot fetch directory listing, no local results file path set in" << listResultLocalPathConf.key()); + if (options.localDirPath.isEmpty() || options.fileName.isEmpty()) { + SOCIALD_LOG_ERROR("Cannot fetch directory listing, no local results file path set"); setStatus(SocialNetworkSyncAdaptor::Error); return; } - listResultLocalPathConf.set(QString()); - - QUrl url(QStringLiteral("https://api.onedrive.com/v1.0/drive/special/approot:/%1:/").arg(remotePath)); + QUrl url(QStringLiteral("https://api.onedrive.com/v1.0/drive/special/approot:/%1:/").arg(options.remoteDirPath)); QUrlQuery query(url); QList > queryItems; queryItems.append(QPair(QStringLiteral("expand"), QStringLiteral("children"))); @@ -171,8 +173,8 @@ void OneDriveBackupSyncAdaptor::beginListOperation(int accountId, const QString if (reply) { reply->setProperty("accountId", accountId); reply->setProperty("accessToken", accessToken); - reply->setProperty("remotePath", remotePath); - reply->setProperty("listResultPath", listResultPath); + reply->setProperty("remotePath", options.remoteDirPath); + reply->setProperty("listResultPath", options.localDirPath + '/' + options.fileName); connect(reply, &QNetworkReply::finished, this, &OneDriveBackupSyncAdaptor::listOperationFinished); // we're requesting data. Increment the semaphore so that we know we're still busy. @@ -188,6 +190,7 @@ void OneDriveBackupSyncAdaptor::listOperationFinished() QNetworkReply *reply = qobject_cast(sender()); QByteArray data = reply->readAll(); int accountId = reply->property("accountId").toInt(); + QString listResultPath = reply->property("listResultPath").toString(); QString remotePath = reply->property("remotePath").toString(); int httpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); bool isError = reply->property("isError").toBool(); @@ -200,14 +203,6 @@ void OneDriveBackupSyncAdaptor::listOperationFinished() debugDumpResponse(data); } - QString listResultPath = reply->property("listResultPath").toString(); - if (listResultPath.isEmpty()) { - SOCIALD_LOG_ERROR("Cannot save directory listing, no local results file path set"); - setStatus(SocialNetworkSyncAdaptor::Error); - decrementSemaphore(accountId); - return; - } - bool ok = false; const QJsonObject parsed = parseJsonObjectReplyData(data, &ok); const QJsonArray entries = parsed.value("children").toArray(); @@ -282,24 +277,19 @@ void OneDriveBackupSyncAdaptor::listOperationFinished() } -void OneDriveBackupSyncAdaptor::beginSyncOperation(int accountId, const QString &accessToken, const QString &remotePath) +void OneDriveBackupSyncAdaptor::beginSyncOperation(int accountId, const QString &accessToken, const BackupRestoreOptions &options) { - // read from dconf some key values, which determine the direction of sync etc. - MGConfItem localPathConf("/SailfishOS/vault/OneDrive/localPath"); - MGConfItem remoteFileConf("/SailfishOS/vault/OneDrive/remoteFile"); - MGConfItem directionConf("/SailfishOS/vault/OneDrive/direction"); - QString localPath = localPathConf.value(QString()).toString(); - QString remoteFile = remoteFileConf.value(QString()).toString(); - QString direction = directionConf.value(QString()).toString(); - - // Immediately unset the keys to ensure that future scheduled - // or manually triggered syncs fail, until the keys are set. - // Specifically, the value of the direction key is important. - localPathConf.set(QString()); - remoteFileConf.set(QString()); - directionConf.set(QString()); + QString direction = options.operation == BackupRestoreOptions::Upload + ? Buteo::VALUE_TO_REMOTE + : (options.operation == BackupRestoreOptions::Download ? Buteo::VALUE_FROM_REMOTE : QString()); + if (direction.isEmpty()) { + SOCIALD_LOG_ERROR("Invalid sync operation" << options.operation << "for OneDrive account:" << accountId); + setStatus(SocialNetworkSyncAdaptor::Error); + return; + } // set defaults if required. + QString localPath = options.localDirPath; if (localPath.isEmpty()) { localPath = QString::fromLatin1("%1/Backups/").arg(QString::fromLatin1(PRIVILEGED_DATA_DIR)); } @@ -315,7 +305,7 @@ void OneDriveBackupSyncAdaptor::beginSyncOperation(int accountId, const QString // either upsync or downsync as required. if (direction == Buteo::VALUE_TO_REMOTE || direction == Buteo::VALUE_FROM_REMOTE) { // Perform an initial app folder request before upload/download. - initialiseAppFolderRequest(accountId, accessToken, localPath, remotePath, remoteFile, direction); + initialiseAppFolderRequest(accountId, accessToken, localPath, options.remoteDirPath, options.fileName, direction); } else { SOCIALD_LOG_ERROR("No direction set for OneDrive Backup sync with account:" << accountId); setStatus(SocialNetworkSyncAdaptor::Error); diff --git a/src/onedrive/onedrive-backup/onedrivebackupsyncadaptor.h b/src/onedrive/onedrive-backup/onedrivebackupsyncadaptor.h index 07966eb..f015bc3 100644 --- a/src/onedrive/onedrive-backup/onedrivebackupsyncadaptor.h +++ b/src/onedrive/onedrive-backup/onedrivebackupsyncadaptor.h @@ -1,7 +1,7 @@ /**************************************************************************** ** - ** Copyright (C) 2015 Jolla Ltd. - ** Contact: Chris Adams + ** Copyright (C) 2015-2019 Jolla Ltd. + ** Copyright (C) 2019 Open Mobile Platform LLC ** ** This program/library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public License @@ -23,6 +23,7 @@ #define ONEDRIVEBACKUPSYNCADAPTOR_H #include "onedrivedatatypesyncadaptor.h" +#include "backuprestoreoptions_p.h" #include #include @@ -35,12 +36,16 @@ #include #include +namespace Buteo { + class ProfileManager; +} + class OneDriveBackupSyncAdaptor : public OneDriveDataTypeSyncAdaptor { Q_OBJECT public: - OneDriveBackupSyncAdaptor(QObject *parent); + OneDriveBackupSyncAdaptor(const QString &profileName, QObject *parent); ~OneDriveBackupSyncAdaptor(); QString syncServiceName() const; @@ -79,10 +84,13 @@ private Q_SLOTS: void uploadProgressHandler(qint64 bytesSent, qint64 bytesTotal); private: - void beginListOperation(int accountId, const QString &accessToken, const QString &remotePath); - void beginSyncOperation(int accountId, const QString &accessToken, const QString &remotePath); + void beginListOperation(int accountId, const QString &accessToken, const BackupRestoreOptions &options); + void beginSyncOperation(int accountId, const QString &accessToken, const BackupRestoreOptions &options); void listOperationFinished(); + Buteo::ProfileManager *m_profileManager; + + QString m_profileName; QString m_remoteAppDir; struct RemoteDirectory {