You've already forked qBittorrent
mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-10-09 18:32:15 +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
|
||||
copyright:
|
||||
- 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)
|
||||
- Chinese (Simplified): Guo Yue (yue.guo0418@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: Bandwidth scheduler (automatically use alternative speed limits for a given period)
|
||||
- FEATURE: Added "Added/Completed On" columns to transfer list
|
||||
@@ -15,6 +34,9 @@
|
||||
- FEATURE: Support for multiple scan folders (Patch by Christian Kandeler)
|
||||
- BUGFIX: Only one log window can be opened at a time
|
||||
- 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
|
||||
|
||||
* 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()) {
|
||||
conf->addDefine("DISABLE_GUI");
|
||||
}
|
||||
if(QT_VERSION >= 0x040500) {
|
||||
conf->addDefine("QT_4_5");
|
||||
}
|
||||
return(QT_VERSION >= 0x040400);
|
||||
|
||||
}
|
||||
};
|
||||
#line 1 "pkg-config.qcm"
|
||||
|
@@ -15,10 +15,6 @@ public:
|
||||
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
||||
conf->addDefine("DISABLE_GUI");
|
||||
}
|
||||
if(QT_VERSION >= 0x040500) {
|
||||
conf->addDefine("QT_4_5");
|
||||
}
|
||||
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(downloadFromUrlFailure(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString)));
|
||||
connect(BTSession, SIGNAL(alternativeSpeedsModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
|
||||
connect(BTSession, SIGNAL(recursiveTorrentDownloadPossible(QTorrentHandle&)), this, SLOT(askRecursiveTorrentDownloadConfirmation(QTorrentHandle&)));
|
||||
|
||||
qDebug("create tabWidget");
|
||||
tabs = new QTabWidget();
|
||||
@@ -227,6 +228,8 @@ GUI::~GUI() {
|
||||
delete aboutDlg;
|
||||
if(options)
|
||||
delete options;
|
||||
if(downloadFromURLDialog)
|
||||
delete downloadFromURLDialog;
|
||||
if(rssWidget)
|
||||
delete rssWidget;
|
||||
delete searchEngine;
|
||||
@@ -251,6 +254,12 @@ GUI::~GUI() {
|
||||
delete switchRSSShortcut;
|
||||
// Delete BTSession objects
|
||||
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
|
||||
// because the Bittorrent session proxy will
|
||||
// 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{
|
||||
// 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));
|
||||
@@ -627,8 +642,8 @@ void GUI::on_actionOpen_triggered() {
|
||||
// Open File Open Dialog
|
||||
// Note: it is possible to select more than one file
|
||||
const QStringList &pathsList = QFileDialog::getOpenFileNames(0,
|
||||
tr("Open Torrent Files"), settings.value(QString::fromUtf8("MainWindowLastDir"), QDir::homePath()).toString(),
|
||||
tr("Torrent Files")+QString::fromUtf8(" (*.torrent)"));
|
||||
tr("Open Torrent Files"), settings.value(QString::fromUtf8("MainWindowLastDir"), QDir::homePath()).toString(),
|
||||
tr("Torrent Files")+QString::fromUtf8(" (*.torrent)"));
|
||||
if(!pathsList.empty()) {
|
||||
const bool useTorrentAdditionDialog = settings.value(QString::fromUtf8("Preferences/Downloads/AdditionDialog"), true).toBool();
|
||||
const uint listSize = pathsList.size();
|
||||
@@ -829,7 +844,7 @@ void GUI::showNotificationBaloon(QString title, QString msg) const {
|
||||
#ifdef WITH_LIBNOTIFY
|
||||
if (notify_init ("summary-body")) {
|
||||
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);
|
||||
g_object_unref(G_OBJECT(notification));
|
||||
notify_uninit ();
|
||||
@@ -954,7 +969,9 @@ void GUI::on_actionOptions_triggered() {
|
||||
// Display an input dialog to prompt user for
|
||||
// an url
|
||||
void GUI::on_actionDownload_from_URL_triggered() {
|
||||
downloadFromURL *downloadFromURLDialog = new downloadFromURL(this);
|
||||
connect(downloadFromURLDialog, SIGNAL(urlsReadyToBeDownloaded(const QStringList&)), this, SLOT(downloadFromURLList(const QStringList&)));
|
||||
if(!downloadFromURLDialog) {
|
||||
downloadFromURLDialog = new downloadFromURL(this);
|
||||
connect(downloadFromURLDialog, SIGNAL(urlsReadyToBeDownloaded(const QStringList&)), this, SLOT(downloadFromURLList(const QStringList&)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -58,6 +58,7 @@ class StatusBar;
|
||||
class consoleDlg;
|
||||
class about;
|
||||
class createtorrent;
|
||||
class downloadFromURL;
|
||||
|
||||
class GUI : public QMainWindow, private Ui::MainWindow{
|
||||
Q_OBJECT
|
||||
@@ -115,6 +116,7 @@ protected slots:
|
||||
void addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker);
|
||||
void processDownloadedFiles(QString path, QString url);
|
||||
void finishedTorrent(QTorrentHandle& h) const;
|
||||
void askRecursiveTorrentDownloadConfirmation(QTorrentHandle &h);
|
||||
// Options slots
|
||||
void on_actionOptions_triggered();
|
||||
void optionsSaved();
|
||||
@@ -139,6 +141,7 @@ private:
|
||||
QPointer<consoleDlg> console;
|
||||
QPointer<about> aboutDlg;
|
||||
QPointer<createtorrent> createTorrentDlg;
|
||||
QPointer<downloadFromURL> downloadFromURLDialog;
|
||||
QPointer<QSystemTrayIcon> systrayIcon;
|
||||
QPointer<QTimer> systrayCreator;
|
||||
QMenu *myTrayIconMenu;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Categories=Qt;Network;P2P;
|
||||
Comment=V2.2.0
|
||||
Comment=V2.2.2
|
||||
Exec=qbittorrent %f
|
||||
GenericName=Bittorrent client
|
||||
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(QString::fromUtf8(
|
||||
"<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>Chinese (Simplified):</u> Guo Yue (yue.guo0418@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>
|
||||
#endif
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
|
||||
#include <libtorrent/session.hpp>
|
||||
#include <libtorrent/ip_filter.hpp>
|
||||
@@ -115,13 +116,11 @@ public:
|
||||
qlonglong getETA(QString hash);
|
||||
bool useTemporaryFolder() const;
|
||||
QString getDefaultSavePath() const;
|
||||
ScanFoldersModel* getScanFoldersModel() const;
|
||||
|
||||
public slots:
|
||||
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), 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 saveSessionState();
|
||||
void downloadFromUrl(QString url);
|
||||
@@ -184,6 +183,7 @@ public slots:
|
||||
void downloadFromURLList(const QStringList& urls);
|
||||
void configureSession();
|
||||
void banIP(QString ip);
|
||||
void recursiveTorrentDownload(const QTorrentHandle &h);
|
||||
|
||||
protected:
|
||||
QString getSavePath(QString hash, bool fromScanDir = false, QString filePath = QString());
|
||||
@@ -195,6 +195,7 @@ protected slots:
|
||||
void deleteBigRatios();
|
||||
void takeETASamples();
|
||||
void exportTorrentFiles(QString path);
|
||||
void saveTempFastResumeData();
|
||||
|
||||
signals:
|
||||
void addedTorrent(QTorrentHandle& h);
|
||||
@@ -204,7 +205,7 @@ signals:
|
||||
void finishedTorrent(QTorrentHandle& h);
|
||||
void fullDiskError(QTorrentHandle& h, 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 updateFileSize(QString hash);
|
||||
void downloadFromUrlFailure(QString url, QString reason);
|
||||
@@ -213,6 +214,7 @@ signals:
|
||||
void savePathChanged(QTorrentHandle &h);
|
||||
void newConsoleMessage(QString msg);
|
||||
void alternativeSpeedsModeChanged(bool alternative);
|
||||
void recursiveTorrentDownloadPossible(QTorrentHandle &h);
|
||||
|
||||
private:
|
||||
// Bittorrent
|
||||
@@ -222,6 +224,7 @@ private:
|
||||
QMap<QUrl, QString> savepath_fromurl;
|
||||
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
|
||||
QStringList torrentsToPausedAfterChecking;
|
||||
QTimer resumeDataTimer;
|
||||
// Ratio
|
||||
QPointer<QTimer> BigRatioTimer;
|
||||
// HTTP
|
||||
|
@@ -46,6 +46,7 @@ class consoleDlg : public QDialog, private Ui_ConsoleDlg{
|
||||
consoleDlg(QWidget *parent, Bittorrent* _BTSession) : QDialog(parent) {
|
||||
setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setModal(true);
|
||||
BTSession = _BTSession;
|
||||
textConsole->setHtml(BTSession->getConsoleMessages().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){
|
||||
setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setModal(true);
|
||||
creatorThread = new torrentCreatorThread(this);
|
||||
connect(creatorThread, SIGNAL(creationSuccess(QString, const char*)), this, SLOT(handleCreationSuccess(QString, const char*)));
|
||||
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(){
|
||||
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())
|
||||
textInputPath->setText(file);
|
||||
}
|
||||
|
@@ -53,34 +53,49 @@ public:
|
||||
setFixedHeight(BAR_HEIGHT);
|
||||
}
|
||||
|
||||
void setProgress(bitfield pieces) {
|
||||
void setProgress(const bitfield &pieces, const bitfield &downloading_pieces) {
|
||||
if(pieces.empty()) {
|
||||
// Empty bar
|
||||
QPixmap pix = QPixmap(1, 1);
|
||||
pix.fill();
|
||||
pixmap = pix;
|
||||
} else {
|
||||
int nb_pieces = pieces.size();
|
||||
const int nb_pieces = pieces.size();
|
||||
// Reduce the number of pieces before creating the pixmap
|
||||
// otherwise it can crash when there are too many pieces
|
||||
if(nb_pieces > width()) {
|
||||
int ratio = floor(nb_pieces/(double)width());
|
||||
QVector<bool> scaled_pieces;
|
||||
const int ratio = floor(nb_pieces/(double)width());
|
||||
std::vector<bool> scaled_pieces;
|
||||
std::vector<bool> scaled_downloading;
|
||||
for(int i=0; i<nb_pieces; i+= ratio) {
|
||||
bool have = true;
|
||||
for(int j=i; j<qMin(i+ratio, nb_pieces); ++j) {
|
||||
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);
|
||||
pix.fill();
|
||||
QPainter painter(&pix);
|
||||
for(int i=0; i<scaled_pieces.size(); ++i) {
|
||||
if(scaled_pieces[i])
|
||||
for(uint i=0; i<scaled_pieces.size(); ++i) {
|
||||
if(scaled_pieces[i]) {
|
||||
painter.setPen(Qt::blue);
|
||||
else
|
||||
painter.setPen(Qt::white);
|
||||
} else {
|
||||
if(scaled_downloading[i]) {
|
||||
painter.setPen(Qt::yellow);
|
||||
} else {
|
||||
painter.setPen(Qt::white);
|
||||
}
|
||||
}
|
||||
painter.drawPoint(i,0);
|
||||
}
|
||||
pixmap = pix;
|
||||
@@ -89,10 +104,15 @@ public:
|
||||
pix.fill();
|
||||
QPainter painter(&pix);
|
||||
for(uint i=0; i<pieces.size(); ++i) {
|
||||
if(pieces[i])
|
||||
if(pieces[i]) {
|
||||
painter.setPen(Qt::blue);
|
||||
else
|
||||
painter.setPen(Qt::white);
|
||||
} else {
|
||||
if(downloading_pieces[i]) {
|
||||
painter.setPen(Qt::yellow);
|
||||
} else {
|
||||
painter.setPen(Qt::white);
|
||||
}
|
||||
}
|
||||
painter.drawPoint(i,0);
|
||||
}
|
||||
pixmap = pix;
|
||||
|
@@ -47,6 +47,7 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{
|
||||
setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
icon_lbl->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/url.png")));
|
||||
setModal(true);
|
||||
show();
|
||||
// Paste clipboard if there is an URL in it
|
||||
QString clip_txt = qApp->clipboard()->text();
|
||||
|
@@ -59,7 +59,7 @@ void downloadThread::processDlFinished(QNetworkReply* reply) {
|
||||
QVariant redirection = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
if(redirection.isValid()) {
|
||||
// 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);
|
||||
downloadUrl(redirection.toUrl().toString());
|
||||
return;
|
||||
@@ -74,7 +74,7 @@ void downloadThread::processDlFinished(QNetworkReply* reply) {
|
||||
tmpfile.setAutoRemove(false);
|
||||
if (tmpfile.open()) {
|
||||
filePath = tmpfile.fileName();
|
||||
qDebug("Temporary filename is: %s", filePath.toLocal8Bit().data());
|
||||
qDebug("Temporary filename is: %s", qPrintable(filePath));
|
||||
if(reply->open(QIODevice::ReadOnly)) {
|
||||
// TODO: Support GZIP compression
|
||||
tmpfile.write(reply->readAll());
|
||||
@@ -95,7 +95,12 @@ void downloadThread::processDlFinished(QNetworkReply* reply) {
|
||||
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
|
||||
applyProxySettings();
|
||||
// Process download request
|
||||
@@ -104,8 +109,27 @@ void downloadThread::downloadUrl(QString url){
|
||||
// Spoof Firefox 3.5 user agent to avoid
|
||||
// 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");
|
||||
qDebug("Downloading %s...", request.url().toString().toLocal8Bit().data());
|
||||
networkManager->get(request);
|
||||
qDebug("Downloading %s...", qPrintable(request.url().toString()));
|
||||
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() {
|
||||
@@ -117,7 +141,7 @@ void downloadThread::applyProxySettings() {
|
||||
QString IP = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/IP"), "0.0.0.0").toString();
|
||||
proxy.setHostName(IP);
|
||||
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());
|
||||
// Default proxy type is HTTP, we must change if it is SOCKS5
|
||||
if(intValue == SOCKS5 || intValue == SOCKS5_PW) {
|
||||
|
@@ -51,7 +51,8 @@ signals:
|
||||
public:
|
||||
downloadThread(QObject* parent);
|
||||
~downloadThread();
|
||||
void downloadUrl(QString url);
|
||||
QNetworkReply* downloadUrl(QString url);
|
||||
void downloadTorrentUrl(QString url);
|
||||
//void setProxy(QString IP, int port, QString username, QString password);
|
||||
|
||||
protected:
|
||||
@@ -60,6 +61,7 @@ protected:
|
||||
|
||||
protected slots:
|
||||
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"));
|
||||
QString file;
|
||||
foreach(file, files) {
|
||||
qDebug("dropped %s", file.toLocal8Bit().data());
|
||||
qDebug("dropped %s", qPrintable(file));
|
||||
file = file.replace("file://", "");
|
||||
if(file.startsWith("http://", Qt::CaseInsensitive) || file.startsWith("https://", Qt::CaseInsensitive) || file.startsWith("ftp://", Qt::CaseInsensitive)) {
|
||||
downloader->downloadUrl(file);
|
||||
@@ -99,7 +99,7 @@ void engineSelectDlg::dropEvent(QDropEvent *event) {
|
||||
void engineSelectDlg::dragEnterEvent(QDragEnterEvent *event) {
|
||||
QString mime;
|
||||
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"))) {
|
||||
event->acceptProposedAction();
|
||||
@@ -251,12 +251,12 @@ bool engineSelectDlg::isUpdateNeeded(QString plugin_name, float new_version) con
|
||||
}
|
||||
|
||||
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);
|
||||
qDebug("Version to be installed: %.2f", new_version);
|
||||
if(!isUpdateNeeded(plugin_name, new_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;
|
||||
}
|
||||
// Process with install
|
||||
@@ -280,12 +280,12 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
||||
// restore backup
|
||||
QFile::copy(dest_path+".bak", dest_path);
|
||||
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;
|
||||
} else {
|
||||
// Remove broken file
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -294,10 +294,10 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
||||
QFile::remove(dest_path+".bak");
|
||||
}
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@@ -390,17 +390,17 @@ bool engineSelectDlg::parseVersionsFile(QString versions_file) {
|
||||
plugin_name.chop(1); // remove trailing ':'
|
||||
bool 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;
|
||||
file_correct = true;
|
||||
if(isUpdateNeeded(plugin_name, version)) {
|
||||
qDebug("Plugin: %s is outdated", plugin_name.toLocal8Bit().data());
|
||||
qDebug("Plugin: %s is outdated", qPrintable(plugin_name));
|
||||
// Downloading update
|
||||
downloader->downloadUrl(UPDATE_URL+plugin_name+".py");
|
||||
//downloader->downloadUrl(UPDATE_URL+plugin_name+".png");
|
||||
updated = true;
|
||||
}else {
|
||||
qDebug("Plugin: %s is up to date", plugin_name.toLocal8Bit().data());
|
||||
qDebug("Plugin: %s is up to date", qPrintable(plugin_name));
|
||||
}
|
||||
}
|
||||
// Close file
|
||||
@@ -414,7 +414,7 @@ bool engineSelectDlg::parseVersionsFile(QString versions_file) {
|
||||
}
|
||||
|
||||
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)){
|
||||
// Icon downloaded
|
||||
QImage fileIcon;
|
||||
@@ -456,7 +456,7 @@ void engineSelectDlg::processDownloadedFile(QString url, QString filePath) {
|
||||
|
||||
void engineSelectDlg::handleDownloadFailure(QString url, QString reason) {
|
||||
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;
|
||||
}
|
||||
if(url.endsWith("versions.txt")) {
|
||||
@@ -467,6 +467,6 @@ void engineSelectDlg::handleDownloadFailure(QString url, QString reason) {
|
||||
// a plugin update download has been failed
|
||||
QString plugin_name = url.split('/').last();
|
||||
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 "bittorrent.h"
|
||||
#include "scannedfoldersmodel.h"
|
||||
#include "misc.h"
|
||||
#include "preferences.h"
|
||||
//#include "proplistdelegate.h"
|
||||
@@ -129,10 +130,29 @@ void EventManager::setGlobalPreferences(QVariantMap m) const {
|
||||
Preferences::setTempPathEnabled(m["temp_path_enabled"].toBool());
|
||||
if(m.contains("temp_path"))
|
||||
Preferences::setTempPath(m["temp_path"].toString());
|
||||
if(m.contains("scan_dirs"))
|
||||
Preferences::setScanDirs(m["scan_dirs"].toStringList());
|
||||
if(m.contains("download_in_scan_dirs"))
|
||||
Preferences::setDownloadInScanDirs(m["download_in_scan_dirs"].toList());
|
||||
if(m.contains("scan_dirs") && m.contains("download_in_scan_dirs")) {
|
||||
QVariantList download_at_path = m["download_in_scan_dirs"].toList();
|
||||
QStringList old_folders = Preferences::getScanDirs();
|
||||
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"))
|
||||
Preferences::setExportDir(m["export_dir"].toString());
|
||||
if(m.contains("preallocate_all"))
|
||||
@@ -169,6 +189,10 @@ void EventManager::setGlobalPreferences(QVariantMap m) const {
|
||||
// Bittorrent
|
||||
if(m.contains("dht"))
|
||||
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"))
|
||||
Preferences::setPeXEnabled(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();
|
||||
// Bittorrent
|
||||
data["dht"] = Preferences::isDHTEnabled();
|
||||
data["dhtSameAsBT"] = Preferences::isDHTPortSameAsBT();
|
||||
data["dht_port"] = Preferences::getDHTPort();
|
||||
data["pex"] = Preferences::isPeXEnabled();
|
||||
data["lsd"] = Preferences::isLSDEnabled();
|
||||
data["encryption"] = Preferences::getEncryptionSetting();
|
||||
@@ -295,23 +321,23 @@ QVariantMap EventManager::getPropGeneralInfo(QString hash) const {
|
||||
data["creation_date"] = h.creation_date();
|
||||
// Comment
|
||||
data["comment"] = h.comment();
|
||||
data["total_wasted"] = 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_downloaded"] = misc::friendlyUnit(h.all_time_download()) + " ("+misc::friendlyUnit(h.total_payload_download())+" "+tr("this session")+")";
|
||||
data["total_wasted"] = QVariant(misc::friendlyUnit(h.total_failed_bytes()+h.total_redundant_bytes()));
|
||||
data["total_uploaded"] = QVariant(misc::friendlyUnit(h.all_time_upload()) + " ("+misc::friendlyUnit(h.total_payload_upload())+" "+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)
|
||||
data["up_limit"] = QString::fromUtf8("∞");
|
||||
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)
|
||||
data["dl_limit"] = QString::fromUtf8("∞");
|
||||
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());
|
||||
if(h.is_seed()) {
|
||||
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")";
|
||||
}
|
||||
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
|
||||
double ratio = BTSession->getRealRatio(h.hash());
|
||||
if(ratio > 100.)
|
||||
|
@@ -28,15 +28,16 @@ public:
|
||||
setColumnCount(1);
|
||||
QTreeWidgetItem *___qtreewidgetitem = headerItem();
|
||||
___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->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")));
|
||||
itemAdded(unread_item, rssmanager);
|
||||
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(updateCurrentFeed(QTreeWidgetItem*)));
|
||||
setCurrentItem(unread_item);
|
||||
}
|
||||
|
||||
~FeedList() {
|
||||
disconnect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(updateCurrentFeed(QTreeWidgetItem*)));
|
||||
delete unread_item;
|
||||
}
|
||||
|
||||
@@ -121,19 +122,19 @@ public:
|
||||
}
|
||||
|
||||
RssFile* getRSSItem(QTreeWidgetItem *item) const {
|
||||
return mapping[item];
|
||||
return mapping.value(item, 0);
|
||||
}
|
||||
|
||||
RssFile::FileType getItemType(QTreeWidgetItem *item) const {
|
||||
return mapping[item]->getType();
|
||||
return mapping.value(item)->getType();
|
||||
}
|
||||
|
||||
QString getItemID(QTreeWidgetItem *item) const {
|
||||
return mapping[item]->getID();
|
||||
return mapping.value(item)->getID();
|
||||
}
|
||||
|
||||
QTreeWidgetItem* getTreeItemFromUrl(QString url) const{
|
||||
return feeds_items[url];
|
||||
return feeds_items.value(url, 0);
|
||||
}
|
||||
|
||||
RssStream* getRSSItemFromUrl(QString url) const {
|
||||
|
@@ -46,7 +46,7 @@
|
||||
#include "bittorrent.h"
|
||||
#include "ui_feeddownloader.h"
|
||||
|
||||
#ifdef QT_4_5
|
||||
#if QT_VERSION >= 0x040500
|
||||
#include <QHash>
|
||||
#else
|
||||
#include <QMap>
|
||||
@@ -64,11 +64,9 @@ public:
|
||||
|
||||
bool matches(QString s) {
|
||||
QStringList match_tokens = getMatchingTokens();
|
||||
//qDebug("Checking matching tokens: \"%s\"", getMatchingTokens_str().toLocal8Bit().data());
|
||||
foreach(const QString& token, match_tokens) {
|
||||
if(token.isEmpty() || token == "")
|
||||
continue;
|
||||
//qDebug("Token: %s", token.toLocal8Bit().data());
|
||||
QRegExp reg(token, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||
//reg.setMinimal(false);
|
||||
if(reg.indexIn(s) < 0) return false;
|
||||
@@ -226,7 +224,7 @@ public:
|
||||
void save() {
|
||||
QSettings qBTRSS("qBittorrent", "qBittorrent-rss");
|
||||
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;
|
||||
qBTRSS.setValue("feed_filters", all_feeds_filters);
|
||||
}
|
||||
@@ -261,7 +259,6 @@ public:
|
||||
// Restore saved info
|
||||
enableDl_cb->setChecked(filters.isDownloadingEnabled());
|
||||
fillFiltersList();
|
||||
filtersList->sortItems(Qt::AscendingOrder);
|
||||
if(filters.size() > 0) {
|
||||
// Select first filter
|
||||
filtersList->setCurrentItem(filtersList->item(0));
|
||||
@@ -388,7 +385,6 @@ protected slots:
|
||||
if(selected_filter == current_name)
|
||||
selected_filter = new_name;
|
||||
item->setText(new_name);
|
||||
filtersList->sortItems(Qt::AscendingOrder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +438,6 @@ protected slots:
|
||||
}
|
||||
}while(!validated);
|
||||
QListWidgetItem *it = new QListWidgetItem(filter_name, filtersList);
|
||||
filtersList->sortItems(Qt::AscendingOrder);
|
||||
filtersList->setCurrentItem(it);
|
||||
//showFilterSettings(it);
|
||||
}
|
||||
|
@@ -49,10 +49,10 @@ protected:
|
||||
file += QDir::separator();
|
||||
file += ".";
|
||||
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);
|
||||
} 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) {
|
||||
case EACCES:
|
||||
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)));
|
||||
}
|
||||
|
||||
FileSystemWatcher(QString path, QObject *parent): QFileSystemWatcher(parent) {
|
||||
filters << "*.torrent";
|
||||
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
|
||||
addPath(path);
|
||||
}
|
||||
|
||||
~FileSystemWatcher() {
|
||||
#ifndef Q_WS_WIN
|
||||
if(watch_timer)
|
||||
@@ -148,7 +142,7 @@ public:
|
||||
} else {
|
||||
#endif
|
||||
// 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);
|
||||
scanLocalFolder(path);
|
||||
#ifndef Q_WS_WIN
|
||||
@@ -190,7 +184,7 @@ protected slots:
|
||||
QStringList torrents;
|
||||
// Network folders scan
|
||||
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);
|
||||
}
|
||||
// Report detected torrent files
|
||||
|
@@ -86,9 +86,9 @@ public:
|
||||
exportEmbeddedDb();
|
||||
#endif
|
||||
if(QFile::exists(geoipDBpath(false))) {
|
||||
qDebug("Loading GeoIP database from %s...", geoipDBpath(false).toLocal8Bit().data());
|
||||
if(!s->load_country_db(geoipDBpath(false).toLocal8Bit().data())) {
|
||||
std::cerr << "Failed to load Geoip Database at " << geoipDBpath(false).toLocal8Bit().data() << std::endl;
|
||||
qDebug("Loading GeoIP database from %s...", qPrintable(geoipDBpath(false)));
|
||||
if(!s->load_country_db(geoipDBpath(false).toLocal8Bit().constData())) {
|
||||
std::cerr << "Failed to load Geoip Database at " << qPrintable(geoipDBpath(false)) << std::endl;
|
||||
}
|
||||
} else {
|
||||
qDebug("ERROR: Impossible to find local Geoip Database");
|
||||
|
@@ -41,97 +41,98 @@
|
||||
class HeadlessLoader: QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QLocalServer *localServer;
|
||||
Bittorrent *BTSession;
|
||||
|
||||
public:
|
||||
HeadlessLoader(QStringList torrentCmdLine) {
|
||||
// Enable Web UI
|
||||
Preferences::setWebUiEnabled(true);
|
||||
// Instanciate Bittorrent Object
|
||||
BTSession = new Bittorrent();
|
||||
connect(BTSession, SIGNAL(newConsoleMessage(QString)), this, SLOT(displayConsoleMessage(QString)));
|
||||
// Resume unfinished torrents
|
||||
BTSession->startUpTorrents();
|
||||
// Process command line parameters
|
||||
processParams(torrentCmdLine);
|
||||
// Use a tcp server to allow only one instance of qBittorrent
|
||||
localServer = new QLocalServer();
|
||||
QString uid = QString::number(getuid());
|
||||
public:
|
||||
HeadlessLoader(QStringList torrentCmdLine) {
|
||||
// Enable Web UI
|
||||
Preferences::setWebUiEnabled(true);
|
||||
// Instanciate Bittorrent Object
|
||||
BTSession = new Bittorrent();
|
||||
connect(BTSession, SIGNAL(newConsoleMessage(QString)), this, SLOT(displayConsoleMessage(QString)));
|
||||
// Resume unfinished torrents
|
||||
BTSession->startUpTorrents();
|
||||
// Process command line parameters
|
||||
processParams(torrentCmdLine);
|
||||
// Use a tcp server to allow only one instance of qBittorrent
|
||||
localServer = new QLocalServer();
|
||||
const QString &uid = QString::number(getuid());
|
||||
#ifdef Q_WS_X11
|
||||
if(QFile::exists(QDir::tempPath()+QDir::separator()+QString("qBittorrent-")+uid)) {
|
||||
// Socket was not closed cleanly
|
||||
std::cerr << "Warning: Local domain socket was not closed cleanly, deleting file...\n";
|
||||
QFile::remove(QDir::tempPath()+QDir::separator()+QString("qBittorrent-")+uid);
|
||||
}
|
||||
if(QFile::exists(QDir::tempPath()+QDir::separator()+QString("qBittorrent-")+uid)) {
|
||||
// Socket was not closed cleanly
|
||||
std::cerr << "Warning: Local domain socket was not closed cleanly, deleting file..." << std::endl;
|
||||
QFile::remove(QDir::tempPath()+QDir::separator()+QString("qBittorrent-")+uid);
|
||||
}
|
||||
#endif
|
||||
if (!localServer->listen("qBittorrent-"+uid)) {
|
||||
std::cerr << "Couldn't create socket, single instance mode won't work...\n";
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (!localServer->listen("qBittorrent-"+uid)) {
|
||||
std::cerr << "Couldn't create socket, single instance mode won't work..." << std::endl;
|
||||
}
|
||||
|
||||
~HeadlessLoader() {
|
||||
delete BTSession;
|
||||
connect(localServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
|
||||
// Display some information to the user
|
||||
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:
|
||||
// Call this function to exit qBittorrent headless loader
|
||||
// and return to prompt (object will be deleted by main)
|
||||
void exit() {
|
||||
qApp->quit();
|
||||
}
|
||||
~HeadlessLoader() {
|
||||
delete localServer;
|
||||
delete BTSession;
|
||||
}
|
||||
|
||||
void displayConsoleMessage(QString msg) {
|
||||
std::cout << msg.toLocal8Bit().data() << std::endl;
|
||||
}
|
||||
public slots:
|
||||
// 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.
|
||||
// This function parse the parameters and call
|
||||
// the right addTorrent function, considering
|
||||
// the parameter type.
|
||||
void processParams(const QStringList& params) {
|
||||
foreach(QString param, params) {
|
||||
param = param.trimmed();
|
||||
if(param.startsWith("--")) continue;
|
||||
if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) {
|
||||
BTSession->downloadFromUrl(param);
|
||||
}else{
|
||||
if(param.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||
BTSession->addMagnetUri(param);
|
||||
} else {
|
||||
BTSession->addTorrent(param);
|
||||
}
|
||||
void displayConsoleMessage(QString msg) {
|
||||
std::cout << qPrintable(msg) << std::endl;
|
||||
}
|
||||
|
||||
// As program parameters, we can get paths or urls.
|
||||
// This function parse the parameters and call
|
||||
// the right addTorrent function, considering
|
||||
// the parameter type.
|
||||
void processParams(const QStringList& params) {
|
||||
foreach(QString param, params) {
|
||||
param = param.trimmed();
|
||||
if(param.startsWith("--")) continue;
|
||||
if(param.startsWith(QString::fromUtf8("http://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("ftp://"), Qt::CaseInsensitive) || param.startsWith(QString::fromUtf8("https://"), Qt::CaseInsensitive)) {
|
||||
BTSession->downloadFromUrl(param);
|
||||
}else{
|
||||
if(param.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||
BTSession->addMagnetUri(param);
|
||||
} else {
|
||||
BTSession->addTorrent(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void acceptConnection() {
|
||||
QLocalSocket *clientConnection = localServer->nextPendingConnection();
|
||||
connect(clientConnection, SIGNAL(disconnected()), this, SLOT(readParamsOnSocket()));
|
||||
qDebug("accepted connection from another instance");
|
||||
}
|
||||
void acceptConnection() {
|
||||
QLocalSocket *clientConnection = localServer->nextPendingConnection();
|
||||
connect(clientConnection, SIGNAL(disconnected()), this, SLOT(readParamsOnSocket()));
|
||||
qDebug("accepted connection from another instance");
|
||||
}
|
||||
|
||||
void readParamsOnSocket() {
|
||||
QLocalSocket *clientConnection = static_cast<QLocalSocket*>(sender());
|
||||
if(clientConnection) {
|
||||
QByteArray params = clientConnection->readAll();
|
||||
if(!params.isEmpty()) {
|
||||
processParams(QString::fromUtf8(params.data()).split(QString::fromUtf8("\n")));
|
||||
qDebug("Received parameters from another instance");
|
||||
}
|
||||
clientConnection->deleteLater();
|
||||
void readParamsOnSocket() {
|
||||
QLocalSocket *clientConnection = static_cast<QLocalSocket*>(sender());
|
||||
if(clientConnection) {
|
||||
const QByteArray ¶ms = clientConnection->readAll();
|
||||
if(!params.isEmpty()) {
|
||||
processParams(QString(params).split("\n"));
|
||||
qDebug("Received parameters from another instance");
|
||||
}
|
||||
clientConnection->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QLocalServer *localServer;
|
||||
Bittorrent *BTSession;
|
||||
|
||||
};
|
||||
|
||||
|
@@ -47,7 +47,7 @@
|
||||
#include <QTemporaryFile>
|
||||
|
||||
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);
|
||||
connect(socket, SIGNAL(readyRead()), this, SLOT(read()));
|
||||
@@ -104,7 +104,7 @@ void HttpConnection::write()
|
||||
}
|
||||
|
||||
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;
|
||||
bool found = false;
|
||||
do {
|
||||
@@ -117,9 +117,9 @@ QString HttpConnection::translateDocument(QString data) {
|
||||
QString translation = word;
|
||||
int context_index= 0;
|
||||
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;
|
||||
}while(translation == word && context_index < 12);
|
||||
}while(translation == word && context_index < 13);
|
||||
//qDebug("Translation is %s", translation.toUtf8().data());
|
||||
data = data.replace(i, regex.matchedLength(), translation);
|
||||
i += translation.length();
|
||||
@@ -131,19 +131,28 @@ QString HttpConnection::translateDocument(QString data) {
|
||||
|
||||
void HttpConnection::respond() {
|
||||
//qDebug("Respond called");
|
||||
int nb_fail = parent->client_failed_attempts.value(socket->peerAddress().toString(), 0);
|
||||
if(nb_fail > 4) {
|
||||
const QString &peer_ip = socket->peerAddress().toString();
|
||||
const int nb_fail = parent->NbFailedAttemptsForIp(peer_ip);
|
||||
if(nb_fail >= MAX_AUTH_FAILED_ATTEMPTS) {
|
||||
generator.setStatusLine(403, "Forbidden");
|
||||
generator.setMessage(tr("Your IP address has been banned after too many failed authentication attempts."));
|
||||
write();
|
||||
return;
|
||||
}
|
||||
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())) {
|
||||
// Update failed attempt counter
|
||||
parent->client_failed_attempts.insert(socket->peerAddress().toString(), nb_fail+1);
|
||||
qDebug("client IP: %s (%d failed attempts)", socket->peerAddress().toString().toLocal8Bit().data(), nb_fail);
|
||||
parent->increaseNbFailedAttemptsForIp(peer_ip);
|
||||
qDebug("client IP: %s (%d failed attempts)", qPrintable(peer_ip), nb_fail+1);
|
||||
// Return unauthorized header
|
||||
generator.setStatusLine(401, "Unauthorized");
|
||||
generator.setValue("WWW-Authenticate", "Digest realm=\""+QString(QBT_REALM)+"\", nonce=\""+parent->generateNonce()+"\", algorithm=\"MD5\", qop=\"auth\"");
|
||||
@@ -151,7 +160,7 @@ void HttpConnection::respond() {
|
||||
return;
|
||||
}
|
||||
// Client sucessfuly authenticated, reset number of failed attempts
|
||||
parent->client_failed_attempts.remove(socket->peerAddress().toString());
|
||||
parent->resetNbFailedAttemptsForIp(peer_ip);
|
||||
QString url = parser.url();
|
||||
// Favicon
|
||||
if(url.endsWith("favicon.ico")) {
|
||||
@@ -225,7 +234,6 @@ void HttpConnection::respond() {
|
||||
else
|
||||
list.prepend("webui");
|
||||
url = ":/" + list.join("/");
|
||||
//qDebug("Resource URL: %s", url.toLocal8Bit().data());
|
||||
QFile file(url);
|
||||
if(!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
@@ -261,7 +269,6 @@ void HttpConnection::respondJson()
|
||||
QString string = json::toJson(manager->getEventList());
|
||||
generator.setStatusLine(200, "OK");
|
||||
generator.setContentTypeByExt("js");
|
||||
//qDebug("JSON: %s", string.toLocal8Bit().data());
|
||||
generator.setMessage(string);
|
||||
write();
|
||||
}
|
||||
@@ -290,7 +297,6 @@ void HttpConnection::respondFilesPropertiesJson(QString hash) {
|
||||
generator.setStatusLine(200, "OK");
|
||||
generator.setContentTypeByExt("js");
|
||||
generator.setMessage(string);
|
||||
//qDebug("JSON: %s", string.toLocal8Bit().data());
|
||||
write();
|
||||
}
|
||||
|
||||
@@ -391,7 +397,6 @@ void HttpConnection::respondCommand(QString command)
|
||||
}
|
||||
if(command == "setPreferences") {
|
||||
QString json_str = parser.post("json");
|
||||
//qDebug("setPreferences, json: %s", json_str.toLocal8Bit().data());
|
||||
EventManager* manager = parent->eventManager();
|
||||
manager->setGlobalPreferences(json::fromJson(json_str));
|
||||
}
|
||||
|
@@ -37,6 +37,48 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QTime>
|
||||
#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) {
|
||||
username = Preferences::getWebUiUsername().toLocal8Bit();
|
||||
@@ -132,16 +174,12 @@ void HttpServer::setAuthorization(QString _username, QString _password_ha1) {
|
||||
password_ha1 = _password_ha1.toLocal8Bit();
|
||||
}
|
||||
|
||||
// AUTH string is: Digest username="chris",
|
||||
// realm="Web UI Access",
|
||||
// nonce="570d04de93444b7fd3eaeaecb00e635e",
|
||||
// uri="/", algorithm=MD5,
|
||||
// response="ba886766d19b45313c0e2195e4344264",
|
||||
// qop=auth, nc=00000001, cnonce="e8ac970779c17075"
|
||||
// Parse HTTP AUTH string
|
||||
// http://tools.ietf.org/html/rfc2617
|
||||
bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
||||
qDebug("AUTH string is %s", auth.data());
|
||||
// Get user name
|
||||
QRegExp regex_user(".*username=\"([^\"]+)\".*");
|
||||
QRegExp regex_user(".*username=\"([^\"]+)\".*"); // Must be a quoted string
|
||||
if(regex_user.indexIn(auth) < 0) return false;
|
||||
QString prop_user = regex_user.cap(1);
|
||||
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;
|
||||
}
|
||||
// Get realm
|
||||
QRegExp regex_realm(".*realm=\"([^\"]+)\".*");
|
||||
QRegExp regex_realm(".*realm=\"([^\"]+)\".*"); // Must be a quoted string
|
||||
if(regex_realm.indexIn(auth) < 0) {
|
||||
qDebug("AUTH-PROB: Missing realm");
|
||||
return false;
|
||||
@@ -162,7 +200,7 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
||||
return false;
|
||||
}
|
||||
// get nonce
|
||||
QRegExp regex_nonce(".*nonce=\"([^\"]+)\".*");
|
||||
QRegExp regex_nonce(".*nonce=[\"]?([\\w=]+)[\"]?.*");
|
||||
if(regex_nonce.indexIn(auth) < 0) {
|
||||
qDebug("AUTH-PROB: missing nonce");
|
||||
return false;
|
||||
@@ -178,7 +216,7 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
||||
QByteArray prop_uri = regex_uri.cap(1).toLocal8Bit();
|
||||
qDebug("prop uri is: %s", prop_uri.data());
|
||||
// get response
|
||||
QRegExp regex_response(".*response=\"([^\"]+)\".*");
|
||||
QRegExp regex_response(".*response=[\"]?([\\w=]+)[\"]?.*");
|
||||
if(regex_response.indexIn(auth) < 0) {
|
||||
qDebug("AUTH-PROB: Missing response");
|
||||
return false;
|
||||
@@ -193,14 +231,14 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
||||
if(auth.contains("qop=")) {
|
||||
QCryptographicHash md5_ha(QCryptographicHash::Md5);
|
||||
// Get nc
|
||||
QRegExp regex_nc(".*nc=(\\w+).*");
|
||||
QRegExp regex_nc(".*nc=[\"]?([\\w=]+)[\"]?.*");
|
||||
if(regex_nc.indexIn(auth) < 0) {
|
||||
qDebug("AUTH-PROB: qop but missing nc");
|
||||
return false;
|
||||
}
|
||||
QByteArray prop_nc = regex_nc.cap(1).toLocal8Bit();
|
||||
qDebug("prop nc is: %s", prop_nc.data());
|
||||
QRegExp regex_cnonce(".*cnonce=\"([^\"]+)\".*");
|
||||
QRegExp regex_cnonce(".*cnonce=[\"]?([\\w=]+)[\"]?.*");
|
||||
if(regex_cnonce.indexIn(auth) < 0) {
|
||||
qDebug("AUTH-PROB: qop but missing cnonce");
|
||||
return false;
|
||||
@@ -221,7 +259,7 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
|
||||
md5_ha.addData(password_ha1+":"+prop_nonce+":"+ha2);
|
||||
response = md5_ha.result().toHex();
|
||||
}
|
||||
qDebug("AUTH: comparing reponses");
|
||||
qDebug("AUTH: comparing reponses: (%d)", static_cast<int>(prop_response == response));
|
||||
return prop_response == response;
|
||||
}
|
||||
|
||||
|
@@ -42,28 +42,34 @@ class Bittorrent;
|
||||
class QTimer;
|
||||
class EventManager;
|
||||
|
||||
const int MAX_AUTH_FAILED_ATTEMPTS = 5;
|
||||
|
||||
class HttpServer : public QTcpServer {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QByteArray username;
|
||||
QByteArray password_ha1;
|
||||
Bittorrent *BTSession;
|
||||
EventManager *manager;
|
||||
QTimer *timer;
|
||||
public:
|
||||
HttpServer(Bittorrent *BTSession, int msec, QObject* parent = 0);
|
||||
~HttpServer();
|
||||
void setAuthorization(QString username, QString password_ha1);
|
||||
bool isAuthorized(QByteArray auth, QString method) const;
|
||||
EventManager *eventManager() const;
|
||||
QString generateNonce() const;
|
||||
int NbFailedAttemptsForIp(QString ip) const;
|
||||
void increaseNbFailedAttemptsForIp(QString ip);
|
||||
void resetNbFailedAttemptsForIp(QString ip);
|
||||
|
||||
public:
|
||||
HttpServer(Bittorrent *BTSession, int msec, QObject* parent = 0);
|
||||
~HttpServer();
|
||||
void setAuthorization(QString username, QString password_ha1);
|
||||
bool isAuthorized(QByteArray auth, QString method) const;
|
||||
EventManager *eventManager() const;
|
||||
QString generateNonce() const;
|
||||
QHash<QString, int> client_failed_attempts;
|
||||
private slots:
|
||||
void newHttpConnection();
|
||||
void onTimer();
|
||||
void UnbanTimerEvent();
|
||||
|
||||
private slots:
|
||||
void newHttpConnection();
|
||||
void onTimer();
|
||||
private:
|
||||
QByteArray username;
|
||||
QByteArray password_ha1;
|
||||
Bittorrent *BTSession;
|
||||
EventManager *manager;
|
||||
QTimer *timer;
|
||||
QHash<QString, int> client_failed_attempts;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
44
src/json.h
44
src/json.h
@@ -113,7 +113,24 @@ namespace json {
|
||||
if(json.startsWith("{") && json.endsWith("}")) {
|
||||
json.chop(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) {
|
||||
QStringList parts = couple.split(":");
|
||||
if(parts.size() != 2) continue;
|
||||
@@ -124,12 +141,29 @@ namespace json {
|
||||
}
|
||||
QString value_str = parts.last();
|
||||
QVariant value;
|
||||
if(value_str.startsWith("\"") && value_str.endsWith("\"")) {
|
||||
if(value_str.startsWith("[") && value_str.endsWith("]")) {
|
||||
value_str.chop(1);
|
||||
value_str = value_str.replace(0, 1, "");
|
||||
value = value_str;
|
||||
value_str.replace(0, 1, "");
|
||||
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 {
|
||||
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);
|
||||
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