From 6c77294a86f32c826c97ae58eede896481fbf8a5 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Fri, 29 May 2020 17:36:01 +0200 Subject: [PATCH] Fixes to imobiledeviceconnection support --- src/device/afcdevice.cpp | 34 ++++++++++++++++++++------ src/device/afcdevice.h | 14 ++++++----- src/device/afctransfer.cpp | 4 +-- src/device/afctransfer.h | 1 - src/device/connecteddevice.cpp | 2 +- src/device/connecteddevice.h | 2 +- src/device/giolister.cpp | 10 +++++++- src/device/gpoddevice.cpp | 6 ++++- src/device/gpoddevice.h | 8 +----- src/device/gpodloader.h | 2 +- src/device/ilister.cpp | 16 +++++++----- src/device/ilister.h | 13 +++++----- src/device/imobiledeviceconnection.cpp | 26 ++++++++++++++------ src/device/imobiledeviceconnection.h | 2 +- src/device/mtpdevice.h | 2 +- 15 files changed, 91 insertions(+), 51 deletions(-) diff --git a/src/device/afcdevice.cpp b/src/device/afcdevice.cpp index 7559d8a2..e91a4c72 100644 --- a/src/device/afcdevice.cpp +++ b/src/device/afcdevice.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include + #include #include #include @@ -28,6 +30,7 @@ #include "core/application.h" #include "core/utilities.h" +#include "core/song.h" #include "afcdevice.h" #include "afcfile.h" #include "afctransfer.h" @@ -35,13 +38,23 @@ #include "gpodloader.h" #include "imobiledeviceconnection.h" -AfcDevice::AfcDevice(const QUrl &url, DeviceLister* lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time) - : GPodDevice(url, lister, unique_id, manager, app, database_id, first_time), transfer_(nullptr) -{ -} +AfcDevice::AfcDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, const int database_id, const bool first_time) : GPodDevice(url, lister, unique_id, manager, app, database_id, first_time), transfer_(nullptr) {} AfcDevice::~AfcDevice() { + Utilities::RemoveRecursive(local_path_); + + if (loader_) { + loader_->deleteLater(); + loader_ = nullptr; + } + + if (loader_thread_) { + loader_thread_->exit(); + loader_thread_->deleteLater(); + loader_thread_ = nullptr; + } + } bool AfcDevice::Init() { @@ -51,11 +64,16 @@ bool AfcDevice::Init() { InitBackendDirectory(local_path_, first_time_, false); model_->Init(); + if (!loader_thread_) loader_thread_ = new QThread(); + + if (url_.isEmpty() || url_.path().isEmpty()) return false; + transfer_ = new AfcTransfer(url_.host(), local_path_, app_->task_manager(), shared_from_this()); transfer_->moveToThread(loader_thread_); connect(transfer_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int))); connect(transfer_, SIGNAL(CopyFinished(bool)), SLOT(CopyFinished(bool))); + connect(loader_thread_, SIGNAL(started()), transfer_, SLOT(CopyFromDevice())); loader_thread_->start(); @@ -63,7 +81,7 @@ bool AfcDevice::Init() { } -void AfcDevice::CopyFinished(bool success) { +void AfcDevice::CopyFinished(const bool success) { transfer_->deleteLater(); transfer_ = nullptr; @@ -76,12 +94,12 @@ void AfcDevice::CopyFinished(bool success) { // Now load the songs from the local database loader_ = new GPodLoader(local_path_, app_->task_manager(), backend_, shared_from_this()); loader_->set_music_path_prefix("afc://" + url_.host()); - //loader_->set_song_type(Song::Type_Stream); + loader_->set_song_type(Song::FileType_Stream); loader_->moveToThread(loader_thread_); - connect(loader_, SIGNAL(Error(QString)), SIGNAL(Error(QString))); + connect(loader_, SIGNAL(Error(QString)), SLOT(LoaderError(QString))); connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int))); - connect(loader_, SIGNAL(LoadFinished(Itdb_iTunesDB*)), SLOT(LoadFinished(Itdb_iTunesDB*))); + connect(loader_, SIGNAL(LoadFinished(Itdb_iTunesDB*, bool)), SLOT(LoadFinished(Itdb_iTunesDB*, bool))); QMetaObject::invokeMethod(loader_, "LoadDatabase"); } diff --git a/src/device/afcdevice.h b/src/device/afcdevice.h index 151464a4..09133675 100644 --- a/src/device/afcdevice.h +++ b/src/device/afcdevice.h @@ -23,6 +23,8 @@ #include "config.h" +#include + #include #include @@ -41,7 +43,7 @@ class AfcDevice : public GPodDevice { Q_OBJECT public: - Q_INVOKABLE AfcDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time); + Q_INVOKABLE AfcDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, const int database_id, const bool first_time); ~AfcDevice(); bool Init(); @@ -50,20 +52,20 @@ public: bool StartCopy(QList *supported_types); bool CopyToStorage(const CopyJob &job); - void FinishCopy(bool success); + void FinishCopy(const bool success); bool DeleteFromStorage(const DeleteJob &job); -protected: + protected: void FinaliseDatabase(); -private slots: + private slots: void CopyFinished(bool success); -private: + private: void RemoveRecursive(const QString &path); -private: + private: AfcTransfer *transfer_; std::shared_ptr connection_; diff --git a/src/device/afctransfer.cpp b/src/device/afctransfer.cpp index 3aa6a463..32ed5f90 100644 --- a/src/device/afctransfer.cpp +++ b/src/device/afctransfer.cpp @@ -45,9 +45,6 @@ AfcTransfer::AfcTransfer(const QString &uuid, const QString &local_destination, } -AfcTransfer::~AfcTransfer() { -} - void AfcTransfer::CopyFromDevice() { int task_id = 0; @@ -57,6 +54,7 @@ void AfcTransfer::CopyFromDevice() { } // Connect to the device + iMobileDeviceConnection c(uuid_); // Copy directories. If one fails we stop. diff --git a/src/device/afctransfer.h b/src/device/afctransfer.h index 1b70c9ae..94c8c353 100644 --- a/src/device/afctransfer.h +++ b/src/device/afctransfer.h @@ -40,7 +40,6 @@ class AfcTransfer : public QObject { public: explicit AfcTransfer(const QString &uuid, const QString &local_destination, TaskManager *task_manager, std::shared_ptr device); - ~AfcTransfer(); bool CopyToDevice(iMobileDeviceConnection *connection); diff --git a/src/device/connecteddevice.cpp b/src/device/connecteddevice.cpp index f2755fee..d2156fa9 100644 --- a/src/device/connecteddevice.cpp +++ b/src/device/connecteddevice.cpp @@ -78,7 +78,7 @@ ConnectedDevice::~ConnectedDevice() { backend_->deleteLater(); } -void ConnectedDevice::InitBackendDirectory(const QString &mount_point, bool first_time, bool rewrite_path) { +void ConnectedDevice::InitBackendDirectory(const QString &mount_point, const bool first_time, const bool rewrite_path) { if (first_time || backend_->GetAllDirectories().isEmpty()) { backend_->AddDirectory(mount_point); diff --git a/src/device/connecteddevice.h b/src/device/connecteddevice.h index 43aefaf4..8bbf5814 100644 --- a/src/device/connecteddevice.h +++ b/src/device/connecteddevice.h @@ -79,7 +79,7 @@ class ConnectedDevice : public QObject, public virtual MusicStorage, public std: void CloseFinished(const QString& id); protected: - void InitBackendDirectory(const QString &mount_point, bool first_time, bool rewrite_path = true); + void InitBackendDirectory(const QString &mount_point, const bool first_time, const bool rewrite_path = true); protected: Application *app_; diff --git a/src/device/giolister.cpp b/src/device/giolister.cpp index f173b305..c3e9bb6a 100644 --- a/src/device/giolister.cpp +++ b/src/device/giolister.cpp @@ -283,6 +283,10 @@ void GioLister::VolumeAdded(GVolume *volume) { DeviceInfo info; info.ReadVolumeInfo(volume); + if (info.volume_root_uri.startsWith("afc://") || info.volume_root_uri.startsWith("gphoto2://")) { + // Handled by iLister. + return; + } #ifdef HAVE_AUDIOCD if (info.volume_root_uri.startsWith("cdda")) // Audio CD devices are already handled by CDDA lister @@ -322,6 +326,10 @@ void GioLister::MountAdded(GMount *mount) { DeviceInfo info; info.ReadVolumeInfo(g_mount_get_volume(mount)); + if (info.volume_root_uri.startsWith("afc://") || info.volume_root_uri.startsWith("gphoto2://")) { + // Handled by iLister. + return; + } #ifdef HAVE_AUDIOCD if (info.volume_root_uri.startsWith("cdda")) // Audio CD devices are already handled by CDDA lister @@ -566,7 +574,7 @@ void GioLister::UpdateDeviceFreeSpace(const QString &id) { bool GioLister::DeviceNeedsMount(const QString &id) { QMutexLocker l(&mutex_); - return devices_.contains(id) && !devices_[id].mount_ptr && !devices_[id].volume_root_uri.startsWith("mtp://"); + return devices_.contains(id) && !devices_[id].mount_ptr && !devices_[id].volume_root_uri.startsWith("mtp://") && !devices_[id].volume_root_uri.startsWith("gphoto2://"); } diff --git a/src/device/gpoddevice.cpp b/src/device/gpoddevice.cpp index 6e68dfdf..146ca405 100644 --- a/src/device/gpoddevice.cpp +++ b/src/device/gpoddevice.cpp @@ -46,7 +46,7 @@ class DeviceLister; class DeviceManager; -GPodDevice::GPodDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time) +GPodDevice::GPodDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, const int database_id, const bool first_time) : ConnectedDevice(url, lister, unique_id, manager, app, database_id, first_time), loader_(nullptr), loader_thread_(nullptr), @@ -72,11 +72,15 @@ bool GPodDevice::Init() { } GPodDevice::~GPodDevice() { + if (loader_) { loader_thread_->exit(); loader_->deleteLater(); loader_thread_->deleteLater(); + loader_ = nullptr; + loader_thread_ = nullptr; } + } void GPodDevice::ConnectAsync() { diff --git a/src/device/gpoddevice.h b/src/device/gpoddevice.h index 17cd3942..f12a24f6 100644 --- a/src/device/gpoddevice.h +++ b/src/device/gpoddevice.h @@ -47,13 +47,7 @@ class GPodDevice : public ConnectedDevice, public virtual MusicStorage { Q_OBJECT public: - Q_INVOKABLE GPodDevice( - const QUrl &url, DeviceLister *lister, - const QString &unique_id, - DeviceManager *manager, - Application *app, - int database_id, - bool first_time); + Q_INVOKABLE GPodDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, const int database_id, const bool first_time); ~GPodDevice(); bool Init(); diff --git a/src/device/gpodloader.h b/src/device/gpodloader.h index af89c82f..31b0a984 100644 --- a/src/device/gpodloader.h +++ b/src/device/gpodloader.h @@ -52,7 +52,7 @@ class GPodLoader : public QObject { void LoadDatabase(); signals: - void Error(const QString &message); + void Error(QString message); void TaskStarted(int task_id); void LoadFinished(Itdb_iTunesDB *db, bool success); diff --git a/src/device/ilister.cpp b/src/device/ilister.cpp index 39b61095..c7426f3d 100644 --- a/src/device/ilister.cpp +++ b/src/device/ilister.cpp @@ -36,15 +36,17 @@ iLister::iLister() {} iLister::~iLister() {} bool iLister::Init() { + idevice_event_subscribe(&EventCallback, reinterpret_cast(this)); return true; + } void iLister::EventCallback(const idevice_event_t *event, void *context) { iLister *me = reinterpret_cast(context); - const char *uuid = event->udid; + QString uuid = QString::fromUtf8(event->udid); switch (event->event) { case IDEVICE_DEVICE_ADD: @@ -60,7 +62,7 @@ void iLister::EventCallback(const idevice_event_t *event, void *context) { } -void iLister::DeviceAddedCallback(const char *uuid) { +void iLister::DeviceAddedCallback(const QString uuid) { DeviceInfo info = ReadDeviceInfo(uuid); if (!info.valid) return; @@ -82,9 +84,10 @@ void iLister::DeviceAddedCallback(const char *uuid) { } -void iLister::DeviceRemovedCallback(const char *uuid) { +void iLister::DeviceRemovedCallback(const QString uuid) { QString id = UniqueId(uuid); + { QMutexLocker l(&mutex_); if (!devices_.contains(id)) @@ -97,8 +100,8 @@ void iLister::DeviceRemovedCallback(const char *uuid) { } -QString iLister::UniqueId(const char *uuid) { - return "ithing/" + QString::fromUtf8(uuid); +QString iLister::UniqueId(const QString uuid) { + return "ithing/" + uuid; } QStringList iLister::DeviceUniqueIDs() { @@ -191,12 +194,13 @@ QList iLister::MakeDeviceUrls(const QString &id) { } -iLister::DeviceInfo iLister::ReadDeviceInfo(const char *uuid) { +iLister::DeviceInfo iLister::ReadDeviceInfo(const QString uuid) { DeviceInfo ret; iMobileDeviceConnection conn(uuid); if (!conn.is_valid()) return ret; + ret.valid = conn.is_valid(); ret.uuid = uuid; ret.product_type = conn.GetProperty("ProductType").toString(); diff --git a/src/device/ilister.h b/src/device/ilister.h index 17eb55a3..de50269b 100644 --- a/src/device/ilister.h +++ b/src/device/ilister.h @@ -37,6 +37,7 @@ class iLister : public DeviceLister { Q_OBJECT + public: explicit iLister(); ~iLister(); @@ -58,7 +59,7 @@ class iLister : public DeviceLister { private: struct DeviceInfo { - DeviceInfo() : valid(false), free_bytes(0), total_bytes(0) {} + DeviceInfo() : valid(false), free_bytes(0), total_bytes(0), password_protected(false) {} bool valid; @@ -83,16 +84,16 @@ class iLister : public DeviceLister { static void EventCallback(const idevice_event_t *event, void *context); - void DeviceAddedCallback(const char *uuid); - void DeviceRemovedCallback(const char *uuid); + void DeviceAddedCallback(const QString uuid); + void DeviceRemovedCallback(const QString uuid); - DeviceInfo ReadDeviceInfo(const char *uuid); - static QString UniqueId(const char *uuid); + DeviceInfo ReadDeviceInfo(const QString uuid); + static QString UniqueId(const QString uuid); template T LockAndGetDeviceInfo(const QString &id, T DeviceInfo::*field); -private: + private: QMutex mutex_; QMap devices_; }; diff --git a/src/device/imobiledeviceconnection.cpp b/src/device/imobiledeviceconnection.cpp index bce77cf7..26ddaad9 100644 --- a/src/device/imobiledeviceconnection.cpp +++ b/src/device/imobiledeviceconnection.cpp @@ -22,6 +22,11 @@ #include +#include +#include +#include +#include + #include #include #include @@ -29,15 +34,18 @@ #include #include #include +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +# include +#endif #include "core/logging.h" #include "imobiledeviceconnection.h" -iMobileDeviceConnection::iMobileDeviceConnection(const QString &uuid) : device_(nullptr), afc_(nullptr) { +iMobileDeviceConnection::iMobileDeviceConnection(const QString uuid) : device_(nullptr), afc_(nullptr) { idevice_error_t err = idevice_new(&device_, uuid.toUtf8().constData()); if (err != IDEVICE_E_SUCCESS) { - qLog(Warning) << "idevice error:" << err; + qLog(Warning) << "idevice_new error:" << err; return; } @@ -47,27 +55,25 @@ iMobileDeviceConnection::iMobileDeviceConnection(const QString &uuid) : device_( lockdownd_client_t lockdown; lockdownd_error_t lockdown_err = lockdownd_client_new_with_handshake(device_, &lockdown, label); if (lockdown_err != LOCKDOWN_E_SUCCESS) { - qLog(Warning) << "lockdown error:" << lockdown_err; + qLog(Warning) << "lockdownd_client_new_with_handshake error:" << lockdown_err; return; } lockdownd_service_descriptor_t lockdown_service_desc; lockdown_err = lockdownd_start_service(lockdown, "com.apple.afc", &lockdown_service_desc); if (lockdown_err != LOCKDOWN_E_SUCCESS) { - qLog(Warning) << "lockdown error:" << lockdown_err; + qLog(Warning) << "lockdownd_start_service error:" << lockdown_err; lockdownd_client_free(lockdown); return; } afc_error_t afc_err = afc_client_new(device_, lockdown_service_desc, &afc_); if (afc_err != AFC_E_SUCCESS) { - qLog(Warning) << "afc error:" << afc_err; - lockdownd_service_descriptor_free(lockdown_service_desc); + qLog(Warning) << "afc_client_new error:" << afc_err; lockdownd_client_free(lockdown); return; } - lockdownd_service_descriptor_free(lockdown_service_desc); lockdownd_client_free(lockdown); } @@ -187,6 +193,7 @@ QString iMobileDeviceConnection::GetFileInfo(const QString &path, const QString char **infolist = nullptr; afc_error_t err = afc_get_file_info(afc_, path.toUtf8().constData(), &infolist); if (err != AFC_E_SUCCESS || !infolist) { + qLog(Debug) << "afc_get_file_info error:" << path << err; return ret; } @@ -232,7 +239,12 @@ QString iMobileDeviceConnection::GetUnusedFilename(Itdb_iTunesDB *itdb, const So } // Pick one at random +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + const int dir_num = QRandomGenerator::global()->bounded(total_musicdirs); +#else const int dir_num = qrand() % total_musicdirs; +#endif + QString dir = QString::asprintf("/iTunes_Control/Music/F%02d", dir_num); if (!Exists(dir)) { diff --git a/src/device/imobiledeviceconnection.h b/src/device/imobiledeviceconnection.h index 9959775b..a6bff221 100644 --- a/src/device/imobiledeviceconnection.h +++ b/src/device/imobiledeviceconnection.h @@ -38,7 +38,7 @@ class iMobileDeviceConnection { public: - explicit iMobileDeviceConnection(const QString &uuid); + explicit iMobileDeviceConnection(const QString uuid); ~iMobileDeviceConnection(); afc_client_t afc() { return afc_; } diff --git a/src/device/mtpdevice.h b/src/device/mtpdevice.h index 4e6533f3..f93b88c4 100644 --- a/src/device/mtpdevice.h +++ b/src/device/mtpdevice.h @@ -51,7 +51,7 @@ class MtpDevice : public ConnectedDevice { Q_INVOKABLE MtpDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time); ~MtpDevice(); - static QStringList url_schemes() { return QStringList() << "mtp" << "gphoto2"; } + static QStringList url_schemes() { return QStringList() << "mtp"; } bool Init(); void ConnectAsync();