1 /* This file is part of the KDE project
3 Copyright (C) 2007-2008 Lukas Appelhans <l.appelhans@gmx.de>
4 Copyright (C) 2007 Joris Guisson <joris.guisson@gmail.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
12 #include "bttransfer.h"
13 #include "bittorrentsettings.h"
14 #include "bttransferhandler.h"
15 #include "btchunkselector.h"
16 #include "advanceddetails/monitor.h"
17 #include "core/kget.h"
18 #include "core/download.h"
20 #include <torrent/torrent.h>
21 #include <peer/peermanager.h>
22 #include <util/error.h>
23 #include <torrent/globals.h>
24 #include <torrent/server.h>
25 #include <util/constants.h>
26 #include <util/functions.h>
28 #include <peer/authenticationmonitor.h>
29 #include <btversion.h>
33 #include <KIconLoader>
34 #include <KStandardDirs>
36 #include <KMessageBox>
39 #include <QDomElement>
43 BTTransfer::BTTransfer(TransferGroup
* parent
, TransferFactory
* factory
,
44 Scheduler
* scheduler
, const KUrl
& src
, const KUrl
& dest
,
45 const QDomElement
* e
)
46 : Transfer(parent
, factory
, scheduler
, src
, dest
, e
),
48 m_tmp(KStandardDirs::locateLocal("appdata", "tmp/")),
50 m_downloadFinished(false)
54 BTTransfer::~BTTransfer()
56 if (torrent
&& m_ready
)
57 torrent
->setMonitor(0);
62 /** Reimplemented functions from Transfer-Class **/
63 bool BTTransfer::isResumable() const
68 void BTTransfer::start()
72 if (!m_source
.isLocalFile())
74 kDebug(5001) << m_dest
.path();
75 Download
*download
= new Download(m_source
, KStandardDirs::locateLocal("appdata", "tmp/") + m_source
.fileName());
77 setStatus(Job::Stopped
, i18n("Downloading Torrent File...."), SmallIcon("document-save"));
78 setTransferChange(Tc_Status
, true);
80 //m_source = KStandardDirs::locateLocal("appdata", "tmp/") + m_source.fileName();
81 connect(download
, SIGNAL(finishedSuccessfully(KUrl
, QByteArray
)), SLOT(init(KUrl
, QByteArray
)));
90 void BTTransfer::stop()
98 /**Own public functions**/
99 void BTTransfer::update()
104 if (torrent
->hasMissingFiles(files
))
106 torrent
->recreateMissingFiles();
114 void BTTransfer::postDeleteEvent()
117 kDebug(5001) << m_tmp
+ m_source
.fileName().remove(".torrent");
118 tmpDir
.rmdir(m_source
.fileName().remove(".torrent") + "/dnd");
119 tmpDir
.cd(m_source
.fileName().remove(".torrent"));
120 QStringList list
= tmpDir
.entryList();
122 foreach (const QString
&file
, list
)
127 tmpDir
.rmdir(m_source
.fileName().remove(".torrent"));
129 kDebug(5001) << m_source
.url();
130 QFile
torrentFile(m_source
.path());
131 torrentFile
.remove();
134 /**void BTTransfer::load(const QDomElement &e)
137 m_source = KUrl(e.attribute("Source"));
138 m_dest = KUrl(e.attribute("Dest"));
140 m_totalSize = e.attribute("TotalSize").toULongLong();
141 m_processedSize = e.attribute("ProcessedSize").toULongLong();
143 if( m_totalSize != 0)
144 m_percent = (int)((100.0 * m_processedSize) / m_totalSize);
148 if((m_totalSize == m_processedSize) && (m_totalSize != 0))
150 setStatus(Job::Finished, i18nc("transfer state: finished", "Finished"), SmallIcon("dialog-ok"));
151 // "ok" icon should probably be "dialog-success", but we don't have that icon in KDE 4.0
155 setStatus(status(), i18nc("transfer state: stopped", "Stopped"), SmallIcon("process-stop"));
159 void BTTransfer::save(const QDomElement &element)
163 QDomElement e = element;
168 /**Public functions of BTTransfer**/
170 void BTTransfer::setPort(int port
)
172 bt::Globals::instance().getServer().changePort(port
);
175 void BTTransfer::setSpeedLimits(int ulLimit
, int dlLimit
)
181 torrent
->setTrafficLimits(ulLimit
* 1000, dlLimit
* 1000);
184 void BTTransfer::addTracker(const QString
&url
)
187 if(torrent
->getStats().priv_torrent
)
189 KMessageBox::sorry(0, i18n("Cannot add a tracker to a private torrent."));
193 if(!KUrl(url
).isValid())
195 KMessageBox::error(0, i18n("Malformed URL."));
199 torrent
->getTrackersList()->addTracker(url
,true);
202 /**Private functions**/
204 void BTTransfer::startTorrent()
208 //kDebug(5001) << "Going to download that stuff :-0";
209 setSpeedLimits(uploadLimit(Transfer::InvisibleSpeedLimit
), downloadLimit(Transfer::InvisibleSpeedLimit
));//Set traffic-limits before starting
210 torrent
->setMonitor(this);
213 setStatus(Job::Running
, i18nc("transfer state: downloading", "Downloading...."), SmallIcon("media-playback-start"));
214 m_totalSize
= torrent
->getStats().total_bytes_to_download
;
215 setTransferChange(Tc_Status
| Tc_TrackersList
| Tc_TotalSize
, true);
219 void BTTransfer::stopTorrent()
222 torrent
->setMonitor(0);
226 if (m_downloadFinished
)
228 setStatus(Job::Stopped
, i18nc("transfer state: finished", "Finished"), SmallIcon("dialog-ok"));
231 setStatus(Job::Stopped
, i18nc("transfer state: stopped", "Stopped"), SmallIcon("process-stop"));
232 setTransferChange(Tc_Status
, true);
235 void BTTransfer::updateTorrent()
237 //kDebug(5001) << "Update torrent";
238 if (chunksTotal() == chunksDownloaded())
239 slotDownloadFinished(torrent
);
241 bt::UpdateCurrentTime();
242 bt::AuthenticationMonitor::instance().update();
245 ChangesFlags changesFlags
= 0;
247 if (m_downloadedSize
!= (m_downloadedSize
= torrent
->getStats().bytes_downloaded
))
248 changesFlags
|= Tc_DownloadedSize
;
250 if (m_uploadSpeed
!= torrent
->getStats().upload_rate
)
252 m_uploadSpeed
= torrent
->getStats().upload_rate
;
253 changesFlags
|= Tc_UploadSpeed
;
256 if (m_downloadSpeed
!= torrent
->getStats().download_rate
)
258 m_downloadSpeed
= torrent
->getStats().download_rate
;
259 changesFlags
|= Tc_DownloadSpeed
;
262 int percent
= (((float) chunksDownloaded() / (float) chunksTotal()) * 100);
263 if (m_percent
!= percent
) {
265 changesFlags
|= Tc_Percent
;
268 setTransferChange(changesFlags
, true);
271 void BTTransfer::init(const KUrl
&src
, const QByteArray
&data
)
275 if (src
!= m_source
&& !src
.isEmpty())
278 QFile
file(m_source
.toLocalFile());
283 setStatus(Job::Running
, i18n("Analyzing torrent...."), SmallIcon("document-preview")); // jpetso says: you should probably use the "process-working" icon here (from the animations category), but that's a multi-frame PNG so it's hard for me to test
284 setTransferChange(Tc_Status
, true);
286 bt::InitLog(KStandardDirs::locateLocal("appdata", "torrentlog.log"));//initialize the torrent-log
288 bt::SetClientInfo("KGet", 2, KDE_VERSION_MINOR
, KDE_VERSION_RELEASE
, bt::NORMAL
, "KG");//Set client info to KGet
293 bt::Globals::instance().initServer(BittorrentSettings::port() + i
);
295 }while (!bt::Globals::instance().getServer().isOK() && i
< 10);
297 if (!bt::Globals::instance().getServer().isOK())
300 QDir
tmpDir(m_tmp
+ m_source
.fileName().remove(".torrent"));
303 tmpDir
.remove("torrent");
307 torrent
= new bt::TorrentControl();
309 if (!BittorrentSettings::tmpDir().isEmpty() && QFileInfo(BittorrentSettings::tmpDir()).isDir())
311 m_tmp
= BittorrentSettings::tmpDir();
316 kDebug() << "Source:" << m_source
.path() << "Destination:" << m_dest
.path();
317 torrent
->init(0, m_source
.path(), m_tmp
+ m_source
.fileName().remove(".torrent"), KUrl(m_dest
.directory()).path(), 0);
319 m_dest
= torrent
->getStats().multi_file_torrent
? torrent
->getStats().output_path
: torrent
->getStats().output_path
+ torrent
->getStats().torrent_name
;
321 torrent
->createFiles();
323 torrent
->setPreallocateDiskSpace(BittorrentSettings::preAlloc());
325 connect(torrent
, SIGNAL(stoppedByError(bt::TorrentInterface
*, QString
)), SLOT(slotStoppedByError(bt::TorrentInterface
*, QString
)));
326 connect(torrent
, SIGNAL(finished(bt::TorrentInterface
*)), this, SLOT(slotDownloadFinished(bt::TorrentInterface
* )));
327 //FIXME connect(tc,SIGNAL(corruptedDataFound( bt::TorrentInterface* )), this, SLOT(emitCorruptedData( bt::TorrentInterface* )));//TODO: Fix it
329 catch (bt::Error
&err
)
332 setStatus(Job::Aborted
, i18n("An error occurred...."), SmallIcon("document-preview"));
333 KMessageBox::error(0, err
.toString(), i18n("Error"));
336 connect(&timer
, SIGNAL(timeout()), SLOT(update()));
339 void BTTransfer::slotStoppedByError(const bt::TorrentInterface
* &error
, const QString
&errormsg
)
343 setStatus(Job::Aborted
, i18n("An error occurred...."), SmallIcon("document-preview"));
344 KMessageBox::error(0, errormsg
, i18n("Error"));
347 void BTTransfer::slotDownloadFinished(bt::TorrentInterface
* ti
)
349 kDebug(5001) << "Start seeding *********************************************************************";
351 m_downloadFinished
= true;
353 setStatus(Job::Running
, i18nc("Transfer status: seeding", "Seeding...."), SmallIcon("media-playback-start"));
354 setTransferChange(Tc_Status
, true);
357 /**Property-Functions**/
358 KUrl::List
BTTransfer::trackersList() const
363 const KUrl::List trackers
= torrent
->getTrackersList()->getTrackerURLs();
367 int BTTransfer::sessionBytesDownloaded() const
372 return torrent
->getStats().session_bytes_downloaded
;
375 int BTTransfer::sessionBytesUploaded() const
380 return torrent
->getStats().session_bytes_uploaded
;
383 int BTTransfer::chunksTotal() const
388 return torrent
->getTorrent().getNumChunks();
391 int BTTransfer::chunksDownloaded() const
396 return torrent
->downloadedChunksBitSet().numOnBits();
399 int BTTransfer::chunksExcluded() const
404 return torrent
->excludedChunksBitSet().numOnBits();
407 int BTTransfer::chunksLeft() const
412 return chunksTotal() - chunksDownloaded();
415 int BTTransfer::seedsConnected() const
420 return torrent
->getStats().seeders_connected_to
;
423 int BTTransfer::seedsDisconnected() const
428 return torrent
->getStats().seeders_total
;
431 int BTTransfer::leechesConnected() const
436 return torrent
->getStats().leechers_connected_to
;
439 int BTTransfer::leechesDisconnected() const
444 return torrent
->getStats().leechers_total
;
447 int BTTransfer::elapsedTime() const
452 return torrent
->getRunningTimeDL();
455 int BTTransfer::remainingTime() const
458 return Transfer::remainingTime();
460 return torrent
->getETA();
463 bt::TorrentControl
* BTTransfer::torrentControl()
468 bool BTTransfer::ready()
473 void BTTransfer::downloadRemoved(bt::ChunkDownloadInterface
* cd
)
475 if (static_cast<BTTransferHandler
*>(handler())->torrentMonitor())
476 static_cast<BTTransferHandler
*>(handler())->torrentMonitor()->downloadRemoved(cd
);
478 setTransferChange(Tc_ChunksDownloaded
| Tc_ChunksExcluded
| Tc_ChunksLeft
, true);
481 void BTTransfer::downloadStarted(bt::ChunkDownloadInterface
* cd
)
483 if (static_cast<BTTransferHandler
*>(handler())->torrentMonitor())
484 static_cast<BTTransferHandler
*>(handler())->torrentMonitor()->downloadStarted(cd
);
486 setTransferChange(Tc_ChunksDownloaded
| Tc_ChunksExcluded
| Tc_ChunksLeft
, true);
489 void BTTransfer::peerAdded(bt::PeerInterface
* peer
)
491 if (static_cast<BTTransferHandler
*>(handler())->torrentMonitor())
492 static_cast<BTTransferHandler
*>(handler())->torrentMonitor()->peerAdded(peer
);
494 setTransferChange(Tc_SeedsConnected
| Tc_SeedsDisconnected
| Tc_LeechesConnected
| Tc_LeechesDisconnected
, true);
497 void BTTransfer::peerRemoved(bt::PeerInterface
* peer
)
499 if (static_cast<BTTransferHandler
*>(handler())->torrentMonitor())
500 static_cast<BTTransferHandler
*>(handler())->torrentMonitor()->peerRemoved(peer
);
502 setTransferChange(Tc_SeedsConnected
| Tc_SeedsDisconnected
| Tc_LeechesConnected
| Tc_LeechesDisconnected
, true);
505 void BTTransfer::stopped()
507 if (static_cast<BTTransferHandler
*>(handler())->torrentMonitor())
508 static_cast<BTTransferHandler
*>(handler())->torrentMonitor()->stopped();
511 void BTTransfer::destroyed()
513 if (static_cast<BTTransferHandler
*>(handler())->torrentMonitor())
514 static_cast<BTTransferHandler
*>(handler())->torrentMonitor()->destroyed();
517 #include "bttransfer.moc"