Browse Source

- Moved from libcommoncpp to libcurl for downloads from urls

- Added SOCKS5 proxy support when downloading from urls
adaptive-webui-19844
Christophe Dumez 17 years ago
parent
commit
61eb921e44
  1. 2
      INSTALL
  2. 58
      configure
  3. 2
      qbittorrent.qc
  4. 61
      qcm/libcurl.qcm
  5. 133
      src/downloadThread.cpp
  6. 16
      src/downloadThread.h
  7. 2
      src/src.pro

2
INSTALL

@ -25,7 +25,7 @@ Dependencies: @@ -25,7 +25,7 @@ Dependencies:
- libboost: libboost-filesystem, libboost-date-time, libboost-thread, libboost-serialization
- libcommoncpp2
- libcurl
- python >= 2.3 (needed by search engine)

58
configure vendored

@ -22,8 +22,8 @@ Dependency options: @@ -22,8 +22,8 @@ Dependency options:
--with-libtorrent-lib=[path] Path to libtorrent library files
--with-libtorrent-static-lib=[path] Path to libtorrent .a file
--with-libboost-inc=[path] Path to libboost include files
--with-libcommoncpp2-inc=[path] Path to libcommoncpp2 include files
--with-libcommoncpp2-lib=[path] Path to libcommoncpp2 library files
--with-libcurl-inc=[path] Path to libcurl include files
--with-libcurl-lib=[path] Path to libcurl library files
--disable-libmagick Disable use of libmagick
--with-libmagick-inc=[path] Path to libmagick++ include files
--with-libmagick-lib=[path] Path to libmagick++ library files
@ -166,13 +166,13 @@ while [ $# -gt 0 ]; do @@ -166,13 +166,13 @@ while [ $# -gt 0 ]; do
shift
;;
--with-libcommoncpp2-inc=*)
QC_WITH_LIBCOMMONCPP2_INC=$optarg
--with-libcurl-inc=*)
QC_WITH_LIBCURL_INC=$optarg
shift
;;
--with-libcommoncpp2-lib=*)
QC_WITH_LIBCOMMONCPP2_LIB=$optarg
--with-libcurl-lib=*)
QC_WITH_LIBCURL_LIB=$optarg
shift
;;
@ -231,8 +231,8 @@ echo QC_WITH_LIBTORRENT_INC=$QC_WITH_LIBTORRENT_INC @@ -231,8 +231,8 @@ echo QC_WITH_LIBTORRENT_INC=$QC_WITH_LIBTORRENT_INC
echo QC_WITH_LIBTORRENT_LIB=$QC_WITH_LIBTORRENT_LIB
echo QC_WITH_LIBTORRENT_STATIC_LIB=$QC_WITH_LIBTORRENT_STATIC_LIB
echo QC_WITH_LIBBOOST_INC=$QC_WITH_LIBBOOST_INC
echo QC_WITH_LIBCOMMONCPP2_INC=$QC_WITH_LIBCOMMONCPP2_INC
echo QC_WITH_LIBCOMMONCPP2_LIB=$QC_WITH_LIBCOMMONCPP2_LIB
echo QC_WITH_LIBCURL_INC=$QC_WITH_LIBCURL_INC
echo QC_WITH_LIBCURL_LIB=$QC_WITH_LIBCURL_LIB
echo QC_DISABLE_libmagick=$QC_DISABLE_libmagick
echo QC_WITH_LIBMAGICK_INC=$QC_WITH_LIBMAGICK_INC
echo QC_WITH_LIBMAGICK_LIB=$QC_WITH_LIBMAGICK_LIB
@ -485,25 +485,25 @@ public: @@ -485,25 +485,25 @@ public:
return true;
}
};
#line 1 "libcommoncpp2.qcm"
#line 1 "libcurl.qcm"
/*
-----BEGIN QCMOD-----
name: libcommoncpp2
arg: with-libcommoncpp2-inc=[path], Path to libcommoncpp2 include files
arg: with-libcommoncpp2-lib=[path], Path to libcommoncpp2 library files
arg: with-libcurl-inc=[path], Path to libcurl include files
arg: with-libcurl-lib=[path], Path to libcurl library files
-----END QCMOD-----
*/
class qc_libcommoncpp2 : public ConfObj
class qc_libcurl : public ConfObj
{
public:
qc_libcommoncpp2(Conf *c) : ConfObj(c) {}
QString name() const { return "GNU Common C++ library (libcommoncpp2)"; }
QString shortname() const { return "libcommoncpp2"; }
qc_libcurl(Conf *c) : ConfObj(c) {}
QString name() const { return "libcurl"; }
QString shortname() const { return "libcurl"; }
bool exec(){
QString s;
s = conf->getenv("QC_WITH_LIBCOMMONCPP2_INC");
s = conf->getenv("QC_WITH_LIBCURL_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "cc++/url.h")) {
if(!conf->checkHeader(s, "curl/curl.h")) {
return false;
}
}else{
@ -512,7 +512,7 @@ public: @@ -512,7 +512,7 @@ public:
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "cc++/url.h")){
if(conf->checkHeader(s, "curl/curl.h")){
found = true;
break;
}
@ -523,12 +523,10 @@ public: @@ -523,12 +523,10 @@ public:
}
conf->addIncludePath(s);
s = conf->getenv("QC_WITH_LIBCOMMONCPP2_LIB");
s = conf->getenv("QC_WITH_LIBCURL_LIB");
if(!s.isEmpty()) {
if(!QFile::exists(s+QString("/libccext2.so")))
return false;
if(!QFile::exists(s+QString("/libccgnu2.so")))
return false;
if(!QFile::exists(s+QString("/libcurl.so")))
return false;
conf->addLib(QString("-L") + s);
}else{
QStringList sl;
@ -538,11 +536,9 @@ public: @@ -538,11 +536,9 @@ public:
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(QFile::exists(s+QString("libccext2.so"))){
if(QFile::exists(s+QString("libccgnu2.so"))){
found = true;
break;
}
if(QFile::exists(s+QString("libcurl.so"))){
found = true;
break;
}
}
if(!found) return false;
@ -715,7 +711,7 @@ cat >$1/modules_new.cpp <<EOT @@ -715,7 +711,7 @@ cat >$1/modules_new.cpp <<EOT
o = new qc_libboost(conf);
o->required = true;
o->disabled = false;
o = new qc_libcommoncpp2(conf);
o = new qc_libcurl(conf);
o->required = true;
o->disabled = false;
o = new qc_libmagick(conf);
@ -1673,8 +1669,8 @@ export QC_WITH_LIBTORRENT_INC @@ -1673,8 +1669,8 @@ export QC_WITH_LIBTORRENT_INC
export QC_WITH_LIBTORRENT_LIB
export QC_WITH_LIBTORRENT_STATIC_LIB
export QC_WITH_LIBBOOST_INC
export QC_WITH_LIBCOMMONCPP2_INC
export QC_WITH_LIBCOMMONCPP2_LIB
export QC_WITH_LIBCURL_INC
export QC_WITH_LIBCURL_LIB
export QC_DISABLE_libmagick
export QC_WITH_LIBMAGICK_INC
export QC_WITH_LIBMAGICK_LIB

2
qbittorrent.qc

@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
<dep type='libboost'>
<required/>
</dep>
<dep type='libcommoncpp2'>
<dep type='libcurl'>
<required/>
</dep>
<dep type='libmagick'/>

61
qcm/libcurl.qcm

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
/*
-----BEGIN QCMOD-----
name: libcommoncpp2
arg: with-libcurl-inc=[path], Path to libcurl include files
arg: with-libcurl-lib=[path], Path to libcurl library files
-----END QCMOD-----
*/
class qc_libcurl : public ConfObj
{
public:
qc_libcurl(Conf *c) : ConfObj(c) {}
QString name() const { return "libcurl"; }
QString shortname() const { return "libcurl"; }
bool exec(){
QString s;
s = conf->getenv("QC_WITH_LIBCURL_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "curl/curl.h")) {
return false;
}
}else{
QStringList sl;
sl << "/usr/include";
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "curl/curl.h")){
found = true;
break;
}
}
if(!found) {
return false;
}
}
conf->addIncludePath(s);
s = conf->getenv("QC_WITH_LIBCURL_LIB");
if(!s.isEmpty()) {
if(!QFile::exists(s+QString("/libcurl.so")))
return false;
conf->addLib(QString("-L") + s);
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(QFile::exists(s+QString("libcurl.so"))){
found = true;
break;
}
}
if(!found) return false;
conf->addLib(QString("-L") + s);
}
return true;
}
};

133
src/downloadThread.cpp

@ -21,66 +21,45 @@ @@ -21,66 +21,45 @@
#include "downloadThread.h"
#include <iostream>
#include <cc++/common.h>
#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){
case 1://ost::URLStream::errUnreachable:
case CURLE_COULDNT_RESOLVE_HOST:
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)");
case 3://ost::URLStream::errDenied:
case CURLE_LOGIN_DENIED:
return tr("Connection was denied");
case 4://ost::URLStream::errInvalid:
case CURLE_URL_MALFORMAT:
return tr("Url is invalid");
case 5://ost::URLStream::errForbidden:
return tr("Connection forbidden (403)");
case 6://ost::URLStream::errUnauthorized:
return tr("Connection was not authorized (401)");
case 7://ost::URLStream::errRelocated:
return tr("Content has moved (301)");
case 8://ost::URLStream::errFailure:
case CURLE_COULDNT_RESOLVE_PROXY:
return tr("Could not resolve proxy");
//case 5:
// return tr("Connection forbidden (403)");
//case 6:
// return tr("Connection was not authorized (401)");
//case 7:
// return tr("Content has moved (301)");
case CURLE_COULDNT_CONNECT:
return tr("Connection failure");
case 9://ost::URLStream::errTimeout:
case CURLE_OPERATION_TIMEOUTED:
return tr("Connection was timed out");
case 10://ost::URLStream::errInterface:
case CURLE_INTERFACE_FAILED:
return tr("Incorrect network interface");
default:
return tr("Unknown error");
}
}
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(QObject *parent, QString url) : QThread(parent), url(url), abort(false){}
subDownloadThread::~subDownloadThread(){
abort = true;
wait();
delete url_stream;
}
void subDownloadThread::run(){
@ -91,38 +70,54 @@ void subDownloadThread::run(){ @@ -91,38 +70,54 @@ void subDownloadThread::run(){
filePath = tmpfile->fileName();
}
delete tmpfile;
QFile dest_file(filePath);
if(!dest_file.open(QIODevice::WriteOnly | QIODevice::Text)){
std::cerr << "Error: could't create temporary file: " << (const char*)filePath.toUtf8() << '\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);
FILE *f = fopen(filePath.toUtf8().data(), "w");
if(!f) {
std::cerr << "couldn't open destination file" << "\n";
return;
}
qDebug("Downloading %s...", (const char*)url.toUtf8());
char cbuf[1024];
int len;
while(!url_stream->eof()) {
url_stream->read(cbuf, sizeof(cbuf));
len = url_stream->gcount();
if(len > 0)
dest_file.write(cbuf, len);
if(abort){
dest_file.close();
url_stream->close();
return;
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
std::string c_url = url.toUtf8().data();
curl_easy_setopt(curl, CURLOPT_URL, c_url.c_str());
// 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();
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 **/

16
src/downloadThread.h

@ -29,29 +29,18 @@ @@ -29,29 +29,18 @@
#include <QMutexLocker>
#include <QWaitCondition>
#include <QStringList>
namespace ost {
class URLStream;
}
typedef struct {
QString IP;
int port;
QString username;
QString password;
} tmp_proxy;
#include <curl/curl.h>
class subDownloadThread : public QThread {
Q_OBJECT
private:
QString url;
ost::URLStream *url_stream;
bool abort;
public:
subDownloadThread(QObject *parent, QString url);
~subDownloadThread();
QString errorCodeToString(int status);
QString errorCodeToString(CURLcode status);
signals:
// For subthreads
@ -90,7 +79,6 @@ class downloadThread : public QThread { @@ -90,7 +79,6 @@ class downloadThread : public QThread {
protected slots:
void propagateDownloadedFile(subDownloadThread* st, QString url, QString path);
void propagateDownloadFailure(subDownloadThread* st, QString url, QString reason);
};

2
src/src.pro

@ -81,7 +81,7 @@ QMAKE_CXXFLAGS_RELEASE += -fwrapv -O2 @@ -81,7 +81,7 @@ QMAKE_CXXFLAGS_RELEASE += -fwrapv -O2
QMAKE_CXXFLAGS_DEBUG += -fwrapv -O1
CONFIG += link_pkgconfig
PKGCONFIG += "libtorrent libccext2 libccgnu2"
PKGCONFIG += "libtorrent libcurl"
!contains(DEFINES, HAVE_MAGICK){
message(ImageMagick disabled)

Loading…
Cancel
Save