From dc89c5d381c855f53f4dd656bf234cb628d738f2 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Mon, 5 Mar 2007 17:35:38 +0000 Subject: [PATCH] - A lot of fixes/improvements in bittorrent class (now compiling) - Half way, now I need to rewrite the GUI class to use the bittorrent class --- src/GUI.cpp | 89 +++++------------------ src/GUI.h | 3 +- src/bittorrent.cpp | 171 +++++++++++++++++++++++++++++++++++---------- src/bittorrent.h | 32 +++++++-- src/options_imp.h | 4 +- src/src.pro | 6 +- 6 files changed, 185 insertions(+), 120 deletions(-) diff --git a/src/GUI.cpp b/src/GUI.cpp index 2a79d6716..d811d05d9 100644 --- a/src/GUI.cpp +++ b/src/GUI.cpp @@ -218,14 +218,14 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent){ if(!loadColWidthSearchList()){ resultsBrowser->header()->resizeSection(0, 275); } - + // new qCompleter to the search pattern startSearchHistory(); QCompleter *searchCompleter = new QCompleter(searchHistory, this); searchCompleter->setCaseSensitivity(Qt::CaseInsensitive); search_pattern->setCompleter(searchCompleter); - - + + // Boolean initialization search_stopped = false; // Connect signals to slots (search part) @@ -895,6 +895,18 @@ void GUI::closeEvent(QCloseEvent *e){ return; } } + //TODO: Clean finished torrents on exit +// if(options->getClearFinishedOnExit()){ +// torrentBackup.remove(fileHash+".torrent"); +// torrentBackup.remove(fileHash+".fastresume"); +// torrentBackup.remove(fileHash+".paused"); +// torrentBackup.remove(fileHash+".incremental"); +// torrentBackup.remove(fileHash+".pieces"); +// torrentBackup.remove(fileHash+".savepath"); +// if(isScanningDir){ +// QFile::remove(scan_dir+fileHash+".torrent"); +// } +// } // save the searchHistory for later uses saveSearchHistory(); // Save DHT entry @@ -1685,40 +1697,6 @@ void GUI::configureSession(){ qDebug("Session configured"); } -// Pause All Downloads in DL list -void GUI::pauseAll(){ - QString fileHash; - bool changes=false; - // Browse Handles to pause all downloads - foreach(torrent_handle h, handles){ - if(!h.is_paused()){ - fileHash = QString(misc::toString(h.info_hash()).c_str()); - changes=true; - h.pause(); - // Create .paused file - QFile paused_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+fileHash+".paused"); - paused_file.open(QIODevice::WriteOnly | QIODevice::Text); - paused_file.close(); - // update DL Status - int row = getRowFromHash(fileHash); - if(row == -1){ - std::cerr << "Error: Filename could not be found in download list...\n"; - continue; - } - DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.)); - DLListModel->setData(DLListModel->index(row, STATUS), QVariant(tr("Paused"))); - DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1)); - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(":/Icons/skin/paused.png")), Qt::DecorationRole); - setRowColor(row, "red"); - } - } - //Set Info Bar - if(changes){ - setInfoBar(tr("All Downloads Paused.")); - } -} - // pause selected items in the list void GUI::pauseSelection(){ QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); @@ -1749,35 +1727,6 @@ void GUI::pauseSelection(){ } } -// Start All Downloads in DL list -void GUI::startAll(){ - QString fileHash; - bool changes=false; - // Browse Handles to pause all downloads - foreach(torrent_handle h, handles){ - if(h.is_paused()){ - fileHash = QString(misc::toString(h.info_hash()).c_str()); - changes=true; - h.resume(); - // Delete .paused file - QFile::remove(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+fileHash+".paused"); - // update DL Status - int row = getRowFromHash(fileHash); - if(row == -1){ - std::cerr << "Error: Filename could not be found in download list...\n"; - continue; - } - DLListModel->setData(DLListModel->index(row, STATUS), QVariant(tr("Connecting..."))); - DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(":/Icons/skin/connecting.png")), Qt::DecorationRole); - setRowColor(row, "grey"); - } - } - //Set Info Bar - if(changes){ - setInfoBar(tr("All Downloads Resumed.")); - } -} - // start selected items in the list void GUI::startSelection(){ QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes(); @@ -1947,8 +1896,8 @@ void GUI::checkConnectionStatus(){ // get the last searchs from a QSettings to a QStringList void GUI::startSearchHistory(){ QSettings settings("qBittorrent", "qBittorrent"); - settings.beginGroup("Search"); - searchHistory = settings.value("searchHistory",-1).toStringList(); + settings.beginGroup("Search"); + searchHistory = settings.value("searchHistory",-1).toStringList(); settings.endGroup(); } @@ -1956,7 +1905,7 @@ void GUI::startSearchHistory(){ void GUI::saveSearchHistory() { QSettings settings("qBittorrent", "qBittorrent"); - settings.beginGroup("Search"); + settings.beginGroup("Search"); settings.setValue("searchHistory",searchHistory); settings.endGroup(); } @@ -1981,7 +1930,7 @@ void GUI::on_search_button_clicked(){ search_pattern->setCompleter(searchCompleter); } - + // Getting checked search engines if(!mininova->isChecked() && ! piratebay->isChecked()/* && !reactor->isChecked()*/ && !isohunt->isChecked()/* && !btjunkie->isChecked()*/ && !meganova->isChecked()){ QMessageBox::critical(0, tr("No seach engine selected"), tr("You must select at least one search engine.")); diff --git a/src/GUI.h b/src/GUI.h index cce064a4d..a8e0de442 100644 --- a/src/GUI.h +++ b/src/GUI.h @@ -44,6 +44,7 @@ #include "previewSelect.h" #include "trackerLogin.h" #include "deleteThread.h" +#include "bittorrent.h" #define TIME_TRAY_BALLOON 5000 @@ -147,8 +148,6 @@ class GUI : public QMainWindow, private Ui::MainWindow{ void showProperties(const QModelIndex &index); void propertiesSelection(); void addTorrent(const QString& path, bool fromScanDir = false, const QString& from_url = QString()); - void pauseAll(); - void startAll(); void pauseSelection(); void startSelection(); void askForTorrents(); diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index 0c226c97e..b097bd260 100644 --- a/src/bittorrent.cpp +++ b/src/bittorrent.cpp @@ -19,53 +19,64 @@ * Contact : chris@qbittorrent.org */ #include "bittorrent.h" +#include "misc.h" #include +#include // Main constructor bittorrent::bittorrent(){ + supported_preview_extensions << "AVI" << "DIVX" << "MPG" << "MPEG" << "MP3" << "OGG" << "WMV" << "WMA" << "RMV" << "RMVB" << "ASF" << "MOV" << "WAV" << "MP2" << "SWF" << "AC3"; // Creating bittorrent session s = new session(fingerprint("qB", VERSION_MAJOR, VERSION_MINOR, VERSION_BUGFIX, 0)); // Set severity level of libtorrent session s->set_severity_level(alert::info); // DHT (Trackerless), disabled until told otherwise DHTEnabled = false; - // directory scanning, disabled until told otherwise - scanningEnabled = false; // Enabling metadata plugin s->add_extension(&create_metadata_plugin); + timerAlerts = new QTimer(this); + connect(timerAlerts, SIGNAL(timeout()), this, SLOT(readAlerts())); + timerAlerts->start(3000); } // Main destructor bittorrent::~bittorrent(){ disableDirectoryScanning(); + delete timerAlerts; delete s; } // Return the torrent handle, given its hash -torrent_handle& bittorrent::getTorrentHandle(const QString& hash) const{ - return s->find_torrent(sha_hash(hash.toUtf8())); +torrent_handle bittorrent::getTorrentHandle(const QString& hash) const{ + return s->find_torrent(misc::fromString((hash.toStdString()))); } // Delete a torrent from the session, given its hash // permanent = true means that the torrent will be removed from the hard-drive too void bittorrent::deleteTorrent(const QString& hash, bool permanent){ - torrent_handle& h = s->find_torrent(sha_hash(hash.toUtf8())); + torrent_handle h = s->find_torrent(misc::fromString((hash.toStdString()))); + if(!h.is_valid()){ + return; + } + QString savePath = QString::fromUtf8(h.save_path().string().c_str()); + QString fileName = QString(h.name().c_str()); // Remove it from session s->remove_torrent(h); // Remove it from torrent backup directory - torrentBackup.remove(fileHash+".torrent"); - torrentBackup.remove(fileHash+".fastresume"); - torrentBackup.remove(fileHash+".paused"); - torrentBackup.remove(fileHash+".incremental"); - torrentBackup.remove(fileHash+".pieces"); - torrentBackup.remove(fileHash+".savepath"); + QDir torrentBackup(misc::qBittorrentPath() + "BT_backup"); + torrentBackup.remove(hash+".torrent"); + torrentBackup.remove(hash+".fastresume"); + torrentBackup.remove(hash+".paused"); + torrentBackup.remove(hash+".incremental"); + torrentBackup.remove(hash+".pieces"); + torrentBackup.remove(hash+".savepath"); if(permanent){ // Remove from Hard drive qDebug("Removing this on hard drive: %s", qPrintable(savePath+QDir::separator()+fileName)); // Deleting in a thread to avoid GUI freeze deleteThread *deleter = new deleteThread(savePath+QDir::separator()+fileName); - connect(deleter, SIGNAL(deletionFinished(deleteThread*)), this, SLOT(cleanDeleter(deleteThread*))) + connect(deleter, SIGNAL(deletionFinished(deleteThread*)), this, SLOT(cleanDeleter(deleteThread*))); } } @@ -77,7 +88,7 @@ void bittorrent::cleanDeleter(deleteThread* deleter){ // Pause a running torrent void bittorrent::pauseTorrent(const QString& hash){ - torrent_handle& h = s->find_torrent(sha_hash(hash.toUtf8())); + torrent_handle h = s->find_torrent(misc::fromString((hash.toStdString()))); if(h.is_valid() && !h.is_paused()){ h.pause(); } @@ -85,14 +96,14 @@ void bittorrent::pauseTorrent(const QString& hash){ // Resume a torrent in paused state void bittorrent::resumeTorrent(const QString& hash){ - torrent_handle& h = s->find_torrent(sha_hash(hash.toUtf8())); + torrent_handle h = s->find_torrent(misc::fromString((hash.toStdString()))); if(h.is_valid() && h.is_paused()){ h.resume(); } } // Add a torrent to the bittorrent session -void bittorrent::addTorrent(const QString& path, bool fromScanDir = false, const QString& from_url = QString()){ +void bittorrent::addTorrent(const QString& path, bool fromScanDir, const QString& from_url){ torrent_handle h; entry resume_data; bool fastResume=false; @@ -103,8 +114,8 @@ void bittorrent::addTorrent(const QString& path, bool fromScanDir = false, const // create it if it is not if(! torrentBackup.exists()){ if(! torrentBackup.mkpath(torrentBackup.path())){ - std::cerr << "Couldn't create the directory: '" << torrentBackup.path().toUtf8() << "'\n"; - exit 1; + std::cerr << "Couldn't create the directory: '" << (const char*)(torrentBackup.path().toUtf8()) << "'\n"; + exit(1); } } // Processing torrents @@ -158,7 +169,6 @@ void bittorrent::addTorrent(const QString& path, bool fromScanDir = false, const catch (fs::filesystem_error&) {} } QString savePath = getSavePath(hash); - int row = DLListModel->rowCount(); // Adding files to bittorrent session if(hasFilteredFiles(hash)){ h = s->add_torrent(t, fs::path((const char*)savePath.toUtf8()), resume_data, false); @@ -188,12 +198,6 @@ void bittorrent::addTorrent(const QString& path, bool fromScanDir = false, const QFile::copy(file, newFile); } //qDebug("Copied to torrent backup directory"); - if(fromScanDir){ - scan_dir = options->getScanDir(); - if(scan_dir.at(scan_dir.length()-1) != QDir::separator()){ - scan_dir += QDir::separator(); - } - } // Pause torrent if it was paused last time if(QFile::exists(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".paused")){ h.pause(); @@ -251,7 +255,7 @@ void bittorrent::addTorrent(const QString& path, bool fromScanDir = false, const // Check in .pieces file if the user filtered files // in this torrent. -bool bittorrent::hasFilteredFiles(const QString& fileHash){ +bool bittorrent::hasFilteredFiles(const QString& fileHash) const{ QFile pieces_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+fileHash+".pieces"); // Read saved file if(!pieces_file.open(QIODevice::ReadOnly | QIODevice::Text)){ @@ -280,8 +284,17 @@ bool bittorrent::isDHTEnabled() const{ // Enable DHT void bittorrent::enableDHT(){ if(!DHTEnabled){ + boost::filesystem::ifstream dht_state_file((const char*)(misc::qBittorrentPath()+QString("dht_state")).toUtf8(), std::ios_base::binary); + dht_state_file.unsetf(std::ios_base::skipws); + entry dht_state; + try{ + dht_state = bdecode(std::istream_iterator(dht_state_file), std::istream_iterator()); + }catch (std::exception&) {} + s->start_dht(dht_state); + s->add_dht_router(std::make_pair(std::string("router.bittorrent.com"), 6881)); + s->add_dht_router(std::make_pair(std::string("router.utorrent.com"), 6881)); + s->add_dht_router(std::make_pair(std::string("router.bitcomet.com"), 6881)); DHTEnabled = true; - s->start_dht(); qDebug("DHT enabled"); } } @@ -339,7 +352,7 @@ void bittorrent::saveFastResumeData(){ } // Write fast resume data std::vector handles = s->get_torrents(); - for(int i=0; ifind_torrent(sha_hash(hash.toUtf8())); + torrent_handle h = s->find_torrent(misc::fromString((hash.toStdString()))); if(!h.is_valid()){ - return; + return false; } torrent_info torrentInfo = h.get_torrent_info(); for(int i=0; iuseAdditionDialog()){ - torrentAdditionDialog *dialog = new torrentAdditionDialog(this); - connect(dialog, SIGNAL(torrentAddition(const QString&, bool, const QString&)), this, SLOT(addTorrent(const QString&, bool, const QString&))); - connect(dialog, SIGNAL(setInfoBarGUI(const QString&, const QString&)), this, SLOT(setInfoBar(const QString&, const QString&))); - dialog->showLoad(file, true); - }else{ + // TODO: Support torrent addition dialog addTorrent(file, true); - } } } } @@ -410,9 +417,10 @@ void bittorrent::scanDirectory(){ // Enable directory scanning void bittorrent::enableDirectoryScanning(const QString& _scan_dir){ if(!_scan_dir.isEmpty()){ - scan_dir = _scan_dir + scan_dir = _scan_dir; timerScan = new QTimer(this); connect(timerScan, SIGNAL(timeout()), this, SLOT(scanDirectory())); + timerScan->start(5000); } } @@ -420,6 +428,9 @@ void bittorrent::enableDirectoryScanning(const QString& _scan_dir){ void bittorrent::disableDirectoryScanning(){ if(!scan_dir.isNull()){ scan_dir = QString::null; + if(timerScan->isActive()){ + timerScan->stop(); + } delete timerScan; } } @@ -446,7 +457,91 @@ void bittorrent::setUploadRateLimit(int rate){ // This function will apply to same ratio to all torrents void bittorrent::setGlobalRatio(float ratio){ std::vector handles = s->get_torrents(); - for(int i=0; iadd_extension(&create_ut_pex_plugin); +} + +// Set DHT port (>= 1000) +void bittorrent::setDHTPort(int dht_port){ + if(dht_port >= 1000){ + struct dht_settings DHTSettings; + DHTSettings.service_port = dht_port; + s->set_dht_settings(DHTSettings); + qDebug("Set DHT Port to %d", dht_port); + } +} + +// Enable IP Filtering +void bittorrent::enableIPFilter(ip_filter filter){ + s->set_ip_filter(filter); +} + +// Disable IP Filtering +void bittorrent::disableIPFilter(){ + s->set_ip_filter(ip_filter()); +} + +// Set BT session settings (proxy, user_agent) +void bittorrent::setSessionSettings(session_settings sessionSettings){ + s->set_settings(sessionSettings); +} + +// Read alerts sent by the bittorrent session +void bittorrent::readAlerts(){ + // look at session alerts and display some infos + std::auto_ptr a = s->pop_alert(); + while (a.get()){ + if (torrent_finished_alert* p = dynamic_cast(a.get())){ + emit finishedTorrent(p->handle); + } + else if (file_error_alert* p = dynamic_cast(a.get())){ + emit fullDiskError(QString(p->handle.get_torrent_info().name().c_str())); + } + else if (dynamic_cast(a.get())){ + // Level: fatal + emit portListeningFailure(); + } + else if (tracker_alert* p = dynamic_cast(a.get())){ + // Level: fatal + QString fileHash = QString(misc::toString(p->handle.info_hash()).c_str()); + emit trackerError(fileHash, QTime::currentTime().toString("hh:mm:ss"), QString(a->msg().c_str())); + // Authentication + if(p->status_code == 401){ + emit trackerAuthenticationRequired(p->handle); + } + } + a = s->pop_alert(); + } +} + +QString bittorrent::getSavePath(const QString& hash){ + QFile savepath_file(misc::qBittorrentPath()+"BT_backup"+QDir::separator()+hash+".savepath"); + QByteArray line; + QString savePath; + if(savepath_file.open(QIODevice::ReadOnly | QIODevice::Text)){ + line = savepath_file.readAll(); + savepath_file.close(); + qDebug("Save path: %s", line.data()); + savePath = QString::fromUtf8(line.data()); + }else{ + //TODO: always create .savepath file +// savePath = options->getSavePath(); + } + // Checking if savePath Dir exists + // create it if it is not + QDir saveDir(savePath); + if(!saveDir.exists()){ + if(!saveDir.mkpath(saveDir.path())){ + std::cerr << "Couldn't create the save directory: " << (const char*)saveDir.path().toUtf8() << "\n"; + // TODO: handle this better + return QDir::homePath(); + } + } + return savePath; +} diff --git a/src/bittorrent.h b/src/bittorrent.h index 38b580c43..49622a654 100644 --- a/src/bittorrent.h +++ b/src/bittorrent.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -50,26 +51,34 @@ using namespace libtorrent; namespace fs = boost::filesystem; -class bittorrent{ +class bittorrent : public QObject{ + Q_OBJECT + private: session *s; - QHash trackerErrors; bool DHTEnabled; - String scan_dir; + QString scan_dir; QTimer *timerScan; + QTimer *timerAlerts; + QWidget *parent; + QStringList supported_preview_extensions; // Constructor / Destructor bittorrent(); ~bittorrent(); + protected: + QString getSavePath(const QString& hash); + public: - torrent_handle& getTorrentHandle(const QString& hash) const; + torrent_handle getTorrentHandle(const QString& hash) const; bool hasFilteredFiles(const QString& fileHash) const; + bool isFilePreviewPossible(const QString& fileHash) const; bool isDHTEnabled() const; public slots: void addTorrent(const QString& path, bool fromScanDir = false, const QString& from_url = QString()); - void deleteTorrent(const QString& hash, bool permanent=false); + void deleteTorrent(const QString& hash, bool permanent = false); void pauseTorrent(const QString& hash); void resumeTorrent(const QString& hash); void enableDHT(); @@ -77,22 +86,33 @@ class bittorrent{ void saveFastResumeData(); void enableDirectoryScanning(const QString& scan_dir); void disableDirectoryScanning(); + void enablePeerExchange(); + void enableIPFilter(ip_filter filter); + void disableIPFilter(); // Session configuration - Setters void setListeningPortsRange(std::pair ports); void setDownloadRateLimit(int rate); void setUploadRateLimit(int rate); void setGlobalRatio(float ratio); + void setDHTPort(int dht_port); + void setSessionSettings(session_settings sessionSettings); protected slots: void cleanDeleter(deleteThread* deleter); void loadFilteredFiles(torrent_handle& h); void scanDirectory(); + void readAlerts(); signals: void invalidTorrent(const QString& path); void duplicateTorrent(const QString& path); void addedTorrent(const QString& path, torrent_handle& h, bool fastResume); void resumedTorrent(const QString& path); -} + void finishedTorrent(torrent_handle& h); + void fullDiskError(const QString& fileName); + void trackerError(const QString& hash, const QString& time, const QString& msg); + void portListeningFailure(); + void trackerAuthenticationRequired(torrent_handle& h); +}; #endif diff --git a/src/options_imp.h b/src/options_imp.h index e5fa6f8d7..dc3fab77c 100644 --- a/src/options_imp.h +++ b/src/options_imp.h @@ -24,8 +24,8 @@ #include #include "ui_options.h" -#include "libtorrent/session.hpp" -#include "libtorrent/ip_filter.hpp" +#include +#include using namespace libtorrent; diff --git a/src/src.pro b/src/src.pro index 6dfea24da..f0c9bb585 100644 --- a/src/src.pro +++ b/src/src.pro @@ -102,7 +102,8 @@ HEADERS += GUI.h misc.h options_imp.h about_imp.h \ PropListDelegate.h previewSelect.h \ PreviewListDelegate.h trackerLogin.h \ downloadThread.h downloadFromURLImp.h \ - torrentAddition.h deleteThread.h + torrentAddition.h deleteThread.h \ + bittorrent.h FORMS += MainWindow.ui options.ui about.ui \ properties.ui createtorrent.ui preview.ui \ login.ui downloadFromURL.ui addTorrentDialog.ui @@ -110,5 +111,6 @@ SOURCES += GUI.cpp \ main.cpp \ options_imp.cpp \ properties_imp.cpp \ - createtorrent_imp.cpp + createtorrent_imp.cpp \ + bittorrent.cpp