Show invite menu in wlm chat window immediately
[kdenetwork.git] / kget / transfer-plugins / bittorrent / bttransfer.cpp
blob9581842d7419e0178d7705766616efa4c5329c99
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>
27 #include <util/log.h>
28 #include <peer/authenticationmonitor.h>
29 #include <btversion.h>
31 #include <KDebug>
32 #include <KLocale>
33 #include <KIconLoader>
34 #include <KStandardDirs>
35 #include <KUrl>
36 #include <KMessageBox>
38 #include <QFile>
39 #include <QDomElement>
40 #include <QFileInfo>
41 #include <QDir>
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),
47 torrent(0),
48 m_tmp(KStandardDirs::locateLocal("appdata", "tmp/")),
49 m_ready(false),
50 m_downloadFinished(false)
54 BTTransfer::~BTTransfer()
56 if (torrent && m_ready)
57 torrent->setMonitor(0);
59 delete torrent;
62 /** Reimplemented functions from Transfer-Class **/
63 bool BTTransfer::isResumable() const
65 return true;
68 void BTTransfer::start()
70 if (!torrent)
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)));
83 else
84 init();
86 else
87 startTorrent();
90 void BTTransfer::stop()
92 if (m_ready)
94 stopTorrent();
98 /**Own public functions**/
99 void BTTransfer::update()
101 if (torrent)
103 QStringList files;
104 if (torrent->hasMissingFiles(files))
106 torrent->recreateMissingFiles();
108 updateTorrent();
110 else
111 timer.stop();
114 void BTTransfer::postDeleteEvent()
116 QDir tmpDir(m_tmp);
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)
124 tmpDir.remove(file);
126 tmpDir.cdUp();
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)
136 kDebug(5001);
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);
145 else
146 m_percent = 0;
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
153 else
155 setStatus(status(), i18nc("transfer state: stopped", "Stopped"), SmallIcon("process-stop"));
159 void BTTransfer::save(const QDomElement &element)
161 kDebug(5001);
163 QDomElement e = element;
165 Transfer::save(e);
166 }**/
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)
177 kDebug(5001);
178 if (!torrent)
179 return;
181 torrent->setTrafficLimits(ulLimit * 1000, dlLimit * 1000);
184 void BTTransfer::addTracker(const QString &url)
186 kDebug(5001);
187 if(torrent->getStats().priv_torrent)
189 KMessageBox::sorry(0, i18n("Cannot add a tracker to a private torrent."));
190 return;
193 if(!KUrl(url).isValid())
195 KMessageBox::error(0, i18n("Malformed URL."));
196 return;
199 torrent->getTrackersList()->addTracker(url,true);
202 /**Private functions**/
204 void BTTransfer::startTorrent()
206 if (m_ready)
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);
211 torrent->start();
212 timer.start(250);
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()
221 torrent->stop(true);
222 torrent->setMonitor(0);
223 m_downloadSpeed = 0;
224 timer.stop();
226 if (m_downloadFinished)
228 setStatus(Job::Stopped, i18nc("transfer state: finished", "Finished"), SmallIcon("dialog-ok"));
230 else
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();
243 torrent->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) {
264 m_percent = percent;
265 changesFlags |= Tc_Percent;
268 setTransferChange(changesFlags, true);
271 void BTTransfer::init(const KUrl &src, const QByteArray &data)
273 Q_UNUSED(data);
274 kDebug(5001);
275 if (src != m_source && !src.isEmpty())
276 m_source = src;
278 QFile file(m_source.toLocalFile());
280 if (!file.exists())
281 return;
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
290 bt::Uint16 i = 0;
293 bt::Globals::instance().initServer(BittorrentSettings::port() + i);
294 i++;
295 }while (!bt::Globals::instance().getServer().isOK() && i < 10);
297 if (!bt::Globals::instance().getServer().isOK())
298 return;
300 QDir tmpDir(m_tmp + m_source.fileName().remove(".torrent"));
301 if (tmpDir.exists())
303 tmpDir.remove("torrent");
307 torrent = new bt::TorrentControl();
309 if (!BittorrentSettings::tmpDir().isEmpty() && QFileInfo(BittorrentSettings::tmpDir()).isDir())
311 m_tmp = BittorrentSettings::tmpDir();
314 m_ready = true;
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)
331 m_ready = false;
332 setStatus(Job::Aborted, i18n("An error occurred...."), SmallIcon("document-preview"));
333 KMessageBox::error(0, err.toString(), i18n("Error"));
335 startTorrent();
336 connect(&timer, SIGNAL(timeout()), SLOT(update()));
339 void BTTransfer::slotStoppedByError(const bt::TorrentInterface* &error, const QString &errormsg)
341 Q_UNUSED(error);
342 stop();
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 *********************************************************************";
350 Q_UNUSED(ti);
351 m_downloadFinished = true;
352 //timer.stop();
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
360 if (!torrent)
361 return KUrl::List();
363 const KUrl::List trackers = torrent->getTrackersList()->getTrackerURLs();
364 return trackers;
367 int BTTransfer::sessionBytesDownloaded() const
369 if (!torrent)
370 return -1;
372 return torrent->getStats().session_bytes_downloaded;
375 int BTTransfer::sessionBytesUploaded() const
377 if (!torrent)
378 return -1;
380 return torrent->getStats().session_bytes_uploaded;
383 int BTTransfer::chunksTotal() const
385 if (!torrent)
386 return -1;
388 return torrent->getTorrent().getNumChunks();
391 int BTTransfer::chunksDownloaded() const
393 if (!torrent)
394 return -1;
396 return torrent->downloadedChunksBitSet().numOnBits();
399 int BTTransfer::chunksExcluded() const
401 if (!torrent)
402 return -1;
404 return torrent->excludedChunksBitSet().numOnBits();
407 int BTTransfer::chunksLeft() const
409 if (!torrent)
410 return -1;
412 return chunksTotal() - chunksDownloaded();
415 int BTTransfer::seedsConnected() const
417 if (!torrent)
418 return -1;
420 return torrent->getStats().seeders_connected_to;
423 int BTTransfer::seedsDisconnected() const
425 if (!torrent)
426 return -1;
428 return torrent->getStats().seeders_total;
431 int BTTransfer::leechesConnected() const
433 if (!torrent)
434 return -1;
436 return torrent->getStats().leechers_connected_to;
439 int BTTransfer::leechesDisconnected() const
441 if (!torrent)
442 return -1;
444 return torrent->getStats().leechers_total;
447 int BTTransfer::elapsedTime() const
449 if (!torrent)
450 return -1;
452 return torrent->getRunningTimeDL();
455 int BTTransfer::remainingTime() const
457 if (!torrent)
458 return Transfer::remainingTime();
460 return torrent->getETA();
463 bt::TorrentControl * BTTransfer::torrentControl()
465 return torrent;
468 bool BTTransfer::ready()
470 return m_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"