1 /* -*- mode: c++; c-basic-offset:4 -*-
2     commands/command.cpp
3 
4     This file is part of Kleopatra, the KDE keymanager
5     SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include <config-kleopatra.h>
11 
12 #include "command.h"
13 #include "command_p.h"
14 
15 #include "signencryptfilescommand.h"
16 #include "importcertificatefromfilecommand.h"
17 #include "decryptverifyfilescommand.h"
18 #include "detailscommand.h"
19 #include "lookupcertificatescommand.h"
20 #include "checksumverifyfilescommand.h"
21 
22 #include <Libkleo/KeyCache>
23 #include <Libkleo/Classify>
24 
25 
26 #include <view/tabwidget.h>
27 
28 #include "kleopatra_debug.h"
29 #include <KWindowSystem>
30 
31 #include <QAbstractItemView>
32 #include <QFileInfo>
33 
34 using namespace Kleo;
35 using namespace Kleo::Commands;
36 using namespace GpgME;
37 
Private(Command * qq)38 Command::Private::Private(Command *qq)
39     : q(qq),
40       autoDelete(true),
41       warnWhenRunningAtShutdown(true)
42 {
43 }
44 
Private(Command * qq,KeyListController * controller)45 Command::Private::Private(Command *qq, KeyListController *controller)
46     : q(qq),
47       autoDelete(true),
48       warnWhenRunningAtShutdown(true),
49       controller_(controller)
50 {
51 }
52 
Private(Command * qq,QWidget * parent)53 Command::Private::Private(Command *qq, QWidget *parent)
54     : q(qq),
55       autoDelete(true),
56       warnWhenRunningAtShutdown(true),
57       parentWidget_(parent)
58 {
59 }
60 
~Private()61 Command::Private::~Private()
62 {
63     qCDebug(KLEOPATRA_LOG);
64 }
65 
Command(KeyListController * p)66 Command::Command(KeyListController *p)
67     : QObject(p), d(new Private(this, p))
68 {
69     if (p) {
70         p->registerCommand(this);
71     }
72 }
73 
Command(QAbstractItemView * v,KeyListController * p)74 Command::Command(QAbstractItemView *v, KeyListController *p)
75     : QObject(p), d(new Private(this, p))
76 {
77     if (p) {
78         p->registerCommand(this);
79     }
80     if (v) {
81         setView(v);
82     }
83 }
84 
Command(Private * pp)85 Command::Command(Private *pp)
86     : QObject(pp->controller_), d(pp)
87 {
88     if (pp->controller_) {
89         pp->controller_->registerCommand(this);
90     }
91 }
92 
Command(QAbstractItemView * v,Private * pp)93 Command::Command(QAbstractItemView *v, Private *pp)
94     : QObject(pp->controller_), d(pp)
95 {
96     if (pp->controller_) {
97         pp->controller_->registerCommand(this);
98     }
99     if (v) {
100         setView(v);
101     }
102 }
103 
Command(const GpgME::Key & key)104 Command::Command(const GpgME::Key &key)
105     : QObject(nullptr), d(new Private(this))
106 {
107     d->keys_ = std::vector<Key>(1, key);
108 }
109 
Command(const std::vector<GpgME::Key> & keys)110 Command::Command(const std::vector<GpgME::Key> &keys)
111     : QObject(nullptr), d(new Private(this))
112 {
113     d->keys_ = keys;
114 }
115 
Command(const Key & key,Private * pp)116 Command::Command(const Key &key, Private *pp)
117     : QObject(nullptr), d(pp)
118 {
119     d->keys_ = std::vector<Key>(1, key);
120 }
121 
Command(const std::vector<GpgME::Key> & keys,Private * pp)122 Command::Command(const std::vector<GpgME::Key> &keys, Private *pp)
123     : QObject(nullptr), d(pp)
124 {
125     d->keys_ = keys;
126 }
127 
~Command()128 Command::~Command()
129 {
130     qCDebug(KLEOPATRA_LOG);
131 }
132 
setAutoDelete(bool on)133 void Command::setAutoDelete(bool on)
134 {
135     d->autoDelete = on;
136 }
137 
autoDelete() const138 bool Command::autoDelete() const
139 {
140     return d->autoDelete;
141 }
142 
setWarnWhenRunningAtShutdown(bool on)143 void Command::setWarnWhenRunningAtShutdown(bool on)
144 {
145     d->warnWhenRunningAtShutdown = on;
146 }
147 
warnWhenRunningAtShutdown() const148 bool Command::warnWhenRunningAtShutdown() const
149 {
150     return d->warnWhenRunningAtShutdown;
151 }
152 
setParentWidget(QWidget * widget)153 void Command::setParentWidget(QWidget *widget)
154 {
155     d->parentWidget_ = widget;
156 }
157 
setParentWId(WId wid)158 void Command::setParentWId(WId wid)
159 {
160     d->parentWId = wid;
161 }
162 
setView(QAbstractItemView * view)163 void Command::setView(QAbstractItemView *view)
164 {
165     if (view == d->view_) {
166         return;
167     }
168     d->view_ = view;
169     if (!view || !d->indexes_.empty()) {
170         return;
171     }
172     const QItemSelectionModel *const sm = view->selectionModel();
173     if (!sm) {
174         qCWarning(KLEOPATRA_LOG) << "view " << (void *)view << " has no selectionModel!";
175         return;
176     }
177     const QList<QModelIndex> selected = sm->selectedRows();
178     if (!selected.empty()) {
179         std::copy(selected.begin(), selected.end(), std::back_inserter(d->indexes_));
180         return;
181     }
182 }
183 
setIndex(const QModelIndex & idx)184 void Command::setIndex(const QModelIndex &idx)
185 {
186     d->indexes_.clear();
187     d->indexes_.push_back(idx);
188 }
189 
setIndexes(const QList<QModelIndex> & idx)190 void Command::setIndexes(const QList<QModelIndex> &idx)
191 {
192     d->indexes_.clear();
193     std::copy(idx.begin(), idx.end(), std::back_inserter(d->indexes_));
194 }
195 
setKey(const Key & key)196 void Command::setKey(const Key &key)
197 {
198     d->keys_.clear();
199     if (!key.isNull()) {
200         d->keys_.push_back(key);
201     }
202 }
203 
setKeys(const std::vector<Key> & keys)204 void Command::setKeys(const std::vector<Key> &keys)
205 {
206     d->keys_ = keys;
207 }
208 
start()209 void Command::start()
210 {
211     doStart();
212 }
213 
cancel()214 void Command::cancel()
215 {
216     qCDebug(KLEOPATRA_LOG) << metaObject()->className();
217     doCancel();
218     Q_EMIT canceled();
219 }
220 
addTemporaryView(const QString & title,AbstractKeyListSortFilterProxyModel * proxy,const QString & tabToolTip)221 void Command::addTemporaryView(const QString &title, AbstractKeyListSortFilterProxyModel *proxy, const QString &tabToolTip)
222 {
223     if (TabWidget *const tw = d->controller_ ? d->controller_->tabWidget() : nullptr)
224         if (QAbstractItemView *const v = tw->addTemporaryView(title, proxy, tabToolTip)) {
225             setView(v);
226         }
227 }
228 
applyWindowID(QWidget * w) const229 void Command::applyWindowID(QWidget *w) const
230 {
231     if (w) {
232         if (d->parentWId) {
233             if (QWidget *pw = QWidget::find(d->parentWId)) {
234                 // remember the current focus widget; re-parenting resets it
235                 QWidget *focusWidget = w->focusWidget();
236                 w->setParent(pw, w->windowFlags());
237                 if (focusWidget) {
238                     focusWidget->setFocus();
239                 }
240             } else {
241                 w->setAttribute(Qt::WA_NativeWindow, true);
242                 KWindowSystem::setMainWindow(w->windowHandle(), d->parentWId);
243             }
244         } else {
245             // remember the current focus widget; re-parenting resets it
246             QWidget *focusWidget = w->focusWidget();
247             w->setParent(d->parentWidgetOrView(), w->windowFlags());
248             if (focusWidget) {
249                 focusWidget->setFocus();
250             }
251         }
252     }
253 }
254 
255 // static
commandsForFiles(const QStringList & files)256 QVector <Command *> Command::commandsForFiles(const QStringList &files)
257 {
258     QStringList importFiles, decryptFiles, encryptFiles, checksumFiles;
259     QVector <Command *> cmds;
260     for (const QString &fileName : files) {
261         const unsigned int classification = classify(fileName);
262 
263         if (classification & Class::AnyCertStoreType) {
264             importFiles << fileName;
265         } else if (classification & Class::AnyMessageType) {
266             // For any message we decrypt / verify. This includes
267             // the class CipherText
268             decryptFiles << fileName;
269         } else if (isChecksumFile(fileName)) {
270             checksumFiles << fileName;
271         } else {
272             QFileInfo fi(fileName);
273             if (fi.isReadable()) {
274                 encryptFiles << fileName;
275             }
276         }
277     }
278     if (!importFiles.isEmpty()) {
279         cmds << new ImportCertificateFromFileCommand(importFiles, nullptr);
280     }
281     if (!decryptFiles.isEmpty()) {
282         cmds << new DecryptVerifyFilesCommand(decryptFiles, nullptr);
283     }
284     if (!encryptFiles.isEmpty()) {
285         cmds << new SignEncryptFilesCommand(encryptFiles, nullptr);
286     }
287     if (!checksumFiles.isEmpty()) {
288         cmds << new ChecksumVerifyFilesCommand(checksumFiles, nullptr);
289     }
290     return cmds;
291 }
292 
293 // static
commandForQuery(const QString & query)294 Command *Command::commandForQuery(const QString &query)
295 {
296     const auto cache = Kleo::KeyCache::instance();
297     GpgME::Key key = cache->findByKeyIDOrFingerprint(query.toLocal8Bit().data());
298 
299     if (key.isNull() && query.size() > 16) {
300         // Try to find by subkeyid
301         std::vector<std::string> id;
302         id.push_back(query.right(16).toStdString());
303         auto keys = cache->findSubkeysByKeyID(id);
304         if (keys.size()) {
305             key = keys[0].parent();
306         }
307     }
308     if (key.isNull()) {
309         return new LookupCertificatesCommand(query, nullptr);
310     } else {
311         return new DetailsCommand(key, nullptr);
312     }
313 }
314