You've already forked qBittorrent
mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-10-09 18:32:15 +02:00
Compare commits
1 Commits
release-3.
...
release-2.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c506a01dea |
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)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
* Unreleased - Christophe Dumez <chris@qbittorrent.org> - v2.2.0
|
||||
* 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 +15,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);
|
||||
|
||||
}
|
||||
};
|
||||
|
20
src/GUI.cpp
20
src/GUI.cpp
@@ -227,6 +227,8 @@ GUI::~GUI() {
|
||||
delete aboutDlg;
|
||||
if(options)
|
||||
delete options;
|
||||
if(downloadFromURLDialog)
|
||||
delete downloadFromURLDialog;
|
||||
if(rssWidget)
|
||||
delete rssWidget;
|
||||
delete searchEngine;
|
||||
@@ -251,6 +253,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
|
||||
@@ -627,8 +635,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 +837,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 +962,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
|
||||
@@ -139,6 +140,7 @@ private:
|
||||
QPointer<consoleDlg> console;
|
||||
QPointer<about> aboutDlg;
|
||||
QPointer<createtorrent> createTorrentDlg;
|
||||
QPointer<downloadFromURL> downloadFromURLDialog;
|
||||
QPointer<QSystemTrayIcon> systrayIcon;
|
||||
QPointer<QTimer> systrayCreator;
|
||||
QMenu *myTrayIconMenu;
|
||||
|
@@ -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
@@ -119,9 +119,6 @@ public:
|
||||
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);
|
||||
@@ -204,7 +201,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);
|
||||
|
@@ -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)));
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -295,23 +295,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()));
|
||||
@@ -117,7 +117,7 @@ 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);
|
||||
//qDebug("Translation is %s", translation.toUtf8().data());
|
||||
@@ -131,19 +131,20 @@ 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());
|
||||
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 +152,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 +226,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 +261,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 +289,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 +389,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;
|
||||
|
@@ -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
|
||||
|
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
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user