android: Fix XML form filter.
[qpwmc.git] / pwmdSaveWidget.cpp
blob32dcf7825d21052cbe9c084ef23ed4a86b39b64f
1 /*
2 Copyright (C) 2010-2023 Ben Kibbey <bjk@luxsci.net>
4 This file is part of qpwmc.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 USA
21 #include <QApplication>
22 #include <QDir>
23 #include <QCommonStyle>
24 #include <QDateTime>
25 #include <QSettings>
26 #include <QTimer>
27 #include <QMessageBox>
28 #include <QClipboard>
29 #include <QScroller>
30 #include <QShortcut>
32 #include "pwmdSaveDialog.h"
33 #include "pwmdSaveWidget.h"
34 #include "cmdIds.h"
35 #include "pwmdPasswordDialog.h"
36 #include "pwmdKeyGenDialog.h"
38 static bool searching;
40 PwmdSaveWidget::PwmdSaveWidget (QWidget *p) : QFrame (p)
42 ui.setupUi (this);
43 QCommonStyle style;
44 pwm = nullptr;
45 newFile = false;
46 _recipients = QString ();
47 _signers = QString ();
48 _needsRefresh = true;
49 newSigners = QString ();
50 newRecipients = QString ();
51 currentKeyListIndex = 0;
52 selectSignKeyId = false;
53 QSettings cfg ("qpwmc");
54 keyFile = QString ();
55 encryptKeyFile = QString ();
56 signKeyFile = QString ();
57 init = true;
58 generatedKeyId = QString ();
60 ui.keyList->setParent(this);
61 ui.recipientList->setParent(this);
62 ui.recipientList->setIsRecipientList();
63 connect (ui.tb_refreshKeyList, SIGNAL (clicked()), this, SLOT(slotRefreshKeyList()));
64 ui.tb_refreshKeyList->setIcon (QIcon (":icons/matt-icons_view-refresh.svg"));
65 connect (ui.keyList, SIGNAL (currentItemChanged (QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT (slotKeyIdChanged (QTreeWidgetItem *, QTreeWidgetItem *)));
66 connect (ui.keyList, SIGNAL (itemSelectionChanged ()), this, SLOT (slotKeySelectionChanged ()));
67 connect (ui.recipientList, SIGNAL (currentItemChanged (QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT (slotKeyIdChanged (QTreeWidgetItem *, QTreeWidgetItem *)));
68 QStringList list;
69 list << tr("Key ID") << tr("Validity") << tr("Trust") << tr ("Flags")
70 << tr ("User ID");
71 ui.keyList->setHeaderLabels(list);
72 ui.recipientList->setHeaderLabels(list);
73 ui.keyList->header()->restoreState(cfg.value ("keyListHeaderState").toByteArray());
74 ui.recipientList->header()->restoreState(cfg.value ("keyListHeaderState").toByteArray());
76 connect (ui.keyList->header(), SIGNAL(sectionResized(int, int, int)), this, SLOT (slotHeaderSectionResized(int, int, int)));
78 connect (ui.pb_generate, SIGNAL (clicked ()), this, SLOT (slotGenerate ()));
79 connect (ui.ck_symmetric, SIGNAL (stateChanged (int)), this, SLOT (slotSymmetricChanged(int)));
80 connect (ui.ck_secretOnly, SIGNAL (stateChanged (int)), this, SLOT (slotSecretOnlyChanged (int)));
81 ui.tb_addRecipient->setIcon (QIcon (":icons/matt-icons_list-add.svg"));
82 connect (ui.tb_addRecipient, SIGNAL (clicked()), this, SLOT (slotAddRecipients()));
83 ui.tb_removeRecipient->setIcon (QIcon (":icons/matt-icons_list-remove.svg"));
84 connect (ui.tb_removeRecipient, SIGNAL (clicked()), this, SLOT (slotRemoveRecipients()));
86 QShortcut *sc = new QShortcut (QKeySequence ("Ctrl+F"), this);
87 connect (sc, SIGNAL (activated ()), this, SLOT (slotFindKeyActivated ()));
88 connect (ui.le_searchKeyList, SIGNAL (textChanged (const QString &)), this,
89 SLOT (slotSearchKeyListChanged (const QString &)));
90 connect (ui.le_searchKeyList, SIGNAL (returnPressed()), this,
91 SLOT (slotSearchKeyList()));
92 connect (ui.tb_searchKeyList, SIGNAL (clicked()), this,
93 SLOT (slotSearchKeyList()));
95 connect (ui.tb_learn, SIGNAL (clicked()), this, SLOT (slotLearn()));
96 ui.tb_learn->setIcon (QIcon (":icons/rodentia-icons_emblem-information.svg"));
98 connect (ui.pb_keyFileOptions, SIGNAL (clicked()), this, SLOT (slotSelectKeyFile()));
100 connect (ui.tb_delete, SIGNAL (clicked ()), SLOT (slotDeleteKey ()));
101 ui.tb_delete->setIcon (QIcon (":icons/rodentia-icons_user-trash-full.svg"));
102 ui.tb_delete->setEnabled (false);
103 ui.tb_removeRecipient->setEnabled (false);
104 ui.tb_addRecipient->setEnabled (false);
105 QScroller::grabGesture(ui.scrollArea, QScroller::TouchGesture);
108 PwmdSaveWidget::~PwmdSaveWidget ()
110 QSettings cfg ("qpwmc");
112 cfg.setValue ("keyListHeaderState", ui.keyList->header()->saveState());
113 clearKeyList ();
116 bool
117 PwmdSaveWidget::isSearching ()
119 return ui.le_searchKeyList->hasFocus ();
122 void
123 PwmdSaveWidget::slotKeySelectionChanged ()
125 QList <QTreeWidgetItem *> list = ui.keyList->selectedItems ();
127 ui.tb_delete->setEnabled (!(list.isEmpty () || list.size () > 1));
130 void
131 PwmdSaveWidget::slotStatusMessage (QString line, void *user)
133 (void)user;
134 QStringList l = QString (line).split (" ");
136 if (l.at (0) == "GENKEY" && l.size () == 3)
138 generatedKeyId = l.at(2);
142 void
143 PwmdSaveWidget::slotGenerate ()
145 PwmdKeyGenDialog d (this, pwm);
146 d.exec ();
149 void
150 PwmdSaveWidget::slotLearn ()
152 pwm->command (new PwmdCommandQueueItem (PwmdCmdIdSaveLearn, "KEYINFO", nullptr,
153 new PwmdInquireData ("--learn")));
156 void
157 PwmdSaveWidget::slotCopyKeyIdToClipboard ()
159 QClipboard *c = QApplication::clipboard ();
160 QTreeWidgetItem *item = ui.keyList->currentItem ();
161 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
163 if (c->supportsSelection ())
164 c->setText (data->subKey()->keyId (), QClipboard::Selection);
165 c->setText (data->subKey()->keyId ());
168 void
169 PwmdSaveWidget::slotCopyRecipientKeyIdToClipboard ()
171 QClipboard *c = QApplication::clipboard ();
172 QTreeWidgetItem *item = ui.recipientList->currentItem ();
173 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
175 if (c->supportsSelection ())
176 c->setText (data->subKey()->keyId (), QClipboard::Selection);
177 c->setText (data->subKey()->keyId ());
180 void
181 PwmdSaveWidget::slotDeleteKey ()
183 QList <QTreeWidgetItem *> list = ui.keyList->selectedItems ();
184 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(list.at (0)->data (0, Qt::UserRole));
185 QString key = QString ("User ID: %1\nFingerprint: %2").arg (data->key()->userIds ().at(0)->userId(), data->subKey ()->fingerprint ());
186 int b = QMessageBox::question (this, tr ("Delete key pair?"),
187 QString (tr ("Do you really want to delete the following public and private keys from the keyring?\n\n%1").arg (key)),
188 QMessageBox::Yes | QMessageBox::No,
189 QMessageBox::No);
191 if (b != QMessageBox::Yes)
192 return;
194 PwmdCommandQueueItem *item = new PwmdCommandQueueItem (PwmdCmdIdSaveDeleteKey,
195 "DELETEKEY", nullptr,
196 new PwmdInquireData (data->subKey ()->fingerprint ()));
197 pwm->command (item);
200 void
201 PwmdSaveWidget::slotCommandResult (PwmdCommandQueueItem *item,
202 QString result, gpg_error_t rc, bool queued)
204 PwmdInquireData *inq = item->data ();
206 if ((item->id () >= 0 && item->id () <= PwmdCmdIdOpenMax)
207 || item->id () >= PwmdCmdIdSaveMax)
209 item->setSeen ();
210 return;
213 switch (item->id ())
215 case PwmdCmdIdInternalConnect:
216 case PwmdCmdIdInternalOpen:
217 case PwmdCmdIdInternalPassword:
218 item->setSeen ();
219 return;
220 case PwmdCmdIdInternalSave:
221 (void)pwmd_setopt (pwm->handle (), PWMD_OPTION_LOCAL_PINENTRY, 0);
222 (void)pwmd_setopt (pwm->handle (), PWMD_OPTION_OVERRIDE_INQUIRE, 0);
223 saveFinalize ();
224 break;
225 case PwmdCmdIdSaveKeyInfo:
226 if (!rc)
227 updateCurrentKeyInfoFinalize (result);
228 break;
229 case PwmdCmdIdInternalGenKey:
230 (void)pwmd_setopt (pwm->handle (), PWMD_OPTION_LOCAL_PINENTRY, 0);
231 (void)pwmd_setopt (pwm->handle (), PWMD_OPTION_OVERRIDE_INQUIRE, 0);
232 if (!rc)
233 refreshKeyLists (true);
234 else
236 item->setSeen ();
237 return;
239 break;
240 case PwmdCmdIdSaveLearn:
241 if (!rc)
242 refreshKeyLists (true);
243 break;
244 case PwmdCmdIdSaveListKeys:
245 if (!rc)
246 getKeyListFinalize (result, inq->userBool());
247 break;
248 case PwmdCmdIdSaveDeleteKey:
249 if (!rc)
250 refreshKeyLists (true);
251 break;
252 default:
253 break;
256 if (rc && !item->checkError (rc) && !queued)
257 Pwmd::showError (rc, pwm);
259 item->setSeen ();
262 void
263 PwmdSaveWidget::slotSelectKeyFile ()
265 PwmdPasswordDialog *d = new PwmdPasswordDialog (this);
267 slotConfirmKeySelection ();
268 d->setSymmetric (ui.ck_symmetric->isChecked ());
269 d->setHasSigners (!newSigners.isEmpty ());
270 d->setNewFile (newFile);
271 d->setDecryptKeyFile (keyFile);
272 d->setEncryptKeyFile (encryptKeyFile);
273 d->setSignKeyFile (signKeyFile);
275 if (d->exec () && d->useKeyFile ())
277 keyFile = d->decryptKeyFile ();
278 encryptKeyFile = d->encryptKeyFile ();
279 signKeyFile = d->signKeyFile ();
281 else
282 keyFile = encryptKeyFile = signKeyFile = QString ();
284 delete d;
287 void
288 PwmdSaveWidget::slotSecretOnlyChanged (int s)
290 updateKeyList (s == Qt::Checked);
293 void
294 PwmdSaveWidget::resetRecipients ()
296 newRecipients = QString ();
297 newSigners = QString ();
298 clearRecipientList ();
301 void
302 PwmdSaveWidget::slotResetRecipients ()
304 if (keyList.count() && (recipients().isEmpty () || signers().isEmpty()))
305 updateCurrentKeyInfo ();
307 setKeyListRecipients ();
310 void
311 PwmdSaveWidget::slotSymmetricChanged (int s)
313 bool b = s == Qt::Checked ? true : false;
315 ui.ck_secretOnly->setChecked (b);
316 ui.ck_secretOnly->setEnabled (!b);
317 ui.pb_keyFileOptions->setEnabled (ui.recipientList->topLevelItemCount () || b);
318 emit saveReady (testRecipients ());
321 void
322 PwmdSaveWidget::reset ()
326 bool
327 PwmdSaveWidget::needsRefresh ()
329 return _needsRefresh;
332 void
333 PwmdSaveWidget::setNeedsRefresh (bool b)
335 _needsRefresh = b;
338 void
339 PwmdSaveWidget::refreshKeyLists (bool force)
341 slotResetRecipients ();
343 if (needsRefresh () || force)
345 _recipients = QString ();
346 _signers = QString ();
347 updateCurrentKeyInfo ();
348 getKeyList (QString (), force, ui.ck_symmetric->isChecked ());
352 void
353 PwmdSaveWidget::showEvent (QShowEvent *ev)
355 if (!ev->spontaneous())
356 refreshKeyLists (false);
358 QFrame::showEvent (ev);
361 void
362 PwmdSaveWidget::updateCurrentKeyInfoFinalize (const QString &result)
364 QStringList list = result.split ("\n");
365 bool sign = false;
366 QString str;
368 for (int n = 0; n < list.count(); n++)
370 if (list.at(n).at(0) == 'S' && !sign)
372 if (!str.isEmpty())
373 str.chop(1);
375 _recipients = str;
376 sign = true;
377 str = QString ();
380 if (sign)
381 str.append (list.at(n).mid(1)+",");
382 else
383 str.append (list.at(n)+",");
386 if (!str.isEmpty())
387 str.chop(1);
389 if (sign)
390 _signers = str;
391 else
392 _recipients = str;
394 setSymmetric ();
395 setNeedsRefresh (false);
398 void
399 PwmdSaveWidget::updateCurrentKeyInfo ()
401 pwm->command (new PwmdCommandQueueItem (PwmdCmdIdSaveKeyInfo, "KEYINFO",
402 nullptr, new PwmdInquireData ()));
405 void
406 PwmdSaveWidget::slotHeaderSectionResized (int idx, int old, int newSize)
408 (void)idx;
409 (void)old;
410 (void)newSize;
411 QByteArray b = ui.keyList->header()->saveState();
413 ui.recipientList->header()->restoreState (b);
416 void
417 PwmdSaveWidget::keyPressEvent (QKeyEvent *ev)
419 QFrame::keyPressEvent (ev);
422 void
423 PwmdSaveWidget::setSymmetric ()
425 if (recipients().isEmpty ())
427 ui.ck_symmetric->setHidden (!newFile);
428 ui.ck_symmetric->setChecked (!newFile);
430 else
432 ui.ck_symmetric->setHidden (!newFile);
433 ui.ck_symmetric->setChecked (false);
437 void
438 PwmdSaveWidget::setIsNew (bool b)
440 newFile = b;
441 setSymmetric ();
444 void
445 PwmdSaveWidget::setHandle (Pwmd *p, bool isNewFile)
447 if (pwm)
448 disconnect (pwm, SIGNAL (commandResult (PwmdCommandQueueItem *, QString, gpg_error_t, bool)), this, SLOT (slotCommandResult (PwmdCommandQueueItem *, QString, gpg_error_t, bool)));
450 pwm = p;
451 connect (pwm, SIGNAL (commandResult (PwmdCommandQueueItem *, QString, gpg_error_t, bool)), this, SLOT (slotCommandResult (PwmdCommandQueueItem *, QString, gpg_error_t, bool)));
452 connect (pwm, SIGNAL (statusMessage (QString, void *)), this,
453 SLOT (slotStatusMessage (QString, void *)));
454 setIsNew (isNewFile);
457 void
458 PwmdSaveWidget::saveFinalize ()
460 newFile = false;
461 _signers = newSigners;
462 _recipients = newRecipients;
463 updateCurrentKeyInfo ();
464 setKeyListRecipients ();
467 gpg_error_t
468 PwmdSaveWidget::save (const QString &args, bool fromWidget)
471 gpg_error_t rc = 0;
472 PwmdInquireData *inq = new PwmdInquireData (pwm->handle (), pwm->filename ());
473 QString saveArgs = args;
474 bool useKeyFile = false;
476 if (fromWidget)
478 pwm->save (saveArgs, Pwmd::inquireCallback, inq);
479 return 0;
482 slotConfirmKeySelection ();
484 if (!keyFile.isEmpty () || !encryptKeyFile.isEmpty ()
485 || !signKeyFile.isEmpty())
486 useKeyFile = true;
488 if (ui.ck_symmetric->isChecked () && ui.ck_symmetric->isEnabled ())
489 saveArgs.append (" --symmetric");
491 if (!newRecipients.isEmpty())
492 saveArgs.append(QString(" --keyid=%1").arg (newRecipients));
494 if (!newSigners.isEmpty())
495 saveArgs.append(QString(" --sign-keyid=%1").arg (newSigners));
496 else if (newSigners.isEmpty() && ui.ck_symmetric->isChecked() && !init)
497 saveArgs.append(QString(" --sign-keyid="));
499 if (useKeyFile)
501 pwmd_socket_t type;
503 pwmd_socket_type (pwm->handle (), &type);
504 if (type != PWMD_SOCKET_LOCAL || useKeyFile)
506 if (useKeyFile)
508 inq->setKeyFile (keyFile);
509 inq->setEncryptKeyFile (encryptKeyFile);
510 inq->setSignKeyFile (signKeyFile);
513 rc = pwmd_setopt (pwm->handle (), PWMD_OPTION_LOCAL_PINENTRY, 1);
514 if (!rc)
515 rc = pwmd_setopt (pwm->handle (), PWMD_OPTION_OVERRIDE_INQUIRE, 1);
517 if (rc)
519 reset ();
520 delete inq;
521 return rc;
524 pwm->save (saveArgs, Pwmd::inquireCallback, inq);
526 else
527 pwm->save (saveArgs, Pwmd::inquireCallback, inq);
529 return 0;
532 static QString
533 keyFlags (PwmdKey *key)
535 QString s;
537 if (key->canEncrypt())
538 s.append ("e");
540 if (key->canSign())
541 s.append ("s");
543 if (key->canCertify())
544 s.append ("c");
546 if (key->canAuthenticate())
547 s.append("a");
549 return s;
552 static int
553 currentKeyListItemIndex (QTreeWidget *w, QTreeWidgetItem *item)
555 int i;
556 QList < QTreeWidgetItem * >list = w->findItems ("*", Qt::MatchWildcard | Qt::MatchRecursive);
558 for (i = 0; i < list.count(); i++)
560 if (list.at(i) == item)
561 return i;
564 return -1;
567 static QString
568 openpgp_algorithm (PwmdSubKey *key)
570 switch (key->pubkeyAlgo())
572 case 1:
573 case 2:
574 case 3:
575 return "RSA";
576 case 16:
577 case 20:
578 return "ELG";
579 case 17:
580 return "DSA";
581 case 301:
582 case 302:
583 case 18:
584 return "ECC";
585 default:
586 break;
589 return QApplication::tr("unknown");
592 void
593 PwmdSaveWidget::slotKeyIdChanged (QTreeWidgetItem * item,
594 QTreeWidgetItem * old)
596 (void) old;
598 if (!item)
600 if (old && old->treeWidget () == ui.keyList)
601 ui.tb_addRecipient->setEnabled (false);
602 else if (old && old->treeWidget () == ui.recipientList)
603 ui.tb_removeRecipient->setEnabled (false);
604 return;
607 ui.pb_keyFileOptions->setEnabled (ui.recipientList->topLevelItemCount ()
608 || ui.ck_symmetric->isChecked ());
609 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
610 ui.l_fingerprint->setText(data->subKey()->fingerprint());
611 ui.l_keygrip->setText(data->subKey()->keygrip());
613 QString cn = data->subKey()->cardNumber();
614 ui.l_cardNumber->setText(cn.isEmpty () ? "-" : cn);
616 QDateTime t = QDateTime::fromSecsSinceEpoch (data->subKey()->created());
617 ui.l_created->setText(t.toString("MM/dd/yyyy hh:mm:ss"));
619 if (data->subKey()->expires())
621 t = QDateTime::fromSecsSinceEpoch (data->subKey()->expires());
622 ui.l_expires->setText(t.toString("MM/dd/yyyy hh:mm:ss"));
624 else
625 ui.l_expires->setText("-");
627 if (data->subKey()->curve().isEmpty ())
628 ui.l_algorithm->setText (QString ("%1-%2").arg (openpgp_algorithm(data->subKey())).arg (data->subKey()->nBits()));
629 else
630 ui.l_algorithm->setText (QString ("%1-%2-%3").arg (openpgp_algorithm(data->subKey())).arg (data->subKey()->nBits()).arg (data->subKey()->curve()));
632 if (item->treeWidget () == ui.keyList)
634 if (ui.ck_symmetric->isChecked () && !data->subKey()->canSign ())
635 ui.tb_addRecipient->setEnabled (false);
636 else
637 ui.tb_addRecipient->setEnabled (true);
639 else if (item->treeWidget () == ui.recipientList)
640 ui.tb_removeRecipient->setEnabled (true);
642 ui.keyList->scrollToItem (item);
644 if (!searching)
645 currentKeyListIndex = currentKeyListItemIndex (ui.keyList,
646 ui.keyList->currentItem ());
649 void
650 PwmdSaveWidget::slotConfirmKeySelection ()
652 QList <QTreeWidgetItem *> list;
654 list = ui.recipientList->findItems ("*", Qt::MatchWildcard);
655 int i;
656 QString signer, recipient;
658 for (i = 0; i < list.count(); i++)
660 QTreeWidgetItem *item = list.at(i);
661 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
662 PwmdSubKey *s = data->subKey();
664 if (s->canSign())
665 signer.append (s->fingerprint()+",");
667 if (s->canEncrypt())
668 recipient.append (s->keyId()+",");
671 if (signer.size())
672 signer.chop(1);
674 if (recipient.size())
675 recipient.chop(1);
677 newSigners = signer;
678 newRecipients = recipient;
681 void
682 PwmdSaveWidget::slotRefreshKeyList ()
684 ui.l_created->setText (tr("-"));
685 ui.l_expires->setText (tr("-"));
686 ui.l_fingerprint->setText (tr("-"));
687 ui.l_keygrip->setText (tr("-"));
688 ui.l_cardNumber->setText (tr("-"));
689 getKeyList (QString (), true, selectSignKeyId);
690 updateCurrentKeyInfo ();
693 QTreeWidgetItem *
694 PwmdSaveWidget::searchKeyList (const QString &str, int &index, bool next,
695 bool wrapAround)
697 QList < QTreeWidgetItem * >items = ui.keyList->findItems ("*", Qt::MatchWildcard | Qt::MatchRecursive);
698 int i, x;
699 QTreeWidgetItem *item = nullptr;
701 if (index >= items.count())
702 x = 0;
703 else
704 x = index < 0 ? 0 : index;
706 for (i = x; i < items.count(); i++)
708 item = items.at(i);
709 if (item->isHidden())
710 continue;
712 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
713 int n;
715 for (n = 0; n < data->key()->userIds().count(); n++)
717 if (data->key()->userIds().at(n)->userId().contains (str, Qt::CaseInsensitive)
718 && ui.keyList->indexOfTopLevelItem (item) != -1)
719 goto done;
720 else if (data->key()->userIds().at(n)->comment().contains (str, Qt::CaseInsensitive)
721 && ui.keyList->indexOfTopLevelItem (item) != -1)
722 goto done;
725 if (data->subKey()->fingerprint().contains (str, Qt::CaseInsensitive))
726 goto done;
727 if (data->subKey()->keygrip().contains (str, Qt::CaseInsensitive))
728 goto done;
729 else if (data->subKey()->keyId().contains (str, Qt::CaseInsensitive))
730 goto done;
733 done:
734 if (i < items.count())
735 index = i+1;
736 else if (next && !wrapAround)
738 x = 0;
739 item = searchKeyList (str, x, next, true);
740 if (item)
741 index = x;
742 return item;
745 return i < items.count() ? item : nullptr;
748 void
749 PwmdSaveWidget::slotSearchKeyListChanged (const QString &str)
751 ui.tb_searchKeyList->setEnabled (!str.isEmpty ());
752 if (str.isEmpty())
753 return;
755 int n = currentKeyListIndex;
756 QTreeWidgetItem *item = searchKeyList (str, n);
757 if (!item)
758 return;
760 ui.keyList->setCurrentItem (item);
761 ui.keyList->scrollToItem (item);
764 void
765 PwmdSaveWidget::slotFindKeyActivated ()
767 ui.le_searchKeyList->setFocus ();
768 if (ui.le_searchKeyList->text ().isEmpty ())
769 return;
771 ui.le_searchKeyList->setSelection (0, ui.le_searchKeyList->text ().length ());
774 void
775 PwmdSaveWidget::slotSearchKeyList ()
777 if (ui.le_searchKeyList->text ().isEmpty ())
778 return;
780 QTreeWidgetItem *item = searchKeyList (ui.le_searchKeyList->text(),
781 currentKeyListIndex, true);
782 if (!item)
783 return;
785 // Fixes slotKeyIdChanged changing currentKeyListIndex.
786 searching = true;
787 ui.keyList->setCurrentItem (item);
788 ui.keyList->scrollToItem (item);
789 searching = false;
792 static QString
793 ownerTrust (PwmdKey *key)
795 if (key->protocol() != 0) // GPGME_PROTOCOL_OPENPGP
796 return QString ();
798 switch (key->ownerTrust())
800 case 0:
801 return QApplication::tr("Unknown");
802 case 1:
803 return QApplication::tr("Undefined");
804 case 2:
805 return QApplication::tr("Never");
806 case 3:
807 return QApplication::tr("Marginal");
808 case 4:
809 return QApplication::tr("Full");
810 case 5:
811 return QApplication::tr("Ultimate");
814 return QString ();
817 static QString
818 validity (PwmdKey *key)
820 QString s = QString ();
822 if (key->isRevoked())
823 s = QApplication::tr("Revoked");
824 else if (key->isExpired())
825 s = QApplication::tr("Expired");
826 else if (key->isInvalid())
827 s = QApplication::tr("Invalid");
828 else if (key->isDisabled())
829 s = QApplication::tr("Disabled");
830 else
831 s = QApplication::tr ("Valid");
833 return s;
836 void
837 PwmdSaveWidget::createSubKeyItemOnce (QTreeWidgetItem *item, QString keyId,
838 PwmdKey *key, QString uids)
840 item->setText (0, QString ("0x")+keyId.right (8));
841 item->setText (1, validity (key));
842 item->setText (2, ownerTrust (key));
843 item->setText (3, keyFlags (key));
844 item->setText (4, uids);
847 static QString
848 buildKeyUserIds (PwmdKey *key)
850 QString uids;
851 int i;
853 for (i = 0; i < key->userIds().count(); i++)
854 uids += key->userIds().at(i)->userId() + "\n";
856 uids.chop(1);
857 return uids;
860 void
861 PwmdSaveWidget::createSubKeyItem (PwmdKey *key)
863 int i;
864 QString uids;
865 QTreeWidgetItem *parent = nullptr;
866 PwmdSubKey *subKey = key->subKeys().at(0);
867 QTreeWidgetItem *item = new QTreeWidgetItem (parent);
868 PwmdKeyItemData *data = new PwmdKeyItemData (key, subKey);
870 uids = buildKeyUserIds (key);
871 item->setTextAlignment (0, Qt::AlignTop);
872 item->setTextAlignment (1, Qt::AlignTop);
873 item->setTextAlignment (2, Qt::AlignTop);
874 item->setTextAlignment (3, Qt::AlignTop);
875 item->setTextAlignment (4, Qt::AlignTop);
876 createSubKeyItemOnce (item, subKey->keyId(), key, uids);
877 item->setData (0, Qt::UserRole, QVariant::fromValue (data));
878 ui.keyList->addTopLevelItem (item);
879 parent = item;
881 for (i = 0; i < key->subKeys().count(); i++)
883 subKey = key->subKeys().at(i);
884 item = new QTreeWidgetItem (parent);
885 data = new PwmdKeyItemData (key, subKey);
886 item->setTextAlignment (0, Qt::AlignTop);
887 item->setTextAlignment (1, Qt::AlignTop);
888 item->setTextAlignment (2, Qt::AlignTop);
889 item->setTextAlignment (3, Qt::AlignTop);
890 createSubKeyItemOnce (item, subKey->keyId(), subKey);
891 item->setData (0, Qt::UserRole, QVariant::fromValue (data));
895 void
896 PwmdSaveWidget::setKeyListRecipients ()
898 clearRecipientList ();
899 doSetKeyListRecipients (recipients());
900 doSetKeyListRecipients (signers());
901 emit saveReady (testRecipients ());
904 void
905 PwmdSaveWidget::doSetKeyListRecipients (QString keys)
907 QStringList r;
908 QList <QTreeWidgetItem *> list = ui.keyList->findItems ("*",
909 Qt::MatchWildcard);
910 int i;
912 r = keys.split (",");
913 r.removeDuplicates();
915 for (i = 0; i < r.count(); i++)
917 int n;
919 if (r.at(i).isEmpty())
920 continue;
922 for (n = 0; n < list.count(); n++)
924 QTreeWidgetItem *item = list.at(n);
925 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
926 QString keyId = data->subKey()->keyId ();
927 QString fpr = data->subKey()->fingerprint ();
928 int c;
930 if (keyId.right (8).toLower () == r.at(i).right (8).toLower ()
931 || fpr.right (8).toLower () == r.at(i).right (8).toLower ())
933 addRecipient (data);
934 break;
937 for (c = 0; c < item->childCount(); c++)
939 QTreeWidgetItem *child = item->child(c);
941 data = qvariant_cast <PwmdKeyItemData * >(child->data (0, Qt::UserRole));
942 keyId = data->subKey()->keyId ();
943 fpr = data->subKey()->fingerprint ();
945 if (keyId.right (8).toLower () == r.at(i).right (8).toLower ()
946 || fpr.right (8).toLower () == r.at(i).right (8).toLower ())
948 addRecipient (data);
949 break;
956 void
957 PwmdSaveWidget::updateKeyList (bool secret)
959 QList <QTreeWidgetItem *> list = ui.keyList->findItems ("*",
960 Qt::MatchWildcard|Qt::MatchRecursive);
961 int n;
963 selectSignKeyId = secret;
965 for (n = 0; n < list.count(); n++)
967 QTreeWidgetItem *item = list.at(n);
968 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
969 Qt::ItemFlags flags = item->flags();
970 bool hasSecret = data->key()->isSecret();
971 bool revoked = data->key()->isRevoked() || data->subKey()->isRevoked();
973 if (!data->key()->isSecret() && secret)
974 item->setHidden (true);
975 else if (!secret)
976 item->setHidden (false);
978 if (data->key()->canEncrypt() || data->subKey()->canEncrypt()
979 || ((data->key()->canSign() || data->subKey()->canSign()) && hasSecret))
980 flags |= Qt::ItemIsSelectable;
981 else
982 flags &= ~Qt::ItemIsSelectable;
984 if (revoked)
985 flags &= ~Qt::ItemIsSelectable;
987 item->setFlags (flags);
990 setKeyListRecipients ();
991 if (ui.recipientList->topLevelItemCount ())
993 QTreeWidgetItem *item = ui.recipientList->topLevelItem (0);
994 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
995 slotJumpToKey (data->subKey()->fingerprint ());
996 ui.recipientList->setCurrentItem (item);
997 ui.recipientList->scrollToItem (item);
1001 static QString
1002 openpgp_unescape (QString str)
1004 str.replace (QString("\\x3a"), QString(":"));
1005 str.replace ("\\x5c", "\\");
1006 return str;
1009 void
1010 PwmdSaveWidget::clearRecipientList ()
1012 ui.recipientList->clear ();
1015 void
1016 PwmdSaveWidget::clearKeyList ()
1018 while (!keyList.isEmpty ())
1020 PwmdKey *key = keyList.takeFirst ();
1021 delete key;
1024 foreach (QTreeWidgetItem *item,
1025 ui.keyList->findItems ("*", Qt::MatchWildcard | Qt::MatchRecursive))
1027 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
1028 data->setKey (nullptr);
1029 data->setSubKey (nullptr);
1030 delete data;
1033 ui.keyList->clear ();
1034 clearRecipientList ();
1037 void
1038 PwmdSaveWidget::getKeyListFinalize (const QString &result, bool secret)
1040 QStringList lines;
1041 int l;
1042 QList <PwmdKey *> newKeys;
1044 if (result.isEmpty())
1045 return;
1047 lines = result.split ("\n");
1048 for (l = 0; l < lines.count(); l++)
1050 PwmdKey *key = new PwmdKey();
1051 QStringList fields = lines.at(l).split (":");
1052 int f, i;
1053 QList <PwmdSubKey *> subKeys;
1054 QList <PwmdUserId *> userIds;
1055 unsigned n_subKeys = 0, s;
1057 for (f = i = 0; i < 17; i++, f++)
1059 bool b = false;
1061 if (i < 10)
1062 b = fields.at(f).toInt() == 0 ? false : true;
1064 switch (i)
1066 case 0: key->setRevoked(b); break;
1067 case 1: key->setExpired(b); break;
1068 case 2: key->setDisabled(b); break;
1069 case 3: key->setInvalid(b); break;
1070 case 4: key->setCanEncrypt(b); break;
1071 case 5: key->setCanSign(b); break;
1072 case 6: key->setCanCertify(b); break;
1073 case 7: key->setSecret(b); break;
1074 case 8: key->setCanAuthenticate(b); break;
1075 case 9: key->setQualified(b); break;
1076 case 10: key->setProtocol(fields.at(f).toInt()); break;
1077 case 11: key->setIssuerSerial(fields.at(f)); break;
1078 case 12: key->setIssuerName(fields.at(f)); break;
1079 case 13: key->setChainId(fields.at(f)); break;
1080 case 14: key->setOwnerTrust(fields.at(f).toInt()); break;
1081 case 15: break; // n_userIds = fields.at(f).toUInt(); break;
1082 case 16: n_subKeys = fields.at(f).toUInt(); break;
1086 for (s = 0; s < n_subKeys; s++)
1088 PwmdSubKey *subKey = new PwmdSubKey();
1089 bool b = false;
1091 for (i = 0; i < 20; i++, f++)
1093 if (i < 11)
1094 b = fields.at(f).toInt() == 0 ? false : true;
1096 switch (i)
1098 case 0: subKey->setRevoked(b); break;
1099 case 1: subKey->setExpired(b); break;
1100 case 2: subKey->setDisabled(b); break;
1101 case 3: subKey->setInvalid(b); break;
1102 case 4: subKey->setCanEncrypt(b); break;
1103 case 5: subKey->setCanSign(b); break;
1104 case 6: subKey->setCanCertify(b); break;
1105 case 7: subKey->setSecret(b); break;
1106 case 8: subKey->setCanAuthenticate(b); break;
1107 case 9: subKey->setQualified(b); break;
1108 case 10: subKey->setCardKey(b); break;
1109 case 11: subKey->setPubkeyAlgo(fields.at(f).toInt()); break;
1110 case 12: subKey->setNBits(fields.at(f).toUInt()); break;
1111 case 13: subKey->setKeyId (fields.at(f)); break;
1112 case 14: subKey->setFingerprint (fields.at(f)); break;
1113 case 15: subKey->setKeygrip (fields.at(f)); break;
1114 case 16: subKey->setCreated (fields.at(f).toLong()); break;
1115 case 17: subKey->setExpires (fields.at(f).toLong()); break;
1116 case 18: subKey->setCardNumber (fields.at(f).length() > 1
1117 ? fields.at(f) : QString ());
1118 break;
1119 case 19: subKey->setCurve (openpgp_unescape (fields.at (f)));
1120 break;
1124 subKeys.append (subKey);
1127 // Re-create a line containing the userIds.
1128 for (; f < fields.count (); f++)
1130 PwmdUserId *userId = new PwmdUserId();
1132 userId->setRevoked (fields.at(f++).toUInt());
1133 userId->setInvalid (fields.at(f++).toUInt());
1134 userId->setValidity (fields.at(f++).toUInt());
1135 userId->setUserId (openpgp_unescape (fields.at(f++)));
1136 userId->setName (openpgp_unescape (fields.at(f++)));
1137 userId->setEmail (openpgp_unescape (fields.at(f++)));
1138 userId->setComment (openpgp_unescape (fields.at(f)));
1139 userIds.append(userId);
1142 key->setSubkeys (subKeys);
1143 key->setUserIds (userIds);
1144 newKeys.append (key);
1147 clearKeyList ();
1148 keyList = newKeys;
1150 for (l = 0; l < keyList.count(); l++)
1151 createSubKeyItem (keyList.at(l));
1153 init = false;
1154 updateKeyList (secret);
1156 if (!generatedKeyId.isEmpty ())
1157 slotJumpToKey (generatedKeyId);
1159 generatedKeyId = QString ();
1162 void
1163 PwmdSaveWidget::getKeyList (const QString &s, bool force, bool secret)
1165 if (keyList.count() && !force)
1167 updateKeyList (secret);
1168 return;
1171 PwmdInquireData *inq = new PwmdInquireData (s);
1172 inq->setUserBool (secret);
1173 PwmdCommandQueueItem *item = new PwmdCommandQueueItem (PwmdCmdIdSaveListKeys,
1174 "LISTKEYS",
1175 Pwmd::inquireCallback,
1176 inq);
1177 pwm->command (item);
1180 void
1181 PwmdSaveWidget::slotRemoveRecipients ()
1183 QList <QTreeWidgetItem *> list = ui.recipientList->selectedItems ();
1185 while (!list.isEmpty ())
1187 QTreeWidgetItem *item = list.takeFirst ();
1188 int n = ui.recipientList->indexOfTopLevelItem (item);
1190 ui.recipientList->takeTopLevelItem (n);
1191 delete item;
1194 ui.pb_keyFileOptions->setEnabled (ui.recipientList->topLevelItemCount ()
1195 || ui.ck_symmetric->isChecked ());
1196 emit saveReady (testRecipients ());
1199 void
1200 PwmdSaveWidget::addRecipient (PwmdKeyItemData *data)
1202 QTreeWidgetItem *newItem = new QTreeWidgetItem ();
1203 PwmdKey *key = data->key ();
1204 PwmdSubKey *subKey = data->subKey ();
1206 newItem->setTextAlignment (0, Qt::AlignTop);
1207 newItem->setTextAlignment (1, Qt::AlignTop);
1208 newItem->setTextAlignment (2, Qt::AlignTop);
1209 newItem->setTextAlignment (3, Qt::AlignTop);
1210 newItem->setTextAlignment (4, Qt::AlignTop);
1212 if (subKey->canSign ())
1214 QList < QTreeWidgetItem * >list = ui.recipientList->findItems ("*", Qt::MatchWildcard | Qt::MatchRecursive);
1215 foreach (QTreeWidgetItem *item, list)
1217 PwmdKeyItemData *d = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
1218 if (d->subKey ()->canSign ())
1220 ui.recipientList->takeTopLevelItem (ui.recipientList->indexOfTopLevelItem (item));
1221 delete item;
1222 break;
1227 createSubKeyItemOnce (newItem, subKey->keyId(), subKey, buildKeyUserIds(key));
1228 newItem->setData (0, Qt::UserRole, QVariant::fromValue (data));
1229 ui.recipientList->addTopLevelItem (newItem);
1230 ui.pb_keyFileOptions->setEnabled (true);
1233 void
1234 PwmdSaveWidget::slotAddSubKey ()
1236 QList <QTreeWidgetItem *> keys = ui.keyList->selectedItems();
1237 QTreeWidgetItem *item = keys.at (0);
1239 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
1240 PwmdKeyGenDialog d (this, pwm);
1241 d.setSubKey (data->key ());
1242 d.exec ();
1245 bool
1246 PwmdSaveWidget::testRecipients ()
1248 bool sign = false;
1249 bool encrypt = false;
1251 if (ui.ck_symmetric->isChecked ())
1252 return true;
1254 QList < QTreeWidgetItem * >list = ui.recipientList->findItems ("*", Qt::MatchWildcard | Qt::MatchRecursive);
1256 foreach (QTreeWidgetItem *item, list)
1258 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
1259 PwmdSubKey *s = data->subKey();
1261 if (s->canSign ())
1262 sign = true;
1264 if (s->canEncrypt ())
1265 encrypt = true;
1268 return sign && encrypt ? true : false;
1271 void
1272 PwmdSaveWidget::slotAddRecipients ()
1274 QList <QTreeWidgetItem *> list = ui.keyList->selectedItems();
1276 while (!list.isEmpty ())
1278 QTreeWidgetItem *item = list.takeFirst ();
1279 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
1280 PwmdSubKey *s = data->subKey ();
1282 if (ui.ck_symmetric->isChecked () && !s->canSign ())
1283 continue;
1285 addRecipient (data);
1288 emit saveReady (testRecipients ());
1291 void
1292 PwmdSaveWidget::changeKeyListFocus (PwmdKeyTreeWidget *w, bool out)
1294 if (!out)
1295 slotKeyIdChanged (w->currentItem(), nullptr);
1298 QString
1299 PwmdSaveWidget::recipients ()
1301 return _recipients;
1304 QString
1305 PwmdSaveWidget::signers ()
1307 return _signers;
1310 void
1311 PwmdSaveWidget::slotJumpToKey (const QString &fpr)
1313 QString s = fpr;
1315 if (fpr.isEmpty ())
1317 QList <QTreeWidgetItem *> list = ui.recipientList->selectedItems();
1319 if (list.isEmpty ())
1320 return;
1322 QTreeWidgetItem *item = list.at(0);
1323 PwmdKeyItemData *data = qvariant_cast <PwmdKeyItemData * >(item->data (0, Qt::UserRole));
1324 s = data->subKey()->fingerprint ();
1327 int n = 0;
1328 QTreeWidgetItem *match = searchKeyList (s, n);
1329 if (match)
1331 ui.keyList->setCurrentItem (match);
1332 ui.keyList->scrollToItem (match);