/* This file is part of Clementine. Copyright 2010, David Sansome Clementine 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. Clementine 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 Clementine. If not, see . */ #include "afcdevice.h" #include "afcfile.h" #include "afctransfer.h" #include "devicemanager.h" #include "gpodloader.h" #include "imobiledeviceconnection.h" #include "core/utilities.h" #include AfcDevice::AfcDevice( const QUrl& url, DeviceLister* lister, const QString& unique_id, DeviceManager* manager, int database_id, bool first_time) : GPodDevice(url, lister, unique_id, manager, database_id, first_time), transfer_(NULL) { } AfcDevice::~AfcDevice() { Utilities::RemoveRecursive(local_path_); } void 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(); transfer_ = new AfcTransfer(url_.host(), local_path_, manager_->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(); } void AfcDevice::CopyFinished(bool success) { transfer_->deleteLater(); transfer_ = NULL; if (!success) { emit Error(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_, manager_->task_manager(), backend_, shared_from_this()); loader_->set_music_path_prefix("afc://" + url_.host()); loader_->set_song_type(Song::Type_Stream); loader_->moveToThread(loader_thread_); connect(loader_, SIGNAL(Error(QString)), SIGNAL(Error(QString))); connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int))); connect(loader_, SIGNAL(LoadFinished(Itdb_iTunesDB*)), SLOT(LoadFinished(Itdb_iTunesDB*))); QMetaObject::invokeMethod(loader_, "LoadDatabase"); } bool AfcDevice::StartCopy(QList* 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].toAscii(); } // 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", NULL); 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 organiser thread AfcTransfer transfer(url_.host(), local_path_, NULL, shared_from_this()); itdb_start_sync(db_); bool success = transfer.CopyToDevice(connection_.get()); itdb_stop_sync(db_); if (!success) { emit Error(tr("An error occurred copying the iTunes database onto the device")); return; } } bool AfcDevice::DeleteFromStorage(const DeleteJob& job) { const QString path = QUrl(job.metadata_.filename()).path(); 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 library model songs_to_remove_ << job.metadata_; return true; }