File indexing completed on 2024-04-28 04:57:30

0001 /***************************************************************************
0002  *   Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net>                     *
0003  *                                                                         *
0004  *   This program is free software; you can redistribute it and/or modify  *
0005  *   it under the terms of the GNU General Public License as published by  *
0006  *   the Free Software Foundation; either version 2 of the License, or     *
0007  *   (at your option) any later version.                                   *
0008  *                                                                         *
0009  *   This program is distributed in the hope that it will be useful,       *
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0012  *   GNU General Public License for more details.                          *
0013  *                                                                         *
0014  *   You should have received a copy of the GNU General Public License     *
0015  *   along with this program; if not, write to the                         *
0016  *   Free Software Foundation, Inc.,                                       *
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
0018  ***************************************************************************/
0019 
0020 #include "checksumsearchtransferdatasource.h"
0021 #include "checksumsearch.h"
0022 #include "checksumsearchsettings.h"
0023 #include "kget_debug.h"
0024 
0025 #include <QFile>
0026 
0027 #include <KIO/DeleteJob>
0028 #include <KIO/FileCopyJob>
0029 #include <KIO/ListJob>
0030 
0031 #include <QStandardPaths>
0032 
0033 ChecksumSearchController ChecksumSearchTransferDataSource::s_controller;
0034 
0035 ChecksumSearchController::ChecksumSearchController(QObject *parent)
0036     : QObject(parent)
0037 {
0038 }
0039 
0040 ChecksumSearchController::~ChecksumSearchController()
0041 {
0042 }
0043 
0044 void ChecksumSearchController::registerSearch(ChecksumSearchTransferDataSource *search, const QUrl &baseUrl)
0045 {
0046     if (m_finished.contains(baseUrl)) {
0047         qCDebug(KGET_DEBUG) << "Already downloaded" << baseUrl;
0048         const QUrl urlToFile = m_finished[baseUrl];
0049         if (!urlToFile.isEmpty()) {
0050             search->gotBaseUrl(m_finished[baseUrl]);
0051         }
0052     } else {
0053         const bool alreadySearchedFor = m_searches.contains(baseUrl);
0054         if (!m_searches.contains(baseUrl, search)) {
0055             m_searches.insert(baseUrl, search);
0056 
0057             if (alreadySearchedFor) {
0058                 qCDebug(KGET_DEBUG) << "Search already started for" << baseUrl;
0059                 return;
0060             }
0061             qCDebug(KGET_DEBUG) << "Creating download for" << baseUrl;
0062             static int files = 0;
0063 
0064             const QUrl dest = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/checksumsearch/")
0065                                                   + QString::number(files++));
0066             if (QFile::exists(dest.toLocalFile())) {
0067                 KIO::Job *del = KIO::del(dest, KIO::HideProgressInfo);
0068                 if (!del->exec()) {
0069                     qCDebug(KGET_DEBUG) << "Could not delete " << dest.path();
0070                 }
0071             }
0072 
0073             if (baseUrl.scheme() != "ftp" && baseUrl.scheme() != "sftp") {
0074                 qCDebug(KGET_DEBUG) << "Downloading" << baseUrl;
0075                 KIO::FileCopyJob *job = KIO::file_copy(baseUrl, dest, -1, KIO::HideProgressInfo);
0076                 job->addMetaData("errorPage", "false");
0077                 connect(job, &KJob::result, this, &ChecksumSearchController::slotResult);
0078                 m_jobs[job] = qMakePair(baseUrl, dest);
0079             } else {
0080                 qCDebug(KGET_DEBUG) << "ftp, doing a listjob";
0081                 KIO::ListJob *job = KIO::listDir(baseUrl, KIO::HideProgressInfo);
0082                 connect(job, &KIO::ListJob::entries, this, &ChecksumSearchController::slotEntries);
0083                 connect(job, &KJob::result, this, &ChecksumSearchController::slotResult);
0084                 m_jobs[job] = qMakePair(baseUrl, dest);
0085             }
0086         }
0087     }
0088 }
0089 
0090 void ChecksumSearchController::unregisterSearch(ChecksumSearchTransferDataSource *search, const QUrl &baseUrl)
0091 {
0092     if (baseUrl.isEmpty()) {
0093         const QList<QUrl> keys = m_searches.keys(search);
0094         foreach (const QUrl &key, keys) {
0095             m_searches.remove(key, search);
0096         }
0097     } else {
0098         m_searches.remove(baseUrl, search);
0099     }
0100 }
0101 
0102 void ChecksumSearchController::slotEntries(KIO::Job *job, const KIO::UDSEntryList &entries)
0103 {
0104     qCDebug(KGET_DEBUG);
0105 
0106     if (!m_jobs.contains(job)) {
0107         return;
0108     }
0109 
0110     const QUrl baseUrl = m_jobs[job].first;
0111     const QUrl urlToFile = m_jobs[job].second;
0112     QFile file(urlToFile.toLocalFile());
0113     if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
0114         qCDebug(KGET_DEBUG) << "Could not open file" << urlToFile;
0115     }
0116 
0117     QTextStream out(&file);
0118     foreach (const KIO::UDSEntry &entry, entries) {
0119         if (!entry.isDir()) {
0120             out << entry.stringValue(KIO::UDSEntry::UDS_NAME) << '\n';
0121         }
0122     }
0123     file.close();
0124 }
0125 
0126 void ChecksumSearchController::slotResult(KJob *job)
0127 {
0128     qCDebug(KGET_DEBUG);
0129 
0130     if (!m_jobs.contains(job)) {
0131         return;
0132     }
0133 
0134     const QUrl baseUrl = m_jobs[job].first;
0135     const QUrl urlToFile = m_jobs[job].second;
0136     m_jobs.remove(job);
0137     if (job->error()) {
0138         qCDebug(KGET_DEBUG) << "Error while getting baseurl:" << baseUrl << job->error() << job->errorString();
0139         m_finished[baseUrl] = QUrl();
0140         return;
0141     }
0142 
0143     m_finished[baseUrl] = urlToFile;
0144 
0145     const QList<ChecksumSearchTransferDataSource *> searches = m_searches.values(baseUrl);
0146     m_searches.remove(baseUrl);
0147     foreach (ChecksumSearchTransferDataSource *search, searches) {
0148         search->gotBaseUrl(urlToFile);
0149     }
0150 }
0151 
0152 ChecksumSearchTransferDataSource::ChecksumSearchTransferDataSource(const QUrl &srcUrl, QObject *parent)
0153     : TransferDataSource(srcUrl, parent)
0154 {
0155 }
0156 
0157 ChecksumSearchTransferDataSource::~ChecksumSearchTransferDataSource()
0158 {
0159     s_controller.unregisterSearch(this, m_sourceUrl.adjusted(QUrl::RemoveFilename));
0160 }
0161 
0162 void ChecksumSearchTransferDataSource::start()
0163 {
0164     qCDebug(KGET_DEBUG);
0165 
0166     const QUrl baseUrl = m_sourceUrl.adjusted(QUrl::RemoveFilename);
0167     s_controller.registerSearch(this, baseUrl);
0168 }
0169 
0170 void ChecksumSearchTransferDataSource::gotBaseUrl(const QUrl &urlToFile)
0171 {
0172     QFile file(urlToFile.toLocalFile());
0173     if (!file.open(QIODevice::ReadOnly)) {
0174         qCDebug(KGET_DEBUG) << "Could not open file" << urlToFile;
0175         return;
0176     }
0177 
0178     const QByteArray data = file.readAll();
0179     file.close();
0180 
0181     QStringList changes = ChecksumSearchSettings::self()->searchStrings();
0182     QList<int> modes = ChecksumSearchSettings::self()->urlChangeModeList();
0183     QStringList types = ChecksumSearchSettings::self()->checksumTypeList();
0184 
0185     QList<QUrl> urls;
0186 
0187     for (int i = 0, k = 0; i < changes.size(); ++i) {
0188         const auto mode = static_cast<ChecksumSearch::UrlChangeMode>(modes.at(i));
0189         const QUrl source = ChecksumSearch::createUrl(m_sourceUrl, changes.at(i), mode);
0190         if (data.indexOf(source.fileName().toLatin1()) != -1) {
0191             urls.append(source);
0192             ++k;
0193         } else {
0194             types.removeAt(k);
0195         }
0196     }
0197 
0198     qCDebug(KGET_DEBUG) << "Creating Checksumsearch for" << urls.count() << "urls.";
0199 
0200     if (urls.count() && types.count()) {
0201         auto *search = new ChecksumSearch(urls, m_sourceUrl.fileName(), types);
0202 
0203         connect(search, &ChecksumSearch::data, this, [this](QString type, QString checksum) {
0204             this->data(type, checksum);
0205         });
0206     }
0207 }
0208 
0209 void ChecksumSearchTransferDataSource::stop()
0210 {
0211     qCDebug(KGET_DEBUG);
0212 }
0213 
0214 void ChecksumSearchTransferDataSource::addSegments(const QPair<KIO::fileoffset_t, KIO::fileoffset_t> &segmentSize, const QPair<int, int> &segmentRange)
0215 {
0216     Q_UNUSED(segmentSize)
0217     Q_UNUSED(segmentRange)
0218     qCDebug(KGET_DEBUG);
0219 }
0220 
0221 #include "moc_checksumsearchtransferdatasource.cpp"