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