You've already forked qBittorrent
mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-10-12 03:12:18 +02:00
Compare commits
25 Commits
release-4.
...
release-2.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2fd2b07b08 | ||
![]() |
c5d92f3d69 | ||
![]() |
54487c8247 | ||
![]() |
be64008870 | ||
![]() |
8113b150dd | ||
![]() |
4a33367cb0 | ||
![]() |
0af5d82114 | ||
![]() |
10c4fd330a | ||
![]() |
9a30d5a295 | ||
![]() |
724b47d999 | ||
![]() |
2c0f7c33a2 | ||
![]() |
ce33e266fe | ||
![]() |
2f291daefa | ||
![]() |
722f2aeb5d | ||
![]() |
d5b9598b5b | ||
![]() |
cc7d74b67c | ||
![]() |
e853b0b736 | ||
![]() |
5e395b24a9 | ||
![]() |
9c3789f83f | ||
![]() |
758595dc8c | ||
![]() |
01f9e989ef | ||
![]() |
eb9f0cb559 | ||
![]() |
2592948182 | ||
![]() |
6f6ab1c439 | ||
![]() |
b10e606dda |
2
AUTHORS
2
AUTHORS
@@ -61,7 +61,7 @@ Translations authors:
|
|||||||
* files: src/lang/*.ts
|
* files: src/lang/*.ts
|
||||||
copyright:
|
copyright:
|
||||||
- Brazilian: Nick Marinho (nickmarinho@gmail.com)
|
- Brazilian: Nick Marinho (nickmarinho@gmail.com)
|
||||||
- Bulgarian: Tsvetan & Boiko Bankov (emerge_life@users.sourceforge.net)
|
- Bulgarian: Tsvetan & Boyko Bankoff (emerge_life@users.sourceforge.net)
|
||||||
- Catalan: Francisco Luque Contreras (frannoe@ya.com)
|
- Catalan: Francisco Luque Contreras (frannoe@ya.com)
|
||||||
- Chinese (Simplified): Guo Yue (yue.guo0418@gmail.com)
|
- Chinese (Simplified): Guo Yue (yue.guo0418@gmail.com)
|
||||||
- Chinese (Traditional): Yi-Shun Wang (dnextstep@gmail.com)
|
- Chinese (Traditional): Yi-Shun Wang (dnextstep@gmail.com)
|
||||||
|
24
Changelog
24
Changelog
@@ -1,4 +1,23 @@
|
|||||||
* Unreleased - Christophe Dumez <chris@qbittorrent.org> - v2.2.0
|
* Mon Mar 22 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.2
|
||||||
|
- FEATURE: DHT port can be set from Web UI
|
||||||
|
- BUGFIX: Fix possible crash with folder scanning
|
||||||
|
- BUGFIX: Fix Mac compilation
|
||||||
|
- BUGFIX: Save fast resume data every 3 minutes (for robustness)
|
||||||
|
- I18N: Updated Polish translation (thanks Szymon Świerkosz)
|
||||||
|
|
||||||
|
* Sat Mar 20 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.1
|
||||||
|
- FEATURE: Display pieces that are being downloaded
|
||||||
|
- FEATURE: Added back folder watching in Web UI
|
||||||
|
- FEATURE: Added back file prioritizing in Web UI
|
||||||
|
- BUGFIX: Fix compilation with Qt 4.4
|
||||||
|
- BUGFIX: Fix Web UI compatibility with Safari
|
||||||
|
- BUGFIX: Fix progress display with cleanlook style
|
||||||
|
- BUGFIX: Fix file filtering in complex torrents
|
||||||
|
- BUGFIX: Ask for user confirmation for recursive torrent download
|
||||||
|
- BUGFIX: Fix "add file" dialog in torrent creation tool
|
||||||
|
- BUGFIX: Fix "Ctrl+A" in Web UI
|
||||||
|
|
||||||
|
* Sun Mar 14 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.0
|
||||||
- FEATURE: User can set alternative speed limits for fast toggling
|
- FEATURE: User can set alternative speed limits for fast toggling
|
||||||
- FEATURE: Bandwidth scheduler (automatically use alternative speed limits for a given period)
|
- FEATURE: Bandwidth scheduler (automatically use alternative speed limits for a given period)
|
||||||
- FEATURE: Added "Added/Completed On" columns to transfer list
|
- FEATURE: Added "Added/Completed On" columns to transfer list
|
||||||
@@ -15,6 +34,9 @@
|
|||||||
- FEATURE: Support for multiple scan folders (Patch by Christian Kandeler)
|
- FEATURE: Support for multiple scan folders (Patch by Christian Kandeler)
|
||||||
- BUGFIX: Only one log window can be opened at a time
|
- BUGFIX: Only one log window can be opened at a time
|
||||||
- BUGFIX: Optimized RSS module memory usage
|
- BUGFIX: Optimized RSS module memory usage
|
||||||
|
- BUGFIX: Consider HTTP downloads >1MB as invalid .torrent files and abort
|
||||||
|
- BUGFIX: Fix Web UI authentication with some browsers
|
||||||
|
- BUGFIX: Set Web UI ban period to 1 hour
|
||||||
- COSMETIC: Improved style management
|
- COSMETIC: Improved style management
|
||||||
|
|
||||||
* Mon Jan 18 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.1.0
|
* Mon Jan 18 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.1.0
|
||||||
|
4
configure
vendored
4
configure
vendored
@@ -312,11 +312,7 @@ public:
|
|||||||
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
||||||
conf->addDefine("DISABLE_GUI");
|
conf->addDefine("DISABLE_GUI");
|
||||||
}
|
}
|
||||||
if(QT_VERSION >= 0x040500) {
|
|
||||||
conf->addDefine("QT_4_5");
|
|
||||||
}
|
|
||||||
return(QT_VERSION >= 0x040400);
|
return(QT_VERSION >= 0x040400);
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#line 1 "pkg-config.qcm"
|
#line 1 "pkg-config.qcm"
|
||||||
|
@@ -15,10 +15,6 @@ public:
|
|||||||
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
||||||
conf->addDefine("DISABLE_GUI");
|
conf->addDefine("DISABLE_GUI");
|
||||||
}
|
}
|
||||||
if(QT_VERSION >= 0x040500) {
|
|
||||||
conf->addDefine("QT_4_5");
|
|
||||||
}
|
|
||||||
return(QT_VERSION >= 0x040400);
|
return(QT_VERSION >= 0x040400);
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
27
src/GUI.cpp
27
src/GUI.cpp
@@ -117,6 +117,7 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
|
|||||||
connect(BTSession, SIGNAL(newDownloadedTorrent(QString, QString)), this, SLOT(processDownloadedFiles(QString, QString)));
|
connect(BTSession, SIGNAL(newDownloadedTorrent(QString, QString)), this, SLOT(processDownloadedFiles(QString, QString)));
|
||||||
connect(BTSession, SIGNAL(downloadFromUrlFailure(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString)));
|
connect(BTSession, SIGNAL(downloadFromUrlFailure(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString)));
|
||||||
connect(BTSession, SIGNAL(alternativeSpeedsModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
|
connect(BTSession, SIGNAL(alternativeSpeedsModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
|
||||||
|
connect(BTSession, SIGNAL(recursiveTorrentDownloadPossible(QTorrentHandle&)), this, SLOT(askRecursiveTorrentDownloadConfirmation(QTorrentHandle&)));
|
||||||
|
|
||||||
qDebug("create tabWidget");
|
qDebug("create tabWidget");
|
||||||
tabs = new QTabWidget();
|
tabs = new QTabWidget();
|
||||||
@@ -227,6 +228,8 @@ GUI::~GUI() {
|
|||||||
delete aboutDlg;
|
delete aboutDlg;
|
||||||
if(options)
|
if(options)
|
||||||
delete options;
|
delete options;
|
||||||
|
if(downloadFromURLDialog)
|
||||||
|
delete downloadFromURLDialog;
|
||||||
if(rssWidget)
|
if(rssWidget)
|
||||||
delete rssWidget;
|
delete rssWidget;
|
||||||
delete searchEngine;
|
delete searchEngine;
|
||||||
@@ -251,6 +254,12 @@ GUI::~GUI() {
|
|||||||
delete switchRSSShortcut;
|
delete switchRSSShortcut;
|
||||||
// Delete BTSession objects
|
// Delete BTSession objects
|
||||||
delete BTSession;
|
delete BTSession;
|
||||||
|
// Deleting remaining top level widgets
|
||||||
|
qDebug("Deleting remaining top level widgets");
|
||||||
|
foreach (QWidget *win, QApplication::topLevelWidgets()) {
|
||||||
|
if(win && win != this)
|
||||||
|
delete win;
|
||||||
|
}
|
||||||
// May freeze for a few seconds after the next line
|
// May freeze for a few seconds after the next line
|
||||||
// because the Bittorrent session proxy will
|
// because the Bittorrent session proxy will
|
||||||
// actually be deleted now and destruction
|
// actually be deleted now and destruction
|
||||||
@@ -405,6 +414,12 @@ void GUI::readParamsOnSocket() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUI::askRecursiveTorrentDownloadConfirmation(QTorrentHandle &h) {
|
||||||
|
if(QMessageBox::question(this, tr("Recursive download confirmation"), tr("The torrent %1 contains torrent files, do you want to proceed with their download?").arg(h.name()), QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes) {
|
||||||
|
BTSession->recursiveTorrentDownload(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GUI::handleDownloadFromUrlFailure(QString url, QString reason) const{
|
void GUI::handleDownloadFromUrlFailure(QString url, QString reason) const{
|
||||||
// Display a message box
|
// Display a message box
|
||||||
QMessageBox::critical(0, tr("Url download error"), tr("Couldn't download file at url: %1, reason: %2.").arg(url).arg(reason));
|
QMessageBox::critical(0, tr("Url download error"), tr("Couldn't download file at url: %1, reason: %2.").arg(url).arg(reason));
|
||||||
@@ -627,8 +642,8 @@ void GUI::on_actionOpen_triggered() {
|
|||||||
// Open File Open Dialog
|
// Open File Open Dialog
|
||||||
// Note: it is possible to select more than one file
|
// Note: it is possible to select more than one file
|
||||||
const QStringList &pathsList = QFileDialog::getOpenFileNames(0,
|
const QStringList &pathsList = QFileDialog::getOpenFileNames(0,
|
||||||
tr("Open Torrent Files"), settings.value(QString::fromUtf8("MainWindowLastDir"), QDir::homePath()).toString(),
|
tr("Open Torrent Files"), settings.value(QString::fromUtf8("MainWindowLastDir"), QDir::homePath()).toString(),
|
||||||
tr("Torrent Files")+QString::fromUtf8(" (*.torrent)"));
|
tr("Torrent Files")+QString::fromUtf8(" (*.torrent)"));
|
||||||
if(!pathsList.empty()) {
|
if(!pathsList.empty()) {
|
||||||
const bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool();
|
const bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool();
|
||||||
const uint listSize = pathsList.size();
|
const uint listSize = pathsList.size();
|
||||||
@@ -829,7 +844,7 @@ void GUI::showNotificationBaloon(QString title, QString msg) const {
|
|||||||
#ifdef WITH_LIBNOTIFY
|
#ifdef WITH_LIBNOTIFY
|
||||||
if (notify_init ("summary-body")) {
|
if (notify_init ("summary-body")) {
|
||||||
NotifyNotification* notification;
|
NotifyNotification* notification;
|
||||||
notification = notify_notification_new (title.toLocal8Bit().data(), msg.toLocal8Bit().data(), "qbittorrent", 0);
|
notification = notify_notification_new (qPrintable(title), qPrintable(msg), "qbittorrent", 0);
|
||||||
gboolean success = notify_notification_show (notification, NULL);
|
gboolean success = notify_notification_show (notification, NULL);
|
||||||
g_object_unref(G_OBJECT(notification));
|
g_object_unref(G_OBJECT(notification));
|
||||||
notify_uninit ();
|
notify_uninit ();
|
||||||
@@ -954,7 +969,9 @@ void GUI::on_actionOptions_triggered() {
|
|||||||
// Display an input dialog to prompt user for
|
// Display an input dialog to prompt user for
|
||||||
// an url
|
// an url
|
||||||
void GUI::on_actionDownload_from_URL_triggered() {
|
void GUI::on_actionDownload_from_URL_triggered() {
|
||||||
downloadFromURL *downloadFromURLDialog = new downloadFromURL(this);
|
if(!downloadFromURLDialog) {
|
||||||
connect(downloadFromURLDialog, SIGNAL(urlsReadyToBeDownloaded(const QStringList&)), this, SLOT(downloadFromURLList(const QStringList&)));
|
downloadFromURLDialog = new downloadFromURL(this);
|
||||||
|
connect(downloadFromURLDialog, SIGNAL(urlsReadyToBeDownloaded(const QStringList&)), this, SLOT(downloadFromURLList(const QStringList&)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -58,6 +58,7 @@ class StatusBar;
|
|||||||
class consoleDlg;
|
class consoleDlg;
|
||||||
class about;
|
class about;
|
||||||
class createtorrent;
|
class createtorrent;
|
||||||
|
class downloadFromURL;
|
||||||
|
|
||||||
class GUI : public QMainWindow, private Ui::MainWindow{
|
class GUI : public QMainWindow, private Ui::MainWindow{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -115,6 +116,7 @@ protected slots:
|
|||||||
void addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker);
|
void addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker);
|
||||||
void processDownloadedFiles(QString path, QString url);
|
void processDownloadedFiles(QString path, QString url);
|
||||||
void finishedTorrent(QTorrentHandle& h) const;
|
void finishedTorrent(QTorrentHandle& h) const;
|
||||||
|
void askRecursiveTorrentDownloadConfirmation(QTorrentHandle &h);
|
||||||
// Options slots
|
// Options slots
|
||||||
void on_actionOptions_triggered();
|
void on_actionOptions_triggered();
|
||||||
void optionsSaved();
|
void optionsSaved();
|
||||||
@@ -139,6 +141,7 @@ private:
|
|||||||
QPointer<consoleDlg> console;
|
QPointer<consoleDlg> console;
|
||||||
QPointer<about> aboutDlg;
|
QPointer<about> aboutDlg;
|
||||||
QPointer<createtorrent> createTorrentDlg;
|
QPointer<createtorrent> createTorrentDlg;
|
||||||
|
QPointer<downloadFromURL> downloadFromURLDialog;
|
||||||
QPointer<QSystemTrayIcon> systrayIcon;
|
QPointer<QSystemTrayIcon> systrayIcon;
|
||||||
QPointer<QTimer> systrayCreator;
|
QPointer<QTimer> systrayCreator;
|
||||||
QMenu *myTrayIconMenu;
|
QMenu *myTrayIconMenu;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Categories=Qt;Network;P2P;
|
Categories=Qt;Network;P2P;
|
||||||
Comment=V2.2.0
|
Comment=V2.2.2
|
||||||
Exec=qbittorrent %f
|
Exec=qbittorrent %f
|
||||||
GenericName=Bittorrent client
|
GenericName=Bittorrent client
|
||||||
GenericName[bg]=Торент клиент
|
GenericName[bg]=Торент клиент
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
@@ -63,7 +63,7 @@ class about : public QDialog, private Ui::AboutDlg{
|
|||||||
te_translation->append(tr("I would like to thank the following people who volunteered to translate qBittorrent:")+QString::fromUtf8("<br>"));
|
te_translation->append(tr("I would like to thank the following people who volunteered to translate qBittorrent:")+QString::fromUtf8("<br>"));
|
||||||
te_translation->append(QString::fromUtf8(
|
te_translation->append(QString::fromUtf8(
|
||||||
"<i>- <u>Brazilian:</u> Nick Marinho (nickmarinho@gmail.com)<br>\
|
"<i>- <u>Brazilian:</u> Nick Marinho (nickmarinho@gmail.com)<br>\
|
||||||
- <u>Bulgarian:</u> Tsvetan & Boiko Bankov (emerge_life@users.sourceforge.net)<br>\
|
- <u>Bulgarian:</u> Tsvetan & Boyko Bankoff (emerge_life@users.sourceforge.net)<br>\
|
||||||
- <u>Catalan:</u> Francisco Luque Contreras (frannoe@ya.com)<br>\
|
- <u>Catalan:</u> Francisco Luque Contreras (frannoe@ya.com)<br>\
|
||||||
- <u>Chinese (Simplified):</u> Guo Yue (yue.guo0418@gmail.com)<br>\
|
- <u>Chinese (Simplified):</u> Guo Yue (yue.guo0418@gmail.com)<br>\
|
||||||
- <u>Chinese (Traditional):</u> Yi-Shun Wang (dnextstep@gmail.com)<br>\
|
- <u>Chinese (Traditional):</u> Yi-Shun Wang (dnextstep@gmail.com)<br>\
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,7 @@
|
|||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#endif
|
#endif
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include <libtorrent/session.hpp>
|
#include <libtorrent/session.hpp>
|
||||||
#include <libtorrent/ip_filter.hpp>
|
#include <libtorrent/ip_filter.hpp>
|
||||||
@@ -115,13 +116,11 @@ public:
|
|||||||
qlonglong getETA(QString hash);
|
qlonglong getETA(QString hash);
|
||||||
bool useTemporaryFolder() const;
|
bool useTemporaryFolder() const;
|
||||||
QString getDefaultSavePath() const;
|
QString getDefaultSavePath() const;
|
||||||
|
ScanFoldersModel* getScanFoldersModel() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
|
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
|
||||||
QTorrentHandle addMagnetUri(QString magnet_uri, bool resumed=false);
|
QTorrentHandle addMagnetUri(QString magnet_uri, bool resumed=false);
|
||||||
void importOldTorrents();
|
|
||||||
void applyFormerAttributeFiles(QTorrentHandle h);
|
|
||||||
void importOldTempData(QString torrent_path);
|
|
||||||
void loadSessionState();
|
void loadSessionState();
|
||||||
void saveSessionState();
|
void saveSessionState();
|
||||||
void downloadFromUrl(QString url);
|
void downloadFromUrl(QString url);
|
||||||
@@ -184,6 +183,7 @@ public slots:
|
|||||||
void downloadFromURLList(const QStringList& urls);
|
void downloadFromURLList(const QStringList& urls);
|
||||||
void configureSession();
|
void configureSession();
|
||||||
void banIP(QString ip);
|
void banIP(QString ip);
|
||||||
|
void recursiveTorrentDownload(const QTorrentHandle &h);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString getSavePath(QString hash, bool fromScanDir = false, QString filePath = QString());
|
QString getSavePath(QString hash, bool fromScanDir = false, QString filePath = QString());
|
||||||
@@ -195,6 +195,7 @@ protected slots:
|
|||||||
void deleteBigRatios();
|
void deleteBigRatios();
|
||||||
void takeETASamples();
|
void takeETASamples();
|
||||||
void exportTorrentFiles(QString path);
|
void exportTorrentFiles(QString path);
|
||||||
|
void saveTempFastResumeData();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void addedTorrent(QTorrentHandle& h);
|
void addedTorrent(QTorrentHandle& h);
|
||||||
@@ -204,7 +205,7 @@ signals:
|
|||||||
void finishedTorrent(QTorrentHandle& h);
|
void finishedTorrent(QTorrentHandle& h);
|
||||||
void fullDiskError(QTorrentHandle& h, QString msg);
|
void fullDiskError(QTorrentHandle& h, QString msg);
|
||||||
void trackerError(QString hash, QString time, QString msg);
|
void trackerError(QString hash, QString time, QString msg);
|
||||||
void trackerAuthenticationRequired(const QTorrentHandle& h);
|
void trackerAuthenticationRequired(QTorrentHandle& h);
|
||||||
void newDownloadedTorrent(QString path, QString url);
|
void newDownloadedTorrent(QString path, QString url);
|
||||||
void updateFileSize(QString hash);
|
void updateFileSize(QString hash);
|
||||||
void downloadFromUrlFailure(QString url, QString reason);
|
void downloadFromUrlFailure(QString url, QString reason);
|
||||||
@@ -213,6 +214,7 @@ signals:
|
|||||||
void savePathChanged(QTorrentHandle &h);
|
void savePathChanged(QTorrentHandle &h);
|
||||||
void newConsoleMessage(QString msg);
|
void newConsoleMessage(QString msg);
|
||||||
void alternativeSpeedsModeChanged(bool alternative);
|
void alternativeSpeedsModeChanged(bool alternative);
|
||||||
|
void recursiveTorrentDownloadPossible(QTorrentHandle &h);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Bittorrent
|
// Bittorrent
|
||||||
@@ -222,6 +224,7 @@ private:
|
|||||||
QMap<QUrl, QString> savepath_fromurl;
|
QMap<QUrl, QString> savepath_fromurl;
|
||||||
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
|
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
|
||||||
QStringList torrentsToPausedAfterChecking;
|
QStringList torrentsToPausedAfterChecking;
|
||||||
|
QTimer resumeDataTimer;
|
||||||
// Ratio
|
// Ratio
|
||||||
QPointer<QTimer> BigRatioTimer;
|
QPointer<QTimer> BigRatioTimer;
|
||||||
// HTTP
|
// HTTP
|
||||||
|
@@ -46,6 +46,7 @@ class consoleDlg : public QDialog, private Ui_ConsoleDlg{
|
|||||||
consoleDlg(QWidget *parent, Bittorrent* _BTSession) : QDialog(parent) {
|
consoleDlg(QWidget *parent, Bittorrent* _BTSession) : QDialog(parent) {
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
setModal(true);
|
||||||
BTSession = _BTSession;
|
BTSession = _BTSession;
|
||||||
textConsole->setHtml(BTSession->getConsoleMessages().join("<br>"));
|
textConsole->setHtml(BTSession->getConsoleMessages().join("<br>"));
|
||||||
textBannedPeers->setHtml(BTSession->getPeerBanMessages().join("<br>"));
|
textBannedPeers->setHtml(BTSession->getPeerBanMessages().join("<br>"));
|
||||||
|
@@ -65,6 +65,7 @@ bool file_filter(boost::filesystem::path const& filename)
|
|||||||
createtorrent::createtorrent(QWidget *parent): QDialog(parent){
|
createtorrent::createtorrent(QWidget *parent): QDialog(parent){
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
setModal(true);
|
||||||
creatorThread = new torrentCreatorThread(this);
|
creatorThread = new torrentCreatorThread(this);
|
||||||
connect(creatorThread, SIGNAL(creationSuccess(QString, const char*)), this, SLOT(handleCreationSuccess(QString, const char*)));
|
connect(creatorThread, SIGNAL(creationSuccess(QString, const char*)), this, SLOT(handleCreationSuccess(QString, const char*)));
|
||||||
connect(creatorThread, SIGNAL(creationFailure(QString)), this, SLOT(handleCreationFailure(QString)));
|
connect(creatorThread, SIGNAL(creationFailure(QString)), this, SLOT(handleCreationFailure(QString)));
|
||||||
@@ -84,7 +85,7 @@ void createtorrent::on_addFolder_button_clicked(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void createtorrent::on_addFile_button_clicked(){
|
void createtorrent::on_addFile_button_clicked(){
|
||||||
QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath(), QString(), 0, QFileDialog::ShowDirsOnly);
|
QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath());
|
||||||
if(!file.isEmpty())
|
if(!file.isEmpty())
|
||||||
textInputPath->setText(file);
|
textInputPath->setText(file);
|
||||||
}
|
}
|
||||||
|
@@ -53,34 +53,49 @@ public:
|
|||||||
setFixedHeight(BAR_HEIGHT);
|
setFixedHeight(BAR_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setProgress(bitfield pieces) {
|
void setProgress(const bitfield &pieces, const bitfield &downloading_pieces) {
|
||||||
if(pieces.empty()) {
|
if(pieces.empty()) {
|
||||||
// Empty bar
|
// Empty bar
|
||||||
QPixmap pix = QPixmap(1, 1);
|
QPixmap pix = QPixmap(1, 1);
|
||||||
pix.fill();
|
pix.fill();
|
||||||
pixmap = pix;
|
pixmap = pix;
|
||||||
} else {
|
} else {
|
||||||
int nb_pieces = pieces.size();
|
const int nb_pieces = pieces.size();
|
||||||
// Reduce the number of pieces before creating the pixmap
|
// Reduce the number of pieces before creating the pixmap
|
||||||
// otherwise it can crash when there are too many pieces
|
// otherwise it can crash when there are too many pieces
|
||||||
if(nb_pieces > width()) {
|
if(nb_pieces > width()) {
|
||||||
int ratio = floor(nb_pieces/(double)width());
|
const int ratio = floor(nb_pieces/(double)width());
|
||||||
QVector<bool> scaled_pieces;
|
std::vector<bool> scaled_pieces;
|
||||||
|
std::vector<bool> scaled_downloading;
|
||||||
for(int i=0; i<nb_pieces; i+= ratio) {
|
for(int i=0; i<nb_pieces; i+= ratio) {
|
||||||
bool have = true;
|
bool have = true;
|
||||||
for(int j=i; j<qMin(i+ratio, nb_pieces); ++j) {
|
for(int j=i; j<qMin(i+ratio, nb_pieces); ++j) {
|
||||||
if(!pieces[i]) { have = false; break; }
|
if(!pieces[i]) { have = false; break; }
|
||||||
}
|
}
|
||||||
scaled_pieces << have;
|
scaled_pieces.push_back(have);
|
||||||
|
if(have) {
|
||||||
|
scaled_downloading.push_back(false);
|
||||||
|
} else {
|
||||||
|
bool downloading = false;
|
||||||
|
for(int j=i; j<qMin(i+ratio, nb_pieces); ++j) {
|
||||||
|
if(downloading_pieces[i]) { downloading = true; break; }
|
||||||
|
}
|
||||||
|
scaled_downloading.push_back(downloading);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QPixmap pix = QPixmap(scaled_pieces.size(), 1);
|
QPixmap pix = QPixmap(scaled_pieces.size(), 1);
|
||||||
pix.fill();
|
pix.fill();
|
||||||
QPainter painter(&pix);
|
QPainter painter(&pix);
|
||||||
for(int i=0; i<scaled_pieces.size(); ++i) {
|
for(uint i=0; i<scaled_pieces.size(); ++i) {
|
||||||
if(scaled_pieces[i])
|
if(scaled_pieces[i]) {
|
||||||
painter.setPen(Qt::blue);
|
painter.setPen(Qt::blue);
|
||||||
else
|
} else {
|
||||||
painter.setPen(Qt::white);
|
if(scaled_downloading[i]) {
|
||||||
|
painter.setPen(Qt::yellow);
|
||||||
|
} else {
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
}
|
||||||
|
}
|
||||||
painter.drawPoint(i,0);
|
painter.drawPoint(i,0);
|
||||||
}
|
}
|
||||||
pixmap = pix;
|
pixmap = pix;
|
||||||
@@ -89,10 +104,15 @@ public:
|
|||||||
pix.fill();
|
pix.fill();
|
||||||
QPainter painter(&pix);
|
QPainter painter(&pix);
|
||||||
for(uint i=0; i<pieces.size(); ++i) {
|
for(uint i=0; i<pieces.size(); ++i) {
|
||||||
if(pieces[i])
|
if(pieces[i]) {
|
||||||
painter.setPen(Qt::blue);
|
painter.setPen(Qt::blue);
|
||||||
else
|
} else {
|
||||||
painter.setPen(Qt::white);
|
if(downloading_pieces[i]) {
|
||||||
|
painter.setPen(Qt::yellow);
|
||||||
|
} else {
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
}
|
||||||
|
}
|
||||||
painter.drawPoint(i,0);
|
painter.drawPoint(i,0);
|
||||||
}
|
}
|
||||||
pixmap = pix;
|
pixmap = pix;
|
||||||
|
@@ -47,6 +47,7 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{
|
|||||||
setupUi(this);
|
setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
icon_lbl->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/url.png")));
|
icon_lbl->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/url.png")));
|
||||||
|
setModal(true);
|
||||||
show();
|
show();
|
||||||
// Paste clipboard if there is an URL in it
|
// Paste clipboard if there is an URL in it
|
||||||
QString clip_txt = qApp->clipboard()->text();
|
QString clip_txt = qApp->clipboard()->text();
|
||||||
|
@@ -59,7 +59,7 @@ void downloadThread::processDlFinished(QNetworkReply* reply) {
|
|||||||
QVariant redirection = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
QVariant redirection = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||||
if(redirection.isValid()) {
|
if(redirection.isValid()) {
|
||||||
// We should redirect
|
// We should redirect
|
||||||
qDebug("Redirecting from %s to %s", url.toLocal8Bit().data(), redirection.toUrl().toString().toLocal8Bit().data());
|
qDebug("Redirecting from %s to %s", qPrintable(url), qPrintable(redirection.toUrl().toString()));
|
||||||
redirect_mapping.insert(redirection.toUrl().toString(), url);
|
redirect_mapping.insert(redirection.toUrl().toString(), url);
|
||||||
downloadUrl(redirection.toUrl().toString());
|
downloadUrl(redirection.toUrl().toString());
|
||||||
return;
|
return;
|
||||||
@@ -74,7 +74,7 @@ void downloadThread::processDlFinished(QNetworkReply* reply) {
|
|||||||
tmpfile.setAutoRemove(false);
|
tmpfile.setAutoRemove(false);
|
||||||
if (tmpfile.open()) {
|
if (tmpfile.open()) {
|
||||||
filePath = tmpfile.fileName();
|
filePath = tmpfile.fileName();
|
||||||
qDebug("Temporary filename is: %s", filePath.toLocal8Bit().data());
|
qDebug("Temporary filename is: %s", qPrintable(filePath));
|
||||||
if(reply->open(QIODevice::ReadOnly)) {
|
if(reply->open(QIODevice::ReadOnly)) {
|
||||||
// TODO: Support GZIP compression
|
// TODO: Support GZIP compression
|
||||||
tmpfile.write(reply->readAll());
|
tmpfile.write(reply->readAll());
|
||||||
@@ -95,7 +95,12 @@ void downloadThread::processDlFinished(QNetworkReply* reply) {
|
|||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void downloadThread::downloadUrl(QString url){
|
void downloadThread::downloadTorrentUrl(QString url){
|
||||||
|
QNetworkReply *reply = downloadUrl(url);
|
||||||
|
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(checkDownloadSize(qint64,qint64)));
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkReply* downloadThread::downloadUrl(QString url){
|
||||||
// Update proxy settings
|
// Update proxy settings
|
||||||
applyProxySettings();
|
applyProxySettings();
|
||||||
// Process download request
|
// Process download request
|
||||||
@@ -104,8 +109,27 @@ void downloadThread::downloadUrl(QString url){
|
|||||||
// Spoof Firefox 3.5 user agent to avoid
|
// Spoof Firefox 3.5 user agent to avoid
|
||||||
// Web server banning
|
// Web server banning
|
||||||
request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5");
|
request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5");
|
||||||
qDebug("Downloading %s...", request.url().toString().toLocal8Bit().data());
|
qDebug("Downloading %s...", qPrintable(request.url().toString()));
|
||||||
networkManager->get(request);
|
return networkManager->get(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void downloadThread::checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal) {
|
||||||
|
if(bytesTotal > 0) {
|
||||||
|
QNetworkReply *reply = static_cast<QNetworkReply*>(sender());
|
||||||
|
// Total number of bytes is available
|
||||||
|
if(bytesTotal > 1048576) {
|
||||||
|
// More than 1MB, this is probably not a torrent file, aborting...
|
||||||
|
reply->abort();
|
||||||
|
} else {
|
||||||
|
disconnect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(checkDownloadSize(qint64,qint64)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(bytesReceived > 1048576) {
|
||||||
|
// More than 1MB, this is probably not a torrent file, aborting...
|
||||||
|
QNetworkReply *reply = static_cast<QNetworkReply*>(sender());
|
||||||
|
reply->abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void downloadThread::applyProxySettings() {
|
void downloadThread::applyProxySettings() {
|
||||||
@@ -117,7 +141,7 @@ void downloadThread::applyProxySettings() {
|
|||||||
QString IP = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/IP"), "0.0.0.0").toString();
|
QString IP = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/IP"), "0.0.0.0").toString();
|
||||||
proxy.setHostName(IP);
|
proxy.setHostName(IP);
|
||||||
QString port = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/Port"), 8080).toString();
|
QString port = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/Port"), 8080).toString();
|
||||||
qDebug("Using proxy: %s", (IP+QString(":")+port).toLocal8Bit().data());
|
qDebug("Using proxy: %s", qPrintable(IP));
|
||||||
proxy.setPort(port.toUShort());
|
proxy.setPort(port.toUShort());
|
||||||
// Default proxy type is HTTP, we must change if it is SOCKS5
|
// Default proxy type is HTTP, we must change if it is SOCKS5
|
||||||
if(intValue == SOCKS5 || intValue == SOCKS5_PW) {
|
if(intValue == SOCKS5 || intValue == SOCKS5_PW) {
|
||||||
|
@@ -51,7 +51,8 @@ signals:
|
|||||||
public:
|
public:
|
||||||
downloadThread(QObject* parent);
|
downloadThread(QObject* parent);
|
||||||
~downloadThread();
|
~downloadThread();
|
||||||
void downloadUrl(QString url);
|
QNetworkReply* downloadUrl(QString url);
|
||||||
|
void downloadTorrentUrl(QString url);
|
||||||
//void setProxy(QString IP, int port, QString username, QString password);
|
//void setProxy(QString IP, int port, QString username, QString password);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -60,6 +61,7 @@ protected:
|
|||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void processDlFinished(QNetworkReply* reply);
|
void processDlFinished(QNetworkReply* reply);
|
||||||
|
void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -81,7 +81,7 @@ void engineSelectDlg::dropEvent(QDropEvent *event) {
|
|||||||
QStringList files=event->mimeData()->text().split(QString::fromUtf8("\n"));
|
QStringList files=event->mimeData()->text().split(QString::fromUtf8("\n"));
|
||||||
QString file;
|
QString file;
|
||||||
foreach(file, files) {
|
foreach(file, files) {
|
||||||
qDebug("dropped %s", file.toLocal8Bit().data());
|
qDebug("dropped %s", qPrintable(file));
|
||||||
file = file.replace("file://", "");
|
file = file.replace("file://", "");
|
||||||
if(file.startsWith("http://", Qt::CaseInsensitive) || file.startsWith("https://", Qt::CaseInsensitive) || file.startsWith("ftp://", Qt::CaseInsensitive)) {
|
if(file.startsWith("http://", Qt::CaseInsensitive) || file.startsWith("https://", Qt::CaseInsensitive) || file.startsWith("ftp://", Qt::CaseInsensitive)) {
|
||||||
downloader->downloadUrl(file);
|
downloader->downloadUrl(file);
|
||||||
@@ -99,7 +99,7 @@ void engineSelectDlg::dropEvent(QDropEvent *event) {
|
|||||||
void engineSelectDlg::dragEnterEvent(QDragEnterEvent *event) {
|
void engineSelectDlg::dragEnterEvent(QDragEnterEvent *event) {
|
||||||
QString mime;
|
QString mime;
|
||||||
foreach(mime, event->mimeData()->formats()){
|
foreach(mime, event->mimeData()->formats()){
|
||||||
qDebug("mimeData: %s", mime.toLocal8Bit().data());
|
qDebug("mimeData: %s", qPrintable(mime));
|
||||||
}
|
}
|
||||||
if (event->mimeData()->hasFormat(QString::fromUtf8("text/plain")) || event->mimeData()->hasFormat(QString::fromUtf8("text/uri-list"))) {
|
if (event->mimeData()->hasFormat(QString::fromUtf8("text/plain")) || event->mimeData()->hasFormat(QString::fromUtf8("text/uri-list"))) {
|
||||||
event->acceptProposedAction();
|
event->acceptProposedAction();
|
||||||
@@ -251,12 +251,12 @@ bool engineSelectDlg::isUpdateNeeded(QString plugin_name, float new_version) con
|
|||||||
}
|
}
|
||||||
|
|
||||||
void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
||||||
qDebug("Asked to install plugin at %s", path.toLocal8Bit().data());
|
qDebug("Asked to install plugin at %s", qPrintable(path));
|
||||||
float new_version = SearchEngine::getPluginVersion(path);
|
float new_version = SearchEngine::getPluginVersion(path);
|
||||||
qDebug("Version to be installed: %.2f", new_version);
|
qDebug("Version to be installed: %.2f", new_version);
|
||||||
if(!isUpdateNeeded(plugin_name, new_version)) {
|
if(!isUpdateNeeded(plugin_name, new_version)) {
|
||||||
qDebug("Apparently update is not needed, we have a more recent version");
|
qDebug("Apparently update is not needed, we have a more recent version");
|
||||||
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("A more recent version of %1 search engine plugin is already installed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("A more recent version of %1 search engine plugin is already installed.", "%1 is the name of the search engine").arg(plugin_name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Process with install
|
// Process with install
|
||||||
@@ -280,12 +280,12 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
|||||||
// restore backup
|
// restore backup
|
||||||
QFile::copy(dest_path+".bak", dest_path);
|
QFile::copy(dest_path+".bak", dest_path);
|
||||||
QFile::remove(dest_path+".bak");
|
QFile::remove(dest_path+".bak");
|
||||||
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be updated, keeping old version.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be updated, keeping old version.", "%1 is the name of the search engine").arg(plugin_name));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Remove broken file
|
// Remove broken file
|
||||||
QFile::remove(dest_path);
|
QFile::remove(dest_path);
|
||||||
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be installed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be installed.", "%1 is the name of the search engine").arg(plugin_name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,10 +294,10 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
|||||||
QFile::remove(dest_path+".bak");
|
QFile::remove(dest_path+".bak");
|
||||||
}
|
}
|
||||||
if(update) {
|
if(update) {
|
||||||
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin was successfully updated.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin was successfully updated.", "%1 is the name of the search engine").arg(plugin_name));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin was successfully installed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin was successfully installed.", "%1 is the name of the search engine").arg(plugin_name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,17 +390,17 @@ bool engineSelectDlg::parseVersionsFile(QString versions_file) {
|
|||||||
plugin_name.chop(1); // remove trailing ':'
|
plugin_name.chop(1); // remove trailing ':'
|
||||||
bool ok;
|
bool ok;
|
||||||
float version = list.last().toFloat(&ok);
|
float version = list.last().toFloat(&ok);
|
||||||
qDebug("read line %s: %.2f", plugin_name.toLocal8Bit().data(), version);
|
qDebug("read line %s: %.2f", qPrintable(plugin_name), version);
|
||||||
if(!ok) continue;
|
if(!ok) continue;
|
||||||
file_correct = true;
|
file_correct = true;
|
||||||
if(isUpdateNeeded(plugin_name, version)) {
|
if(isUpdateNeeded(plugin_name, version)) {
|
||||||
qDebug("Plugin: %s is outdated", plugin_name.toLocal8Bit().data());
|
qDebug("Plugin: %s is outdated", qPrintable(plugin_name));
|
||||||
// Downloading update
|
// Downloading update
|
||||||
downloader->downloadUrl(UPDATE_URL+plugin_name+".py");
|
downloader->downloadUrl(UPDATE_URL+plugin_name+".py");
|
||||||
//downloader->downloadUrl(UPDATE_URL+plugin_name+".png");
|
//downloader->downloadUrl(UPDATE_URL+plugin_name+".png");
|
||||||
updated = true;
|
updated = true;
|
||||||
}else {
|
}else {
|
||||||
qDebug("Plugin: %s is up to date", plugin_name.toLocal8Bit().data());
|
qDebug("Plugin: %s is up to date", qPrintable(plugin_name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Close file
|
// Close file
|
||||||
@@ -414,7 +414,7 @@ bool engineSelectDlg::parseVersionsFile(QString versions_file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void engineSelectDlg::processDownloadedFile(QString url, QString filePath) {
|
void engineSelectDlg::processDownloadedFile(QString url, QString filePath) {
|
||||||
qDebug("engineSelectDlg received %s", url.toLocal8Bit().data());
|
qDebug("engineSelectDlg received %s", qPrintable(url));
|
||||||
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
|
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
|
||||||
// Icon downloaded
|
// Icon downloaded
|
||||||
QImage fileIcon;
|
QImage fileIcon;
|
||||||
@@ -456,7 +456,7 @@ void engineSelectDlg::processDownloadedFile(QString url, QString filePath) {
|
|||||||
|
|
||||||
void engineSelectDlg::handleDownloadFailure(QString url, QString reason) {
|
void engineSelectDlg::handleDownloadFailure(QString url, QString reason) {
|
||||||
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
|
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
|
||||||
qDebug("Could not download favicon: %s, reason: %s", url.toLocal8Bit().data(), reason.toLocal8Bit().data());
|
qDebug("Could not download favicon: %s, reason: %s", qPrintable(url), qPrintable(reason));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(url.endsWith("versions.txt")) {
|
if(url.endsWith("versions.txt")) {
|
||||||
@@ -467,6 +467,6 @@ void engineSelectDlg::handleDownloadFailure(QString url, QString reason) {
|
|||||||
// a plugin update download has been failed
|
// a plugin update download has been failed
|
||||||
QString plugin_name = url.split('/').last();
|
QString plugin_name = url.split('/').last();
|
||||||
plugin_name.replace(".py", "", Qt::CaseInsensitive);
|
plugin_name.replace(".py", "", Qt::CaseInsensitive);
|
||||||
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, %1 search plugin install failed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, %1 search plugin install failed.", "%1 is the name of the search engine").arg(plugin_name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "eventmanager.h"
|
#include "eventmanager.h"
|
||||||
#include "bittorrent.h"
|
#include "bittorrent.h"
|
||||||
|
#include "scannedfoldersmodel.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
//#include "proplistdelegate.h"
|
//#include "proplistdelegate.h"
|
||||||
@@ -129,10 +130,29 @@ void EventManager::setGlobalPreferences(QVariantMap m) const {
|
|||||||
Preferences::setTempPathEnabled(m["temp_path_enabled"].toBool());
|
Preferences::setTempPathEnabled(m["temp_path_enabled"].toBool());
|
||||||
if(m.contains("temp_path"))
|
if(m.contains("temp_path"))
|
||||||
Preferences::setTempPath(m["temp_path"].toString());
|
Preferences::setTempPath(m["temp_path"].toString());
|
||||||
if(m.contains("scan_dirs"))
|
if(m.contains("scan_dirs") && m.contains("download_in_scan_dirs")) {
|
||||||
Preferences::setScanDirs(m["scan_dirs"].toStringList());
|
QVariantList download_at_path = m["download_in_scan_dirs"].toList();
|
||||||
if(m.contains("download_in_scan_dirs"))
|
QStringList old_folders = Preferences::getScanDirs();
|
||||||
Preferences::setDownloadInScanDirs(m["download_in_scan_dirs"].toList());
|
QStringList new_folders = m["scan_dirs"].toStringList();
|
||||||
|
if(download_at_path.size() == new_folders.size()) {
|
||||||
|
Preferences::setScanDirs(new_folders);
|
||||||
|
Preferences::setDownloadInScanDirs(download_at_path);
|
||||||
|
foreach(const QString &old_folder, old_folders) {
|
||||||
|
// Update deleted folders
|
||||||
|
if(!new_folders.contains(old_folder)) {
|
||||||
|
BTSession->getScanFoldersModel()->removePath(old_folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
foreach(const QString &new_folder, new_folders) {
|
||||||
|
// Update new folders
|
||||||
|
if(!old_folders.contains(new_folder)) {
|
||||||
|
BTSession->getScanFoldersModel()->addPath(new_folder, download_at_path.at(i).toBool());
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if(m.contains("export_dir"))
|
if(m.contains("export_dir"))
|
||||||
Preferences::setExportDir(m["export_dir"].toString());
|
Preferences::setExportDir(m["export_dir"].toString());
|
||||||
if(m.contains("preallocate_all"))
|
if(m.contains("preallocate_all"))
|
||||||
@@ -169,6 +189,10 @@ void EventManager::setGlobalPreferences(QVariantMap m) const {
|
|||||||
// Bittorrent
|
// Bittorrent
|
||||||
if(m.contains("dht"))
|
if(m.contains("dht"))
|
||||||
Preferences::setDHTEnabled(m["dht"].toBool());
|
Preferences::setDHTEnabled(m["dht"].toBool());
|
||||||
|
if(m.contains("dhtSameAsBT"))
|
||||||
|
Preferences::setDHTPortSameAsBT(m["dhtSameAsBT"].toBool());
|
||||||
|
if(m.contains("dht_port"))
|
||||||
|
Preferences::setDHTPort(m["dht_port"].toInt());
|
||||||
if(m.contains("pex"))
|
if(m.contains("pex"))
|
||||||
Preferences::setPeXEnabled(m["pex"].toBool());
|
Preferences::setPeXEnabled(m["pex"].toBool());
|
||||||
qDebug("Pex support: %d", (int)m["pex"].toBool());
|
qDebug("Pex support: %d", (int)m["pex"].toBool());
|
||||||
@@ -254,6 +278,8 @@ QVariantMap EventManager::getGlobalPreferences() const {
|
|||||||
data["max_uploads_per_torrent"] = Preferences::getMaxUploadsPerTorrent();
|
data["max_uploads_per_torrent"] = Preferences::getMaxUploadsPerTorrent();
|
||||||
// Bittorrent
|
// Bittorrent
|
||||||
data["dht"] = Preferences::isDHTEnabled();
|
data["dht"] = Preferences::isDHTEnabled();
|
||||||
|
data["dhtSameAsBT"] = Preferences::isDHTPortSameAsBT();
|
||||||
|
data["dht_port"] = Preferences::getDHTPort();
|
||||||
data["pex"] = Preferences::isPeXEnabled();
|
data["pex"] = Preferences::isPeXEnabled();
|
||||||
data["lsd"] = Preferences::isLSDEnabled();
|
data["lsd"] = Preferences::isLSDEnabled();
|
||||||
data["encryption"] = Preferences::getEncryptionSetting();
|
data["encryption"] = Preferences::getEncryptionSetting();
|
||||||
@@ -295,23 +321,23 @@ QVariantMap EventManager::getPropGeneralInfo(QString hash) const {
|
|||||||
data["creation_date"] = h.creation_date();
|
data["creation_date"] = h.creation_date();
|
||||||
// Comment
|
// Comment
|
||||||
data["comment"] = h.comment();
|
data["comment"] = h.comment();
|
||||||
data["total_wasted"] = misc::friendlyUnit(h.total_failed_bytes()+h.total_redundant_bytes());
|
data["total_wasted"] = QVariant(misc::friendlyUnit(h.total_failed_bytes()+h.total_redundant_bytes()));
|
||||||
data["total_uploaded"] = misc::friendlyUnit(h.all_time_upload()) + " ("+misc::friendlyUnit(h.total_payload_upload())+" "+tr("this session")+")";
|
data["total_uploaded"] = QVariant(misc::friendlyUnit(h.all_time_upload()) + " ("+misc::friendlyUnit(h.total_payload_upload())+" "+tr("this session")+")");
|
||||||
data["total_downloaded"] = misc::friendlyUnit(h.all_time_download()) + " ("+misc::friendlyUnit(h.total_payload_download())+" "+tr("this session")+")";
|
data["total_downloaded"] = QVariant(misc::friendlyUnit(h.all_time_download()) + " ("+misc::friendlyUnit(h.total_payload_download())+" "+tr("this session")+")");
|
||||||
if(h.upload_limit() <= 0)
|
if(h.upload_limit() <= 0)
|
||||||
data["up_limit"] = QString::fromUtf8("∞");
|
data["up_limit"] = QString::fromUtf8("∞");
|
||||||
else
|
else
|
||||||
data["up_limit"] = misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)");
|
data["up_limit"] = QVariant(misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)"));
|
||||||
if(h.download_limit() <= 0)
|
if(h.download_limit() <= 0)
|
||||||
data["dl_limit"] = QString::fromUtf8("∞");
|
data["dl_limit"] = QString::fromUtf8("∞");
|
||||||
else
|
else
|
||||||
data["dl_limit"] = misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)");
|
data["dl_limit"] = QVariant(misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)"));
|
||||||
QString elapsed_txt = misc::userFriendlyDuration(h.active_time());
|
QString elapsed_txt = misc::userFriendlyDuration(h.active_time());
|
||||||
if(h.is_seed()) {
|
if(h.is_seed()) {
|
||||||
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")";
|
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")";
|
||||||
}
|
}
|
||||||
data["time_elapsed"] = elapsed_txt;
|
data["time_elapsed"] = elapsed_txt;
|
||||||
data["nb_connections"] = QString::number(h.num_connections())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit()))+")";
|
data["nb_connections"] = QVariant(QString::number(h.num_connections())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit()))+")");
|
||||||
// Update ratio info
|
// Update ratio info
|
||||||
double ratio = BTSession->getRealRatio(h.hash());
|
double ratio = BTSession->getRealRatio(h.hash());
|
||||||
if(ratio > 100.)
|
if(ratio > 100.)
|
||||||
|
@@ -28,15 +28,16 @@ public:
|
|||||||
setColumnCount(1);
|
setColumnCount(1);
|
||||||
QTreeWidgetItem *___qtreewidgetitem = headerItem();
|
QTreeWidgetItem *___qtreewidgetitem = headerItem();
|
||||||
___qtreewidgetitem->setText(0, QApplication::translate("RSS", "RSS feeds", 0, QApplication::UnicodeUTF8));
|
___qtreewidgetitem->setText(0, QApplication::translate("RSS", "RSS feeds", 0, QApplication::UnicodeUTF8));
|
||||||
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(updateCurrentFeed(QTreeWidgetItem*)));
|
|
||||||
unread_item = new QTreeWidgetItem(this);
|
unread_item = new QTreeWidgetItem(this);
|
||||||
unread_item->setText(0, tr("Unread") + QString::fromUtf8(" (") + QString::number(rssmanager->getNbUnRead(), 10)+ QString(")"));
|
unread_item->setText(0, tr("Unread") + QString::fromUtf8(" (") + QString::number(rssmanager->getNbUnRead(), 10)+ QString(")"));
|
||||||
unread_item->setData(0,Qt::DecorationRole, QVariant(QIcon(":/Icons/oxygen/mail-folder-inbox.png")));
|
unread_item->setData(0,Qt::DecorationRole, QVariant(QIcon(":/Icons/oxygen/mail-folder-inbox.png")));
|
||||||
itemAdded(unread_item, rssmanager);
|
itemAdded(unread_item, rssmanager);
|
||||||
|
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(updateCurrentFeed(QTreeWidgetItem*)));
|
||||||
setCurrentItem(unread_item);
|
setCurrentItem(unread_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
~FeedList() {
|
~FeedList() {
|
||||||
|
disconnect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(updateCurrentFeed(QTreeWidgetItem*)));
|
||||||
delete unread_item;
|
delete unread_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,19 +122,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
RssFile* getRSSItem(QTreeWidgetItem *item) const {
|
RssFile* getRSSItem(QTreeWidgetItem *item) const {
|
||||||
return mapping[item];
|
return mapping.value(item, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
RssFile::FileType getItemType(QTreeWidgetItem *item) const {
|
RssFile::FileType getItemType(QTreeWidgetItem *item) const {
|
||||||
return mapping[item]->getType();
|
return mapping.value(item)->getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getItemID(QTreeWidgetItem *item) const {
|
QString getItemID(QTreeWidgetItem *item) const {
|
||||||
return mapping[item]->getID();
|
return mapping.value(item)->getID();
|
||||||
}
|
}
|
||||||
|
|
||||||
QTreeWidgetItem* getTreeItemFromUrl(QString url) const{
|
QTreeWidgetItem* getTreeItemFromUrl(QString url) const{
|
||||||
return feeds_items[url];
|
return feeds_items.value(url, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
RssStream* getRSSItemFromUrl(QString url) const {
|
RssStream* getRSSItemFromUrl(QString url) const {
|
||||||
|
@@ -46,7 +46,7 @@
|
|||||||
#include "bittorrent.h"
|
#include "bittorrent.h"
|
||||||
#include "ui_feeddownloader.h"
|
#include "ui_feeddownloader.h"
|
||||||
|
|
||||||
#ifdef QT_4_5
|
#if QT_VERSION >= 0x040500
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#else
|
#else
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
@@ -64,11 +64,9 @@ public:
|
|||||||
|
|
||||||
bool matches(QString s) {
|
bool matches(QString s) {
|
||||||
QStringList match_tokens = getMatchingTokens();
|
QStringList match_tokens = getMatchingTokens();
|
||||||
//qDebug("Checking matching tokens: \"%s\"", getMatchingTokens_str().toLocal8Bit().data());
|
|
||||||
foreach(const QString& token, match_tokens) {
|
foreach(const QString& token, match_tokens) {
|
||||||
if(token.isEmpty() || token == "")
|
if(token.isEmpty() || token == "")
|
||||||
continue;
|
continue;
|
||||||
//qDebug("Token: %s", token.toLocal8Bit().data());
|
|
||||||
QRegExp reg(token, Qt::CaseInsensitive, QRegExp::Wildcard);
|
QRegExp reg(token, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||||
//reg.setMinimal(false);
|
//reg.setMinimal(false);
|
||||||
if(reg.indexIn(s) < 0) return false;
|
if(reg.indexIn(s) < 0) return false;
|
||||||
@@ -226,7 +224,7 @@ public:
|
|||||||
void save() {
|
void save() {
|
||||||
QSettings qBTRSS("qBittorrent", "qBittorrent-rss");
|
QSettings qBTRSS("qBittorrent", "qBittorrent-rss");
|
||||||
QHash<QString, QVariant> all_feeds_filters = qBTRSS.value("feed_filters", QHash<QString, QVariant>()).toHash();
|
QHash<QString, QVariant> all_feeds_filters = qBTRSS.value("feed_filters", QHash<QString, QVariant>()).toHash();
|
||||||
qDebug("Saving filters for feed: %s (%d filters)", feed_url.toLocal8Bit().data(), (*this).size());
|
qDebug("Saving filters for feed: %s (%d filters)", qPrintable(feed_url), (*this).size());
|
||||||
all_feeds_filters[feed_url] = *this;
|
all_feeds_filters[feed_url] = *this;
|
||||||
qBTRSS.setValue("feed_filters", all_feeds_filters);
|
qBTRSS.setValue("feed_filters", all_feeds_filters);
|
||||||
}
|
}
|
||||||
@@ -261,7 +259,6 @@ public:
|
|||||||
// Restore saved info
|
// Restore saved info
|
||||||
enableDl_cb->setChecked(filters.isDownloadingEnabled());
|
enableDl_cb->setChecked(filters.isDownloadingEnabled());
|
||||||
fillFiltersList();
|
fillFiltersList();
|
||||||
filtersList->sortItems(Qt::AscendingOrder);
|
|
||||||
if(filters.size() > 0) {
|
if(filters.size() > 0) {
|
||||||
// Select first filter
|
// Select first filter
|
||||||
filtersList->setCurrentItem(filtersList->item(0));
|
filtersList->setCurrentItem(filtersList->item(0));
|
||||||
@@ -388,7 +385,6 @@ protected slots:
|
|||||||
if(selected_filter == current_name)
|
if(selected_filter == current_name)
|
||||||
selected_filter = new_name;
|
selected_filter = new_name;
|
||||||
item->setText(new_name);
|
item->setText(new_name);
|
||||||
filtersList->sortItems(Qt::AscendingOrder);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,7 +438,6 @@ protected slots:
|
|||||||
}
|
}
|
||||||
}while(!validated);
|
}while(!validated);
|
||||||
QListWidgetItem *it = new QListWidgetItem(filter_name, filtersList);
|
QListWidgetItem *it = new QListWidgetItem(filter_name, filtersList);
|
||||||
filtersList->sortItems(Qt::AscendingOrder);
|
|
||||||
filtersList->setCurrentItem(it);
|
filtersList->setCurrentItem(it);
|
||||||
//showFilterSettings(it);
|
//showFilterSettings(it);
|
||||||
}
|
}
|
||||||
|
@@ -49,10 +49,10 @@ protected:
|
|||||||
file += QDir::separator();
|
file += QDir::separator();
|
||||||
file += ".";
|
file += ".";
|
||||||
struct statfs buf;
|
struct statfs buf;
|
||||||
if(!statfs(file.toLocal8Bit().data(), &buf)) {
|
if(!statfs(file.toLocal8Bit().constData(), &buf)) {
|
||||||
return (buf.f_type == (long)CIFS_MAGIC_NUMBER || buf.f_type == (long)NFS_SUPER_MAGIC);
|
return (buf.f_type == (long)CIFS_MAGIC_NUMBER || buf.f_type == (long)NFS_SUPER_MAGIC);
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Error: statfs() call failed for " << file.toLocal8Bit().data() << ". Supposing it is a local folder..." << std::endl;
|
std::cerr << "Error: statfs() call failed for " << qPrintable(file) << ". Supposing it is a local folder..." << std::endl;
|
||||||
switch(errno) {
|
switch(errno) {
|
||||||
case EACCES:
|
case EACCES:
|
||||||
std::cerr << "Search permission is denied for a component of the path prefix of the path" << std::endl;
|
std::cerr << "Search permission is denied for a component of the path prefix of the path" << std::endl;
|
||||||
@@ -103,12 +103,6 @@ public:
|
|||||||
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
|
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystemWatcher(QString path, QObject *parent): QFileSystemWatcher(parent) {
|
|
||||||
filters << "*.torrent";
|
|
||||||
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
|
|
||||||
addPath(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
~FileSystemWatcher() {
|
~FileSystemWatcher() {
|
||||||
#ifndef Q_WS_WIN
|
#ifndef Q_WS_WIN
|
||||||
if(watch_timer)
|
if(watch_timer)
|
||||||
@@ -148,7 +142,7 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
// Normal mode
|
// Normal mode
|
||||||
qDebug("FS Watching is watching %s in normal mode", path.toLocal8Bit().data());
|
qDebug("FS Watching is watching %s in normal mode", qPrintable(path));
|
||||||
QFileSystemWatcher::addPath(path);
|
QFileSystemWatcher::addPath(path);
|
||||||
scanLocalFolder(path);
|
scanLocalFolder(path);
|
||||||
#ifndef Q_WS_WIN
|
#ifndef Q_WS_WIN
|
||||||
@@ -190,7 +184,7 @@ protected slots:
|
|||||||
QStringList torrents;
|
QStringList torrents;
|
||||||
// Network folders scan
|
// Network folders scan
|
||||||
foreach (const QDir &dir, watched_folders) {
|
foreach (const QDir &dir, watched_folders) {
|
||||||
qDebug("FSWatcher: Polling manually folder %s", qPrintable(dir.path()));
|
//qDebug("FSWatcher: Polling manually folder %s", qPrintable(dir.path()));
|
||||||
addTorrentsFromDir(dir, torrents);
|
addTorrentsFromDir(dir, torrents);
|
||||||
}
|
}
|
||||||
// Report detected torrent files
|
// Report detected torrent files
|
||||||
|
@@ -86,9 +86,9 @@ public:
|
|||||||
exportEmbeddedDb();
|
exportEmbeddedDb();
|
||||||
#endif
|
#endif
|
||||||
if(QFile::exists(geoipDBpath(false))) {
|
if(QFile::exists(geoipDBpath(false))) {
|
||||||
qDebug("Loading GeoIP database from %s...", geoipDBpath(false).toLocal8Bit().data());
|
qDebug("Loading GeoIP database from %s...", qPrintable(geoipDBpath(false)));
|
||||||
if(!s->load_country_db(geoipDBpath(false).toLocal8Bit().data())) {
|
if(!s->load_country_db(geoipDBpath(false).toLocal8Bit().constData())) {
|
||||||
std::cerr << "Failed to load Geoip Database at " << geoipDBpath(false).toLocal8Bit().data() << std::endl;
|
std::cerr << "Failed to load Geoip Database at " << qPrintable(geoipDBpath(false)) << std::endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug("ERROR: Impossible to find local Geoip Database");
|
qDebug("ERROR: Impossible to find local Geoip Database");
|
||||||
|
@@ -41,97 +41,98 @@
|
|||||||
class HeadlessLoader: QObject {
|
class HeadlessLoader: QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
public:
|
||||||
QLocalServer *localServer;
|
HeadlessLoader(QStringList torrentCmdLine) {
|
||||||
Bittorrent *BTSession;
|
// Enable Web UI
|
||||||
|
Preferences::setWebUiEnabled(true);
|
||||||
public:
|
// Instanciate Bittorrent Object
|
||||||
HeadlessLoader(QStringList torrentCmdLine) {
|
BTSession = new Bittorrent();
|
||||||
// Enable Web UI
|
connect(BTSession, SIGNAL(newConsoleMessage(QString)), this, SLOT(displayConsoleMessage(QString)));
|
||||||
Preferences::setWebUiEnabled(true);
|
// Resume unfinished torrents
|
||||||
// Instanciate Bittorrent Object
|
BTSession->startUpTorrents();
|
||||||
BTSession = new Bittorrent();
|
// Process command line parameters
|
||||||
connect(BTSession, SIGNAL(newConsoleMessage(QString)), this, SLOT(displayConsoleMessage(QString)));
|
processParams(torrentCmdLine);
|
||||||
// Resume unfinished torrents
|
// Use a tcp server to allow only one instance of qBittorrent
|
||||||
BTSession->startUpTorrents();
|
localServer = new QLocalServer();
|
||||||
// Process command line parameters
|
const QString &uid = QString::number(getuid());
|
||||||
processParams(torrentCmdLine);
|
|
||||||
// Use a tcp server to allow only one instance of qBittorrent
|
|
||||||
localServer = new QLocalServer();
|
|
||||||
QString uid = QString::number(getuid());
|
|
||||||
#ifdef Q_WS_X11
|
#ifdef Q_WS_X11
|
||||||
if(QFile::exists(QDir::tempPath()+QDir::separator()+QString("qBittorrent-")+uid)) {
|
if(QFile::exists(QDir::tempPath()+QDir::separator()+QString("qBittorrent-")+uid)) {
|
||||||
// Socket was not closed cleanly
|
// Socket was not closed cleanly
|
||||||
std::cerr << "Warning: Local domain socket was not closed cleanly, deleting file...\n";
|
std::cerr << "Warning: Local domain socket was not closed cleanly, deleting file..." << std::endl;
|
||||||
QFile::remove(QDir::tempPath()+QDir::separator()+QString("qBittorrent-")+uid);
|
QFile::remove(QDir::tempPath()+QDir::separator()+QString("qBittorrent-")+uid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!localServer->listen("qBittorrent-"+uid)) {
|
if (!localServer->listen("qBittorrent-"+uid)) {
|
||||||
std::cerr << "Couldn't create socket, single instance mode won't work...\n";
|
std::cerr << "Couldn't create socket, single instance mode won't work..." << std::endl;
|
||||||
}
|
|
||||||
connect(localServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
|
|
||||||
// Display some information to the user
|
|
||||||
std::cout << std::endl << "******** " << tr("Information").toLocal8Bit().data() << " ********" << std::endl;
|
|
||||||
std::cout << tr("To control qBittorrent, access the Web UI at http://localhost:%1").arg(QString::number(Preferences::getWebUiPort())).toLocal8Bit().data() << std::endl;
|
|
||||||
std::cout << tr("The Web UI administrator user name is: %1").arg(Preferences::getWebUiUsername()).toLocal8Bit().data() << std::endl;
|
|
||||||
if(Preferences::getWebUiPassword() == "f6fdffe48c908deb0f4c3bd36c032e72") {
|
|
||||||
std::cout << tr("The Web UI administrator password is still the default one: %1").arg("adminadmin").toLocal8Bit().data() << std::endl;
|
|
||||||
std::cout << tr("This is a security risk, please consider changing your password from program preferences.").toLocal8Bit().data() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
connect(localServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
|
||||||
~HeadlessLoader() {
|
// Display some information to the user
|
||||||
delete BTSession;
|
std::cout << std::endl << "******** " << qPrintable(tr("Information")) << " ********" << std::endl;
|
||||||
|
std::cout << qPrintable(tr("To control qBittorrent, access the Web UI at http://localhost:%1").arg(QString::number(Preferences::getWebUiPort()))) << std::endl;
|
||||||
|
std::cout << qPrintable(tr("The Web UI administrator user name is: %1").arg(Preferences::getWebUiUsername())) << std::endl;
|
||||||
|
if(Preferences::getWebUiPassword() == "f6fdffe48c908deb0f4c3bd36c032e72") {
|
||||||
|
std::cout << qPrintable(tr("The Web UI administrator password is still the default one: %1").arg("adminadmin")) << std::endl;
|
||||||
|
std::cout << qPrintable(tr("This is a security risk, please consider changing your password from program preferences.")) << std::endl;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public slots:
|
~HeadlessLoader() {
|
||||||
// Call this function to exit qBittorrent headless loader
|
delete localServer;
|
||||||
// and return to prompt (object will be deleted by main)
|
delete BTSession;
|
||||||
void exit() {
|
}
|
||||||
qApp->quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void displayConsoleMessage(QString msg) {
|
public slots:
|
||||||
std::cout << msg.toLocal8Bit().data() << std::endl;
|
// Call this function to exit qBittorrent headless loader
|
||||||
}
|
// and return to prompt (object will be deleted by main)
|
||||||
|
void exit() {
|
||||||
|
qApp->quit();
|
||||||
|
}
|
||||||
|
|
||||||
// As program parameters, we can get paths or urls.
|
void displayConsoleMessage(QString msg) {
|
||||||
// This function parse the parameters and call
|
std::cout << qPrintable(msg) << std::endl;
|
||||||
// the right addTorrent function, considering
|
}
|
||||||
// the parameter type.
|
|
||||||
void processParams(const QStringList& params) {
|
// As program parameters, we can get paths or urls.
|
||||||
foreach(QString param, params) {
|
// This function parse the parameters and call
|
||||||
param = param.trimmed();
|
// the right addTorrent function, considering
|
||||||
if(param.startsWith("--")) continue;
|
// the parameter type.
|
||||||
if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) {
|
void processParams(const QStringList& params) {
|
||||||
BTSession->downloadFromUrl(param);
|
foreach(QString param, params) {
|
||||||
}else{
|
param = param.trimmed();
|
||||||
if(param.startsWith("magnet:", Qt::CaseInsensitive)) {
|
if(param.startsWith("--")) continue;
|
||||||
BTSession->addMagnetUri(param);
|
if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) {
|
||||||
} else {
|
BTSession->downloadFromUrl(param);
|
||||||
BTSession->addTorrent(param);
|
}else{
|
||||||
}
|
if(param.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||||
|
BTSession->addMagnetUri(param);
|
||||||
|
} else {
|
||||||
|
BTSession->addTorrent(param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void acceptConnection() {
|
void acceptConnection() {
|
||||||
QLocalSocket *clientConnection = localServer->nextPendingConnection();
|
QLocalSocket *clientConnection = localServer->nextPendingConnection();
|
||||||
connect(clientConnection, SIGNAL(disconnected()), this, SLOT(readParamsOnSocket()));
|
connect(clientConnection, SIGNAL(disconnected()), this, SLOT(readParamsOnSocket()));
|
||||||
qDebug("accepted connection from another instance");
|
qDebug("accepted connection from another instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
void readParamsOnSocket() {
|
void readParamsOnSocket() {
|
||||||
QLocalSocket *clientConnection = static_cast<QLocalSocket*>(sender());
|
QLocalSocket *clientConnection = static_cast<QLocalSocket*>(sender());
|
||||||
if(clientConnection) {
|
if(clientConnection) {
|
||||||
QByteArray params = clientConnection->readAll();
|
const QByteArray ¶ms = clientConnection->readAll();
|
||||||
if(!params.isEmpty()) {
|
if(!params.isEmpty()) {
|
||||||
processParams(QString::fromUtf8(params.data()).split(QString::fromUtf8("\n")));
|
processParams(QString(params).split("\n"));
|
||||||
qDebug("Received parameters from another instance");
|
qDebug("Received parameters from another instance");
|
||||||
}
|
|
||||||
clientConnection->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
clientConnection->deleteLater();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLocalServer *localServer;
|
||||||
|
Bittorrent *BTSession;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -47,7 +47,7 @@
|
|||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
HttpConnection::HttpConnection(QTcpSocket *socket, Bittorrent *BTSession, HttpServer *parent)
|
HttpConnection::HttpConnection(QTcpSocket *socket, Bittorrent *BTSession, HttpServer *parent)
|
||||||
: QObject(parent), socket(socket), parent(parent), BTSession(BTSession)
|
: QObject(parent), socket(socket), parent(parent), BTSession(BTSession)
|
||||||
{
|
{
|
||||||
socket->setParent(this);
|
socket->setParent(this);
|
||||||
connect(socket, SIGNAL(readyRead()), this, SLOT(read()));
|
connect(socket, SIGNAL(readyRead()), this, SLOT(read()));
|
||||||
@@ -104,7 +104,7 @@ void HttpConnection::write()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString HttpConnection::translateDocument(QString data) {
|
QString HttpConnection::translateDocument(QString data) {
|
||||||
std::string contexts[] = {"TransferListFiltersWidget", "TransferListWidget", "PropertiesWidget", "GUI", "MainWindow", "HttpServer", "confirmDeletionDlg", "TrackerList", "TorrentFilesModel", "options_imp", "Preferences", "TrackersAdditionDlg"};
|
std::string contexts[] = {"TransferListFiltersWidget", "TransferListWidget", "PropertiesWidget", "GUI", "MainWindow", "HttpServer", "confirmDeletionDlg", "TrackerList", "TorrentFilesModel", "options_imp", "Preferences", "TrackersAdditionDlg", "ScanFoldersModel"};
|
||||||
int i=0;
|
int i=0;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
do {
|
do {
|
||||||
@@ -117,9 +117,9 @@ QString HttpConnection::translateDocument(QString data) {
|
|||||||
QString translation = word;
|
QString translation = word;
|
||||||
int context_index= 0;
|
int context_index= 0;
|
||||||
do {
|
do {
|
||||||
translation = qApp->translate(contexts[context_index].c_str(), word.toLocal8Bit().data(), 0, QCoreApplication::UnicodeUTF8, 1);
|
translation = qApp->translate(contexts[context_index].c_str(), word.toLocal8Bit().constData(), 0, QCoreApplication::UnicodeUTF8, 1);
|
||||||
++context_index;
|
++context_index;
|
||||||
}while(translation == word && context_index < 12);
|
}while(translation == word && context_index < 13);
|
||||||
//qDebug("Translation is %s", translation.toUtf8().data());
|
//qDebug("Translation is %s", translation.toUtf8().data());
|
||||||
data = data.replace(i, regex.matchedLength(), translation);
|
data = data.replace(i, regex.matchedLength(), translation);
|
||||||
i += translation.length();
|
i += translation.length();
|
||||||
@@ -131,19 +131,28 @@ QString HttpConnection::translateDocument(QString data) {
|
|||||||
|
|
||||||
void HttpConnection::respond() {
|
void HttpConnection::respond() {
|
||||||
//qDebug("Respond called");
|
//qDebug("Respond called");
|
||||||
int nb_fail = parent->client_failed_attempts.value(socket->peerAddress().toString(), 0);
|
const QString &peer_ip = socket->peerAddress().toString();
|
||||||
if(nb_fail > 4) {
|
const int nb_fail = parent->NbFailedAttemptsForIp(peer_ip);
|
||||||
|
if(nb_fail >= MAX_AUTH_FAILED_ATTEMPTS) {
|
||||||
generator.setStatusLine(403, "Forbidden");
|
generator.setStatusLine(403, "Forbidden");
|
||||||
generator.setMessage(tr("Your IP address has been banned after too many failed authentication attempts."));
|
generator.setMessage(tr("Your IP address has been banned after too many failed authentication attempts."));
|
||||||
write();
|
write();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString auth = parser.value("Authorization");
|
QString auth = parser.value("Authorization");
|
||||||
qDebug("Auth: %s", auth.split(" ").first().toLocal8Bit().data());
|
if(auth.isEmpty()) {
|
||||||
|
// Return unauthorized header
|
||||||
|
qDebug("Auth is Empty...");
|
||||||
|
generator.setStatusLine(401, "Unauthorized");
|
||||||
|
generator.setValue("WWW-Authenticate", "Digest realm=\""+QString(QBT_REALM)+"\", nonce=\""+parent->generateNonce()+"\", opaque=\""+parent->generateNonce()+"\", stale=\"false\", algorithm=\"MD5\", qop=\"auth\"");
|
||||||
|
write();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug("Auth: %s", qPrintable(auth.split(" ").first()));
|
||||||
if (QString::compare(auth.split(" ").first(), "Digest", Qt::CaseInsensitive) != 0 || !parent->isAuthorized(auth.toLocal8Bit(), parser.method())) {
|
if (QString::compare(auth.split(" ").first(), "Digest", Qt::CaseInsensitive) != 0 || !parent->isAuthorized(auth.toLocal8Bit(), parser.method())) {
|
||||||
// Update failed attempt counter
|
// Update failed attempt counter
|
||||||
parent->client_failed_attempts.insert(socket->peerAddress().toString(), nb_fail+1);
|
parent->increaseNbFailedAttemptsForIp(peer_ip);
|
||||||
qDebug("client IP: %s (%d failed attempts)", socket->peerAddress().toString().toLocal8Bit().data(), nb_fail);
|
qDebug("client IP: %s (%d failed attempts)", qPrintable(peer_ip), nb_fail+1);
|
||||||
// Return unauthorized header
|
// Return unauthorized header
|
||||||
generator.setStatusLine(401, "Unauthorized");
|
generator.setStatusLine(401, "Unauthorized");
|
||||||
generator.setValue("WWW-Authenticate", "Digest realm=\""+QString(QBT_REALM)+"\", nonce=\""+parent->generateNonce()+"\", algorithm=\"MD5\", qop=\"auth\"");
|
generator.setValue("WWW-Authenticate", "Digest realm=\""+QString(QBT_REALM)+"\", nonce=\""+parent->generateNonce()+"\", algorithm=\"MD5\", qop=\"auth\"");
|
||||||
@@ -151,7 +160,7 @@ void HttpConnection::respond() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Client sucessfuly authenticated, reset number of failed attempts
|
// Client sucessfuly authenticated, reset number of failed attempts
|
||||||
parent->client_failed_attempts.remove(socket->peerAddress().toString());
|
parent->resetNbFailedAttemptsForIp(peer_ip);
|
||||||
QString url = parser.url();
|
QString url = parser.url();
|
||||||
// Favicon
|
// Favicon
|
||||||
if(url.endsWith("favicon.ico")) {
|
if(url.endsWith("favicon.ico")) {
|
||||||
@@ -225,7 +234,6 @@ void HttpConnection::respond() {
|
|||||||
else
|
else
|
||||||
list.prepend("webui");
|
list.prepend("webui");
|
||||||
url = ":/" + list.join("/");
|
url = ":/" + list.join("/");
|
||||||
//qDebug("Resource URL: %s", url.toLocal8Bit().data());
|
|
||||||
QFile file(url);
|
QFile file(url);
|
||||||
if(!file.open(QIODevice::ReadOnly))
|
if(!file.open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
@@ -261,7 +269,6 @@ void HttpConnection::respondJson()
|
|||||||
QString string = json::toJson(manager->getEventList());
|
QString string = json::toJson(manager->getEventList());
|
||||||
generator.setStatusLine(200, "OK");
|
generator.setStatusLine(200, "OK");
|
||||||
generator.setContentTypeByExt("js");
|
generator.setContentTypeByExt("js");
|
||||||
//qDebug("JSON: %s", string.toLocal8Bit().data());
|
|
||||||
generator.setMessage(string);
|
generator.setMessage(string);
|
||||||
write();
|
write();
|
||||||
}
|
}
|
||||||
@@ -290,7 +297,6 @@ void HttpConnection::respondFilesPropertiesJson(QString hash) {
|
|||||||
generator.setStatusLine(200, "OK");
|
generator.setStatusLine(200, "OK");
|
||||||
generator.setContentTypeByExt("js");
|
generator.setContentTypeByExt("js");
|
||||||
generator.setMessage(string);
|
generator.setMessage(string);
|
||||||
//qDebug("JSON: %s", string.toLocal8Bit().data());
|
|
||||||
write();
|
write();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +397,6 @@ void HttpConnection::respondCommand(QString command)
|
|||||||
}
|
}
|
||||||
if(command == "setPreferences") {
|
if(command == "setPreferences") {
|
||||||
QString json_str = parser.post("json");
|
QString json_str = parser.post("json");
|
||||||
//qDebug("setPreferences, json: %s", json_str.toLocal8Bit().data());
|
|
||||||
EventManager* manager = parent->eventManager();
|
EventManager* manager = parent->eventManager();
|
||||||
manager->setGlobalPreferences(json::fromJson(json_str));
|
manager->setGlobalPreferences(json::fromJson(json_str));
|
||||||
}
|
}
|
||||||
|
@@ -37,6 +37,48 @@
|
|||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
const int BAN_TIME = 3600000; // 1 hour
|
||||||
|
|
||||||
|
class UnbanTimer: public QTimer {
|
||||||
|
public:
|
||||||
|
UnbanTimer(QObject *parent, QString peer_ip): QTimer(parent), peer_ip(peer_ip){
|
||||||
|
setSingleShot(true);
|
||||||
|
setInterval(BAN_TIME);
|
||||||
|
}
|
||||||
|
~UnbanTimer() {
|
||||||
|
qDebug("||||||||||||Deleting ban timer|||||||||||||||");
|
||||||
|
}
|
||||||
|
QString peer_ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
void HttpServer::UnbanTimerEvent() {
|
||||||
|
UnbanTimer* ubantimer = static_cast<UnbanTimer*>(sender());
|
||||||
|
qDebug("Ban period has expired for %s", qPrintable(ubantimer->peer_ip));
|
||||||
|
client_failed_attempts.remove(ubantimer->peer_ip);
|
||||||
|
ubantimer->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
int HttpServer::NbFailedAttemptsForIp(QString ip) const {
|
||||||
|
return client_failed_attempts.value(ip, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::increaseNbFailedAttemptsForIp(QString ip) {
|
||||||
|
const int nb_fail = client_failed_attempts.value(ip, 0);
|
||||||
|
client_failed_attempts.insert(ip, nb_fail+1);
|
||||||
|
if(nb_fail == MAX_AUTH_FAILED_ATTEMPTS-1) {
|
||||||
|
// Max number of failed attempts reached
|
||||||
|
// Start ban period
|
||||||
|
UnbanTimer* ubantimer = new UnbanTimer(this, ip);
|
||||||
|
connect(ubantimer, SIGNAL(timeout()), this, SLOT(UnbanTimerEvent()));
|
||||||
|
ubantimer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::resetNbFailedAttemptsForIp(QString ip) {
|
||||||
|
client_failed_attempts.remove(ip);
|
||||||
|
}
|
||||||
|
|
||||||
HttpServer::HttpServer(Bittorrent *_BTSession, int msec, QObject* parent) : QTcpServer(parent) {
|
HttpServer::HttpServer(Bittorrent *_BTSession, int msec, QObject* parent) : QTcpServer(parent) {
|
||||||
username = Preferences::getWebUiUsername().toLocal8Bit();
|
username = Preferences::getWebUiUsername().toLocal8Bit();
|
||||||
@@ -132,16 +174,12 @@ void HttpServer::setAuthorization(QString _username, QString _password_ha1) {
|
|||||||
password_ha1 = _password_ha1.toLocal8Bit();
|
password_ha1 = _password_ha1.toLocal8Bit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AUTH string is: Digest username="chris",
|
// Parse HTTP AUTH string
|
||||||
// realm="Web UI Access",
|
// http://tools.ietf.org/html/rfc2617
|
||||||
// nonce="570d04de93444b7fd3eaeaecb00e635e",
|
|
||||||
// uri="/", algorithm=MD5,
|
|
||||||
// response="ba886766d19b45313c0e2195e4344264",
|
|
||||||
// qop=auth, nc=00000001, cnonce="e8ac970779c17075"
|
|
||||||
bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
||||||
qDebug("AUTH string is %s", auth.data());
|
qDebug("AUTH string is %s", auth.data());
|
||||||
// Get user name
|
// Get user name
|
||||||
QRegExp regex_user(".*username=\"([^\"]+)\".*");
|
QRegExp regex_user(".*username=\"([^\"]+)\".*"); // Must be a quoted string
|
||||||
if(regex_user.indexIn(auth) < 0) return false;
|
if(regex_user.indexIn(auth) < 0) return false;
|
||||||
QString prop_user = regex_user.cap(1);
|
QString prop_user = regex_user.cap(1);
|
||||||
qDebug("AUTH: Proposed username is %s, real username is %s", prop_user.toLocal8Bit().data(), username.data());
|
qDebug("AUTH: Proposed username is %s, real username is %s", prop_user.toLocal8Bit().data(), username.data());
|
||||||
@@ -151,7 +189,7 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Get realm
|
// Get realm
|
||||||
QRegExp regex_realm(".*realm=\"([^\"]+)\".*");
|
QRegExp regex_realm(".*realm=\"([^\"]+)\".*"); // Must be a quoted string
|
||||||
if(regex_realm.indexIn(auth) < 0) {
|
if(regex_realm.indexIn(auth) < 0) {
|
||||||
qDebug("AUTH-PROB: Missing realm");
|
qDebug("AUTH-PROB: Missing realm");
|
||||||
return false;
|
return false;
|
||||||
@@ -162,7 +200,7 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// get nonce
|
// get nonce
|
||||||
QRegExp regex_nonce(".*nonce=\"([^\"]+)\".*");
|
QRegExp regex_nonce(".*nonce=[\"]?([\\w=]+)[\"]?.*");
|
||||||
if(regex_nonce.indexIn(auth) < 0) {
|
if(regex_nonce.indexIn(auth) < 0) {
|
||||||
qDebug("AUTH-PROB: missing nonce");
|
qDebug("AUTH-PROB: missing nonce");
|
||||||
return false;
|
return false;
|
||||||
@@ -178,7 +216,7 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
|||||||
QByteArray prop_uri = regex_uri.cap(1).toLocal8Bit();
|
QByteArray prop_uri = regex_uri.cap(1).toLocal8Bit();
|
||||||
qDebug("prop uri is: %s", prop_uri.data());
|
qDebug("prop uri is: %s", prop_uri.data());
|
||||||
// get response
|
// get response
|
||||||
QRegExp regex_response(".*response=\"([^\"]+)\".*");
|
QRegExp regex_response(".*response=[\"]?([\\w=]+)[\"]?.*");
|
||||||
if(regex_response.indexIn(auth) < 0) {
|
if(regex_response.indexIn(auth) < 0) {
|
||||||
qDebug("AUTH-PROB: Missing response");
|
qDebug("AUTH-PROB: Missing response");
|
||||||
return false;
|
return false;
|
||||||
@@ -193,14 +231,14 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
|||||||
if(auth.contains("qop=")) {
|
if(auth.contains("qop=")) {
|
||||||
QCryptographicHash md5_ha(QCryptographicHash::Md5);
|
QCryptographicHash md5_ha(QCryptographicHash::Md5);
|
||||||
// Get nc
|
// Get nc
|
||||||
QRegExp regex_nc(".*nc=(\\w+).*");
|
QRegExp regex_nc(".*nc=[\"]?([\\w=]+)[\"]?.*");
|
||||||
if(regex_nc.indexIn(auth) < 0) {
|
if(regex_nc.indexIn(auth) < 0) {
|
||||||
qDebug("AUTH-PROB: qop but missing nc");
|
qDebug("AUTH-PROB: qop but missing nc");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QByteArray prop_nc = regex_nc.cap(1).toLocal8Bit();
|
QByteArray prop_nc = regex_nc.cap(1).toLocal8Bit();
|
||||||
qDebug("prop nc is: %s", prop_nc.data());
|
qDebug("prop nc is: %s", prop_nc.data());
|
||||||
QRegExp regex_cnonce(".*cnonce=\"([^\"]+)\".*");
|
QRegExp regex_cnonce(".*cnonce=[\"]?([\\w=]+)[\"]?.*");
|
||||||
if(regex_cnonce.indexIn(auth) < 0) {
|
if(regex_cnonce.indexIn(auth) < 0) {
|
||||||
qDebug("AUTH-PROB: qop but missing cnonce");
|
qDebug("AUTH-PROB: qop but missing cnonce");
|
||||||
return false;
|
return false;
|
||||||
@@ -221,7 +259,7 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
|||||||
md5_ha.addData(password_ha1+":"+prop_nonce+":"+ha2);
|
md5_ha.addData(password_ha1+":"+prop_nonce+":"+ha2);
|
||||||
response = md5_ha.result().toHex();
|
response = md5_ha.result().toHex();
|
||||||
}
|
}
|
||||||
qDebug("AUTH: comparing reponses");
|
qDebug("AUTH: comparing reponses: (%d)", static_cast<int>(prop_response == response));
|
||||||
return prop_response == response;
|
return prop_response == response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -42,28 +42,34 @@ class Bittorrent;
|
|||||||
class QTimer;
|
class QTimer;
|
||||||
class EventManager;
|
class EventManager;
|
||||||
|
|
||||||
|
const int MAX_AUTH_FAILED_ATTEMPTS = 5;
|
||||||
|
|
||||||
class HttpServer : public QTcpServer {
|
class HttpServer : public QTcpServer {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
public:
|
||||||
QByteArray username;
|
HttpServer(Bittorrent *BTSession, int msec, QObject* parent = 0);
|
||||||
QByteArray password_ha1;
|
~HttpServer();
|
||||||
Bittorrent *BTSession;
|
void setAuthorization(QString username, QString password_ha1);
|
||||||
EventManager *manager;
|
bool isAuthorized(QByteArray auth, QString method) const;
|
||||||
QTimer *timer;
|
EventManager *eventManager() const;
|
||||||
|
QString generateNonce() const;
|
||||||
|
int NbFailedAttemptsForIp(QString ip) const;
|
||||||
|
void increaseNbFailedAttemptsForIp(QString ip);
|
||||||
|
void resetNbFailedAttemptsForIp(QString ip);
|
||||||
|
|
||||||
public:
|
private slots:
|
||||||
HttpServer(Bittorrent *BTSession, int msec, QObject* parent = 0);
|
void newHttpConnection();
|
||||||
~HttpServer();
|
void onTimer();
|
||||||
void setAuthorization(QString username, QString password_ha1);
|
void UnbanTimerEvent();
|
||||||
bool isAuthorized(QByteArray auth, QString method) const;
|
|
||||||
EventManager *eventManager() const;
|
|
||||||
QString generateNonce() const;
|
|
||||||
QHash<QString, int> client_failed_attempts;
|
|
||||||
|
|
||||||
private slots:
|
private:
|
||||||
void newHttpConnection();
|
QByteArray username;
|
||||||
void onTimer();
|
QByteArray password_ha1;
|
||||||
|
Bittorrent *BTSession;
|
||||||
|
EventManager *manager;
|
||||||
|
QTimer *timer;
|
||||||
|
QHash<QString, int> client_failed_attempts;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
44
src/json.h
44
src/json.h
@@ -113,7 +113,24 @@ namespace json {
|
|||||||
if(json.startsWith("{") && json.endsWith("}")) {
|
if(json.startsWith("{") && json.endsWith("}")) {
|
||||||
json.chop(1);
|
json.chop(1);
|
||||||
json = json.replace(0, 1, "");
|
json = json.replace(0, 1, "");
|
||||||
QStringList couples = json.split(",");
|
QStringList couples;
|
||||||
|
QString tmp = "";
|
||||||
|
bool in_list = false;
|
||||||
|
foreach(QChar c, json) {
|
||||||
|
if(c == ',' && !in_list) {
|
||||||
|
couples << tmp;
|
||||||
|
tmp = "";
|
||||||
|
} else {
|
||||||
|
if(c == '[') {
|
||||||
|
in_list = true;
|
||||||
|
} else {
|
||||||
|
if(c == ']') {
|
||||||
|
in_list = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
foreach(QString couple, couples) {
|
foreach(QString couple, couples) {
|
||||||
QStringList parts = couple.split(":");
|
QStringList parts = couple.split(":");
|
||||||
if(parts.size() != 2) continue;
|
if(parts.size() != 2) continue;
|
||||||
@@ -124,12 +141,29 @@ namespace json {
|
|||||||
}
|
}
|
||||||
QString value_str = parts.last();
|
QString value_str = parts.last();
|
||||||
QVariant value;
|
QVariant value;
|
||||||
if(value_str.startsWith("\"") && value_str.endsWith("\"")) {
|
if(value_str.startsWith("[") && value_str.endsWith("]")) {
|
||||||
value_str.chop(1);
|
value_str.chop(1);
|
||||||
value_str = value_str.replace(0, 1, "");
|
value_str.replace(0, 1, "");
|
||||||
value = value_str;
|
QStringList list_elems = value_str.split(",");
|
||||||
|
QVariantList varlist;
|
||||||
|
foreach(QString list_val, list_elems) {
|
||||||
|
if(list_val.startsWith("\"") && list_val.endsWith("\"")) {
|
||||||
|
list_val.chop(1);
|
||||||
|
list_val = list_val.replace(0, 1, "");
|
||||||
|
varlist << list_val;
|
||||||
|
} else {
|
||||||
|
varlist << list_val.toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = varlist;
|
||||||
} else {
|
} else {
|
||||||
value = value_str.toInt();
|
if(value_str.startsWith("\"") && value_str.endsWith("\"")) {
|
||||||
|
value_str.chop(1);
|
||||||
|
value_str = value_str.replace(0, 1, "");
|
||||||
|
value = value_str;
|
||||||
|
} else {
|
||||||
|
value = value_str.toInt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m.insert(key,value);
|
m.insert(key,value);
|
||||||
qDebug("%s:%s", key.toLocal8Bit().data(), value_str.toLocal8Bit().data());
|
qDebug("%s:%s", key.toLocal8Bit().data(), value_str.toLocal8Bit().data());
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user