File indexing completed on 2024-04-21 04:57:12

0001 /* This file is part of the KDE project
0002 
0003    Copyright (C) 2008 Lukas Appelhans <l.appelhans@gmx.de>
0004 
0005    This program is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 */
0010 
0011 #include "btdatasource.h"
0012 #include "bittorrentsettings.h"
0013 #include "btcache.h"
0014 #include "btchunkselector.h"
0015 #include "core/download.h"
0016 #include <QStandardPaths>
0017 #include <btversion.h>
0018 #include <peer/authenticationmonitor.h>
0019 #include <torrent/globals.h>
0020 #include <torrent/server.h>
0021 #include <torrent/torrentcontrol.h>
0022 #include <util/bitset.h>
0023 #include <util/error.h>
0024 #include <util/functions.h>
0025 #include <util/log.h>
0026 
0027 using namespace bt;
0028 
0029 BTDataSource::BTDataSource(const QUrl &srcUrl, QObject *parent)
0030     : TransferDataSource(srcUrl, parent)
0031     , m_offset(0)
0032     , m_bytes(0)
0033     , m_torrentSource(QUrl())
0034 {
0035     // make sure that the DataLocation directory exists (earlier this used to be handled by KStandardDirs)
0036     if (!QFileInfo::exists(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))) {
0037         QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
0038     }
0039 
0040     bt::InitLog(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/torrentlog.log")); // initialize the torrent-log
0041 
0042     bt::SetClientInfo("KGet", 2, 1, 0, bt::NORMAL, "KG"); // Set client info to KGet, WARNING: Pls change this for every release
0043 
0044     bt::Uint16 i = 0;
0045     do {
0046         qCDebug(KGET_DEBUG) << "Trying to set port to" << BittorrentSettings::port() + i;
0047         bt::Globals::instance().initServer(BittorrentSettings::port() + i);
0048         i++;
0049     } while (!bt::Globals::instance().getServer().isOK() && i < 10);
0050 
0051     if (!bt::Globals::instance().getServer().isOK())
0052         return;
0053     tc = new TorrentControl();
0054     csf = new BTChunkSelectorFactory();
0055     cf = new BTCacheFactory();
0056     connect(cf, SIGNAL(cacheAdded(BTCache *)), SLOT(cacheAdded(BTCache *)));
0057     connect(csf, SIGNAL(selectorAdded(BTChunkSelector *)), SLOT(selectorAdded(BTChunkSelector *)));
0058     tc->setChunkSelectorFactory(csf);
0059     tc->setCacheFactory(cf);
0060     connect(&timer, SIGNAL(timeout()), SLOT(update()));
0061 }
0062 
0063 BTDataSource::~BTDataSource()
0064 {
0065     delete tc;
0066     delete cs;
0067     delete cf;
0068 }
0069 
0070 void BTDataSource::cacheAdded(BTCache *cache)
0071 {
0072     connect(cache, SIGNAL(dataArrived(KIO::fileoffset_t, QByteArray)), SLOT(getData(KIO::fileoffset_t, QByteArray)));
0073 }
0074 
0075 void BTDataSource::selectorAdded(BTChunkSelector *selector)
0076 {
0077     cs = selector;
0078 }
0079 
0080 void BTDataSource::start()
0081 {
0082     if (m_torrentSource.isEmpty()) {
0083         QString tmpDirName = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/tmp/");
0084         // make sure that the /tmp directory exists (earlier this used to be handled by KStandardDirs)
0085         if (!QFileInfo::exists(tmpDirName)) {
0086             QDir().mkpath(tmpDirName);
0087         }
0088         Download *download = new Download(m_source, tmpDirName + m_source.fileName());
0089         connect(download, SIGNAL(finishedSuccessfully(QUrl, QByteArray)), SLOT(init(QUrl, QByteArray)));
0090     } else {
0091         cs->excludeAll();
0092         const BitSet &bits = tc->availableChunksBitSet();
0093         bool av = true;
0094         Uint32 firstChunk = m_offset / tc->getStats().chunk_size;
0095         Uint32 lastChunk = ((m_offset + m_bytes) / tc->getStats().chunk_size) + 1; // The +1 is only a workaround for rounding up, but I dunno how to do it ;)
0096         for (int i = firstChunk * tc->getStats().chunk_size * 8; i <= lastChunk * tc->getStats().chunk_size * 8; i++) {
0097             if (!bits.get(i)) {
0098                 emit broken();
0099                 av = false;
0100                 continue;
0101             }
0102         }
0103         if (av) {
0104             cs->reincluded(firstChunk, lastChunk);
0105             tc->start();
0106             timer.start(250);
0107         }
0108     }
0109 }
0110 
0111 void BTDataSource::stop()
0112 {
0113     tc->stop(true);
0114     timer.stop();
0115 }
0116 
0117 void BTDataSource::update()
0118 {
0119     bt::UpdateCurrentTime();
0120     bt::AuthenticationMonitor::instance().update();
0121     tc->update();
0122 }
0123 
0124 void BTDataSource::init(const QUrl &torrentSource, const QByteArray &data)
0125 {
0126     Q_UNUSED(data)
0127     m_torrentSource = torrentSource;
0128     try {
0129         tc->init(0, m_torrentSource.url(), QString(), QString(), 0);
0130     } catch (bt::Error &err) {
0131         qCDebug(KGET_DEBUG) << err.toString();
0132         // m_ready = false;
0133     }
0134     start();
0135 }
0136 
0137 void BTDataSource::addSegment(const KIO::fileoffset_t offset, const KIO::fileoffset_t bytes, int segmentNum)
0138 {
0139     qCDebug(KGET_DEBUG);
0140 
0141     if (offset < m_offset) {
0142         m_offset = offset;
0143         if (m_bytes < bytes + m_offset - offset) {
0144             m_bytes = bytes + m_offset - offset;
0145         }
0146     }
0147     if (offset > m_offset && m_bytes < bytes + m_offset - offset) {
0148         m_bytes = bytes + m_offset - offset;
0149     }
0150     if (offset == m_offset && m_bytes < bytes) {
0151         m_bytes = bytes;
0152     }
0153 }
0154 
0155 void BTDataSource::getData(const KIO::fileoffset_t &off, const QByteArray &dataArray)
0156 {
0157     QByteArray splittedData;
0158     if (off < m_offset)
0159         splittedData = dataArray.right(dataArray.size() - (m_offset - off));
0160     else if (m_offset + m_bytes < off + dataArray.size())
0161         splittedData = dataArray.left((off + dataArray.size()) - (m_offset + m_bytes));
0162     else
0163         splittedData = dataArray;
0164 
0165     emit data(off, splittedData);
0166 
0167     if (m_offset + m_bytes == off + dataArray.size())
0168         emit finished();
0169 }
0170 
0171 #include "moc_btdatasource.cpp"