2006-09-30 20:02:39 +04:00
|
|
|
/*
|
|
|
|
* Bittorrent Client using Qt4 and libtorrent.
|
2007-07-14 18:31:59 +04:00
|
|
|
* Copyright (C) 2006 Christophe Dumez
|
2006-09-30 20:02:39 +04:00
|
|
|
*
|
2007-07-14 18:31:59 +04:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2006-09-30 20:02:39 +04:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2007-07-14 18:31:59 +04:00
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* Contact : chris@qbittorrent.org
|
2006-09-30 20:02:39 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef DOWNLOADTHREAD_H
|
|
|
|
#define DOWNLOADTHREAD_H
|
|
|
|
|
|
|
|
#include <QThread>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QTemporaryFile>
|
|
|
|
#include <QMutex>
|
|
|
|
#include <QMutexLocker>
|
|
|
|
#include <QWaitCondition>
|
|
|
|
#include <iostream>
|
2007-07-22 07:04:47 +04:00
|
|
|
#include <cc++/common.h>
|
2007-07-21 23:37:10 +04:00
|
|
|
#include "misc.h"
|
2007-07-20 19:55:50 +04:00
|
|
|
|
2007-07-22 07:04:47 +04:00
|
|
|
#ifdef CCXX_NAMESPACES
|
|
|
|
using namespace std;
|
|
|
|
using namespace ost;
|
|
|
|
#endif
|
|
|
|
|
2006-09-30 20:02:39 +04:00
|
|
|
class downloadThread : public QThread {
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
private:
|
|
|
|
QStringList url_list;
|
|
|
|
QMutex mutex;
|
|
|
|
QWaitCondition condition;
|
2007-03-09 21:11:43 +03:00
|
|
|
bool abort;
|
2007-07-22 19:18:09 +04:00
|
|
|
URLStream *url_stream;
|
2007-07-22 17:21:04 +04:00
|
|
|
QList<downloadThread*> subThreads;
|
|
|
|
bool subThread;
|
2006-09-30 20:02:39 +04:00
|
|
|
|
|
|
|
signals:
|
2007-07-22 13:47:27 +04:00
|
|
|
void downloadFinished(QString url, QString file_path);
|
|
|
|
void downloadFailure(QString url, QString reason);
|
2007-07-22 17:21:04 +04:00
|
|
|
// For subthreads
|
|
|
|
void downloadFinishedST(downloadThread* st, QString url, QString file_path);
|
|
|
|
void downloadFailureST(downloadThread* st, QString url, QString reason);
|
2006-09-30 20:02:39 +04:00
|
|
|
|
|
|
|
public:
|
2007-07-22 17:21:04 +04:00
|
|
|
downloadThread(QObject* parent, bool subThread = false) : QThread(parent){
|
2007-07-22 19:02:19 +04:00
|
|
|
qDebug("Creating downloadThread");
|
2007-03-09 21:11:43 +03:00
|
|
|
abort = false;
|
2007-07-22 17:21:04 +04:00
|
|
|
this->subThread = subThread;
|
2007-07-22 19:18:09 +04:00
|
|
|
url_stream = 0;
|
2007-07-22 19:02:19 +04:00
|
|
|
qDebug("downloadThread created");
|
2007-03-09 21:11:43 +03:00
|
|
|
}
|
2006-09-30 20:02:39 +04:00
|
|
|
|
2007-03-09 21:11:43 +03:00
|
|
|
~downloadThread(){
|
2006-09-30 20:02:39 +04:00
|
|
|
mutex.lock();
|
2007-03-09 21:11:43 +03:00
|
|
|
abort = true;
|
|
|
|
condition.wakeOne();
|
|
|
|
mutex.unlock();
|
2007-07-22 19:18:09 +04:00
|
|
|
if(url_stream != 0)
|
|
|
|
delete url_stream;
|
2007-03-09 21:11:43 +03:00
|
|
|
wait();
|
|
|
|
}
|
|
|
|
|
2007-07-22 13:47:27 +04:00
|
|
|
void downloadUrl(QString url){
|
2007-07-22 19:18:09 +04:00
|
|
|
if(subThread && url_stream == 0)
|
|
|
|
url_stream = new URLStream();
|
2007-03-09 21:11:43 +03:00
|
|
|
QMutexLocker locker(&mutex);
|
2006-09-30 20:02:39 +04:00
|
|
|
url_list << url;
|
|
|
|
if(!isRunning()){
|
|
|
|
start();
|
2007-03-09 21:11:43 +03:00
|
|
|
}else{
|
|
|
|
condition.wakeOne();
|
2006-09-30 20:02:39 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-22 07:04:47 +04:00
|
|
|
QString errorCodeToString(URLStream::Error status){
|
|
|
|
switch(status){
|
|
|
|
case URLStream::errUnreachable:
|
|
|
|
return tr("Host is unreachable");
|
|
|
|
case URLStream::errMissing:
|
|
|
|
return tr("File was not found (404)");
|
|
|
|
case URLStream::errDenied:
|
|
|
|
return tr("Connection was denied");
|
|
|
|
case URLStream::errInvalid:
|
|
|
|
return tr("Url is invalid");
|
|
|
|
case URLStream::errForbidden:
|
|
|
|
return tr("Connection forbidden (403)");
|
|
|
|
case URLStream::errUnauthorized:
|
|
|
|
return tr("Connection was not authorized (401)");
|
|
|
|
case URLStream::errRelocated:
|
|
|
|
return tr("Content has moved (301)");
|
|
|
|
case URLStream::errFailure:
|
|
|
|
return tr("Connection failure");
|
|
|
|
case URLStream::errTimeout:
|
|
|
|
return tr("Connection was timed out");
|
|
|
|
case URLStream::errInterface:
|
|
|
|
return tr("Incorrect network interface");
|
|
|
|
default:
|
|
|
|
return tr("Unknown error");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-09 21:11:43 +03:00
|
|
|
protected:
|
2006-09-30 20:02:39 +04:00
|
|
|
void run(){
|
|
|
|
forever{
|
2007-03-09 21:11:43 +03:00
|
|
|
if(abort)
|
|
|
|
return;
|
2006-09-30 20:02:39 +04:00
|
|
|
mutex.lock();
|
|
|
|
if(url_list.size() != 0){
|
|
|
|
QString url = url_list.takeFirst();
|
|
|
|
mutex.unlock();
|
2007-07-22 17:21:04 +04:00
|
|
|
if(!subThread){
|
|
|
|
downloadThread *st = new downloadThread(0, true);
|
|
|
|
subThreads << st;
|
|
|
|
connect(st, SIGNAL(downloadFinishedST(downloadThread*, QString, QString)), this, SLOT(propagateDownloadedFile(downloadThread*, QString, QString)));
|
|
|
|
connect(st, SIGNAL(downloadFailureST(downloadThread*, QString, QString)), this, SLOT(propagateDownloadFailure(downloadThread*, QString, QString)));
|
|
|
|
st->downloadUrl(url);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Sub threads code
|
2007-07-21 23:37:10 +04:00
|
|
|
// XXX: Trick to get a unique filename
|
2007-07-22 07:04:47 +04:00
|
|
|
QString filePath;
|
|
|
|
QTemporaryFile *tmpfile = new QTemporaryFile();
|
2006-09-30 20:02:39 +04:00
|
|
|
if (tmpfile->open()) {
|
2006-10-26 00:35:41 +04:00
|
|
|
filePath = tmpfile->fileName();
|
2006-09-30 20:02:39 +04:00
|
|
|
}
|
|
|
|
delete tmpfile;
|
2007-07-22 07:04:47 +04:00
|
|
|
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';
|
|
|
|
continue;
|
2006-09-30 20:02:39 +04:00
|
|
|
}
|
2007-07-22 19:18:09 +04:00
|
|
|
URLStream::Error status = url_stream->get((const char*)url.toUtf8());
|
2007-07-22 07:04:47 +04:00
|
|
|
if(status){
|
|
|
|
// Failure
|
2007-07-22 19:02:19 +04:00
|
|
|
QString error_msg = errorCodeToString(status);
|
2007-07-22 07:04:47 +04:00
|
|
|
qDebug("Download failed for %s, reason: %s", (const char*)url.toUtf8(), (const char*)error_msg.toUtf8());
|
2007-07-22 19:18:09 +04:00
|
|
|
url_stream->close();
|
2007-07-22 19:02:19 +04:00
|
|
|
emit downloadFailureST(this, url, error_msg);
|
2007-07-22 07:04:47 +04:00
|
|
|
continue;
|
2006-09-30 20:02:39 +04:00
|
|
|
}
|
2007-07-22 07:04:47 +04:00
|
|
|
qDebug("Downloading %s...", (const char*)url.toUtf8());
|
|
|
|
char cbuf[1024];
|
|
|
|
int len;
|
2007-07-22 19:18:09 +04:00
|
|
|
while(!url_stream->eof()) {
|
|
|
|
url_stream->read(cbuf, sizeof(cbuf));
|
|
|
|
len = url_stream->gcount();
|
2007-07-22 16:08:16 +04:00
|
|
|
if(len > 0)
|
2007-07-22 07:04:47 +04:00
|
|
|
dest_file.write(cbuf, len);
|
2007-07-22 16:08:16 +04:00
|
|
|
if(abort){
|
|
|
|
dest_file.close();
|
2007-07-22 19:18:09 +04:00
|
|
|
url_stream->close();
|
2007-07-22 16:08:16 +04:00
|
|
|
return;
|
2007-07-22 07:04:47 +04:00
|
|
|
}
|
2006-09-30 20:02:39 +04:00
|
|
|
}
|
2007-07-22 07:04:47 +04:00
|
|
|
dest_file.close();
|
2007-07-22 19:18:09 +04:00
|
|
|
url_stream->close();
|
2007-07-22 17:21:04 +04:00
|
|
|
emit downloadFinishedST(this, url, filePath);
|
2007-07-22 08:14:44 +04:00
|
|
|
qDebug("download completed here: %s", (const char*)filePath.toUtf8());
|
2006-09-30 20:02:39 +04:00
|
|
|
}else{
|
2007-03-09 21:11:43 +03:00
|
|
|
condition.wait(&mutex);
|
2006-09-30 20:02:39 +04:00
|
|
|
mutex.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-07-22 17:21:04 +04:00
|
|
|
protected slots:
|
|
|
|
void propagateDownloadedFile(downloadThread* st, QString url, QString path){
|
|
|
|
int index = subThreads.indexOf(st);
|
|
|
|
if(index == -1)
|
|
|
|
std::cerr << "ERROR: Couldn't delete download subThread!\n";
|
|
|
|
else
|
|
|
|
subThreads.takeAt(index);
|
|
|
|
delete st;
|
|
|
|
emit downloadFinished(url, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void propagateDownloadFailure(downloadThread* st, QString url, QString reason){
|
|
|
|
int index = subThreads.indexOf(st);
|
|
|
|
if(index == -1)
|
|
|
|
std::cerr << "ERROR: Couldn't delete download subThread!\n";
|
|
|
|
else
|
|
|
|
subThreads.takeAt(index);
|
|
|
|
delete st;
|
|
|
|
emit downloadFailure(url, reason);
|
|
|
|
}
|
2006-09-30 20:02:39 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|