|
|
@ -21,66 +21,45 @@ |
|
|
|
|
|
|
|
|
|
|
|
#include "downloadThread.h" |
|
|
|
#include "downloadThread.h" |
|
|
|
#include <iostream> |
|
|
|
#include <iostream> |
|
|
|
#include <cc++/common.h> |
|
|
|
|
|
|
|
#include <QSettings> |
|
|
|
#include <QSettings> |
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
|
|
|
|
|
|
|
|
|
QString subDownloadThread::errorCodeToString(int status) { |
|
|
|
// http://curl.rtin.bz/libcurl/c/libcurl-errors.html
|
|
|
|
|
|
|
|
QString subDownloadThread::errorCodeToString(CURLcode status) { |
|
|
|
switch(status){ |
|
|
|
switch(status){ |
|
|
|
case 1://ost::URLStream::errUnreachable:
|
|
|
|
case CURLE_COULDNT_RESOLVE_HOST: |
|
|
|
return tr("Host is unreachable"); |
|
|
|
return tr("Host is unreachable"); |
|
|
|
case 2://ost::URLStream::errMissing:
|
|
|
|
case CURLE_READ_ERROR: |
|
|
|
|
|
|
|
case CURLE_FILE_COULDNT_READ_FILE: |
|
|
|
return tr("File was not found (404)"); |
|
|
|
return tr("File was not found (404)"); |
|
|
|
case 3://ost::URLStream::errDenied:
|
|
|
|
case CURLE_LOGIN_DENIED: |
|
|
|
return tr("Connection was denied"); |
|
|
|
return tr("Connection was denied"); |
|
|
|
case 4://ost::URLStream::errInvalid:
|
|
|
|
case CURLE_URL_MALFORMAT: |
|
|
|
return tr("Url is invalid"); |
|
|
|
return tr("Url is invalid"); |
|
|
|
case 5://ost::URLStream::errForbidden:
|
|
|
|
case CURLE_COULDNT_RESOLVE_PROXY: |
|
|
|
return tr("Connection forbidden (403)"); |
|
|
|
return tr("Could not resolve proxy"); |
|
|
|
case 6://ost::URLStream::errUnauthorized:
|
|
|
|
//case 5:
|
|
|
|
return tr("Connection was not authorized (401)"); |
|
|
|
// return tr("Connection forbidden (403)");
|
|
|
|
case 7://ost::URLStream::errRelocated:
|
|
|
|
//case 6:
|
|
|
|
return tr("Content has moved (301)"); |
|
|
|
// return tr("Connection was not authorized (401)");
|
|
|
|
case 8://ost::URLStream::errFailure:
|
|
|
|
//case 7:
|
|
|
|
|
|
|
|
// return tr("Content has moved (301)");
|
|
|
|
|
|
|
|
case CURLE_COULDNT_CONNECT: |
|
|
|
return tr("Connection failure"); |
|
|
|
return tr("Connection failure"); |
|
|
|
case 9://ost::URLStream::errTimeout:
|
|
|
|
case CURLE_OPERATION_TIMEOUTED: |
|
|
|
return tr("Connection was timed out"); |
|
|
|
return tr("Connection was timed out"); |
|
|
|
case 10://ost::URLStream::errInterface:
|
|
|
|
case CURLE_INTERFACE_FAILED: |
|
|
|
return tr("Incorrect network interface"); |
|
|
|
return tr("Incorrect network interface"); |
|
|
|
default: |
|
|
|
default: |
|
|
|
return tr("Unknown error"); |
|
|
|
return tr("Unknown error"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
subDownloadThread::subDownloadThread(QObject *parent, QString url) : QThread(parent), url(url), abort(false){ |
|
|
|
subDownloadThread::subDownloadThread(QObject *parent, QString url) : QThread(parent), url(url), abort(false){} |
|
|
|
url_stream = new ost::URLStream(); |
|
|
|
|
|
|
|
// Proxy support
|
|
|
|
|
|
|
|
QSettings settings("qBittorrent", "qBittorrent"); |
|
|
|
|
|
|
|
int intValue = settings.value(QString::fromUtf8("Preferences/Connection/ProxyType"), 0).toInt(); |
|
|
|
|
|
|
|
if(intValue > 0) { |
|
|
|
|
|
|
|
// Proxy enabled
|
|
|
|
|
|
|
|
QString IP = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/IP"), "0.0.0.0").toString(); |
|
|
|
|
|
|
|
qDebug("Set proxy, hostname: %s, port: %d", IP.toUtf8().data(), settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Port"), 8080).toInt()); |
|
|
|
|
|
|
|
if(intValue==1 || intValue==3) { |
|
|
|
|
|
|
|
if(!IP.startsWith("http://", Qt::CaseInsensitive)) { |
|
|
|
|
|
|
|
// HTTP Proxy without leading http://
|
|
|
|
|
|
|
|
url_stream->setProxy((QString("http://")+settings.value(QString::fromUtf8("Preferences/Connection/Proxy/IP"), "0.0.0.0").toString()).toUtf8().data(), settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Port"), 8080).toInt()); |
|
|
|
|
|
|
|
}else { |
|
|
|
|
|
|
|
url_stream->setProxy(settings.value(QString::fromUtf8("Preferences/Connection/Proxy/IP"), "0.0.0.0").toString().toUtf8().data(), settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Port"), 8080).toInt()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Authentication"), false).toBool()) { |
|
|
|
|
|
|
|
qDebug("Proxy auth required"); |
|
|
|
|
|
|
|
// Authentication required
|
|
|
|
|
|
|
|
url_stream->setProxyUser(settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Username"), QString()).toString().toUtf8().data()); |
|
|
|
|
|
|
|
url_stream->setProxyPassword(settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Password"), QString()).toString().toUtf8().data()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} //TODO: Support SOCKS5 proxies
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subDownloadThread::~subDownloadThread(){ |
|
|
|
subDownloadThread::~subDownloadThread(){ |
|
|
|
abort = true; |
|
|
|
abort = true; |
|
|
|
wait(); |
|
|
|
wait(); |
|
|
|
delete url_stream; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void subDownloadThread::run(){ |
|
|
|
void subDownloadThread::run(){ |
|
|
@ -91,38 +70,54 @@ void subDownloadThread::run(){ |
|
|
|
filePath = tmpfile->fileName(); |
|
|
|
filePath = tmpfile->fileName(); |
|
|
|
} |
|
|
|
} |
|
|
|
delete tmpfile; |
|
|
|
delete tmpfile; |
|
|
|
QFile dest_file(filePath); |
|
|
|
FILE *f = fopen(filePath.toUtf8().data(), "w"); |
|
|
|
if(!dest_file.open(QIODevice::WriteOnly | QIODevice::Text)){ |
|
|
|
if(!f) { |
|
|
|
std::cerr << "Error: could't create temporary file: " << (const char*)filePath.toUtf8() << '\n'; |
|
|
|
std::cerr << "couldn't open destination file" << "\n"; |
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ost::URLStream::Error status = url_stream->get((const char*)url.toUtf8()); |
|
|
|
|
|
|
|
if(status){ |
|
|
|
|
|
|
|
// Failure
|
|
|
|
|
|
|
|
QString error_msg = errorCodeToString((int)status); |
|
|
|
|
|
|
|
qDebug("Download failed for %s, reason: %s", (const char*)url.toUtf8(), (const char*)error_msg.toUtf8()); |
|
|
|
|
|
|
|
url_stream->close(); |
|
|
|
|
|
|
|
emit downloadFailureST(this, url, error_msg); |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
qDebug("Downloading %s...", (const char*)url.toUtf8()); |
|
|
|
CURL *curl; |
|
|
|
char cbuf[1024]; |
|
|
|
CURLcode res; |
|
|
|
int len; |
|
|
|
curl = curl_easy_init(); |
|
|
|
while(!url_stream->eof()) { |
|
|
|
if(curl) { |
|
|
|
url_stream->read(cbuf, sizeof(cbuf)); |
|
|
|
std::string c_url = url.toUtf8().data(); |
|
|
|
len = url_stream->gcount(); |
|
|
|
curl_easy_setopt(curl, CURLOPT_URL, c_url.c_str()); |
|
|
|
if(len > 0) |
|
|
|
// PROXY SUPPORT
|
|
|
|
dest_file.write(cbuf, len); |
|
|
|
QSettings settings("qBittorrent", "qBittorrent"); |
|
|
|
if(abort){ |
|
|
|
int intValue = settings.value(QString::fromUtf8("Preferences/Connection/ProxyType"), 0).toInt(); |
|
|
|
dest_file.close(); |
|
|
|
if(intValue > 0) { |
|
|
|
url_stream->close(); |
|
|
|
// Proxy enabled
|
|
|
|
return; |
|
|
|
QString IP = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/IP"), "0.0.0.0").toString(); |
|
|
|
|
|
|
|
QString port = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Port"), 8080).toString(); |
|
|
|
|
|
|
|
qDebug("Using proxy: %s", (IP+QString(":")+port).toUtf8().data()); |
|
|
|
|
|
|
|
curl_easy_setopt(curl, CURLOPT_PROXYPORT, (IP+QString(":")+port).toUtf8().data()); |
|
|
|
|
|
|
|
// Default proxy type is HTTP, we must change if it is SOCKS5
|
|
|
|
|
|
|
|
if(intValue%2==0) { |
|
|
|
|
|
|
|
qDebug("Proxy is SOCKS5, not HTTP"); |
|
|
|
|
|
|
|
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Authentication?
|
|
|
|
|
|
|
|
if(intValue > 2) { |
|
|
|
|
|
|
|
qDebug("Proxy requires authentication, authenticating"); |
|
|
|
|
|
|
|
QString username = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Username"), QString()).toString(); |
|
|
|
|
|
|
|
QString password = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Password"), QString()).toString(); |
|
|
|
|
|
|
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, (username+QString(":")+password).toUtf8().data()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// TODO: define CURLOPT_WRITEFUNCTION or it will crash on windows
|
|
|
|
|
|
|
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, f); |
|
|
|
|
|
|
|
qDebug("Downloading %s", url.toUtf8().data()); |
|
|
|
|
|
|
|
res = curl_easy_perform(curl); |
|
|
|
|
|
|
|
/* always cleanup */ |
|
|
|
|
|
|
|
curl_easy_cleanup(curl); |
|
|
|
|
|
|
|
fclose(f); |
|
|
|
|
|
|
|
if(res) { |
|
|
|
|
|
|
|
emit downloadFailureST(this, url, errorCodeToString(res)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
emit downloadFinishedST(this, url, filePath); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
std::cerr << "Could not initialize CURL" << "\n"; |
|
|
|
} |
|
|
|
} |
|
|
|
dest_file.close(); |
|
|
|
|
|
|
|
url_stream->close(); |
|
|
|
|
|
|
|
emit downloadFinishedST(this, url, filePath); |
|
|
|
|
|
|
|
qDebug("download completed here: %s", (const char*)filePath.toUtf8()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Download Thread **/ |
|
|
|
/** Download Thread **/ |
|
|
|