QCA

keyselectdlg.cpp
1 /*
2  Copyright (C) 2007 Justin Karneges <[email protected]>
3 
4  Permission is hereby granted, free of charge, to any person obtaining a copy
5  of this software and associated documentation files (the "Software"), to deal
6  in the Software without restriction, including without limitation the rights
7  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  copies of the Software, and to permit persons to whom the Software is
9  furnished to do so, subject to the following conditions:
10 
11  The above copyright notice and this permission notice shall be included in
12  all copies or substantial portions of the Software.
13 
14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21 
22 #include "keyselectdlg.h"
23 
24 #include "ui_keyselect.h"
25 #include <QMenu>
26 #include <QMessageBox>
27 #include <QPushButton>
28 #include <QtCore>
29 #include <QtCrypto>
30 #include <QtGui>
31 
32 #define ONLY_SHOW_KEYBUNDLE
33 
35 
36 class KeyStoreItemShared
37 {
38 public:
39  KeyStoreIconset iconset;
40  QString notAvailableString;
41 };
42 
43 class KeyStoreItem : public QStandardItem
44 {
45 public:
46  enum Type
47  {
48  Store = UserType,
49  Entry
50  };
51 
52  enum Role
53  {
54  NameRole = Qt::UserRole,
55  SubTypeRole,
56  AvailabilityRole,
57  PositionRole
58  };
59 
60  QPixmap entryTypeToIcon(QCA::KeyStoreEntry::Type type) const
61  {
62  QPixmap out;
63  if (!_shared)
64  return out;
65  const KeyStoreIconset &iconset = _shared->iconset;
66  switch (type) {
67  case QCA::KeyStoreEntry::TypeKeyBundle:
68  out = iconset[KeySelectDlg::IconKeyBundle];
69  break;
70  case QCA::KeyStoreEntry::TypeCertificate:
71  out = iconset[KeySelectDlg::IconCert];
72  break;
73  case QCA::KeyStoreEntry::TypeCRL:
74  out = iconset[KeySelectDlg::IconCrl];
75  break;
76  case QCA::KeyStoreEntry::TypePGPSecretKey:
77  out = iconset[KeySelectDlg::IconPgpSec];
78  break;
79  case QCA::KeyStoreEntry::TypePGPPublicKey:
80  out = iconset[KeySelectDlg::IconPgpPub];
81  break;
82  default:
83  break;
84  }
85  return out;
86  }
87 
88  Type _type;
89  KeyStoreItemShared *_shared;
90 
91  QCA::KeyStore * keyStore;
92  QCA::KeyStoreEntry keyStoreEntry;
93 
94  KeyStoreItem(Type type, KeyStoreItemShared *shared)
95  : _type(type)
96  , _shared(shared)
97  {
99  }
100 
101  void setStore(const QString &name, QCA::KeyStore::Type type)
102  {
103  setData(name, NameRole);
104  setData((int)type, SubTypeRole);
105  }
106 
107  void setEntry(const QString &name, QCA::KeyStoreEntry::Type type, bool available, int pos)
108  {
109  setData(name, NameRole);
110  setData((int)type, SubTypeRole);
111  setData(available, AvailabilityRole);
112  setData(pos, PositionRole);
113  }
114 
115  virtual QVariant data(int role) const
116  {
117  if (role == Qt::DisplayRole) {
118  if (_type == Store) {
119  return data(NameRole).toString();
120  } else if (_type == Entry) {
121  QString str = data(NameRole).toString();
122  if (_shared && !data(AvailabilityRole).toBool())
123  str += QString(" ") + _shared->notAvailableString;
124  return str;
125  } else
126  return QStandardItem::data(role);
127  } else if (role == Qt::DecorationRole) {
128  if (_type == Entry) {
129  QCA::KeyStoreEntry::Type type = (QCA::KeyStoreEntry::Type)data(SubTypeRole).toInt();
130  return entryTypeToIcon(type);
131  } else
132  return QStandardItem::data(role);
133  } else
134  return QStandardItem::data(role);
135  }
136 
137  virtual int type() const
138  {
139  return _type;
140  }
141 
142  virtual QStandardItem *clone() const
143  {
144  return new KeyStoreItem(*this);
145  }
146 };
147 
148 class KeyStoreModel : public QStandardItemModel
149 {
150  Q_OBJECT
151 public:
152  KeyStoreItemShared shared;
153 
155 
156  KeyStoreModel(QObject *parent = 0)
157  : QStandardItemModel(parent)
158  , ksm(this)
159  {
160  shared.notAvailableString = tr("(not available)");
161 
162  // make sure keystores are started
164 
165  connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ks_available(const QString &)));
166  QStringList list = ksm.keyStores();
167  foreach (const QString &s, list)
168  ks_available(s);
169 
170  setSortRole(KeyStoreItem::PositionRole);
171  }
172 
173  KeyStoreItem *itemFromStore(QCA::KeyStore *ks) const
174  {
175  for (int n = 0; n < rowCount(); ++n) {
176  KeyStoreItem *i = (KeyStoreItem *)item(n);
177  if (i->keyStore == ks)
178  return i;
179  }
180  return 0;
181  }
182 
183 private Q_SLOTS:
184  void ks_available(const QString &keyStoreId)
185  {
186  QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, &ksm);
187 
188 #ifdef ONLY_SHOW_KEYBUNDLE
189  // only list stores containing keybundles (non-pgp identities)
190  if (!ks->holdsIdentities() || ks->type() == QCA::KeyStore::PGPKeyring)
191  return;
192 #endif
193 
194  connect(ks, SIGNAL(updated()), SLOT(ks_updated()));
195  connect(ks, SIGNAL(unavailable()), SLOT(ks_unavailable()));
196 
197  KeyStoreItem *store_item = new KeyStoreItem(KeyStoreItem::Store, &shared);
198  store_item->setStore(ks->name(), ks->type());
199  store_item->keyStore = ks;
200  ks->startAsynchronousMode();
201  appendRow(store_item);
202  }
203 
204  void ks_updated()
205  {
206  QCA::KeyStore *ks = (QCA::KeyStore *)sender();
207  KeyStoreItem * store_item = itemFromStore(ks);
208  Q_ASSERT(store_item);
209 
210  QList<QCA::KeyStoreEntry> newEntries = ks->entryList();
211 
212 #ifdef ONLY_SHOW_KEYBUNDLE
213  // ignore entries that are not keybundles
214  for (int n = 0; n < newEntries.count(); ++n) {
215  if (newEntries[n].type() != QCA::KeyStoreEntry::TypeKeyBundle) {
216  newEntries.removeAt(n);
217  --n; // adjust position
218  }
219  }
220 #endif
221 
222  // update the store item itself
223  store_item->setStore(ks->name(), ks->type());
224 
225  // handle removed child entries
226  for (int n = 0; n < store_item->rowCount(); ++n) {
227  KeyStoreItem *i = (KeyStoreItem *)store_item->child(n);
228 
229  // is the existing entry in the new list?
230  bool found = false;
231  foreach (const QCA::KeyStoreEntry &ne, newEntries) {
232  if (ne.id() == i->keyStoreEntry.id()) {
233  found = true;
234  break;
235  }
236  }
237 
238  // if not, remove it
239  if (!found) {
240  store_item->removeRow(n);
241  --n; // adjust position
242  }
243  }
244 
245  // handle added/updated child entries
246  for (int n = 0; n < newEntries.count(); ++n) {
247  const QCA::KeyStoreEntry &ne = newEntries[n];
248 
249  // was this entry in the original list?
250  KeyStoreItem *entry_item = 0;
251  for (int k = 0; k < store_item->rowCount(); ++k) {
252  KeyStoreItem *i = (KeyStoreItem *)store_item->child(k);
253  if (i->keyStoreEntry.id() == ne.id()) {
254  entry_item = i;
255  break;
256  }
257  }
258 
259  // if not, add it
260  if (!entry_item) {
261  entry_item = new KeyStoreItem(KeyStoreItem::Entry, &shared);
262  entry_item->keyStoreEntry = ne;
263  entry_item->setEntry(newEntries[n].name(), newEntries[n].type(), newEntries[n].isAvailable(), n);
264  store_item->appendRow(entry_item);
265  }
266  // if so, update it
267  else {
268  entry_item->keyStoreEntry = ne;
269  entry_item->setEntry(newEntries[n].name(), newEntries[n].type(), newEntries[n].isAvailable(), n);
270  }
271  }
272 
273  store_item->sortChildren(0);
274  }
275 
276  void ks_unavailable()
277  {
278  QCA::KeyStore *ks = (QCA::KeyStore *)sender();
279  KeyStoreItem * store_item = itemFromStore(ks);
280  Q_ASSERT(store_item);
281 
282  store_item->removeRows(0, store_item->rowCount());
283  removeRow(store_item->row());
284  delete ks;
285  }
286 };
287 
288 class KeySelectDlg::Private : public QObject
289 {
290  Q_OBJECT
291 public:
292  KeySelectDlg * q;
293  Ui_KeySelect ui;
294  KeyStoreModel * model;
295  QCA::KeyStoreEntry cur_entry;
296  QAction * actionView;
297 
298  Private(KeySelectDlg *_q)
299  : QObject(_q)
300  , q(_q)
301  {
302  ui.setupUi(q);
303 
304  model = new KeyStoreModel(this);
305  connect(&model->ksm, SIGNAL(busyStarted()), SLOT(ksm_busyStarted()));
306  connect(&model->ksm, SIGNAL(busyFinished()), SLOT(ksm_busyFinished()));
307  if (model->ksm.isBusy())
308  ksm_busyStarted();
309 
310  ui.lv_stores->header()->hide();
311  ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
312  ui.lv_stores->setModel(model);
313  ui.lv_stores->setContextMenuPolicy(Qt::CustomContextMenu);
314  connect(ui.lv_stores->selectionModel(),
315  SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
316  SLOT(stores_selectionChanged(const QItemSelection &, const QItemSelection &)));
317  connect(ui.lv_stores,
318  SIGNAL(customContextMenuRequested(const QPoint &)),
319  SLOT(stores_customContextMenuRequested(const QPoint &)));
320 
321  actionView = new QAction(tr("&View"), this);
322  connect(actionView, SIGNAL(triggered()), SLOT(view()));
323  actionView->setEnabled(false);
324  }
325 
326 private Q_SLOTS:
327  void ksm_busyStarted()
328  {
329  ui.lb_busy->setText(tr("Looking for devices..."));
330  }
331 
332  void ksm_busyFinished()
333  {
334  ui.lb_busy->setText("");
335  }
336 
337  void stores_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
338  {
339  Q_UNUSED(deselected);
340 
341  KeyStoreItem *i = 0;
342  if (!selected.indexes().isEmpty()) {
343  QModelIndex index = selected.indexes().first();
344  i = (KeyStoreItem *)model->itemFromIndex(index);
345  }
346 
347  bool viewable = false;
348  bool choosable = false;
349  if (i && i->type() == KeyStoreItem::Entry) {
350  QCA::KeyStoreEntry entry = i->keyStoreEntry;
351  if (entry.type() == QCA::KeyStoreEntry::TypeKeyBundle) {
352  viewable = true;
353  choosable = true;
354  cur_entry = entry;
355  }
356  }
357 
358  if (!choosable)
359  cur_entry = QCA::KeyStoreEntry();
360 
361  actionView->setEnabled(viewable);
362 
363  QPushButton *ok = ui.buttonBox->button(QDialogButtonBox::Ok);
364  if (choosable && !ok->isEnabled())
365  ok->setEnabled(true);
366  else if (!choosable && ok->isEnabled())
367  ok->setEnabled(false);
368  }
369 
370  void stores_customContextMenuRequested(const QPoint &pos)
371  {
372  QItemSelection selection = ui.lv_stores->selectionModel()->selection();
373  if (selection.indexes().isEmpty())
374  return;
375 
376  QModelIndex index = selection.indexes().first();
377  KeyStoreItem *i = (KeyStoreItem *)model->itemFromIndex(index);
378  if (i && i->type() == KeyStoreItem::Entry) {
379  QMenu menu(q);
380  menu.addAction(actionView);
381  menu.exec(ui.lv_stores->viewport()->mapToGlobal(pos));
382  }
383  }
384 
385  void view()
386  {
387  emit q->viewCertificate(cur_entry.keyBundle().certificateChain());
388  }
389 };
390 
391 KeySelectDlg::KeySelectDlg(QWidget *parent)
392  : QDialog(parent)
393 {
394  d = new Private(this);
395 }
396 
397 KeySelectDlg::~KeySelectDlg()
398 {
399  delete d;
400 }
401 
402 void KeySelectDlg::setIcon(IconType type, const QPixmap &icon)
403 {
404  d->model->shared.iconset[type] = icon;
405 }
406 
407 void KeySelectDlg::accept()
408 {
409  QCA::KeyStoreEntry entry = d->cur_entry;
410  QDialog::accept();
411  emit selected(entry);
412 }
413 
414 #include "keyselectdlg.moc"
QModelIndexList indexes() const const
void startAsynchronousMode()
Turns on asynchronous mode for this KeyStore instance.
Type
The type of entry in the KeyStore.
Definition: qca_keystore.h:146
void removeAt(int i)
for a PGP keyring
Definition: qca_keystore.h:429
CustomContextMenu
KCRASH_EXPORT void setFlags(KCrash::CrashFlags flags)
QList< KeyStoreEntry > entryList() const
A list of the KeyStoreEntry objects in this store.
Type type() const
Determine the type of key stored in this object.
bool holdsIdentities() const
test if the KeyStore holds identities (eg KeyBundle or PGPSecretKey)
bool isEnabled() const const
int count(const T &value) const const
General purpose key storage object.
Definition: qca_keystore.h:416
QStringList keyStores() const
A list of all the key stores.
UserRole
Access keystores, and monitor keystores for changes.
Definition: qca_keystore.h:709
virtual void accept()
Single entry in a KeyStore.
Definition: qca_keystore.h:140
Type
The type of keystore.
Definition: qca_keystore.h:423
CertificateChain certificateChain() const
The public certificate part of this bundle.
QString name() const
The name associated with the KeyStore.
Type type() const
The KeyStore Type.
static void start()
Initialize all key store providers.
QString id() const
The ID associated with the key stored in this object.
KeyBundle keyBundle() const
If a KeyBundle is stored in this object, return that bundle.
QString toString() const const
virtual QVariant data(int role) const const
void setEnabled(bool)
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
ItemIsEnabled
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Sep 25 2021 23:05:35 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.