Remove broken iPhone (libimobiledevice) support

Fixes #212
This commit is contained in:
Jonas Kvinge 2020-08-14 21:38:08 +02:00
parent d3664dcf78
commit 171575256c
23 changed files with 5 additions and 1456 deletions

View File

@ -95,9 +95,7 @@ commands:
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libplist-devel
libmtp-devel
libusbmuxd-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
@ -149,8 +147,6 @@ commands:
taglib-devel
libcdio-devel
libgpod-devel
libplist-devel
libusbmuxd-devel
libmtp-devel
libchromaprint-devel
fftw-devel
@ -213,8 +209,6 @@ commands:
libchromaprint-devel
libcdio-devel
libgpod-devel
libplist-devel
libusbmuxd-devel
libmtp-devel
libjpeg-devel
cairo-devel
@ -280,8 +274,6 @@ commands:
lib64gstreamer-plugins-base1.0-devel
lib64cdio-devel
lib64gpod-devel
lib64plist-devel
lib64usbmuxd-devel
lib64mtp-devel
lib64raw1394-devel
lib64chromaprint-devel
@ -335,9 +327,6 @@ commands:
libcdio-dev
libmtp-dev
libgpod-dev
libimobiledevice-dev
libplist-dev
libusbmuxd-dev
install_ubuntu_dependencies:
@ -389,9 +378,6 @@ commands:
libcdio-dev
libmtp-dev
libgpod-dev
libimobiledevice-dev
libplist-dev
libusbmuxd-dev
jobs:

View File

@ -53,9 +53,7 @@ jobs:
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libplist-devel
libmtp-devel
libusbmuxd-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
@ -123,9 +121,7 @@ jobs:
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libplist-devel
libmtp-devel
libusbmuxd-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
@ -201,9 +197,7 @@ jobs:
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libplist-devel
libmtp-devel
libusbmuxd-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
@ -281,9 +275,7 @@ jobs:
libqt5-linguist-devel
libcdio-devel
libgpod-devel
libplist-devel
libmtp-devel
libusbmuxd-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
@ -363,9 +355,7 @@ jobs:
qt6-qt5compat-devel
libcdio-devel
libgpod-devel
libplist-devel
libmtp-devel
libusbmuxd-devel
libchromaprint-devel
desktop-file-utils
update-desktop-files
@ -434,8 +424,6 @@ jobs:
taglib-devel
libcdio-devel
libgpod-devel
libplist-devel
libusbmuxd-devel
libmtp-devel
libchromaprint-devel
fftw-devel
@ -518,8 +506,6 @@ jobs:
libchromaprint-devel
libcdio-devel
libgpod-devel
libplist-devel
libusbmuxd-devel
libmtp-devel
libjpeg-devel
cairo-devel
@ -607,8 +593,6 @@ jobs:
lib64gstreamer-plugins-base1.0-devel
lib64cdio-devel
lib64gpod-devel
lib64plist-devel
lib64usbmuxd-devel
lib64mtp-devel
lib64raw1394-devel
lib64chromaprint-devel
@ -684,9 +668,6 @@ jobs:
libcdio-dev
libmtp-dev
libgpod-dev
libimobiledevice-dev
libplist-dev
libusbmuxd-dev
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
@ -743,9 +724,6 @@ jobs:
libcdio-dev
libmtp-dev
libgpod-dev
libimobiledevice-dev
libplist-dev
libusbmuxd-dev
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
@ -807,9 +785,6 @@ jobs:
libcdio-dev
libmtp-dev
libgpod-dev
libimobiledevice-dev
libplist-dev
libusbmuxd-dev
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
@ -871,9 +846,6 @@ jobs:
libcdio-dev
libmtp-dev
libgpod-dev
libimobiledevice-dev
libplist-dev
libusbmuxd-dev
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
@ -935,9 +907,6 @@ jobs:
libcdio-dev
libmtp-dev
libgpod-dev
libimobiledevice-dev
libplist-dev
libusbmuxd-dev
- name: Create Build Environment
shell: bash
run: cmake -E make_directory build
@ -980,8 +949,6 @@ jobs:
gst-libav
libcdio
libmtp
libimobiledevice
libplist
create-dmg
taglib
@ -1045,7 +1012,6 @@ jobs:
-DENABLE_WIN32_CONSOLE=OFF
-DENABLE_DBUS=OFF
-DENABLE_LIBGPOD=OFF
-DENABLE_IMOBILEDEVICE=OFF
-DENABLE_LIBMTP=OFF
-DProtobuf_PROTOC_EXECUTABLE=/usr/src/strawberry-mxe/usr/x86_64-pc-linux-gnu/bin/protoc

View File

@ -23,7 +23,7 @@ before_install:
brew unlink python@2 || travis_terminate 1;
brew install glib pkgconfig libffi protobuf protobuf-c qt gettext gnutls fftw sqlite chromaprint zlib taglib;
brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav;
brew install libcdio libmtp libimobiledevice libplist;
brew install libcdio libmtp;
brew install create-dmg;
brew cask install sparkle;
sudo ln -s /usr/local/Caskroom/sparkle/$(ls /usr/local/Caskroom/sparkle | head -n1)/Sparkle.framework /Library/Frameworks/Sparkle.framework;

View File

@ -126,9 +126,6 @@ pkg_check_modules(LIBPULSE libpulse)
pkg_check_modules(CHROMAPRINT libchromaprint)
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0)
pkg_check_modules(LIBIMOBILEDEVICE libimobiledevice-1.0)
pkg_search_module(LIBUSBMUXD libusbmuxd-2.0 libusbmuxd)
pkg_search_module(LIBPLIST libplist-2.0 libplist)
find_package(Gettext)
find_package(FFTW3)
@ -344,13 +341,6 @@ optional_component(LIBMTP ON "Devices: MTP support"
DEPENDS "libmtp" LIBMTP_FOUND
)
optional_component(IMOBILEDEVICE ON "Devices: iPhone, iPod Touch, iPad and Apple TV support"
DEPENDS "libimobiledevice" LIBIMOBILEDEVICE_FOUND
DEPENDS "libplist" LIBPLIST_FOUND
DEPENDS "libusbmuxd" LIBUSBMUXD_FOUND
DEPENDS "libgpod" HAVE_LIBGPOD
)
optional_component(SPARKLE ON "Sparkle integration"
DEPENDS "macOS" APPLE
DEPENDS "Sparkle" SPARKLE

View File

@ -36,6 +36,7 @@ Unreleased:
Removed features:
* Removed Xine engine support.
* Removed broken imobiledevice (iPhone) support.
0.6.13:

View File

@ -44,7 +44,7 @@ You can also make a one-time payment through [paypal.me/jonaskvinge](https://pay
* Support for multiple backends
* Audio analyzer
* Audio equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Transfer music to iPod, MTP or mass-storage USB player
* Scrobbler with support for [Last.fm](https://www.last.fm/), [Libre.fm](https://libre.fm/) and [ListenBrainz](https://listenbrainz.org/)
* Subsonic and Tidal streaming support
@ -78,7 +78,6 @@ Optional dependencies:
* Audio CD: [libcdio](https://www.gnu.org/software/libcdio/)
* MTP devices: [libmtp](http://libmtp.sourceforge.net/)
* iPod Classic devices: [libgpod](http://www.gtkpod.org/libgpod/)
* iPhone, iPod Touch, iPad and Apple TV devices: [libimobiledevice, libplist and libusbmuxd](https://www.libimobiledevice.org/)
* Moodbar: [fftw3](http://www.fftw.org/)
Either GStreamer or VLC engine is required, but only GStreamer is fully implemented so far.

3
debian/control vendored
View File

@ -24,10 +24,7 @@ Build-Depends: debhelper (>= 11),
libgstreamer-plugins-base1.0-dev,
libcdio-dev,
libgpod-dev,
libimobiledevice-dev,
libmtp-dev,
libplist-dev,
libusbmuxd-dev,
libchromaprint-dev,
libfftw3-dev
Standards-Version: 4.2.1

View File

@ -28,9 +28,6 @@ depends=(
libgpod
libcdio
libmtp
libusbmuxd
libplist
libimobiledevice
fftw
)
optdepends=(

View File

@ -106,7 +106,7 @@ Features:
- Support for multiple backends
- Audio analyzer
- Audio equalizer
- Transfer music to iPod, iPhone, MTP or mass-storage USB player
- Transfer music to iPod, MTP or mass-storage USB player
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
- Streaming support for Subsonic

View File

@ -101,11 +101,8 @@ parts:
- libgstreamer-plugins-base1.0-dev
- libvlc-dev
- libcdio-dev
- libgpod-dev
- libimobiledevice-dev
- libgpod-devdev
- libmtp-dev
- libplist-dev
- libusbmuxd-dev
- libchromaprint-dev
- libfftw3-dev
@ -131,9 +128,6 @@ parts:
- libcdio17
- libgpod4
- libmtp9
- libimobiledevice6
- libplist3
- libusbmuxd4
- libvlc5
- libvlccore9
- libtag1v5

View File

@ -737,21 +737,6 @@ optional_source(HAVE_GIO
HEADERS device/giolister.h
)
# imobiledevice backend and device
optional_source(HAVE_IMOBILEDEVICE
SOURCES
device/afcdevice.cpp
device/afcfile.cpp
device/afctransfer.cpp
device/ilister.cpp
device/imobiledeviceconnection.cpp
HEADERS
device/afcdevice.h
device/afcfile.h
device/afctransfer.h
device/ilister.h
)
# mtp device
optional_source(HAVE_LIBMTP
SOURCES
@ -1035,14 +1020,6 @@ if(HAVE_LIBMTP)
link_directories(${LIBMTP_LIBRARY_DIRS})
endif(HAVE_LIBMTP)
if(HAVE_IMOBILEDEVICE)
link_directories(
${LIBUSBMUXD_LIBRARY_DIRS}
${LIBPLIST_LIBRARY_DIRS}
${LIBIMOBILEDEVICE_LIBRARY_DIRS}
)
endif(HAVE_IMOBILEDEVICE)
add_library(strawberry_lib STATIC
${SOURCES}
${MOC}
@ -1163,19 +1140,6 @@ if(HAVE_LIBMTP)
target_link_libraries(strawberry_lib PRIVATE ${LIBMTP_LIBRARIES})
endif(HAVE_LIBMTP)
if(HAVE_IMOBILEDEVICE)
target_include_directories(strawberry_lib SYSTEM PRIVATE
${LIBUSBMUXD_INCLUDE_DIRS}
${LIBPLIST_INCLUDE_DIRS}
${LIBIMOBILEDEVICE_INCLUDE_DIRS}
)
target_link_libraries(strawberry_lib PRIVATE
${LIBUSBMUXD_LIBRARIES}
${LIBPLIST_LIBRARIES}
${LIBIMOBILEDEVICE_LIBRARIES}
)
endif(HAVE_IMOBILEDEVICE)
if(APPLE)
target_link_libraries(strawberry_lib PRIVATE

View File

@ -31,7 +31,6 @@
#cmakedefine HAVE_X11
#cmakedefine HAVE_UDISKS2
#cmakedefine HAVE_ALSA
#cmakedefine HAVE_IMOBILEDEVICE
#cmakedefine HAVE_AUDIOCD
#cmakedefine HAVE_LIBGPOD
#cmakedefine HAVE_LIBMTP

View File

@ -1,213 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <memory>
#include <QThread>
#include <QFile>
#include <QList>
#include <QString>
#include <QUrl>
#include "core/application.h"
#include "core/utilities.h"
#include "core/song.h"
#include "afcdevice.h"
#include "afcfile.h"
#include "afctransfer.h"
#include "devicemanager.h"
#include "gpodloader.h"
#include "imobiledeviceconnection.h"
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() {
// Make a new temporary directory for the iTunesDB. We copy it off the iPod so that libgpod can have a local directory to use.
local_path_ = Utilities::MakeTempDir();
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();
return true;
}
void AfcDevice::CopyFinished(const bool success) {
transfer_->deleteLater();
transfer_ = nullptr;
if (!success) {
app_->AddError(tr("An error occurred copying the iTunes database from the device"));
return;
}
// 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::FileType_Stream);
loader_->moveToThread(loader_thread_);
connect(loader_, SIGNAL(Error(QString)), SLOT(LoaderError(QString)));
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
connect(loader_, SIGNAL(LoadFinished(Itdb_iTunesDB*, bool)), SLOT(LoadFinished(Itdb_iTunesDB*, bool)));
QMetaObject::invokeMethod(loader_, "LoadDatabase");
}
bool AfcDevice::StartCopy(QList<Song::FileType> *supported_types) {
GPodDevice::StartCopy(supported_types);
connection_.reset(new iMobileDeviceConnection(url_.host()));
return true;
}
bool AfcDevice::CopyToStorage(const CopyJob &job) {
Q_ASSERT(db_);
Itdb_Track *track = AddTrackToITunesDb(job.metadata_);
// Get an unused filename on the device
QString dest = connection_->GetUnusedFilename(db_, job.metadata_);
if (dest.isEmpty()) {
itdb_track_remove(track);
return false;
}
// Copy the file
{
QFile source_file(job.source_);
AfcFile dest_file(connection_.get(), dest);
if (!Utilities::Copy(&source_file, &dest_file))
return false;
}
track->transferred = 1;
// Set the filetype_marker
QString suffix = dest.section('.', -1, -1).toUpper();
track->filetype_marker = 0;
for (int i=0 ; i<4 ; ++i) {
track->filetype_marker = track->filetype_marker << 8;
if (i >= suffix.length())
track->filetype_marker |= ' ';
else
track->filetype_marker |= suffix[i].toLatin1();
}
// Set the filename
track->ipod_path = strdup(dest.toUtf8().constData());
itdb_filename_fs2ipod(track->ipod_path);
AddTrackToModel(track, "afc://" + url_.host());
// Remove the original if it was requested
if (job.remove_original_) {
QFile::remove(job.source_);
}
return true;
}
void AfcDevice::FinishCopy(bool success) {
// Temporarily unset the GUID so libgpod doesn't lock the device for syncing
itdb_device_set_sysinfo(db_->device, "FirewireGuid", nullptr);
GPodDevice::FinishCopy(success);
// Close the connection to the device
connection_.reset();
}
void AfcDevice::FinaliseDatabase() {
// Set the GUID again to lock the device for syncing
itdb_device_set_sysinfo(db_->device, "FirewireGuid", url_.host().toUtf8().constData());
// Copy the files back to the iPod
// No need to start another thread since we're already in the organizer thread
AfcTransfer transfer(url_.host(), local_path_, nullptr, shared_from_this());
itdb_start_sync(db_);
bool success = transfer.CopyToDevice(connection_.get());
itdb_stop_sync(db_);
if (!success) {
app_->AddError(tr("An error occurred copying the iTunes database onto the device"));
return;
}
}
bool AfcDevice::DeleteFromStorage(const DeleteJob &job) {
const QString path = job.metadata_.url().toLocalFile();
if (!RemoveTrackFromITunesDb(path))
return false;
// Remove the file
if (afc_remove_path(connection_->afc(), path.toUtf8().constData()) != AFC_E_SUCCESS)
return false;
// Remove it from our collection model
songs_to_remove_ << job.metadata_;
return true;
}

View File

@ -1,75 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AFCDEVICE_H
#define AFCDEVICE_H
#include "config.h"
#include <memory>
#include <gpod/itdb.h>
#include <QObject>
#include <QMutex>
#include <QList>
#include <QString>
#include <QStringList>
#include <QUrl>
#include "gpoddevice.h"
class AfcTransfer;
class iMobileDeviceConnection;
class AfcDevice : public GPodDevice {
Q_OBJECT
public:
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() override;
bool Init() override;
static QStringList url_schemes() { return QStringList() << "afc"; }
bool StartCopy(QList<Song::FileType> *supported_types) override;
bool CopyToStorage(const CopyJob &job) override;
void FinishCopy(const bool success) override;
bool DeleteFromStorage(const DeleteJob &job) override;
protected:
void FinaliseDatabase() override;
private slots:
void CopyFinished(bool success);
private:
void RemoveRecursive(const QString &path);
private:
AfcTransfer *transfer_;
std::shared_ptr<iMobileDeviceConnection> connection_;
QString local_path_;
};
#endif // AFCDEVICE_H

View File

@ -1,95 +0,0 @@
#include "config.h"
#include <libimobiledevice/afc.h>
#include <QtGlobal>
#include <QObject>
#include <QIODevice>
#include <QString>
#include "afcfile.h"
#include "imobiledeviceconnection.h"
AfcFile::AfcFile(iMobileDeviceConnection *connection, const QString &path, QObject *parent)
: QIODevice(parent),
connection_(connection),
handle_(0),
path_(path)
{
}
AfcFile::~AfcFile() {
close();
}
bool AfcFile::open(QIODevice::OpenMode mode) {
afc_file_mode_t afc_mode;
switch (mode) {
case ReadOnly:
afc_mode = AFC_FOPEN_RDONLY;
break;
case WriteOnly:
afc_mode = AFC_FOPEN_WRONLY;
break;
case ReadWrite:
afc_mode = AFC_FOPEN_RW;
break;
default:
afc_mode = AFC_FOPEN_RW;
}
afc_error_t err = afc_file_open(connection_->afc(), path_.toUtf8().constData(), afc_mode, &handle_);
if (err != AFC_E_SUCCESS) {
return false;
}
return QIODevice::open(mode);
}
void AfcFile::close() {
if (handle_) {
afc_file_close(connection_->afc(), handle_);
}
QIODevice::close();
}
bool AfcFile::seek(qint64 pos) {
afc_error_t err = afc_file_seek(connection_->afc(), handle_, pos, SEEK_SET);
if (err != AFC_E_SUCCESS) {
return false;
}
QIODevice::seek(pos);
return true;
}
qint64 AfcFile::readData(char *data, qint64 max_size) {
uint32_t bytes_read = 0;
afc_error_t err = afc_file_read(connection_->afc(), handle_, data, max_size, &bytes_read);
if (err != AFC_E_SUCCESS) {
return -1;
}
return bytes_read;
}
qint64 AfcFile::writeData(const char *data, qint64 max_size) {
uint32_t bytes_written = 0;
afc_error_t err = afc_file_write(connection_->afc(), handle_, data, max_size, &bytes_written);
if (err != AFC_E_SUCCESS) {
return -1;
}
return bytes_written;
}
qint64 AfcFile::size() const {
return connection_->GetFileInfo(path_, "st_size").toLongLong();
}

View File

@ -1,40 +0,0 @@
#ifndef AFCFILE_H
#define AFCFILE_H
#include "config.h"
#include <cstdint>
#include <libimobiledevice/afc.h>
#include <QtGlobal>
#include <QObject>
#include <QIODevice>
#include <QString>
class iMobileDeviceConnection;
class AfcFile : public QIODevice {
Q_OBJECT
public:
explicit AfcFile(iMobileDeviceConnection* connection, const QString &path, QObject *parent = nullptr);
~AfcFile() override;
// QIODevice
void close() override;
bool open(OpenMode mode) override;
bool seek(qint64 pos) override;
qint64 size() const override;
private:
// QIODevice
qint64 readData(char *data, qint64 max_size) override;
qint64 writeData(const char *data, qint64 max_size) override;
iMobileDeviceConnection *connection_;
uint64_t handle_;
QString path_;
};
#endif

View File

@ -1,150 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <memory>
#include <QObject>
#include <QDir>
#include <QFile>
#include <QString>
#include <QtDebug>
#include "core/utilities.h"
#include "core/taskmanager.h"
#include "afcfile.h"
#include "afctransfer.h"
#include "imobiledeviceconnection.h"
AfcTransfer::AfcTransfer(const QString &uuid, const QString &local_destination, TaskManager *task_manager, std::shared_ptr<ConnectedDevice> device)
: QObject(nullptr), device_(device), task_manager_(task_manager), uuid_(uuid), local_destination_(local_destination) {
original_thread_ = thread();
important_directories_ << "/iTunes_Control/Artwork";
important_directories_ << "/iTunes_Control/Device";
important_directories_ << "/iTunes_Control/iTunes";
}
void AfcTransfer::CopyFromDevice() {
int task_id = 0;
if (task_manager_) {
task_id = task_manager_->StartTask(tr("Copying iPod database"));
emit TaskStarted(task_id);
}
// Connect to the device
iMobileDeviceConnection c(uuid_);
// Copy directories. If one fails we stop.
bool success = true;
for (const QString &dir : important_directories_) {
if (!CopyDirFromDevice(&c, dir)) {
success = false;
break;
}
}
if (task_manager_) {
moveToThread(original_thread_);
task_manager_->SetTaskFinished(task_id);
emit CopyFinished(success);
}
}
bool AfcTransfer::CopyToDevice(iMobileDeviceConnection *connection) {
// Connect to the device
if (!connection)
connection = new iMobileDeviceConnection(uuid_);
for (const QString &dir : important_directories_)
if (!CopyDirToDevice(connection, dir))
return false;
return true;
}
bool AfcTransfer::CopyDirFromDevice(iMobileDeviceConnection *c, const QString &path) {
for (const QString &filename : c->ReadDirectory(path, QDir::Files | QDir::NoDotAndDotDot)) {
if (!CopyFileFromDevice(c, path + "/" + filename))
return false;
}
for (const QString &dir : c->ReadDirectory(path, QDir::Dirs | QDir::NoDotAndDotDot)) {
if (!CopyDirFromDevice(c, path + "/" + dir))
return false;
}
return true;
}
bool AfcTransfer::CopyDirToDevice(iMobileDeviceConnection *c, const QString &path) {
QDir dir(local_destination_ + path);
if (!c->Exists(path)) {
c->MkDir(path);
}
for (const QString &i : dir.entryList(QDir::Files | QDir::NoDotAndDotDot)) {
if (!CopyFileToDevice(c, path + "/" + i))
return false;
}
for (const QString &i : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
if (!CopyDirToDevice(c, path + "/" + i))
return false;
}
return true;
}
bool AfcTransfer::CopyFileFromDevice(iMobileDeviceConnection *c, const QString &path) {
QString local_filename = local_destination_ + path;
QString local_dir = local_filename.section('/', 0, -2);
QDir d;
d.mkpath(local_dir);
QFile dest(local_filename);
AfcFile source(c, path);
return Utilities::Copy(&source, &dest);
}
bool AfcTransfer::CopyFileToDevice(iMobileDeviceConnection *c, const QString &path) {
QFile source(local_destination_ + path);
AfcFile dest(c, path);
return Utilities::Copy(&source, &dest);
}

View File

@ -1,70 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AFCTRANSFER_H
#define AFCTRANSFER_H
#include "config.h"
#include <memory>
#include <QObject>
#include <QThread>
#include <QIODevice>
#include <QString>
#include <QStringList>
class TaskManager;
class ConnectedDevice;
class iMobileDeviceConnection;
class AfcTransfer : public QObject {
Q_OBJECT
public:
explicit AfcTransfer(const QString &uuid, const QString &local_destination, TaskManager *task_manager, std::shared_ptr<ConnectedDevice> device);
bool CopyToDevice(iMobileDeviceConnection *connection);
public slots:
void CopyFromDevice();
signals:
void TaskStarted(int task_id);
void CopyFinished(bool success);
private:
bool CopyDirFromDevice(iMobileDeviceConnection *c, const QString &path);
bool CopyDirToDevice(iMobileDeviceConnection *c, const QString &path);
bool CopyFileFromDevice(iMobileDeviceConnection *c, const QString &path);
bool CopyFileToDevice(iMobileDeviceConnection *c, const QString &path);
private:
QThread *original_thread_;
std::shared_ptr<ConnectedDevice> device_;
TaskManager *task_manager_;
QString uuid_;
QString local_destination_;
QStringList important_directories_;
};
#endif // AFCTRANSFER_H

View File

@ -73,10 +73,6 @@
#ifdef HAVE_LIBMTP
# include "mtpdevice.h"
#endif
#ifdef HAVE_IMOBILEDEVICE
# include "afcdevice.h"
# include "ilister.h"
#endif
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
# include "macosdevicelister.h"
#endif
@ -125,9 +121,6 @@ DeviceManager::DeviceManager(Application *app, QObject *parent)
#if defined(Q_OS_MACOS) and defined(HAVE_LIBMTP)
AddLister(new MacOsDeviceLister);
#endif
#ifdef HAVE_IMOBILEDEVICE
AddLister(new iLister);
#endif
#if defined(HAVE_AUDIOCD) && defined(HAVE_GSTREAMER)
AddDeviceClass<CddaDevice>();
@ -143,10 +136,6 @@ DeviceManager::DeviceManager(Application *app, QObject *parent)
AddDeviceClass<MtpDevice>();
#endif
#ifdef HAVE_IMOBILEDEVICE
AddDeviceClass<AfcDevice>();
#endif
}
DeviceManager::~DeviceManager() {

View File

@ -1,239 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <QtGlobal>
#include <QMutex>
#include <QList>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QtDebug>
#include "ilister.h"
#include "imobiledeviceconnection.h"
iLister::iLister() {}
iLister::~iLister() {}
bool iLister::Init() {
idevice_event_subscribe(&EventCallback, reinterpret_cast<void*>(this));
return true;
}
void iLister::EventCallback(const idevice_event_t *event, void *context) {
iLister *me = reinterpret_cast<iLister*>(context);
QString uuid = QString::fromUtf8(event->udid);
switch (event->event) {
case IDEVICE_DEVICE_ADD:
me->DeviceAddedCallback(uuid);
break;
case IDEVICE_DEVICE_REMOVE:
me->DeviceRemovedCallback(uuid);
break;
default:
break;
}
}
void iLister::DeviceAddedCallback(const QString uuid) {
DeviceInfo info = ReadDeviceInfo(uuid);
if (!info.valid) return;
QString id = UniqueId(uuid);
QString name = MakeFriendlyName(id);
if (info.product_type == "iPhone 3,1" || info.product_type.startsWith("iPad")) {
// iPhone 4 and iPad unsupported by libgpod as of 0.7.94.
return;
}
{
QMutexLocker l(&mutex_);
devices_[id] = info;
}
emit DeviceAdded(id);
}
void iLister::DeviceRemovedCallback(const QString uuid) {
QString id = UniqueId(uuid);
{
QMutexLocker l(&mutex_);
if (!devices_.contains(id))
return;
devices_.remove(id);
}
emit DeviceRemoved(id);
}
QString iLister::UniqueId(const QString uuid) {
return "ithing/" + uuid;
}
QStringList iLister::DeviceUniqueIDs() {
return devices_.keys();
}
QVariantList iLister::DeviceIcons(const QString &id) {
Q_UNUSED(id);
return QVariantList() << "ipodtouchicon";
}
QString iLister::DeviceManufacturer(const QString &id) {
Q_UNUSED(id);
return "Apple";
}
QString iLister::DeviceModel(const QString &id) {
return LockAndGetDeviceInfo(id, &DeviceInfo::product_type);
}
quint64 iLister::DeviceCapacity(const QString &id) {
return LockAndGetDeviceInfo(id, &DeviceInfo::total_bytes);
}
quint64 iLister::DeviceFreeSpace(const QString &id) {
return LockAndGetDeviceInfo(id, &DeviceInfo::free_bytes);
}
QVariantMap iLister::DeviceHardwareInfo(const QString &id) {
QVariantMap ret;
ret[tr("Color")] = LockAndGetDeviceInfo(id, &DeviceInfo::colour);
ret["IMEI"] = LockAndGetDeviceInfo(id, &DeviceInfo::imei);
ret[tr("Password Protected")] = LockAndGetDeviceInfo(id, &DeviceInfo::password_protected);
ret[tr("Timezone")] = LockAndGetDeviceInfo(id, &DeviceInfo::timezone);
ret[tr("WiFi MAC Address")] = LockAndGetDeviceInfo(id, &DeviceInfo::wifi_mac);
ret[tr("Bluetooth MAC Address")] = LockAndGetDeviceInfo(id, &DeviceInfo::bt_mac);
return ret;
}
QString iLister::MakeFriendlyName(const QString &id) {
QString name = LockAndGetDeviceInfo(id, &DeviceInfo::name);
if (!name.isEmpty()) {
return name;
}
QString model_id = LockAndGetDeviceInfo(id, &DeviceInfo::product_type);
if (model_id.startsWith("iPhone")) {
QString version = model_id.right(3);
QChar major = version[0];
QChar minor = version[2];
if (major == '1' && minor == '1') {
return "iPhone";
}
if (major == '1' && minor == '2') {
return "iPhone 3G";
}
if (major == '2' && minor == '1') {
return "iPhone 3GS";
}
if (major == '3' && minor == '1') {
return "iPhone 4";
}
}
else if (model_id.startsWith("iPod")) {
return "iPod Touch";
}
else if (model_id.startsWith("iPad")) {
return "iPad";
}
return model_id;
}
QList<QUrl> iLister::MakeDeviceUrls(const QString &id) {
QList<QUrl> ret;
QString uuid = LockAndGetDeviceInfo(id, &DeviceInfo::uuid);
if (uuid.isEmpty())
return ret;
ret << QUrl("afc://" + uuid + "/");
return ret;
}
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();
ret.free_bytes = conn.GetProperty("AmountDataAvailable", "com.apple.disk_usage").toULongLong();
ret.total_bytes = conn.GetProperty("TotalDataCapacity", "com.apple.disk_usage").toULongLong();
ret.name = conn.GetProperty("DeviceName").toString();
ret.colour = conn.GetProperty("DeviceColor").toString();
ret.imei = conn.GetProperty("InternationalMobileEquipmentIdentity").toString();
ret.hardware = conn.GetProperty("HardwareModel").toString();
ret.password_protected = conn.GetProperty("PasswordProtected").toBool();
ret.os_version = conn.GetProperty("ProductVersion").toString();
ret.timezone = conn.GetProperty("TimeZone").toString();
ret.wifi_mac = conn.GetProperty("WiFiAddress").toString();
ret.bt_mac = conn.GetProperty("BluetoothAddress").toString();
return ret;
}
void iLister::UpdateDeviceFreeSpace(const QString &id) {
{
QMutexLocker l(&mutex_);
if (!devices_.contains(id))
return;
DeviceInfo &info = devices_[id];
iMobileDeviceConnection conn(info.uuid);
info.free_bytes = conn.GetProperty("AmountDataAvailable", "com.apple.disk_usage").toULongLong();
}
emit DeviceChanged(id);
}

View File

@ -1,110 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ILISTER_H
#define ILISTER_H
#include "config.h"
#include <libimobiledevice/libimobiledevice.h>
#include <QtGlobal>
#include <QObject>
#include <QMutex>
#include <QMap>
#include <QList>
#include <QString>
#include <QStringList>
#include "devicelister.h"
class iLister : public DeviceLister {
Q_OBJECT
public:
explicit iLister();
~iLister() override;
int priority() const override { return 120; }
QStringList DeviceUniqueIDs() override;
QVariantList DeviceIcons(const QString &id) override;
QString DeviceManufacturer(const QString &id) override;
QString DeviceModel(const QString &id) override;
quint64 DeviceCapacity(const QString &id) override;
quint64 DeviceFreeSpace(const QString &id) override;
QVariantMap DeviceHardwareInfo(const QString &id) override;
QString MakeFriendlyName(const QString &id) override;
QList<QUrl> MakeDeviceUrls(const QString &id) override;
public slots:
void UpdateDeviceFreeSpace(const QString &id) override;
private:
struct DeviceInfo {
DeviceInfo() : valid(false), free_bytes(0), total_bytes(0), password_protected(false) {}
bool valid;
QString uuid;
QString product_type;
quint64 free_bytes;
quint64 total_bytes;
QString name; // Name given to the iDevice by the user.
// Extra information.
QString colour;
QString imei;
QString hardware;
bool password_protected;
QString os_version;
QString timezone;
QString wifi_mac;
QString bt_mac;
};
bool Init() override;
static void EventCallback(const idevice_event_t *event, void *context);
void DeviceAddedCallback(const QString uuid);
void DeviceRemovedCallback(const QString uuid);
DeviceInfo ReadDeviceInfo(const QString uuid);
static QString UniqueId(const QString uuid);
template <typename T>
T LockAndGetDeviceInfo(const QString &id, T DeviceInfo::*field);
private:
QMutex mutex_;
QMap<QString, DeviceInfo> devices_;
};
template <typename T>
T iLister::LockAndGetDeviceInfo(const QString &id, T DeviceInfo::*field) {
QMutexLocker l(&mutex_);
if (!devices_.contains(id))
return T();
return devices_[id].*field;
}
#endif

View File

@ -1,277 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <plist/plist.h>
#include <libimobiledevice/afc.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <QCoreApplication>
#include <QDir>
#include <QByteArray>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QtDebug>
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
# include <QRandomGenerator>
#endif
#include "core/logging.h"
#include "imobiledeviceconnection.h"
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_new error:" << err;
return;
}
QByteArray label_ascii = QCoreApplication::applicationName().toUtf8();
const char *label = label_ascii.constData();
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) << "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) << "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_client_new error:" << afc_err;
lockdownd_client_free(lockdown);
return;
}
lockdownd_client_free(lockdown);
}
iMobileDeviceConnection::~iMobileDeviceConnection() {
if (afc_) {
afc_client_free(afc_);
}
if (device_) {
idevice_free(device_);
}
}
template <typename T, typename F>
T GetPListValue(plist_t node, F f) {
T ret;
f(node, &ret);
return ret;
}
QVariant iMobileDeviceConnection::GetProperty(const QString &property, const QString &domain) {
if (!device_) return QVariant();
lockdownd_client_t lockdown;
QByteArray label_ascii = QCoreApplication::applicationName().toUtf8();
const char *label = label_ascii.constData();
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;
return QVariant();
}
plist_t node = nullptr;
QByteArray domain_ascii = domain.toUtf8();
const char *d = domain_ascii.isEmpty() ? nullptr : domain_ascii.constData();
//const char *d = domain.isEmpty() ? nullptr : "com.apple.disk_usage";
lockdownd_get_value(lockdown, d, property.toUtf8().constData(), &node);
lockdownd_client_free(lockdown);
if (!node) {
qLog(Warning) << "get_value failed" << property << domain;
return QVariant();
}
switch (plist_get_node_type(node)) {
case PLIST_BOOLEAN:
return bool(GetPListValue<quint8>(node, plist_get_bool_val));
case PLIST_UINT:
return QVariant::fromValue(GetPListValue<uint64_t>(node, plist_get_uint_val));
case PLIST_STRING: {
char *data = GetPListValue<char*>(node, plist_get_string_val);
QString ret = QString::fromUtf8(data);
free(data);
return ret;
}
default:
qLog(Warning) << "Unhandled PList type";
return QVariant();
}
}
QStringList iMobileDeviceConnection::ReadDirectory(const QString &path, QDir::Filters filters) {
if (!afc_) return QStringList();
char **list = nullptr;
afc_error_t err = afc_read_directory(afc_, path.toUtf8().constData(), &list);
if (err != AFC_E_SUCCESS || !list) {
return QStringList();
}
QStringList ret;
for (char **p = list ; *p != nullptr ; ++p) {
QString filename = QString::fromUtf8(*p);
free(*p);
if (filters == QDir::NoFilter)
ret << filename;
else {
if (filters & QDir::NoDotAndDotDot && (filename == "." || filename == ".."))
continue;
if (!(filters & QDir::Hidden) && filename.startsWith("."))
continue;
QString filetype = GetFileInfo(path + "/" + filename, "st_ifmt");
if ((filetype == "S_IFREG" && (filters & QDir::Files)) || (filetype == "S_IFDIR" && (filters & QDir::Dirs)) || (filetype == "S_IFLNK" && (!(filters & QDir::NoSymLinks))))
ret << filename;
}
}
free(list);
return ret;
}
bool iMobileDeviceConnection::MkDir(const QString &path) {
if (!afc_) return false;
afc_error_t err = afc_make_directory(afc_, path.toUtf8().constData());
return err == AFC_E_SUCCESS;
}
QString iMobileDeviceConnection::GetFileInfo(const QString &path, const QString &key) {
if (!afc_) return QString();
QString ret;
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;
}
QString last_key;
for (char **p = infolist ; *p != nullptr ; ++p) {
if (last_key.isNull()) {
last_key = QString::fromUtf8(*p);
}
else {
if (last_key == key)
ret = QString::fromUtf8(*p);
last_key = QString();
}
free(*p);
}
free(infolist);
return ret;
}
bool iMobileDeviceConnection::Exists(const QString &path) {
return !GetFileInfo(path, "st_ifmt").isNull();
}
QString iMobileDeviceConnection::GetUnusedFilename(Itdb_iTunesDB *itdb, const Song &metadata) {
Q_UNUSED(itdb);
// This function does the same as itdb_cp_get_dest_filename, except it accesses the device's filesystem through imobiledevice.
// Get the total number of F.. directories
int total_musicdirs = 0;
for ( ; ; ++total_musicdirs) {
QString dir = QString::asprintf("/iTunes_Control/Music/F%02d", total_musicdirs);
if (!Exists(dir))
break;
}
if (total_musicdirs <= 0) {
qLog(Warning) << "No 'F..'' directories found on iPod";
return QString();
}
// 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)) {
qLog(Warning) << "Music directory doesn't exist:" << dir;
return QString();
}
// Use the same file extension as the original file, default to mp3.
QString extension = metadata.url().path().section('.', -1, -1).toLower();
if (extension.isEmpty())
extension = "mp3";
// Loop until we find an unused filename.
// Use the same naming convention as libgpod, which is "libgpod" + 6-digit random number
static const int kRandMax = 999999;
QString filename;
forever {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
filename = QString::asprintf("libgpod%06d", QRandomGenerator::global()->bounded(kRandMax));
#else
filename = QString::asprintf("libgpod%06d", qrand() % kRandMax);
#endif
filename += "." + extension;
if (!Exists(dir + "/" + filename))
break;
}
return dir + "/" + filename;
}

View File

@ -1,64 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef IMOBILEDEVICECONNECTION_H
#define IMOBILEDEVICECONNECTION_H
#include "config.h"
#include <libimobiledevice/afc.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <gpod/itdb.h>
#include <QDir>
#include <QVariant>
#include <QString>
#include <QStringList>
#include "core/song.h"
class iMobileDeviceConnection {
public:
explicit iMobileDeviceConnection(const QString uuid);
~iMobileDeviceConnection();
afc_client_t afc() { return afc_; }
QVariant GetProperty(const QString &property, const QString &domain = QString());
QStringList ReadDirectory(const QString &path, QDir::Filters filters = QDir::NoFilter);
bool MkDir(const QString &path);
QString GetFileInfo(const QString &path, const QString &key);
bool Exists(const QString &path);
QString GetUnusedFilename(Itdb_iTunesDB *itdb, const Song &metadata);
bool is_valid() { return device_ && afc_; }
private:
Q_DISABLE_COPY(iMobileDeviceConnection)
idevice_t device_;
afc_client_t afc_;
};
#endif // IMOBILEDEVICECONNECTION_H