1 /***************************************************************************
2 *   Copyright (C) 2009 Matthias Fuchs <mat69@gmx.net>                     *
3 *                                                                         *
4 *   This program is free software; you can redistribute it and/or modify  *
5 *   it under the terms of the GNU General Public License as published by  *
6 *   the Free Software Foundation; either version 2 of the License, or     *
7 *   (at your option) any later version.                                   *
8 *                                                                         *
9 *   This program is distributed in the hope that it will be useful,       *
10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12 *   GNU General Public License for more details.                          *
13 *                                                                         *
14 *   You should have received a copy of the GNU General Public License     *
15 *   along with this program; if not, write to the                         *
16 *   Free Software Foundation, Inc.,                                       *
17 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
18 ***************************************************************************/
19 
20 #include "filehandler.h"
21 #include "core/verifier.h"
22 
23 #include <QDir>
24 
FileHandlerThread(QObject * parent)25 FileHandlerThread::FileHandlerThread(QObject *parent)
26   : QThread(parent),
27     abort(false)
28 {
29 }
30 
~FileHandlerThread()31 FileHandlerThread::~FileHandlerThread()
32 {
33     mutex.lock();
34     abort = true;
35     mutex.unlock();
36 
37     wait();
38 }
39 
setData(const QList<FileData> & files,const QStringList & types,bool createPartial,const KGetMetalink::Resources & tempResources,const KGetMetalink::CommonData & tempCommonData)40 void FileHandlerThread::setData(const QList<FileData> &files, const QStringList &types, bool createPartial, const KGetMetalink::Resources &tempResources, const KGetMetalink::CommonData &tempCommonData)
41 {
42     QMutexLocker locker(&mutex);
43     m_files.append(files);
44     m_types.append(types);
45     m_createPartial.append(createPartial);
46     m_tempResources.append(tempResources);
47     m_tempCommonDatas.append(tempCommonData);
48 
49     if (!isRunning()) {
50         start();
51     }
52 }
53 
run()54 void FileHandlerThread::run()
55 {
56     mutex.lock();
57     bool run = m_files.count();
58     mutex.unlock();
59 
60     while (run && !abort) {
61         mutex.lock();
62         QList<FileData> files = m_files.takeFirst();
63         QStringList types = m_types.takeFirst();
64         bool createPartial = m_createPartial.takeFirst();
65         KGetMetalink::Resources tempResources = m_tempResources.takeFirst();
66         KGetMetalink::CommonData commonData = m_tempCommonDatas.takeFirst();
67         mutex.unlock();
68 
69         while (files.count() && !abort) {
70             //take the first file and try to handle it
71             FileData data = files.takeFirst();
72             const QUrl url = data.url;
73             KGetMetalink::File file = data.file;
74             file.data = commonData;
75 
76             foreach (const KGetMetalink::Url &metalinkUrl, tempResources.urls) {
77                 KGetMetalink::Url mirror = metalinkUrl;
78                 mirror.url.setPath(mirror.url.toString() + "/" + file.name);
79 
80                 //if the url has already been added, remove it and readd it
81                 for (int i = 0; i < file.resources.urls.count(); ++i) {
82                     if (file.resources.urls[i].url == mirror.url) {
83                         file.resources.urls.removeAt(i);
84                         break;
85                     }
86                 }
87                 file.resources.urls.append(mirror);
88             }
89 
90             foreach (const QString &type, types) {
91                 if (abort) {
92                     return;
93                 }
94 
95                 const QString hash = Verifier::checksum(url, type, &abort);
96                 if (!hash.isEmpty()) {
97                     file.verification.hashes[type] = hash;
98                 }
99             }
100 
101             if (createPartial) {
102                 foreach (const QString &type, types) {
103                     if (abort) {
104                         return;
105                     }
106 
107                     const PartialChecksums partialChecksums = Verifier::partialChecksums(url, type, 0, &abort);
108                     if (partialChecksums.isValid()) {
109                         KGetMetalink::Pieces pieces;
110                         pieces.type = type;
111                         pieces.length = partialChecksums.length();
112                         pieces.hashes = partialChecksums.checksums();
113                         file.verification.pieces.append(pieces);
114                     }
115                 }
116             }
117             if (!abort) {
118                 Q_EMIT fileResult(file);
119             }
120         }
121         mutex.lock();
122         run = m_files.count();
123         mutex.unlock();
124     }
125 }
126 
DirectoryHandler(QObject * parent)127 DirectoryHandler::DirectoryHandler(QObject *parent)
128   : QObject(parent),
129     m_allJobsStarted(false)
130 {
131 }
132 
~DirectoryHandler()133 DirectoryHandler::~DirectoryHandler()
134 {
135 }
136 
takeFiles()137 QList<FileData> DirectoryHandler::takeFiles()
138 {
139     QList<FileData> files = m_files;
140     m_files.clear();
141 
142     return files;
143 }
144 
slotFiles(const QList<QUrl> & files)145 void DirectoryHandler::slotFiles(const QList<QUrl> &files)
146 {
147     if (files.isEmpty()) {
148         return;
149     }
150 
151     m_allJobsStarted = false;
152 
153     foreach (const QUrl &url, files) {
154         QDir dir(url.path());
155         if (dir.exists()) {
156             KIO::ListJob *listJob = KIO::listRecursive(url);
157             m_jobs[listJob] = url;
158 
159             connect(listJob, &KIO::ListJob::entries, this, &DirectoryHandler::slotDirEntries);
160             connect(listJob, &KIO::ListJob::result, this, &DirectoryHandler::slotFinished);
161         } else {
162             FileData data;
163             data.url = url;
164             data.file.name = url.fileName();
165             QFile localFile(url.path());
166             data.file.size = localFile.size();
167 
168             m_files.append(data);
169         }
170     }
171 
172     m_allJobsStarted = true;
173     evaluateFileProcess();
174 }
175 
slotDirEntries(KIO::Job * j,const KIO::UDSEntryList & entries)176 void DirectoryHandler::slotDirEntries(KIO::Job *j, const KIO::UDSEntryList &entries)
177 {
178     KJob *job = j;
179     if (!m_jobs.contains(job)) {
180         return;
181     }
182 
183     const QUrl baseUrl = m_jobs[job];
184     const QString baseDir = baseUrl.fileName() + '/';
185 
186     foreach (const KIO::UDSEntry &entry, entries) {
187         //skip all found dirs
188         if (!entry.isDir()) {
189             const QString name = entry.stringValue(KIO::UDSEntry::UDS_NAME);
190             FileData data;
191             data.url.setPath(baseUrl.toString() + "/" + name);//FIXME: Does this work?
192             data.file.name = baseDir + name;
193             data.file.size = entry.numberValue(KIO::UDSEntry::UDS_SIZE, -1);
194 
195             m_files.append(data);
196         }
197     }
198 }
199 
slotFinished(KJob * job)200 void DirectoryHandler::slotFinished(KJob *job)
201 {
202     if (m_jobs.contains(job)) {
203         m_jobs.remove(job);
204         evaluateFileProcess();
205     }
206 }
207 
evaluateFileProcess()208 void DirectoryHandler::evaluateFileProcess()
209 {
210     //all jobs finished
211     if (m_jobs.isEmpty() && m_allJobsStarted && !m_files.isEmpty()) {
212         Q_EMIT finished();
213     }
214 }
215 
216 
217