00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "bttransfer.h"
00013 #include "bittorrentsettings.h"
00014 #include "bttransferhandler.h"
00015 #include "btchunkselector.h"
00016 #include "advanceddetails/monitor.h"
00017 #include "core/kget.h"
00018 #include "core/download.h"
00019
00020 #include <torrent/torrent.h>
00021 #include <peer/peermanager.h>
00022 #include <util/error.h>
00023 #include <torrent/globals.h>
00024 #include <torrent/server.h>
00025 #include <util/constants.h>
00026 #include <util/functions.h>
00027 #include <util/log.h>
00028 #include <peer/authenticationmonitor.h>
00029 #include <btversion.h>
00030
00031 #include <KDebug>
00032 #include <KLocale>
00033 #include <KIconLoader>
00034 #include <KStandardDirs>
00035 #include <KUrl>
00036 #include <KMessageBox>
00037
00038 #include <QFile>
00039 #include <QDomElement>
00040 #include <QFileInfo>
00041 #include <QDir>
00042
00043 BTTransfer::BTTransfer(TransferGroup* parent, TransferFactory* factory,
00044 Scheduler* scheduler, const KUrl& src, const KUrl& dest,
00045 const QDomElement * e)
00046 : Transfer(parent, factory, scheduler, src, dest, e),
00047 torrent(0),
00048 m_tmp(KStandardDirs::locateLocal("appdata", "tmp/")),
00049 m_ready(false),
00050 m_downloadFinished(false)
00051 {
00052 if (m_source.url().isEmpty())
00053 return;
00054 }
00055
00056 BTTransfer::~BTTransfer()
00057 {
00058 if(torrent)
00059 torrent->setMonitor(0);
00060
00061 delete torrent;
00062 }
00063
00065 bool BTTransfer::isResumable() const
00066 {
00067 return true;
00068 }
00069
00070 void BTTransfer::start()
00071 {
00072 if (!torrent)
00073 {
00074 if (!m_source.isLocalFile())
00075 {
00076 kDebug(5001) << m_dest.path();
00077 Download *download = new Download(m_source, KStandardDirs::locateLocal("appdata", "tmp/") + m_source.fileName());
00078
00079 setStatus(Job::Stopped, i18n("Downloading Torrent-File.."), SmallIcon("document-save"));
00080 setTransferChange(Tc_Status, true);
00081
00082
00083 connect(download, SIGNAL(finishedSuccessfully(KUrl, QByteArray)), SLOT(init(KUrl)));
00084 }
00085 else
00086 init();
00087 }
00088 else
00089 startTorrent();
00090 }
00091
00092 void BTTransfer::stop()
00093 {
00094 if (m_ready)
00095 {
00096 stopTorrent();
00097 }
00098 }
00099
00101 void BTTransfer::update()
00102 {
00103 if (torrent)
00104 {
00105 QStringList files;
00106 if (torrent->hasMissingFiles(files))
00107 {
00108 torrent->recreateMissingFiles();
00109 }
00110 updateTorrent();
00111 }
00112 else
00113 timer.stop();
00114 }
00115
00116 void BTTransfer::postDeleteEvent()
00117 {
00118 QDir tmpDir(m_tmp);
00119 kDebug(5001) << m_tmp + m_source.fileName().remove(".torrent");
00120 tmpDir.rmdir(m_source.fileName().remove(".torrent") + "/dnd");
00121 tmpDir.cd(m_source.fileName().remove(".torrent"));
00122 QStringList list = tmpDir.entryList();
00123
00124 foreach (const QString &file, list)
00125 {
00126 tmpDir.remove(file);
00127 }
00128 tmpDir.cdUp();
00129 tmpDir.rmdir(m_source.fileName().remove(".torrent"));
00130
00131 kDebug(5001) << m_source.url();
00132 QFile torrentFile(m_source.url().remove("file://"));
00133 torrentFile.remove();
00134 }
00135
00172 void BTTransfer::setPort(int port)
00173 {
00174 bt::Globals::instance().getServer().changePort(port);
00175 }
00176
00177 void BTTransfer::setSpeedLimits(int ulLimit, int dlLimit)
00178 {
00179 kDebug(5001);
00180 if (!torrent)
00181 return;
00182
00183 torrent->setTrafficLimits(ulLimit * 1000, dlLimit * 1000);
00184 }
00185
00186 void BTTransfer::addTracker(const QString &url)
00187 {
00188 kDebug(5001);
00189 if(torrent->getStats().priv_torrent)
00190 {
00191 KMessageBox::sorry(0, i18n("Cannot add a tracker to a private torrent."));
00192 return;
00193 }
00194
00195 if(!KUrl(url).isValid())
00196 {
00197 KMessageBox::error(0, i18n("Malformed URL."));
00198 return;
00199 }
00200
00201 torrent->getTrackersList()->addTracker(url,true);
00202 }
00203
00206 void BTTransfer::startTorrent()
00207 {
00208 if (m_ready)
00209 {
00210
00211 setSpeedLimits(uploadLimit(Transfer::InvisibleSpeedLimit), downloadLimit(Transfer::InvisibleSpeedLimit));
00212 torrent->setMonitor(this);
00213 torrent->start();
00214 timer.start(250);
00215 setStatus(Job::Running, i18nc("transfer state: downloading", "Downloading.."), SmallIcon("media-playback-start"));
00216 m_totalSize = torrent->getStats().total_bytes_to_download;
00217 setTransferChange(Tc_Status | Tc_TrackersList | Tc_TotalSize, true);
00218 }
00219 }
00220
00221 void BTTransfer::stopTorrent()
00222 {
00223 torrent->stop(true);
00224 torrent->setMonitor(0);
00225 m_downloadSpeed = 0;
00226 timer.stop();
00227
00228 if (m_downloadFinished)
00229 {
00230 setStatus(Job::Stopped, i18nc("transfer state: finished", "Finished"), SmallIcon("dialog-ok"));
00231 }
00232 else
00233 setStatus(Job::Stopped, i18nc("transfer state: stopped", "Stopped"), SmallIcon("process-stop"));
00234 setTransferChange(Tc_Status, true);
00235 }
00236
00237 void BTTransfer::updateTorrent()
00238 {
00239
00240 if (chunksTotal() == chunksDownloaded())
00241 slotDownloadFinished(torrent);
00242
00243 bt::UpdateCurrentTime();
00244 bt::AuthenticationMonitor::instance().update();
00245 torrent->update();
00246
00247 ChangesFlags changesFlags = 0;
00248
00249 if(m_downloadedSize != (m_downloadedSize = torrent->getStats().bytes_downloaded) )
00250 changesFlags |= Tc_DownloadedSize;
00251
00252 if(m_uploadSpeed != torrent->getStats().upload_rate )
00253 {
00254 m_uploadSpeed = torrent->getStats().upload_rate;
00255 changesFlags |= Tc_UploadSpeed;
00256 }
00257
00258 if(m_downloadSpeed != torrent->getStats().download_rate )
00259 {
00260 m_downloadSpeed = torrent->getStats().download_rate;
00261 changesFlags |= Tc_DownloadSpeed;
00262 }
00263
00264 int percent = (((float) chunksDownloaded() / (float) chunksTotal()) * 100);
00265 if (m_percent != percent) {
00266 m_percent = percent;
00267 changesFlags |= Tc_Percent;
00268 }
00269
00270 setTransferChange(changesFlags, true);
00271 }
00272
00273 void BTTransfer::init(const KUrl &src, const QByteArray &data)
00274 {
00275 Q_UNUSED(data);
00276 kDebug(5001);
00277 if (src != m_source && !src.isEmpty())
00278 m_source = src;
00279
00280 QFile file(m_source.url().remove("file://"));
00281 if (!file.exists())
00282 return;
00283
00284 setStatus(Job::Running, i18n("Analyzing torrent.."), SmallIcon("document-preview"));
00285 setTransferChange(Tc_Status, true);
00286
00287 bt::InitLog(KStandardDirs::locateLocal("appdata", "torrentlog.log"));
00288
00289 bt::SetClientInfo("KGet",2,1,0,bt::NORMAL,"KG");
00290
00291 bt::Uint16 i = 0;
00292 do
00293 {
00294 bt::Globals::instance().initServer(BittorrentSettings::port() + i);
00295 i++;
00296 }while (!bt::Globals::instance().getServer().isOK() && i < 10);
00297
00298 if (!bt::Globals::instance().getServer().isOK())
00299 return;
00300
00301 try
00302 {
00303 torrent = new bt::TorrentControl();
00304
00305 if (!BittorrentSettings::tmpDir().isEmpty())
00306 {
00307 if (QFileInfo(BittorrentSettings::tmpDir()).isDir())
00308 m_tmp = BittorrentSettings::tmpDir();
00309 }
00310
00311 m_ready = true;
00312
00313 torrent->init(0, m_source.url().remove("file://"), m_tmp + m_source.fileName().remove(".torrent"),
00314 m_dest.directory().remove("file://"), 0);
00315
00316 if (torrent->getStats().multi_file_torrent)
00317 m_dest = torrent->getStats().output_path;
00318 else
00319 m_dest = torrent->getDataDir() + torrent->getStats().torrent_name;
00320
00321 torrent->createFiles();
00322
00323 torrent->setPreallocateDiskSpace(BittorrentSettings::preAlloc());
00324
00325 setMaximumShareRatio(BittorrentSettings::maxShareRatio());
00326
00327 connect(torrent, SIGNAL(stoppedByError(bt::TorrentInterface*, QString)), SLOT(slotStoppedByError(bt::TorrentInterface*, QString)));
00328 connect(torrent, SIGNAL(finished(bt::TorrentInterface*)), this, SLOT(slotDownloadFinished(bt::TorrentInterface* )));
00329
00330 }
00331 catch (bt::Error &err)
00332 {
00333 kDebug(5001) << err.toString();
00334
00335 }
00336 startTorrent();
00337 connect(&timer, SIGNAL(timeout()), SLOT(update()));
00338 }
00339
00340 void BTTransfer::slotStoppedByError(const bt::TorrentInterface* &error, const QString &errormsg)
00341 {
00342 Q_UNUSED(error);
00343 kDebug(5001) << errormsg;
00344 }
00345
00346 void BTTransfer::slotDownloadFinished(bt::TorrentInterface* ti)
00347 {
00348 kDebug(5001) << "Start seeding *********************************************************************";
00349 Q_UNUSED(ti);
00350 m_downloadFinished = true;
00351 timer.stop();
00352 setStatus(Job::Running, i18nc("Transfer status: seeding", "Seeding.."), SmallIcon("media-playback-start"));
00353 setTransferChange(Tc_Status, true);
00354 }
00355
00357 KUrl::List BTTransfer::trackersList() const
00358 {
00359 if (!torrent)
00360 return KUrl::List();
00361
00362 const KUrl::List trackers = torrent->getTrackersList()->getTrackerURLs();
00363 return trackers;
00364 }
00365
00366 int BTTransfer::sessionBytesDownloaded() const
00367 {
00368 if (!torrent)
00369 return -1;
00370
00371 return torrent->getStats().session_bytes_downloaded;
00372 }
00373
00374 int BTTransfer::sessionBytesUploaded() const
00375 {
00376 if (!torrent)
00377 return -1;
00378
00379 return torrent->getStats().session_bytes_uploaded;
00380 }
00381
00382 int BTTransfer::chunksTotal() const
00383 {
00384 if (!torrent)
00385 return -1;
00386
00387 return torrent->getTorrent().getNumChunks();
00388 }
00389
00390 int BTTransfer::chunksDownloaded() const
00391 {
00392 if (!torrent)
00393 return -1;
00394
00395 return torrent->downloadedChunksBitSet().numOnBits();
00396 }
00397
00398 int BTTransfer::chunksExcluded() const
00399 {
00400 if (!torrent)
00401 return -1;
00402
00403 return torrent->excludedChunksBitSet().numOnBits();
00404 }
00405
00406 int BTTransfer::chunksLeft() const
00407 {
00408 if (!torrent)
00409 return -1;
00410
00411 return chunksTotal() - chunksDownloaded();
00412 }
00413
00414 int BTTransfer::seedsConnected() const
00415 {
00416 if (!torrent)
00417 return -1;
00418
00419 return torrent->getStats().seeders_connected_to;
00420 }
00421
00422 int BTTransfer::seedsDisconnected() const
00423 {
00424 if (!torrent)
00425 return -1;
00426
00427 return torrent->getStats().seeders_total;
00428 }
00429
00430 int BTTransfer::leechesConnected() const
00431 {
00432 if (!torrent)
00433 return -1;
00434
00435 return torrent->getStats().leechers_connected_to;
00436 }
00437
00438 int BTTransfer::leechesDisconnected() const
00439 {
00440 if (!torrent)
00441 return -1;
00442
00443 return torrent->getStats().leechers_total;
00444 }
00445
00446 int BTTransfer::elapsedTime() const
00447 {
00448 if (!torrent)
00449 return -1;
00450
00451 return torrent->getRunningTimeDL();
00452 }
00453
00454 int BTTransfer::remainingTime() const
00455 {
00456 if (!torrent)
00457 return Transfer::remainingTime();
00458
00459 return torrent->getETA();
00460 }
00461
00462 bt::TorrentControl * BTTransfer::torrentControl()
00463 {
00464 return torrent;
00465 }
00466
00467 bool BTTransfer::ready()
00468 {
00469 return m_ready;
00470 }
00471
00472 void BTTransfer::downloadRemoved(bt::ChunkDownloadInterface* cd)
00473 {
00474 if (static_cast<BTTransferHandler*>(handler())->torrentMonitor())
00475 static_cast<BTTransferHandler*>(handler())->torrentMonitor()->downloadRemoved(cd);
00476
00477 setTransferChange(Tc_ChunksTotal | Tc_ChunksDownloaded | Tc_ChunksExcluded | Tc_ChunksLeft, true);
00478 }
00479
00480 void BTTransfer::downloadStarted(bt::ChunkDownloadInterface* cd)
00481 {
00482 if (static_cast<BTTransferHandler*>(handler())->torrentMonitor())
00483 static_cast<BTTransferHandler*>(handler())->torrentMonitor()->downloadStarted(cd);
00484
00485 setTransferChange(Tc_ChunksTotal | Tc_ChunksDownloaded | Tc_ChunksExcluded | Tc_ChunksLeft, true);
00486 }
00487
00488 void BTTransfer::peerAdded(bt::PeerInterface* peer)
00489 {
00490 if (static_cast<BTTransferHandler*>(handler())->torrentMonitor())
00491 static_cast<BTTransferHandler*>(handler())->torrentMonitor()->peerAdded(peer);
00492
00493 setTransferChange(Tc_SeedsConnected | Tc_SeedsDisconnected | Tc_LeechesConnected | Tc_LeechesDisconnected, true);
00494 }
00495
00496 void BTTransfer::peerRemoved(bt::PeerInterface* peer)
00497 {
00498 if (static_cast<BTTransferHandler*>(handler())->torrentMonitor())
00499 static_cast<BTTransferHandler*>(handler())->torrentMonitor()->peerRemoved(peer);
00500
00501 setTransferChange(Tc_SeedsConnected | Tc_SeedsDisconnected | Tc_LeechesConnected | Tc_LeechesDisconnected, true);
00502 }
00503
00504 void BTTransfer::stopped()
00505 {
00506 if (static_cast<BTTransferHandler*>(handler())->torrentMonitor())
00507 static_cast<BTTransferHandler*>(handler())->torrentMonitor()->stopped();
00508 }
00509
00510 void BTTransfer::destroyed()
00511 {
00512 if (static_cast<BTTransferHandler*>(handler())->torrentMonitor())
00513 static_cast<BTTransferHandler*>(handler())->torrentMonitor()->destroyed();
00514 }
00515
00516 #include "bttransfer.moc"