diff --git a/src/qtlibtorrent/qbtsession.cpp b/src/qtlibtorrent/qbtsession.cpp index df6303524..1c133a499 100755 --- a/src/qtlibtorrent/qbtsession.cpp +++ b/src/qtlibtorrent/qbtsession.cpp @@ -2144,456 +2144,554 @@ void QBtSession::readAlerts() { void QBtSession::handleAlert(libtorrent::alert* a) { try { - if (torrent_finished_alert* p = dynamic_cast(a)) { - QTorrentHandle h(p->handle); - if (h.is_valid()) { - const QString hash = h.hash(); - qDebug("Got a torrent finished alert for %s", qPrintable(h.name())); - // Remove .!qB extension if necessary - if (appendqBExtension) - appendqBextensionToTorrent(h, false); - - const bool was_already_seeded = TorrentPersistentData::isSeed(hash); - qDebug("Was already seeded: %d", was_already_seeded); - if (!was_already_seeded) { - h.save_resume_data(); - qDebug("Checking if the torrent contains torrent files to download"); - // Check if there are torrent files inside - for (int i=0; i t = new torrent_info(fsutils::toNativePath(torrent_fullpath).toUtf8().constData()); - if (t->is_valid()) { - qDebug("emitting recursiveTorrentDownloadPossible()"); - emit recursiveTorrentDownloadPossible(h); - break; - } - } catch(std::exception&) { - qDebug("Caught error loading torrent"); - addConsoleMessage(tr("Unable to decode %1 torrent file.").arg(fsutils::toNativePath(torrent_fullpath)), QString::fromUtf8("red")); - } - } - } - // Move to download directory if necessary - if (!defaultTempPath.isEmpty()) { - // Check if directory is different - const QDir current_dir(h.save_path()); - const QDir save_dir(getSavePath(hash)); - if (current_dir != save_dir) { - qDebug("Moving torrent from the temp folder"); - h.move_storage(save_dir.absolutePath()); - } - } - // Remember finished state - qDebug("Saving seed status"); - TorrentPersistentData::saveSeedStatus(h); - // Recheck if the user asked to - Preferences pref; - if (pref.recheckTorrentsOnCompletion()) { - h.force_recheck(); - } - qDebug("Emitting finishedTorrent() signal"); - emit finishedTorrent(h); - qDebug("Received finished alert for %s", qPrintable(h.name())); -#ifndef DISABLE_GUI - bool will_shutdown = (pref.shutdownWhenDownloadsComplete() || - pref.shutdownqBTWhenDownloadsComplete() || - pref.suspendWhenDownloadsComplete()) - && !hasDownloadingTorrents(); -#else - bool will_shutdown = false; -#endif - // AutoRun program - if (pref.isAutoRunEnabled()) - autoRunExternalProgram(h); - // Move .torrent file to another folder - if (pref.isFinishedTorrentExportEnabled()) - exportTorrentFile(h, FinishedTorrentExportFolder); - // Mail notification - if (pref.isMailNotificationEnabled()) - sendNotificationEmail(h); -#ifndef DISABLE_GUI - // Auto-Shutdown - if (will_shutdown) { - bool suspend = pref.suspendWhenDownloadsComplete(); - bool shutdown = pref.shutdownWhenDownloadsComplete(); - // Confirm shutdown - QString confirm_msg; - if (suspend) { - confirm_msg = tr("The computer will now go to sleep mode unless you cancel within the next 15 seconds..."); - } else if (shutdown) { - confirm_msg = tr("The computer will now be switched off unless you cancel within the next 15 seconds..."); - } else { - confirm_msg = tr("qBittorrent will now exit unless you cancel within the next 15 seconds..."); - } - if (!ShutdownConfirmDlg::askForConfirmation(confirm_msg)) - return; - // Actually shut down - if (suspend || shutdown) { - qDebug("Preparing for auto-shutdown because all downloads are complete!"); - // Disabling it for next time - pref.setShutdownWhenDownloadsComplete(false); - pref.setSuspendWhenDownloadsComplete(false); - // Make sure preferences are synced before exiting - if (suspend) - m_shutdownAct = SUSPEND_COMPUTER; - else - m_shutdownAct = SHUTDOWN_COMPUTER; + switch (a->type()) { + case torrent_finished_alert::alert_type: + handleTorrentFinishedAlert(static_cast(a)); + break; + case save_resume_data_alert::alert_type: + handleSaveResumeDataAlert(static_cast(a)); + break; + case file_renamed_alert::alert_type: + handleFileRenamedAlert(static_cast(a)); + break; + case torrent_deleted_alert::alert_type: + handleTorrentDeletedAlert(static_cast(a)); + break; + case storage_moved_alert::alert_type: + handleStorageMovedAlert(static_cast(a)); + break; + case metadata_received_alert::alert_type: + handleMetadataReceivedAlert(static_cast(a)); + break; + case file_error_alert::alert_type: + handleFileErrorAlert(static_cast(a)); + break; + case file_completed_alert::alert_type: + handleFileCompletedAlert(static_cast(a)); + break; + case torrent_paused_alert::alert_type: + handleTorrentPausedAlert(static_cast(a)); + break; + case tracker_error_alert::alert_type: + handleTrackerErrorAlert(static_cast(a)); + break; + case tracker_reply_alert::alert_type: + handleTrackerReplyAlert(static_cast(a)); + break; + case tracker_warning_alert::alert_type: + handleTrackerWarningAlert(static_cast(a)); + break; + case portmap_error_alert::alert_type: + handlePortmapWarningAlert(static_cast(a)); + break; + case portmap_alert::alert_type: + handlePortmapAlert(static_cast(a)); + break; + case peer_blocked_alert::alert_type: + handlePeerBlockedAlert(static_cast(a)); + break; + case peer_ban_alert::alert_type: + handlePeerBanAlert(static_cast(a)); + break; + case fastresume_rejected_alert::alert_type: + handleFastResumeRejectedAlert(static_cast(a)); + break; + case url_seed_alert::alert_type: + handleUrlSeedAlert(static_cast(a)); + break; + case listen_succeeded_alert::alert_type: + handleListenSucceededAlert(static_cast(a)); + break; + case listen_failed_alert::alert_type: + handleListenFailedAlert(static_cast(a)); + break; + case torrent_checked_alert::alert_type: + handleTorrentCheckedAlert(static_cast(a)); + break; + case external_ip_alert::alert_type: + handleExternalIPAlert(static_cast(a)); + break; + case state_update_alert::alert_type: + handleStateUpdateAlert(static_cast(a)); + break; + case stats_alert::alert_type: + handleStatsAlert(static_cast(a)); + break; + } + } catch (const std::exception& e) { + qWarning() << "Caught exception in readAlerts(): " << e.what(); + } +} + +void QBtSession::handleTorrentFinishedAlert(libtorrent::torrent_finished_alert* p) { + QTorrentHandle h(p->handle); + if (h.is_valid()) { + const QString hash = h.hash(); + qDebug("Got a torrent finished alert for %s", qPrintable(h.name())); + // Remove .!qB extension if necessary + if (appendqBExtension) + appendqBextensionToTorrent(h, false); + + const bool was_already_seeded = TorrentPersistentData::isSeed(hash); + qDebug("Was already seeded: %d", was_already_seeded); + if (!was_already_seeded) { + h.save_resume_data(); + qDebug("Checking if the torrent contains torrent files to download"); + // Check if there are torrent files inside + for (int i=0; i t = new torrent_info(fsutils::toNativePath(torrent_fullpath).toUtf8().constData()); + if (t->is_valid()) { + qDebug("emitting recursiveTorrentDownloadPossible()"); + emit recursiveTorrentDownloadPossible(h); + break; } - qDebug("Exiting the application"); - qApp->exit(); - return; + } catch(std::exception&) { + qDebug("Caught error loading torrent"); + addConsoleMessage(tr("Unable to decode %1 torrent file.").arg(fsutils::toNativePath(torrent_fullpath)), QString::fromUtf8("red")); } -#endif // DISABLE_GUI } } - } - else if (save_resume_data_alert* p = dynamic_cast(a)) { - const QDir torrentBackup(fsutils::BTBackupLocation()); - const QTorrentHandle h(p->handle); - if (h.is_valid() && p->resume_data) { - const QString filepath = torrentBackup.absoluteFilePath(h.hash()+".fastresume"); - QFile resume_file(filepath); - if (resume_file.exists()) - fsutils::forceRemove(filepath); - qDebug("Saving fastresume data in %s", qPrintable(filepath)); - backupPersistentData(h.hash(), p->resume_data); - vector out; - bencode(back_inserter(out), *p->resume_data); - if (!out.empty() && resume_file.open(QIODevice::WriteOnly)) { - resume_file.write(&out[0], out.size()); - resume_file.close(); + // Move to download directory if necessary + if (!defaultTempPath.isEmpty()) { + // Check if directory is different + const QDir current_dir(h.save_path()); + const QDir save_dir(getSavePath(hash)); + if (current_dir != save_dir) { + qDebug("Moving torrent from the temp folder"); + h.move_storage(save_dir.absolutePath()); } } - } - else if (file_renamed_alert* p = dynamic_cast(a)) { - QTorrentHandle h(p->handle); - if (h.is_valid()) { - if (h.num_files() > 1) { - // Check if folders were renamed - QStringList old_path_parts = h.orig_filepath_at(p->index).split("/"); - old_path_parts.removeLast(); - QString old_path = old_path_parts.join("/"); - QStringList new_path_parts = fsutils::fromNativePath(misc::toQStringU(p->name)).split("/"); - new_path_parts.removeLast(); - if (!new_path_parts.isEmpty() && old_path != new_path_parts.join("/")) { - qDebug("Old_path(%s) != new_path(%s)", qPrintable(old_path), qPrintable(new_path_parts.join("/"))); - old_path = h.save_path()+"/"+old_path; - qDebug("Detected folder renaming, attempt to delete old folder: %s", qPrintable(old_path)); - QDir().rmpath(old_path); - } - } else { - // Single-file torrent - // Renaming a file corresponds to changing the save path - emit savePathChanged(h); - } - } - } - else if (torrent_deleted_alert* p = dynamic_cast(a)) { - qDebug("A torrent was deleted from the hard disk, attempting to remove the root folder too..."); - QString hash = misc::toQString(p->info_hash); - if (!hash.isEmpty()) { - if (savePathsToRemove.contains(hash)) { - const QString dirpath = savePathsToRemove.take(hash); - qDebug() << "Removing save path: " << dirpath << "..."; - bool ok = fsutils::smartRemoveEmptyFolderTree(dirpath); - Q_UNUSED(ok); - qDebug() << "Folder was removed: " << ok; - } - } else { - // Fallback - qDebug() << "hash is empty, use fallback to remove save path"; - foreach (const QString& key, savePathsToRemove.keys()) { - // Attempt to delete - if (QDir().rmdir(savePathsToRemove[key])) { - savePathsToRemove.remove(key); - } - } + // Remember finished state + qDebug("Saving seed status"); + TorrentPersistentData::saveSeedStatus(h); + // Recheck if the user asked to + Preferences pref; + if (pref.recheckTorrentsOnCompletion()) { + h.force_recheck(); } - } - else if (storage_moved_alert* p = dynamic_cast(a)) { - QTorrentHandle h(p->handle); - if (h.is_valid()) { - // Attempt to remove old folder if empty - const QString old_save_path = fsutils::fromNativePath(TorrentPersistentData::getPreviousPath(h.hash())); - const QString new_save_path = fsutils::fromNativePath(misc::toQStringU(p->path.c_str())); - qDebug("Torrent moved from %s to %s", qPrintable(old_save_path), qPrintable(new_save_path)); - QDir old_save_dir(old_save_path); - if (old_save_dir != QDir(defaultSavePath) && old_save_dir != QDir(defaultTempPath)) { - qDebug("Attempting to remove %s", qPrintable(old_save_path)); - QDir().rmpath(old_save_path); + qDebug("Emitting finishedTorrent() signal"); + emit finishedTorrent(h); + qDebug("Received finished alert for %s", qPrintable(h.name())); +#ifndef DISABLE_GUI + bool will_shutdown = (pref.shutdownWhenDownloadsComplete() || + pref.shutdownqBTWhenDownloadsComplete() || + pref.suspendWhenDownloadsComplete()) + && !hasDownloadingTorrents(); +#else + bool will_shutdown = false; +#endif + // AutoRun program + if (pref.isAutoRunEnabled()) + autoRunExternalProgram(h); + // Move .torrent file to another folder + if (pref.isFinishedTorrentExportEnabled()) + exportTorrentFile(h, FinishedTorrentExportFolder); + // Mail notification + if (pref.isMailNotificationEnabled()) + sendNotificationEmail(h); +#ifndef DISABLE_GUI + // Auto-Shutdown + if (will_shutdown) { + bool suspend = pref.suspendWhenDownloadsComplete(); + bool shutdown = pref.shutdownWhenDownloadsComplete(); + // Confirm shutdown + QString confirm_msg; + if (suspend) { + confirm_msg = tr("The computer will now go to sleep mode unless you cancel within the next 15 seconds..."); + } else if (shutdown) { + confirm_msg = tr("The computer will now be switched off unless you cancel within the next 15 seconds..."); + } else { + confirm_msg = tr("qBittorrent will now exit unless you cancel within the next 15 seconds..."); } - if (defaultTempPath.isEmpty() || !new_save_path.startsWith(defaultTempPath)) { - qDebug("Storage has been moved, updating save path to %s", qPrintable(new_save_path)); - TorrentPersistentData::saveSavePath(h.hash(), new_save_path); + if (!ShutdownConfirmDlg::askForConfirmation(confirm_msg)) + return; + // Actually shut down + if (suspend || shutdown) { + qDebug("Preparing for auto-shutdown because all downloads are complete!"); + // Disabling it for next time + pref.setShutdownWhenDownloadsComplete(false); + pref.setSuspendWhenDownloadsComplete(false); + // Make sure preferences are synced before exiting + if (suspend) + m_shutdownAct = SUSPEND_COMPUTER; + else + m_shutdownAct = SHUTDOWN_COMPUTER; } - emit savePathChanged(h); - //h.force_recheck(); + qDebug("Exiting the application"); + qApp->exit(); + return; } +#endif // DISABLE_GUI } - else if (metadata_received_alert* p = dynamic_cast(a)) { - QTorrentHandle h(p->handle); - Preferences pref; - if (h.is_valid()) { - QString hash(h.hash()); - if (HiddenData::hasData(hash)) { - HiddenData::gotMetadata(hash); - if (pref.isQueueingSystemEnabled()) { - //Internally decrease the queue limits to ensure that that other queued items aren't started - libtorrent::session_settings sessionSettings(s->settings()); - int max_downloading = pref.getMaxActiveDownloads(); - int max_active = pref.getMaxActiveTorrents(); - if (max_downloading > -1) - sessionSettings.active_downloads = max_downloading + HiddenData::getDownloadingSize(); - else - sessionSettings.active_downloads = max_downloading; - if (max_active > -1) - sessionSettings.active_limit = max_active + HiddenData::getDownloadingSize(); - else - sessionSettings.active_limit = max_active; - s->set_settings(sessionSettings); - } - h.pause(); - } - qDebug("Received metadata for %s", qPrintable(h.hash())); - // Save metadata - const QDir torrentBackup(fsutils::BTBackupLocation()); - if (!QFile::exists(torrentBackup.absoluteFilePath(h.hash()+QString(".torrent")))) - h.save_torrent_file(torrentBackup.absoluteFilePath(h.hash()+QString(".torrent"))); - // Copy the torrent file to the export folder - if (m_torrentExportEnabled) - exportTorrentFile(h); - // Append .!qB to incomplete files - if (appendqBExtension) - appendqBextensionToTorrent(h, true); - - if (!HiddenData::hasData(hash)) - emit metadataReceived(h); - else - emit metadataReceivedHidden(h); + } +} - if (h.is_paused() && !HiddenData::hasData(hash)) { - // XXX: Unfortunately libtorrent-rasterbar does not send a torrent_paused_alert - // and the torrent can be paused when metadata is received - emit pausedTorrent(h); - } +void QBtSession::handleSaveResumeDataAlert(libtorrent::save_resume_data_alert* p) { + const QDir torrentBackup(fsutils::BTBackupLocation()); + const QTorrentHandle h(p->handle); + if (h.is_valid() && p->resume_data) { + const QString filepath = torrentBackup.absoluteFilePath(h.hash()+".fastresume"); + QFile resume_file(filepath); + if (resume_file.exists()) + fsutils::forceRemove(filepath); + qDebug("Saving fastresume data in %s", qPrintable(filepath)); + backupPersistentData(h.hash(), p->resume_data); + vector out; + bencode(back_inserter(out), *p->resume_data); + if (!out.empty() && resume_file.open(QIODevice::WriteOnly)) { + resume_file.write(&out[0], out.size()); + resume_file.close(); + } + } +} +void QBtSession::handleFileRenamedAlert(libtorrent::file_renamed_alert* p) { + QTorrentHandle h(p->handle); + if (h.is_valid()) { + if (h.num_files() > 1) { + // Check if folders were renamed + QStringList old_path_parts = h.orig_filepath_at(p->index).split("/"); + old_path_parts.removeLast(); + QString old_path = old_path_parts.join("/"); + QStringList new_path_parts = fsutils::fromNativePath(misc::toQStringU(p->name)).split("/"); + new_path_parts.removeLast(); + if (!new_path_parts.isEmpty() && old_path != new_path_parts.join("/")) { + qDebug("Old_path(%s) != new_path(%s)", qPrintable(old_path), qPrintable(new_path_parts.join("/"))); + old_path = h.save_path()+"/"+old_path; + qDebug("Detected folder renaming, attempt to delete old folder: %s", qPrintable(old_path)); + QDir().rmpath(old_path); } + } else { + // Single-file torrent + // Renaming a file corresponds to changing the save path + emit savePathChanged(h); } - else if (file_error_alert* p = dynamic_cast(a)) { - QTorrentHandle h(p->handle); - if (h.is_valid()) { - h.pause(); - std::cerr << "File Error: " << p->message().c_str() << std::endl; - addConsoleMessage(tr("An I/O error occurred, '%1' paused.").arg(h.name())); - addConsoleMessage(tr("Reason: %1").arg(misc::toQStringU(p->message()))); - if (h.is_valid()) { - emit fullDiskError(h, misc::toQStringU(p->message())); - //h.pause(); - emit pausedTorrent(h); - } - } + } +} + +void QBtSession::handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p) { + qDebug("A torrent was deleted from the hard disk, attempting to remove the root folder too..."); + QString hash = misc::toQString(p->info_hash); + if (!hash.isEmpty()) { + if (savePathsToRemove.contains(hash)) { + const QString dirpath = savePathsToRemove.take(hash); + qDebug() << "Removing save path: " << dirpath << "..."; + bool ok = fsutils::smartRemoveEmptyFolderTree(dirpath); + Q_UNUSED(ok); + qDebug() << "Folder was removed: " << ok; } - else if (file_completed_alert* p = dynamic_cast(a)) { - QTorrentHandle h(p->handle); - qDebug("A file completed download in torrent %s", qPrintable(h.name())); - if (appendqBExtension) { - qDebug("appendqBTExtension is true"); - QString name = h.filepath_at(p->index); - if (name.endsWith(".!qB")) { - const QString old_name = name; - name.chop(4); - qDebug("Renaming %s to %s", qPrintable(old_name), qPrintable(name)); - h.rename_file(p->index, name); - } + } else { + // Fallback + qDebug() << "hash is empty, use fallback to remove save path"; + foreach (const QString& key, savePathsToRemove.keys()) { + // Attempt to delete + if (QDir().rmdir(savePathsToRemove[key])) { + savePathsToRemove.remove(key); } } - else if (torrent_paused_alert* p = dynamic_cast(a)) { - if (p->handle.is_valid()) { - QTorrentHandle h(p->handle); - if (!HiddenData::hasData(h.hash())) { - if (!h.has_error()) - h.save_resume_data(); - emit pausedTorrent(h); - } - } + } +} + +void QBtSession::handleStorageMovedAlert(libtorrent::storage_moved_alert* p) { + QTorrentHandle h(p->handle); + if (h.is_valid()) { + // Attempt to remove old folder if empty + const QString old_save_path = fsutils::fromNativePath(TorrentPersistentData::getPreviousPath(h.hash())); + const QString new_save_path = fsutils::fromNativePath(misc::toQStringU(p->path.c_str())); + qDebug("Torrent moved from %s to %s", qPrintable(old_save_path), qPrintable(new_save_path)); + QDir old_save_dir(old_save_path); + if (old_save_dir != QDir(defaultSavePath) && old_save_dir != QDir(defaultTempPath)) { + qDebug("Attempting to remove %s", qPrintable(old_save_path)); + QDir().rmpath(old_save_path); } - else if (tracker_error_alert* p = dynamic_cast(a)) { - // Level: fatal - QTorrentHandle h(p->handle); - if (h.is_valid()) { - // Authentication - if (p->status_code != 401) { - qDebug("Received a tracker error for %s: %s", p->url.c_str(), p->msg.c_str()); - const QString tracker_url = misc::toQString(p->url); - QHash trackers_data = trackersInfos.value(h.hash(), QHash()); - TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url)); - data.last_message = misc::toQStringU(p->msg); - trackers_data.insert(tracker_url, data); - trackersInfos[h.hash()] = trackers_data; - } else { - emit trackerAuthenticationRequired(h); - } - } + if (defaultTempPath.isEmpty() || !new_save_path.startsWith(defaultTempPath)) { + qDebug("Storage has been moved, updating save path to %s", qPrintable(new_save_path)); + TorrentPersistentData::saveSavePath(h.hash(), new_save_path); } - else if (tracker_reply_alert* p = dynamic_cast(a)) { - const QTorrentHandle h(p->handle); - if (h.is_valid()) { - qDebug("Received a tracker reply from %s (Num_peers=%d)", p->url.c_str(), p->num_peers); - // Connection was successful now. Remove possible old errors - QHash trackers_data = trackersInfos.value(h.hash(), QHash()); - const QString tracker_url = misc::toQString(p->url); - TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url)); - data.last_message = ""; // Reset error/warning message - data.num_peers = p->num_peers; - trackers_data.insert(tracker_url, data); - trackersInfos[h.hash()] = trackers_data; + emit savePathChanged(h); + //h.force_recheck(); + } +} + +void QBtSession::handleMetadataReceivedAlert(libtorrent::metadata_received_alert* p) { + QTorrentHandle h(p->handle); + Preferences pref; + if (h.is_valid()) { + QString hash(h.hash()); + if (HiddenData::hasData(hash)) { + HiddenData::gotMetadata(hash); + if (pref.isQueueingSystemEnabled()) { + //Internally decrease the queue limits to ensure that that other queued items aren't started + libtorrent::session_settings sessionSettings(s->settings()); + int max_downloading = pref.getMaxActiveDownloads(); + int max_active = pref.getMaxActiveTorrents(); + if (max_downloading > -1) + sessionSettings.active_downloads = max_downloading + HiddenData::getDownloadingSize(); + else + sessionSettings.active_downloads = max_downloading; + if (max_active > -1) + sessionSettings.active_limit = max_active + HiddenData::getDownloadingSize(); + else + sessionSettings.active_limit = max_active; + s->set_settings(sessionSettings); } + h.pause(); } - else if (tracker_warning_alert* p = dynamic_cast(a)) { - const QTorrentHandle h(p->handle); - if (h.is_valid()) { - // Connection was successful now but there is a warning message - QHash trackers_data = trackersInfos.value(h.hash(), QHash()); - const QString tracker_url = misc::toQString(p->url); - TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url)); - data.last_message = misc::toQStringU(p->msg); // Store warning message - trackers_data.insert(tracker_url, data); - trackersInfos[h.hash()] = trackers_data; - qDebug("Received a tracker warning from %s: %s", p->url.c_str(), p->msg.c_str()); - } + qDebug("Received metadata for %s", qPrintable(h.hash())); + // Save metadata + const QDir torrentBackup(fsutils::BTBackupLocation()); + if (!QFile::exists(torrentBackup.absoluteFilePath(h.hash()+QString(".torrent")))) + h.save_torrent_file(torrentBackup.absoluteFilePath(h.hash()+QString(".torrent"))); + // Copy the torrent file to the export folder + if (m_torrentExportEnabled) + exportTorrentFile(h); + // Append .!qB to incomplete files + if (appendqBExtension) + appendqBextensionToTorrent(h, true); + + if (!HiddenData::hasData(hash)) + emit metadataReceived(h); + else + emit metadataReceivedHidden(h); + + if (h.is_paused() && !HiddenData::hasData(hash)) { + // XXX: Unfortunately libtorrent-rasterbar does not send a torrent_paused_alert + // and the torrent can be paused when metadata is received + emit pausedTorrent(h); } - else if (portmap_error_alert* p = dynamic_cast(a)) { - addConsoleMessage(tr("UPnP/NAT-PMP: Port mapping failure, message: %1").arg(misc::toQStringU(p->message())), "red"); - //emit UPnPError(QString(p->msg().c_str())); - } - else if (portmap_alert* p = dynamic_cast(a)) { - qDebug("UPnP Success, msg: %s", p->message().c_str()); - addConsoleMessage(tr("UPnP/NAT-PMP: Port mapping successful, message: %1").arg(misc::toQStringU(p->message())), "blue"); - //emit UPnPSuccess(QString(p->msg().c_str())); - } - else if (peer_blocked_alert* p = dynamic_cast(a)) { - boost::system::error_code ec; - string ip = p->ip.to_string(ec); - if (!ec) { - addPeerBanMessage(QString::fromLatin1(ip.c_str()), true); - //emit peerBlocked(QString::fromLatin1(ip.c_str())); - } + } +} + +void QBtSession::handleFileErrorAlert(libtorrent::file_error_alert* p) { + QTorrentHandle h(p->handle); + if (h.is_valid()) { + h.pause(); + std::cerr << "File Error: " << p->message().c_str() << std::endl; + addConsoleMessage(tr("An I/O error occurred, '%1' paused.").arg(h.name())); + addConsoleMessage(tr("Reason: %1").arg(misc::toQStringU(p->message()))); + if (h.is_valid()) { + emit fullDiskError(h, misc::toQStringU(p->message())); + //h.pause(); + emit pausedTorrent(h); } - else if (peer_ban_alert* p = dynamic_cast(a)) { - boost::system::error_code ec; - string ip = p->ip.address().to_string(ec); - if (!ec) { - addPeerBanMessage(QString::fromLatin1(ip.c_str()), false); - //emit peerBlocked(QString::fromLatin1(ip.c_str())); - } + } +} + +void QBtSession::handleFileCompletedAlert(libtorrent::file_completed_alert* p) { + QTorrentHandle h(p->handle); + qDebug("A file completed download in torrent %s", qPrintable(h.name())); + if (appendqBExtension) { + qDebug("appendqBTExtension is true"); + QString name = h.filepath_at(p->index); + if (name.endsWith(".!qB")) { + const QString old_name = name; + name.chop(4); + qDebug("Renaming %s to %s", qPrintable(old_name), qPrintable(name)); + h.rename_file(p->index, name); } - else if (fastresume_rejected_alert* p = dynamic_cast(a)) { - QTorrentHandle h(p->handle); - if (h.is_valid()) { - qDebug("/!\\ Fast resume failed for %s, reason: %s", qPrintable(h.name()), p->message().c_str()); - if (p->error.value() == 134 && TorrentPersistentData::isSeed(h.hash()) && h.has_missing_files()) { - const QString hash = h.hash(); - // Mismatching file size (files were probably moved - addConsoleMessage(tr("File sizes mismatch for torrent %1, pausing it.").arg(h.name())); - TorrentPersistentData::setErrorState(hash, true); - pauseTorrent(hash); - } else { - addConsoleMessage(tr("Fast resume data was rejected for torrent %1, checking again...").arg(h.name()), QString::fromUtf8("red")); - addConsoleMessage(tr("Reason: %1").arg(misc::toQStringU(p->message()))); - } - } + } +} + +void QBtSession::handleTorrentPausedAlert(libtorrent::torrent_paused_alert* p) { + if (p->handle.is_valid()) { + QTorrentHandle h(p->handle); + if (!HiddenData::hasData(h.hash())) { + if (!h.has_error()) + h.save_resume_data(); + emit pausedTorrent(h); } - else if (url_seed_alert* p = dynamic_cast(a)) { - addConsoleMessage(tr("Url seed lookup failed for url: %1, message: %2").arg(misc::toQString(p->url)).arg(misc::toQStringU(p->message())), QString::fromUtf8("red")); - //emit urlSeedProblem(QString::fromUtf8(p->url.c_str()), QString::fromUtf8(p->msg().c_str())); + } +} + +void QBtSession::handleTrackerErrorAlert(libtorrent::tracker_error_alert* p) { + // Level: fatal + QTorrentHandle h(p->handle); + if (h.is_valid()) { + // Authentication + if (p->status_code != 401) { + qDebug("Received a tracker error for %s: %s", p->url.c_str(), p->msg.c_str()); + const QString tracker_url = misc::toQString(p->url); + QHash trackers_data = trackersInfos.value(h.hash(), QHash()); + TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url)); + data.last_message = misc::toQStringU(p->msg); + trackers_data.insert(tracker_url, data); + trackersInfos[h.hash()] = trackers_data; + } else { + emit trackerAuthenticationRequired(h); + } + } +} + +void QBtSession::handleTrackerReplyAlert(libtorrent::tracker_reply_alert* p) { + const QTorrentHandle h(p->handle); + if (h.is_valid()) { + qDebug("Received a tracker reply from %s (Num_peers=%d)", p->url.c_str(), p->num_peers); + // Connection was successful now. Remove possible old errors + QHash trackers_data = trackersInfos.value(h.hash(), QHash()); + const QString tracker_url = misc::toQString(p->url); + TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url)); + data.last_message = ""; // Reset error/warning message + data.num_peers = p->num_peers; + trackers_data.insert(tracker_url, data); + trackersInfos[h.hash()] = trackers_data; + } +} + +void QBtSession::handleTrackerWarningAlert(libtorrent::tracker_warning_alert* p) { + const QTorrentHandle h(p->handle); + if (h.is_valid()) { + // Connection was successful now but there is a warning message + QHash trackers_data = trackersInfos.value(h.hash(), QHash()); + const QString tracker_url = misc::toQString(p->url); + TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url)); + data.last_message = misc::toQStringU(p->msg); // Store warning message + trackers_data.insert(tracker_url, data); + trackersInfos[h.hash()] = trackers_data; + qDebug("Received a tracker warning from %s: %s", p->url.c_str(), p->msg.c_str()); + } +} + +void QBtSession::handlePortmapWarningAlert(libtorrent::portmap_error_alert* p) { + addConsoleMessage(tr("UPnP/NAT-PMP: Port mapping failure, message: %1").arg(misc::toQStringU(p->message())), "red"); + //emit UPnPError(QString(p->msg().c_str())); +} + +void QBtSession::handlePortmapAlert(libtorrent::portmap_alert* p) { + qDebug("UPnP Success, msg: %s", p->message().c_str()); + addConsoleMessage(tr("UPnP/NAT-PMP: Port mapping successful, message: %1").arg(misc::toQStringU(p->message())), "blue"); + //emit UPnPSuccess(QString(p->msg().c_str())); +} + +void QBtSession::handlePeerBlockedAlert(libtorrent::peer_blocked_alert* p) { + boost::system::error_code ec; + string ip = p->ip.to_string(ec); + if (!ec) { + addPeerBanMessage(QString::fromLatin1(ip.c_str()), true); + //emit peerBlocked(QString::fromLatin1(ip.c_str())); + } +} + +void QBtSession::handlePeerBanAlert(libtorrent::peer_ban_alert* p) { + boost::system::error_code ec; + string ip = p->ip.address().to_string(ec); + if (!ec) { + addPeerBanMessage(QString::fromLatin1(ip.c_str()), false); + //emit peerBlocked(QString::fromLatin1(ip.c_str())); + } +} + +void QBtSession::handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert* p) { + QTorrentHandle h(p->handle); + if (h.is_valid()) { + qDebug("/!\\ Fast resume failed for %s, reason: %s", qPrintable(h.name()), p->message().c_str()); + if (p->error.value() == 134 && TorrentPersistentData::isSeed(h.hash()) && h.has_missing_files()) { + const QString hash = h.hash(); + // Mismatching file size (files were probably moved + addConsoleMessage(tr("File sizes mismatch for torrent %1, pausing it.").arg(h.name())); + TorrentPersistentData::setErrorState(hash, true); + pauseTorrent(hash); + } else { + addConsoleMessage(tr("Fast resume data was rejected for torrent %1, checking again...").arg(h.name()), QString::fromUtf8("red")); + addConsoleMessage(tr("Reason: %1").arg(misc::toQStringU(p->message()))); } - else if (listen_succeeded_alert *p = dynamic_cast(a)) { - boost::system::error_code ec; - QString proto = "TCP"; + } +} + +void QBtSession::handleUrlSeedAlert(libtorrent::url_seed_alert* p) { + addConsoleMessage(tr("Url seed lookup failed for url: %1, message: %2").arg(misc::toQString(p->url)).arg(misc::toQStringU(p->message())), QString::fromUtf8("red")); + //emit urlSeedProblem(QString::fromUtf8(p->url.c_str()), QString::fromUtf8(p->msg().c_str())); +} + +void QBtSession::handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p) { + boost::system::error_code ec; + QString proto = "TCP"; #if LIBTORRENT_VERSION_NUM >= 10000 - if (p->sock_type == listen_succeeded_alert::udp) - proto = "UDP"; - else if (p->sock_type == listen_succeeded_alert::tcp) - proto = "TCP"; - else if (p->sock_type == listen_succeeded_alert::tcp_ssl) - proto = "TCP_SSL"; + if (p->sock_type == listen_succeeded_alert::udp) + proto = "UDP"; + else if (p->sock_type == listen_succeeded_alert::tcp) + proto = "TCP"; + else if (p->sock_type == listen_succeeded_alert::tcp_ssl) + proto = "TCP_SSL"; #endif - qDebug() << "Successfully listening on " << proto << p->endpoint.address().to_string(ec).c_str() << "/" << p->endpoint.port(); - addConsoleMessage(tr("qBittorrent is successfully listening on interface %1 port: %2/%3", "e.g: qBittorrent is successfully listening on interface 192.168.0.1 port: TCP/6881").arg(p->endpoint.address().to_string(ec).c_str()).arg(proto).arg(QString::number(p->endpoint.port())), "blue"); - // Force reannounce on all torrents because some trackers blacklist some ports - std::vector torrents = s->get_torrents(); + qDebug() << "Successfully listening on " << proto << p->endpoint.address().to_string(ec).c_str() << "/" << p->endpoint.port(); + addConsoleMessage(tr("qBittorrent is successfully listening on interface %1 port: %2/%3", "e.g: qBittorrent is successfully listening on interface 192.168.0.1 port: TCP/6881").arg(p->endpoint.address().to_string(ec).c_str()).arg(proto).arg(QString::number(p->endpoint.port())), "blue"); + // Force reannounce on all torrents because some trackers blacklist some ports + std::vector torrents = s->get_torrents(); - std::vector::iterator it = torrents.begin(); - std::vector::iterator itend = torrents.end(); - for ( ; it != itend; ++it) { - it->force_reannounce(); - } - } - else if (listen_failed_alert *p = dynamic_cast(a)) { - boost::system::error_code ec; - QString proto = "TCP"; + std::vector::iterator it = torrents.begin(); + std::vector::iterator itend = torrents.end(); + for ( ; it != itend; ++it) { + it->force_reannounce(); + } +} + +void QBtSession::handleListenFailedAlert(libtorrent::listen_failed_alert *p) { + boost::system::error_code ec; + QString proto = "TCP"; #if LIBTORRENT_VERSION_NUM >= 10000 - if (p->sock_type == listen_failed_alert::udp) - proto = "UDP"; - else if (p->sock_type == listen_failed_alert::tcp) - proto = "TCP"; - else if (p->sock_type == listen_failed_alert::tcp_ssl) - proto = "TCP_SSL"; - else if (p->sock_type == listen_failed_alert::i2p) - proto = "I2P"; - else if (p->sock_type == listen_failed_alert::socks5) - proto = "SOCKS5"; + if (p->sock_type == listen_failed_alert::udp) + proto = "UDP"; + else if (p->sock_type == listen_failed_alert::tcp) + proto = "TCP"; + else if (p->sock_type == listen_failed_alert::tcp_ssl) + proto = "TCP_SSL"; + else if (p->sock_type == listen_failed_alert::i2p) + proto = "I2P"; + else if (p->sock_type == listen_failed_alert::socks5) + proto = "SOCKS5"; #endif - qDebug() << "Failed listening on " << proto << p->endpoint.address().to_string(ec).c_str() << "/" << p->endpoint.port(); - addConsoleMessage(tr("qBittorrent failed listening on interface %1 port: %2/%3. Reason: %4", "e.g: qBittorrent failed listening on interface 192.168.0.1 port: TCP/6881. Reason: already in use").arg(p->endpoint.address().to_string(ec).c_str()).arg(proto).arg(QString::number(p->endpoint.port())).arg(misc::toQStringU(p->error.message())), "red"); - } - else if (torrent_checked_alert* p = dynamic_cast(a)) { - QTorrentHandle h(p->handle); - if (h.is_valid()) { - const QString hash = h.hash(); - qDebug("%s have just finished checking", qPrintable(hash)); - // Save seed status - TorrentPersistentData::saveSeedStatus(h); - // Move to temp directory if necessary - if (!h.is_seed() && !defaultTempPath.isEmpty()) { - // Check if directory is different - const QDir current_dir(h.save_path()); - const QDir save_dir(getSavePath(h.hash())); - if (current_dir == save_dir) { - qDebug("Moving the torrent to the temp directory..."); - QString torrent_tmp_path = defaultTempPath; - h.move_storage(torrent_tmp_path); - } - } - emit torrentFinishedChecking(h); - if (torrentsToPausedAfterChecking.contains(hash)) { - torrentsToPausedAfterChecking.removeOne(hash); - h.pause(); - emit pausedTorrent(h); - } + qDebug() << "Failed listening on " << proto << p->endpoint.address().to_string(ec).c_str() << "/" << p->endpoint.port(); + addConsoleMessage(tr("qBittorrent failed listening on interface %1 port: %2/%3. Reason: %4", "e.g: qBittorrent failed listening on interface 192.168.0.1 port: TCP/6881. Reason: already in use").arg(p->endpoint.address().to_string(ec).c_str()).arg(proto).arg(QString::number(p->endpoint.port())).arg(misc::toQStringU(p->error.message())), "red"); + +} + +void QBtSession::handleTorrentCheckedAlert(libtorrent::torrent_checked_alert* p) { + QTorrentHandle h(p->handle); + if (h.is_valid()) { + const QString hash = h.hash(); + qDebug("%s have just finished checking", qPrintable(hash)); + // Save seed status + TorrentPersistentData::saveSeedStatus(h); + // Move to temp directory if necessary + if (!h.is_seed() && !defaultTempPath.isEmpty()) { + // Check if directory is different + const QDir current_dir(h.save_path()); + const QDir save_dir(getSavePath(h.hash())); + if (current_dir == save_dir) { + qDebug("Moving the torrent to the temp directory..."); + QString torrent_tmp_path = defaultTempPath; + h.move_storage(torrent_tmp_path); } } - else if (external_ip_alert *p = dynamic_cast(a)) { - boost::system::error_code ec; - addConsoleMessage(tr("External IP: %1", "e.g. External IP: 192.168.0.1").arg(p->external_address.to_string(ec).c_str()), "blue"); - } - else if (state_update_alert *p = dynamic_cast(a)) { - emit stateUpdate(p->status); - } - else if (stats_alert *p = dynamic_cast(a)) { - emit statsReceived(*p); + emit torrentFinishedChecking(h); + if (torrentsToPausedAfterChecking.contains(hash)) { + torrentsToPausedAfterChecking.removeOne(hash); + h.pause(); + emit pausedTorrent(h); } - } catch (const std::exception& e) { - qWarning() << "Caught exception in readAlerts(): " << e.what(); } } +void QBtSession::handleExternalIPAlert(libtorrent::external_ip_alert *p) { + boost::system::error_code ec; + addConsoleMessage(tr("External IP: %1", "e.g. External IP: 192.168.0.1").arg(p->external_address.to_string(ec).c_str()), "blue"); +} + +void QBtSession::handleStateUpdateAlert(libtorrent::state_update_alert *p) { + emit stateUpdate(p->status); +} + +void QBtSession::handleStatsAlert(libtorrent::stats_alert *p) { + emit statsReceived(*p); +} + void QBtSession::recheckTorrent(const QString &hash) { QTorrentHandle h = getTorrentHandle(hash); if (h.is_valid() && h.has_metadata()) { diff --git a/src/qtlibtorrent/qbtsession.h b/src/qtlibtorrent/qbtsession.h index 46012b9b8..d2510275a 100755 --- a/src/qtlibtorrent/qbtsession.h +++ b/src/qtlibtorrent/qbtsession.h @@ -195,6 +195,30 @@ private: void recoverPersistentData(const QString &hash, const std::vector &buf); void backupPersistentData(const QString &hash, boost::shared_ptr data); void handleAlert(libtorrent::alert* a); + void handleTorrentFinishedAlert(libtorrent::torrent_finished_alert* p); + void handleSaveResumeDataAlert(libtorrent::save_resume_data_alert* p); + void handleFileRenamedAlert(libtorrent::file_renamed_alert* p); + void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert* p); + void handleStorageMovedAlert(libtorrent::storage_moved_alert* p); + void handleMetadataReceivedAlert(libtorrent::metadata_received_alert* p); + void handleFileErrorAlert(libtorrent::file_error_alert* p); + void handleFileCompletedAlert(libtorrent::file_completed_alert* p); + void handleTorrentPausedAlert(libtorrent::torrent_paused_alert* p); + void handleTrackerErrorAlert(libtorrent::tracker_error_alert* p); + void handleTrackerReplyAlert(libtorrent::tracker_reply_alert* p); + void handleTrackerWarningAlert(libtorrent::tracker_warning_alert* p); + void handlePortmapWarningAlert(libtorrent::portmap_error_alert* p); + void handlePortmapAlert(libtorrent::portmap_alert* p); + void handlePeerBlockedAlert(libtorrent::peer_blocked_alert* p); + void handlePeerBanAlert(libtorrent::peer_ban_alert* p); + void handleFastResumeRejectedAlert(libtorrent::fastresume_rejected_alert* p); + void handleUrlSeedAlert(libtorrent::url_seed_alert* p); + void handleListenSucceededAlert(libtorrent::listen_succeeded_alert *p); + void handleListenFailedAlert(libtorrent::listen_failed_alert *p); + void handleTorrentCheckedAlert(libtorrent::torrent_checked_alert* p); + void handleExternalIPAlert(libtorrent::external_ip_alert *p); + void handleStateUpdateAlert(libtorrent::state_update_alert *p); + void handleStatsAlert(libtorrent::stats_alert *p); private slots: void addTorrentsFromScanFolder(QStringList&);