Add Kyber to algorithm strings.
[qpwmc.git] / applicationForm.cpp
blobf7cd0b302613851ecfef3117d8a9bd46950c2dba
1 /*
2 Copyright (C) 2013-2024 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 <QButtonGroup>
22 #include <QPushButton>
23 #include <QLineEdit>
24 #include <QSpinBox>
25 #include <QMessageBox>
26 #include <QCalendarWidget>
28 #include "pwmdMainWindow.h"
29 #include "pwmdSocketDialog.h"
30 #include "applicationForm.h"
31 #include "applicationFormXmlStream.h"
32 #include "applicationFormRadioButton.h"
33 #include "applicationFormPage.h"
34 #include "applicationFormFileSelector.h"
35 #include "applicationFormFinalizePage.h"
36 #include "applicationFormGeneratePassword.h"
37 #include "applicationFormExpiryButton.h"
38 #include "applicationFormDateSelector.h"
39 #include "pwmdExpireDialog.h"
41 ApplicationForm::ApplicationForm (Pwmd *pwmHandle, const QString &filename,
42 PwmdTreeWidget *w, PwmdMainWindow *p)
43 : QWizard ()
45 parent = p;
46 elementTree = w;
47 _modified = false;
48 QAbstractButton *pb = button (QWizard::CancelButton);
49 connect (pb, SIGNAL (clicked (bool)), this, SLOT (slotCancel (bool)));
50 if (elementTree)
52 connect (elementTree,
53 SIGNAL (currentItemChanged (QTreeWidgetItem *, QTreeWidgetItem *)),
54 this,
55 SLOT (slotFormElementSelected (QTreeWidgetItem *, QTreeWidgetItem *)));
58 pwm = pwmHandle;
59 doForm (filename);
62 void
63 ApplicationForm::setModified ()
65 _modified = true;
68 bool
69 ApplicationForm::modified ()
71 return _modified;
74 void
75 ApplicationForm::slotCancel (bool)
77 setHasError ();
80 ApplicationForm::ApplicationForm (const QString &filename,
81 QString socket, QString dataFilename,
82 QString path) : QWizard ()
84 QAbstractButton *pb = button (QWizard::CancelButton);
85 connect (pb, SIGNAL (clicked (bool)), this, SLOT (slotCancel (bool)));
86 elementTree = nullptr;
87 parent = nullptr;
88 pwm = nullptr;
89 _socket = socket;
90 _dataFilename = dataFilename;
91 _elementPath = path;
92 doForm (filename);
95 ApplicationForm::ApplicationForm (const QString &filename) : QWizard ()
97 QAbstractButton *pb = button (QWizard::CancelButton);
98 connect (pb, SIGNAL (clicked (bool)), this, SLOT (slotCancel (bool)));
99 parent = nullptr;
100 elementTree = nullptr;
101 pwm = nullptr;
102 doForm (filename);
105 void
106 ApplicationForm::slotAccepted ()
110 void
111 ApplicationForm::slotFormElementSelected (QTreeWidgetItem * item,
112 QTreeWidgetItem * old)
114 (void)old;
115 foreach (ApplicationFormWidget *w, stream->widgets ())
117 if (w->id () == "pwmdRootElement")
119 w->setValue (parent->elementPath (item, "<TAB>"));
120 break;
125 void
126 ApplicationForm::addFormRow (QFormLayout *fl, QHBoxLayout *hb,
127 ApplicationFormWidget *w, QWizardPage *wp,
128 bool withLabel)
130 if (w->isRequired () && w->widget ())
132 connect (w->widget (), SIGNAL (textChanged (const QString &)), wp,
133 SIGNAL (completeChanged ()));
136 QLabel *l = new QLabel (w->label ());
137 l->setWhatsThis (w->whatsThis ());
138 widgetsToDelete.append (l);
140 if (hb)
141 fl->addRow (withLabel ? l : 0, hb);
142 else
143 fl->addRow (withLabel ? l : 0, w->widget ());
146 void
147 ApplicationForm::setHasError (bool b)
149 _error = b;
152 bool
153 ApplicationForm::hasError ()
155 return _error;
158 void
159 ApplicationForm::slotPageChanged (int n)
161 if (n == 2)
162 finalPage->commit ();
165 void
166 ApplicationForm::slotChangeExpiry ()
168 QWidget *fw = QApplication::focusWidget ();
169 ApplicationFormExpiryButton *pb = static_cast<ApplicationFormExpiryButton*>(fw);
170 ApplicationFormWidget *w = pb->formWidget ();
171 PwmdExpireDialog *d = new PwmdExpireDialog (w->expiryDate (),
172 w->expiryAge (), this);
174 if (d->exec ())
175 w->setExpiry (d->expire (), d->increment ());
177 delete d;
180 void
181 ApplicationForm::addExpiry (ApplicationFormWidget *w, QHBoxLayout *hb)
183 if (hb && w && w->expiry ())
185 ApplicationFormExpiryButton *pb = new ApplicationFormExpiryButton (w);
187 pb->setIcon (QIcon (":icons/expiry.svg"));
188 hb->addWidget (pb);
189 connect (pb, SIGNAL (clicked ()), this, SLOT (slotChangeExpiry ()));
193 void
194 ApplicationForm::slotDateSelector (const QDate &d)
196 foreach (ApplicationFormWidget *w, stream->widgets ())
198 if (w->dateSelector ())
200 ApplicationFormDateSelector *s = qobject_cast<ApplicationFormDateSelector *> (w->widget ());
201 s->setDate (d);
206 void
207 ApplicationForm::doForm (const QString &filename)
209 setWindowFlags (Qt::WindowTitleHint);
210 setWindowTitle (tr ("Pwmd Application Form"));
211 ui.setupUi (this);
212 stream = nullptr;
213 _error = false;
214 finalPage = nullptr;
215 QRegularExpression rx ("^[!]?[^!\\s][^\\s]*");
216 lineEditValidator = new QRegularExpressionValidator (rx, this);
218 connect (this, SIGNAL (currentIdChanged (int)), this, SLOT (slotPageChanged (int)));
219 connect (this, SIGNAL (accepted ()), this, SLOT (slotAccepted ()));
221 stream = new ApplicationFormXmlStream (filename, this);
222 if (stream->error () != QXmlStreamReader::NoError)
224 _error = true;
225 return;
228 QList<ApplicationFormWidget *> widgets = stream->widgets ();
229 int radioButtonId = 0;
230 ApplicationFormPage *wp = new ApplicationFormPage ();
231 QFormLayout *fl = new QFormLayout (wp);
233 wp->setWidgets (widgets);
235 foreach (ApplicationFormWidget *w, widgets)
237 QHBoxLayout *hb = new QHBoxLayout ();
238 bool withLabel = true;
240 if (w->type () == ApplicationFormWidget::AppWidgetRadioButton)
242 QButtonGroup *bg = new QButtonGroup ();
243 QStringList rbs = w->radioButtons ();
245 widgetsToDelete.append (bg);
247 for (int n = 0; n < rbs.count (); n++)
249 ApplicationFormRadioButton *rb = new ApplicationFormRadioButton (rbs.at (n));
251 bg->addButton (rb);
252 hb->addWidget (rb);
253 rb->setId (radioButtonId);
254 w->addRadioButtonId (radioButtonId++);
255 connect (rb, SIGNAL (clicked (bool)), this,
256 SLOT (slotRadioButtonClicked (bool)));
258 if (w->value () == rbs.at (n))
259 rb->setChecked (true);
263 if (w->elementSelector ())
265 if (elementTree)
267 hb->addWidget (elementTree);
268 addFormRow (fl, hb, w, wp, true);
269 hb = new QHBoxLayout ();
270 hb->addWidget (w->widget ());
271 QLineEdit *le = static_cast <QLineEdit *> (w->widget ());
272 le->setPlaceholderText (tr ("Enter or select from above..."));
273 withLabel = false;
275 else
277 QPushButton *pb = new QPushButton ();
278 pb->setText (tr ("Select"));
279 hb->addWidget (w->widget ());
280 hb->addWidget (pb);
281 if (w->id () == "pwmdSocket")
282 connect (pb, SIGNAL (clicked ()), this,
283 SLOT (slotSocketSelector ()));
284 else
285 connect (pb, SIGNAL (clicked ()), this,
286 SLOT (slotElementSelector ()));
289 else if (w->dateSelector ())
291 QCalendarWidget *cal = new QCalendarWidget ();
292 connect (cal, SIGNAL (clicked (const QDate &)), this,
293 SLOT (slotDateSelector (const QDate &)));
294 hb->addWidget (cal);
295 addFormRow (fl, hb, w, wp, true);
296 hb = new QHBoxLayout ();
297 hb->addWidget (w->widget ());
298 ApplicationFormDateSelector *le = static_cast <ApplicationFormDateSelector*> (w->widget ());
299 le->setText (w->value ());
300 withLabel = false;
302 else if (w->fileSelector ())
304 ApplicationFormFileSelector *pb = new ApplicationFormFileSelector (w->widget (), this);
305 pb->setText (tr ("Select"));
306 hb->addWidget (w->widget ());
307 hb->addWidget (pb);
308 connect (pb, SIGNAL (clicked ()), pb, SLOT (slotFileSelector ()));
310 else if (w->passwordGenerator ())
312 ApplicationFormGeneratePassword *pb = new ApplicationFormGeneratePassword (w, this);
313 pb->setText (tr ("Generate"));
314 hb->addWidget (w->widget ());
315 hb->addWidget (pb);
316 connect (pb, SIGNAL (clicked ()), pb, SLOT (slotGeneratePassword ()));
318 else if (w->widget ())
319 hb->addWidget (w->widget ());
321 if (w->type () == ApplicationFormWidget::AppWidgetLineEdit)
323 /* This QLineEdit creates an element from its value. Not a perfect
324 * RE, though. */
325 if (w->pwmdName ().isEmpty ())
327 QLineEdit *le = static_cast<QLineEdit *>(w->widget ());
328 le->setValidator (lineEditValidator);
332 addExpiry (w, hb);
333 addFormRow (fl, hb, w, wp, withLabel);
336 wp->setTitle (ui.wz_start->title ());
337 wp->setSubTitle (ui.wz_start->subTitle ());
339 if (elementTree)
340 slotFormElementSelected (elementTree->currentItem (), nullptr);
342 slotDateSelector (QDate::currentDate ());
343 addPage (wp);
344 finalPage = new ApplicationFormFinalizePage ();
345 finalPage->setTitle (ui.wz_start->title ());
346 finalPage->setSubTitle (ui.wz_start->subTitle ());
347 finalPage->setHandle (pwm);
348 updateForm (_dataFilename, _elementPath, _socket);
349 addPage (finalPage);
352 QString
353 ApplicationForm::socket ()
355 QString s = QString ();
357 foreach (ApplicationFormWidget *w, stream->widgets ())
359 if (w->id () == "pwmdSocket")
361 QLineEdit *le = static_cast<QLineEdit *>(w->widget ());
363 w->setValue (le->text ());
364 s = w->value ();
368 return s;
371 QString
372 ApplicationForm::filename ()
374 QString s = QString ();
376 foreach (ApplicationFormWidget *w, stream->widgets ())
378 if (w->id () == "pwmdFilename")
380 QLineEdit *le = static_cast<QLineEdit *>(w->widget ());
382 w->setValue (le->text ());
383 s = w->value ();
387 return s;
390 QString
391 ApplicationForm::elementPath ()
393 QString s = QString ();
395 foreach (ApplicationFormWidget *w, stream->widgets ())
397 if (w->id () == "pwmdRootElement")
398 s = w->value ();
401 return s;
404 void
405 ApplicationForm::updateForm (QString filename, QString element, QString sock)
407 foreach (ApplicationFormWidget *w, stream->widgets ())
409 if (w->id () == "pwmdFilename" && !filename.isEmpty ())
410 w->setValue (filename);
411 else if (w->id () == "pwmdRootElement" && !element.isEmpty ())
412 w->setValue (element.replace ("\t", "<TAB>"));
413 else if (w->id () == "pwmdSocket" && !sock.isEmpty ())
414 w->setValue (sock);
418 void
419 ApplicationForm::keyPressEvent (QKeyEvent *ev)
421 if (ev->key () == Qt::Key_Escape)
422 setHasError ();
424 QDialog::keyPressEvent (ev);
427 void
428 ApplicationForm::slotKnownHostCallback (void *data, const char *host,
429 const char *key, size_t len)
431 gpg_error_t rc = Pwmd::knownHostPrompt (data, host, key, len);
432 setHasError (rc != 0);
433 emit knownHostRc (rc);
436 void
437 ApplicationForm::slotElementSelector ()
439 QString result;
440 bool notFound = false;
441 QString filename = buildElementPath (QString (), "pwmdFilename", notFound);
442 QString rootElement = buildElementPath (QString (), "pwmdRootElement",
443 notFound);
444 QString sock = buildElementPath (QString (), "pwmdSocket", notFound);
445 int n;
446 bool ownHandle = false;
448 if (!pwm)
450 ownHandle = true;
451 pwm = new Pwmd (0, 0, 0, this);
452 connect (pwm, SIGNAL (knownHost (void *, const char *, const char *, size_t)), this, SLOT (slotKnownHostCallback (void *, const char *, const char *, size_t)));
455 if (pwm->spawnEditor (result, sock, filename, rootElement, false))
457 sock = Pwmd::extractToken (result, "<SOCKET>", n);
458 filename = Pwmd::extractToken (result, "<FILE>", n);
459 rootElement = Pwmd::extractToken (result, "<PATH>", n);
460 updateForm (filename, rootElement, sock);
463 if (ownHandle)
465 delete pwm;
466 pwm = nullptr;
470 void
471 ApplicationForm::slotSocketSelector ()
473 QString sock = QString ();
475 foreach (ApplicationFormWidget *w, stream->widgets ())
477 if (w->id () == "pwmdSocket")
479 sock = w->value ();
480 break;
484 PwmdSocketDialog *d = new PwmdSocketDialog (sock, this);
485 d->setParent (this, Qt::Dialog);
486 if (d->exec ())
487 updateForm (QString (), QString (), d->socket ());
489 delete d;
492 void
493 ApplicationForm::slotRadioButtonClicked (bool b)
495 (void)b;
496 QWidget *fw = QApplication::focusWidget ();
497 ApplicationFormRadioButton *rb = static_cast<ApplicationFormRadioButton *>(fw);
499 foreach (ApplicationFormWidget *w, stream->widgets ())
501 if (w->type () == ApplicationFormWidget::AppWidgetRadioButton)
503 if (w->hasRadioButtonId (rb->id ()))
505 w->setValue (rb->text ());
506 return;
512 ApplicationForm::~ApplicationForm ()
514 if (stream)
515 delete stream;
517 if (finalPage)
518 delete finalPage;
520 foreach (QObject *w, widgetsToDelete)
522 delete w;
525 if (lineEditValidator)
526 delete lineEditValidator;
529 QString
530 ApplicationForm::buildElementPath (QString path, QString element,
531 bool &notFound)
533 foreach (ApplicationFormWidget *w, stream->widgets ())
535 if (w->id () == element)
537 if (!w->childOf ().isEmpty ())
539 path = buildElementPath (path, w->childOf (), notFound);
540 if (path.isEmpty () && w->childOf () != "pwmdRootElement")
542 qWarning ("%s: could not find parent '%s'\n",
543 element.toUtf8 ().data (),
544 w->childOf ().toUtf8 ().data ());
545 notFound = true;
546 return QString ();
549 if (!w->pwmdName ().isEmpty ())
551 if (!path.isEmpty ())
552 path.append ("\t");
553 path.append (w->pwmdName ());
555 else if (!w->value ().isEmpty ())
557 if (!path.isEmpty ())
558 path.append ("\t");
559 path.append (w->value ());
562 else
564 if (!w->pwmdName ().isEmpty ())
565 path.append (w->pwmdName ());
567 if (!w->value ().isEmpty ())
569 if (!w->pwmdName ().isEmpty ())
570 path.append ("\t");
572 path.append (w->value ());
576 return path;
580 return path;