File indexing completed on 2024-06-23 05:14:00
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 crypto/taskcollection.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB 0006 0007 SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik 0008 SPDX-FileContributor: Intevation GmbH 0009 0010 SPDX-License-Identifier: GPL-2.0-or-later 0011 */ 0012 0013 #include <config-kleopatra.h> 0014 0015 #include "taskcollection.h" 0016 0017 #include "kleopatra_debug.h" 0018 #include "task.h" 0019 0020 #include <Libkleo/GnuPG> 0021 0022 #include <algorithm> 0023 #include <map> 0024 0025 #include <cmath> 0026 0027 #include <KLocalizedString> 0028 0029 using namespace Kleo; 0030 using namespace Kleo::Crypto; 0031 0032 class TaskCollection::Private 0033 { 0034 TaskCollection *const q; 0035 0036 public: 0037 explicit Private(TaskCollection *qq); 0038 0039 void taskProgress(); 0040 void taskResult(const std::shared_ptr<const Task::Result> &); 0041 void taskStarted(); 0042 void calculateAndEmitProgress(); 0043 0044 std::map<int, std::shared_ptr<Task>> m_tasks; 0045 mutable quint64 m_totalProgress; 0046 mutable quint64 m_progress; 0047 unsigned int m_nCompleted; 0048 unsigned int m_nErrors; 0049 bool m_errorOccurred; 0050 bool m_doneEmitted; 0051 }; 0052 0053 TaskCollection::Private::Private(TaskCollection *qq) 0054 : q(qq) 0055 , m_totalProgress(0) 0056 , m_progress(0) 0057 , m_nCompleted(0) 0058 , m_nErrors(0) 0059 , m_errorOccurred(false) 0060 , m_doneEmitted(false) 0061 { 0062 } 0063 0064 int TaskCollection::numberOfCompletedTasks() const 0065 { 0066 return d->m_nCompleted; 0067 } 0068 0069 size_t TaskCollection::size() const 0070 { 0071 return d->m_tasks.size(); 0072 } 0073 0074 bool TaskCollection::allTasksCompleted() const 0075 { 0076 Q_ASSERT(d->m_nCompleted <= d->m_tasks.size()); 0077 return d->m_nCompleted == d->m_tasks.size(); 0078 } 0079 0080 void TaskCollection::Private::taskProgress() 0081 { 0082 calculateAndEmitProgress(); 0083 } 0084 0085 void TaskCollection::Private::taskResult(const std::shared_ptr<const Task::Result> &result) 0086 { 0087 Q_ASSERT(result); 0088 ++m_nCompleted; 0089 0090 if (result->hasError()) { 0091 m_errorOccurred = true; 0092 ++m_nErrors; 0093 } 0094 calculateAndEmitProgress(); 0095 Q_EMIT q->result(result); 0096 if (!m_doneEmitted && q->allTasksCompleted()) { 0097 Q_EMIT q->done(); 0098 m_doneEmitted = true; 0099 } 0100 } 0101 0102 void TaskCollection::Private::taskStarted() 0103 { 0104 const Task *const task = qobject_cast<Task *>(q->sender()); 0105 Q_ASSERT(task); 0106 Q_ASSERT(m_tasks.find(task->id()) != m_tasks.end()); 0107 Q_EMIT q->started(m_tasks[task->id()]); 0108 calculateAndEmitProgress(); // start Knight-Rider-Mode right away (gpgsm doesn't report _any_ progress). 0109 if (m_doneEmitted) { 0110 // We are not done anymore, one task restarted. 0111 m_nCompleted--; 0112 m_nErrors--; 0113 m_doneEmitted = false; 0114 } 0115 } 0116 0117 void TaskCollection::Private::calculateAndEmitProgress() 0118 { 0119 quint64 total = 0; 0120 quint64 processed = 0; 0121 0122 static bool haveWorkingProgress = engineIsVersion(2, 1, 15); 0123 if (!haveWorkingProgress) { 0124 // GnuPG before 2.1.15 would overflow on progress values > max int. 0125 // and did not emit a total for our Qt data types. 0126 // As we can't know if it overflowed or what the total is we just knight 0127 // rider in that case 0128 if (m_doneEmitted) { 0129 Q_EMIT q->progress(1, 1); 0130 } else { 0131 Q_EMIT q->progress(0, 0); 0132 } 0133 return; 0134 } 0135 0136 bool unknowable = false; 0137 for (auto it = m_tasks.begin(), end = m_tasks.end(); it != end; ++it) { 0138 // Sum up progress and totals 0139 const std::shared_ptr<Task> &i = it->second; 0140 Q_ASSERT(i); 0141 if (!i->totalProgress()) { 0142 // There still might be jobs for which we don't know the progress. 0143 qCDebug(KLEOPATRA_LOG) << "Task: " << i->label() << " has no total progress set. "; 0144 unknowable = true; 0145 break; 0146 } 0147 processed += i->currentProgress(); 0148 total += i->totalProgress(); 0149 } 0150 0151 m_totalProgress = total; 0152 m_progress = processed; 0153 if (!unknowable && processed && total >= processed) { 0154 // Scale down to avoid range issues. 0155 int scaled = 1000 * (m_progress / static_cast<double>(m_totalProgress)); 0156 qCDebug(KLEOPATRA_LOG) << "Collection Progress: " << scaled << " total: " << 1000; 0157 if (total == processed) { 0158 // This can happen when an output is finalizing, e.g. extracting an 0159 // archive. 0160 Q_EMIT q->progress(0, 0); 0161 } else { 0162 Q_EMIT q->progress(scaled, 1000); 0163 } 0164 } else { 0165 if (total < processed) { 0166 qCDebug(KLEOPATRA_LOG) << "Total progress is smaller then current progress."; 0167 } 0168 // Knight rider. 0169 Q_EMIT q->progress(0, 0); 0170 } 0171 } 0172 0173 TaskCollection::TaskCollection(QObject *parent) 0174 : QObject(parent) 0175 , d(new Private(this)) 0176 { 0177 } 0178 0179 TaskCollection::~TaskCollection() 0180 { 0181 } 0182 0183 bool TaskCollection::isEmpty() const 0184 { 0185 return d->m_tasks.empty(); 0186 } 0187 0188 bool TaskCollection::errorOccurred() const 0189 { 0190 return d->m_errorOccurred; 0191 } 0192 0193 bool TaskCollection::allTasksHaveErrors() const 0194 { 0195 return d->m_nErrors == d->m_nCompleted; 0196 } 0197 0198 std::shared_ptr<Task> TaskCollection::taskById(int id) const 0199 { 0200 const auto it = d->m_tasks.find(id); 0201 return it != d->m_tasks.end() ? it->second : std::shared_ptr<Task>(); 0202 } 0203 0204 std::vector<std::shared_ptr<Task>> TaskCollection::tasks() const 0205 { 0206 std::vector<std::shared_ptr<Task>> res; 0207 res.reserve(d->m_tasks.size()); 0208 for (auto it = d->m_tasks.begin(), end = d->m_tasks.end(); it != end; ++it) { 0209 res.push_back(it->second); 0210 } 0211 return res; 0212 } 0213 0214 void TaskCollection::setTasks(const std::vector<std::shared_ptr<Task>> &tasks) 0215 { 0216 for (const std::shared_ptr<Task> &i : tasks) { 0217 Q_ASSERT(i); 0218 d->m_tasks[i->id()] = i; 0219 connect(i.get(), &Task::progress, this, [this]() { 0220 d->taskProgress(); 0221 }); 0222 connect(i.get(), 0223 SIGNAL(result(std::shared_ptr<const Kleo::Crypto::Task::Result>)), 0224 this, 0225 SLOT(taskResult(std::shared_ptr<const Kleo::Crypto::Task::Result>))); 0226 connect(i.get(), SIGNAL(started()), this, SLOT(taskStarted())); 0227 } 0228 } 0229 0230 #include "moc_taskcollection.cpp"