LCOV - code coverage report
Current view: top level - src - configdialog.cpp (source / functions) Coverage Total Hit
Test: .lcov.total Lines: 0.0 % 474 0
Test Date: 2026-03-23 21:55:57 Functions: 0.0 % 54 0

            Line data    Source code
       1              : // SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
       2              : // SPDX-License-Identifier: GPL-3.0-or-later
       3              : #include "configdialog.h"
       4              : #include "keygendialog.h"
       5              : #include "mainwindow.h"
       6              : #include "qtpasssettings.h"
       7              : #include "ui_configdialog.h"
       8              : #include "util.h"
       9              : #include <QClipboard>
      10              : #include <QDir>
      11              : #include <QFileDialog>
      12              : #include <QMessageBox>
      13              : #include <QPushButton>
      14              : #include <QSystemTrayIcon>
      15              : #include <QTableWidgetItem>
      16              : #include <utility>
      17              : #ifdef Q_OS_WIN
      18              : #include <windows.h>
      19              : #endif
      20              : 
      21              : #ifdef QT_DEBUG
      22              : #include "debughelper.h"
      23              : #endif
      24              : 
      25              : /**
      26              :  * @brief ConfigDialog::ConfigDialog this sets up the configuration screen.
      27              :  * @param parent
      28              :  */
      29            0 : ConfigDialog::ConfigDialog(MainWindow *parent)
      30            0 :     : QDialog(parent), ui(new Ui::ConfigDialog) {
      31            0 :   mainWindow = parent;
      32            0 :   ui->setupUi(this);
      33              : 
      34            0 :   ui->passPath->setText(QtPassSettings::getPassExecutable());
      35            0 :   setGitPath(QtPassSettings::getGitExecutable());
      36            0 :   ui->gpgPath->setText(QtPassSettings::getGpgExecutable());
      37            0 :   ui->storePath->setText(QtPassSettings::getPassStore());
      38              : 
      39            0 :   ui->spinBoxAutoclearSeconds->setValue(QtPassSettings::getAutoclearSeconds());
      40            0 :   ui->spinBoxAutoclearPanelSeconds->setValue(
      41            0 :       QtPassSettings::getAutoclearPanelSeconds());
      42            0 :   ui->checkBoxHidePassword->setChecked(QtPassSettings::isHidePassword());
      43            0 :   ui->checkBoxHideContent->setChecked(QtPassSettings::isHideContent());
      44            0 :   ui->checkBoxUseMonospace->setChecked(QtPassSettings::isUseMonospace());
      45            0 :   ui->checkBoxDisplayAsIs->setChecked(QtPassSettings::isDisplayAsIs());
      46            0 :   ui->checkBoxNoLineWrapping->setChecked(QtPassSettings::isNoLineWrapping());
      47            0 :   ui->checkBoxAddGPGId->setChecked(QtPassSettings::isAddGPGId(true));
      48              : 
      49            0 :   if (QSystemTrayIcon::isSystemTrayAvailable()) {
      50            0 :     ui->checkBoxHideOnClose->setChecked(QtPassSettings::isHideOnClose());
      51            0 :     ui->checkBoxStartMinimized->setChecked(QtPassSettings::isStartMinimized());
      52              :   } else {
      53            0 :     ui->checkBoxUseTrayIcon->setEnabled(false);
      54            0 :     ui->checkBoxUseTrayIcon->setToolTip(tr("System tray is not available"));
      55            0 :     ui->checkBoxHideOnClose->setEnabled(false);
      56            0 :     ui->checkBoxStartMinimized->setEnabled(false);
      57              :   }
      58              : 
      59            0 :   ui->checkBoxAvoidCapitals->setChecked(QtPassSettings::isAvoidCapitals());
      60            0 :   ui->checkBoxAvoidNumbers->setChecked(QtPassSettings::isAvoidNumbers());
      61            0 :   ui->checkBoxLessRandom->setChecked(QtPassSettings::isLessRandom());
      62            0 :   ui->checkBoxUseSymbols->setChecked(QtPassSettings::isUseSymbols());
      63            0 :   ui->plainTextEditTemplate->setPlainText(QtPassSettings::getPassTemplate());
      64            0 :   ui->checkBoxTemplateAllFields->setChecked(
      65            0 :       QtPassSettings::isTemplateAllFields());
      66            0 :   ui->checkBoxAutoPull->setChecked(QtPassSettings::isAutoPull());
      67            0 :   ui->checkBoxAutoPush->setChecked(QtPassSettings::isAutoPush());
      68            0 :   ui->checkBoxAlwaysOnTop->setChecked(QtPassSettings::isAlwaysOnTop());
      69              : 
      70              : #if defined(Q_OS_WIN)
      71              :   ui->checkBoxUseOtp->hide();
      72              :   ui->checkBoxUseQrencode->hide();
      73              :   ui->label_10->hide();
      74              : #endif
      75              : 
      76            0 :   if (!isPassOtpAvailable()) {
      77            0 :     ui->checkBoxUseOtp->setEnabled(false);
      78            0 :     ui->checkBoxUseOtp->setToolTip(
      79            0 :         tr("Pass OTP extension needs to be installed"));
      80              :   }
      81              : 
      82            0 :   if (!isQrencodeAvailable()) {
      83            0 :     ui->checkBoxUseQrencode->setEnabled(false);
      84            0 :     ui->checkBoxUseQrencode->setToolTip(tr("qrencode needs to be installed"));
      85              :   }
      86              : 
      87            0 :   setProfiles(QtPassSettings::getProfiles(), QtPassSettings::getProfile());
      88            0 :   setPwgenPath(QtPassSettings::getPwgenExecutable());
      89            0 :   setPasswordConfiguration(QtPassSettings::getPasswordConfiguration());
      90              : 
      91            0 :   usePass(QtPassSettings::isUsePass());
      92            0 :   useAutoclear(QtPassSettings::isUseAutoclear());
      93            0 :   useAutoclearPanel(QtPassSettings::isUseAutoclearPanel());
      94            0 :   useTrayIcon(QtPassSettings::isUseTrayIcon());
      95            0 :   useGit(QtPassSettings::isUseGit());
      96              : 
      97            0 :   useOtp(QtPassSettings::isUseOtp());
      98            0 :   useQrencode(QtPassSettings::isUseQrencode());
      99              : 
     100            0 :   usePwgen(QtPassSettings::isUsePwgen());
     101            0 :   useTemplate(QtPassSettings::isUseTemplate());
     102              : 
     103            0 :   ui->profileTable->verticalHeader()->hide();
     104            0 :   ui->profileTable->horizontalHeader()->setSectionResizeMode(
     105              :       1, QHeaderView::Stretch);
     106            0 :   ui->label->setText(ui->label->text() + VERSION);
     107            0 :   ui->comboBoxClipboard->clear();
     108              : 
     109            0 :   ui->comboBoxClipboard->addItem(tr("No Clipboard"));
     110            0 :   ui->comboBoxClipboard->addItem(tr("Always copy to clipboard"));
     111            0 :   ui->comboBoxClipboard->addItem(tr("On-demand copy to clipboard"));
     112              : 
     113            0 :   int currentIndex = QtPassSettings::getClipBoardTypeRaw();
     114            0 :   ui->comboBoxClipboard->setCurrentIndex(currentIndex);
     115            0 :   on_comboBoxClipboard_activated(currentIndex);
     116              : 
     117            0 :   QClipboard *clip = QApplication::clipboard();
     118            0 :   if (!clip->supportsSelection()) {
     119            0 :     useSelection(false);
     120            0 :     ui->checkBoxSelection->setVisible(false);
     121              :   } else {
     122            0 :     useSelection(QtPassSettings::isUseSelection());
     123              :   }
     124              : 
     125            0 :   if (Util::checkConfig()) {
     126              :     // Show Programs tab, which is likely
     127              :     // what the user needs to fix now.
     128            0 :     ui->tabWidget->setCurrentIndex(1);
     129              :   }
     130              : 
     131            0 :   connect(ui->profileTable, &QTableWidget::itemChanged, this,
     132            0 :           &ConfigDialog::onProfileTableItemChanged);
     133            0 :   connect(this, &ConfigDialog::accepted, this, &ConfigDialog::on_accepted);
     134            0 : }
     135              : 
     136              : /**
     137              :  * @brief ConfigDialog::~ConfigDialog config destructor, makes sure the
     138              :  * mainWindow knows about git, gpg and pass executables.
     139              :  */
     140            0 : ConfigDialog::~ConfigDialog() {
     141            0 :   QtPassSettings::setGitExecutable(ui->gitPath->text());
     142            0 :   QtPassSettings::setGpgExecutable(ui->gpgPath->text());
     143            0 :   QtPassSettings::setPassExecutable(ui->passPath->text());
     144            0 : }
     145              : 
     146              : /**
     147              :  * @brief ConfigDialog::setGitPath set the git executable path.
     148              :  * Make sure the checkBoxUseGit is updated.
     149              :  * @param path
     150              :  */
     151            0 : void ConfigDialog::setGitPath(const QString &path) {
     152            0 :   ui->gitPath->setText(path);
     153            0 :   ui->checkBoxUseGit->setEnabled(!path.isEmpty());
     154            0 :   if (path.isEmpty()) {
     155            0 :     useGit(false);
     156              :   }
     157            0 : }
     158              : 
     159              : /**
     160              :  * @brief ConfigDialog::usePass set wether or not we want to use pass.
     161              :  * Update radio buttons accordingly.
     162              :  * @param usePass
     163              :  */
     164            0 : void ConfigDialog::usePass(bool usePass) {
     165            0 :   ui->radioButtonNative->setChecked(!usePass);
     166            0 :   ui->radioButtonPass->setChecked(usePass);
     167            0 :   setGroupBoxState();
     168            0 : }
     169              : 
     170            0 : void ConfigDialog::validate(QTableWidgetItem *item) {
     171              :   bool status = true;
     172              : 
     173            0 :   if (item == nullptr) {
     174            0 :     for (int i = 0; i < ui->profileTable->rowCount(); i++) {
     175            0 :       for (int j = 0; j < ui->profileTable->columnCount(); j++) {
     176            0 :         QTableWidgetItem *_item = ui->profileTable->item(i, j);
     177              : 
     178            0 :         if (_item->text().isEmpty() && j != 2) {
     179            0 :           _item->setBackground(Qt::red);
     180              :           status = false;
     181              :           break;
     182              :         }
     183              :       }
     184              : 
     185              :       if (!status) {
     186              :         break;
     187              :       }
     188              :     }
     189              :   } else {
     190            0 :     if (item->text().isEmpty() && item->column() != 2) {
     191            0 :       item->setBackground(Qt::red);
     192              :       status = false;
     193              :     }
     194              :   }
     195              : 
     196            0 :   ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status);
     197            0 : }
     198              : 
     199            0 : void ConfigDialog::on_accepted() {
     200            0 :   QtPassSettings::setPassExecutable(ui->passPath->text());
     201            0 :   QtPassSettings::setGitExecutable(ui->gitPath->text());
     202            0 :   QtPassSettings::setGpgExecutable(ui->gpgPath->text());
     203            0 :   QtPassSettings::setPassStore(
     204            0 :       Util::normalizeFolderPath(ui->storePath->text()));
     205            0 :   QtPassSettings::setUsePass(ui->radioButtonPass->isChecked());
     206            0 :   QtPassSettings::setClipBoardType(ui->comboBoxClipboard->currentIndex());
     207            0 :   QtPassSettings::setUseSelection(ui->checkBoxSelection->isChecked());
     208            0 :   QtPassSettings::setUseAutoclear(ui->checkBoxAutoclear->isChecked());
     209            0 :   QtPassSettings::setAutoclearSeconds(ui->spinBoxAutoclearSeconds->value());
     210            0 :   QtPassSettings::setUseAutoclearPanel(ui->checkBoxAutoclearPanel->isChecked());
     211            0 :   QtPassSettings::setAutoclearPanelSeconds(
     212            0 :       ui->spinBoxAutoclearPanelSeconds->value());
     213            0 :   QtPassSettings::setHidePassword(ui->checkBoxHidePassword->isChecked());
     214            0 :   QtPassSettings::setHideContent(ui->checkBoxHideContent->isChecked());
     215            0 :   QtPassSettings::setUseMonospace(ui->checkBoxUseMonospace->isChecked());
     216            0 :   QtPassSettings::setDisplayAsIs(ui->checkBoxDisplayAsIs->isChecked());
     217            0 :   QtPassSettings::setNoLineWrapping(ui->checkBoxNoLineWrapping->isChecked());
     218            0 :   QtPassSettings::setAddGPGId(ui->checkBoxAddGPGId->isChecked());
     219            0 :   QtPassSettings::setUseTrayIcon(ui->checkBoxUseTrayIcon->isEnabled() &&
     220            0 :                                  ui->checkBoxUseTrayIcon->isChecked());
     221            0 :   QtPassSettings::setHideOnClose(ui->checkBoxHideOnClose->isEnabled() &&
     222            0 :                                  ui->checkBoxHideOnClose->isChecked());
     223            0 :   QtPassSettings::setStartMinimized(ui->checkBoxStartMinimized->isEnabled() &&
     224            0 :                                     ui->checkBoxStartMinimized->isChecked());
     225            0 :   QtPassSettings::setProfiles(getProfiles());
     226            0 :   QtPassSettings::setUseGit(ui->checkBoxUseGit->isChecked());
     227            0 :   QtPassSettings::setUseOtp(ui->checkBoxUseOtp->isChecked());
     228            0 :   QtPassSettings::setUseQrencode(ui->checkBoxUseQrencode->isChecked());
     229            0 :   QtPassSettings::setPwgenExecutable(ui->pwgenPath->text());
     230            0 :   QtPassSettings::setUsePwgen(ui->checkBoxUsePwgen->isChecked());
     231            0 :   QtPassSettings::setAvoidCapitals(ui->checkBoxAvoidCapitals->isChecked());
     232            0 :   QtPassSettings::setAvoidNumbers(ui->checkBoxAvoidNumbers->isChecked());
     233            0 :   QtPassSettings::setLessRandom(ui->checkBoxLessRandom->isChecked());
     234            0 :   QtPassSettings::setUseSymbols(ui->checkBoxUseSymbols->isChecked());
     235            0 :   QtPassSettings::setPasswordConfiguration(getPasswordConfiguration());
     236            0 :   QtPassSettings::setUseTemplate(ui->checkBoxUseTemplate->isChecked());
     237            0 :   QtPassSettings::setPassTemplate(ui->plainTextEditTemplate->toPlainText());
     238            0 :   QtPassSettings::setTemplateAllFields(
     239            0 :       ui->checkBoxTemplateAllFields->isChecked());
     240            0 :   QtPassSettings::setAutoPush(ui->checkBoxAutoPush->isChecked());
     241            0 :   QtPassSettings::setAutoPull(ui->checkBoxAutoPull->isChecked());
     242            0 :   QtPassSettings::setAlwaysOnTop(ui->checkBoxAlwaysOnTop->isChecked());
     243              : 
     244            0 :   QtPassSettings::setVersion(VERSION);
     245            0 : }
     246              : 
     247            0 : void ConfigDialog::on_autodetectButton_clicked() {
     248            0 :   QString pass = Util::findBinaryInPath("pass");
     249            0 :   if (!pass.isEmpty()) {
     250            0 :     ui->passPath->setText(pass);
     251              :   }
     252            0 :   usePass(!pass.isEmpty());
     253            0 :   QString gpg = Util::findBinaryInPath("gpg2");
     254            0 :   if (gpg.isEmpty()) {
     255            0 :     gpg = Util::findBinaryInPath("gpg");
     256              :   }
     257            0 :   if (!gpg.isEmpty()) {
     258            0 :     ui->gpgPath->setText(gpg);
     259              :   }
     260            0 :   QString git = Util::findBinaryInPath("git");
     261            0 :   if (!git.isEmpty()) {
     262            0 :     ui->gitPath->setText(git);
     263              :   }
     264            0 :   QString pwgen = Util::findBinaryInPath("pwgen");
     265            0 :   if (!pwgen.isEmpty()) {
     266            0 :     ui->pwgenPath->setText(pwgen);
     267              :   }
     268            0 : }
     269              : 
     270              : /**
     271              :  * @brief ConfigDialog::on_radioButtonNative_clicked wrapper for
     272              :  * ConfigDialog::setGroupBoxState()
     273              :  */
     274            0 : void ConfigDialog::on_radioButtonNative_clicked() { setGroupBoxState(); }
     275              : 
     276              : /**
     277              :  * @brief ConfigDialog::on_radioButtonPass_clicked wrapper for
     278              :  * ConfigDialog::setGroupBoxState()
     279              :  */
     280            0 : void ConfigDialog::on_radioButtonPass_clicked() { setGroupBoxState(); }
     281              : 
     282              : /**
     283              :  * @brief ConfigDialog::getSecretKeys get list of secret/private keys
     284              :  * @return QStringList keys
     285              :  */
     286            0 : auto ConfigDialog::getSecretKeys() -> QStringList {
     287            0 :   QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
     288            0 :   QStringList names;
     289              : 
     290            0 :   if (keys.empty()) {
     291              :     return names;
     292              :   }
     293              : 
     294            0 :   foreach (const UserInfo &sec, keys)
     295            0 :     names << sec.name;
     296              : 
     297            0 :   return names;
     298              : }
     299              : 
     300              : /**
     301              :  * @brief ConfigDialog::setGroupBoxState update checkboxes.
     302              :  */
     303            0 : void ConfigDialog::setGroupBoxState() {
     304            0 :   bool state = ui->radioButtonPass->isChecked();
     305            0 :   ui->groupBoxNative->setEnabled(!state);
     306            0 :   ui->groupBoxPass->setEnabled(state);
     307            0 : }
     308              : 
     309              : /**
     310              :  * @brief ConfigDialog::selectExecutable pop-up to choose an executable.
     311              :  * @return
     312              :  */
     313            0 : auto ConfigDialog::selectExecutable() -> QString {
     314            0 :   QFileDialog dialog(this);
     315            0 :   dialog.setFileMode(QFileDialog::ExistingFile);
     316            0 :   dialog.setOption(QFileDialog::ReadOnly);
     317            0 :   if (dialog.exec()) {
     318            0 :     return dialog.selectedFiles().constFirst();
     319              :   }
     320              : 
     321            0 :   return {};
     322            0 : }
     323              : 
     324              : /**
     325              :  * @brief ConfigDialog::selectFolder pop-up to choose a folder.
     326              :  * @return
     327              :  */
     328            0 : auto ConfigDialog::selectFolder() -> QString {
     329            0 :   QFileDialog dialog(this);
     330            0 :   dialog.setFileMode(QFileDialog::Directory);
     331            0 :   dialog.setFilter(QDir::NoFilter);
     332            0 :   dialog.setOption(QFileDialog::ShowDirsOnly);
     333            0 :   if (dialog.exec()) {
     334            0 :     return dialog.selectedFiles().constFirst();
     335              :   }
     336              : 
     337            0 :   return {};
     338            0 : }
     339              : 
     340              : /**
     341              :  * @brief ConfigDialog::on_toolButtonGit_clicked get git application.
     342              :  * Enable checkboxes if found.
     343              :  */
     344            0 : void ConfigDialog::on_toolButtonGit_clicked() {
     345            0 :   QString git = selectExecutable();
     346            0 :   bool state = !git.isEmpty();
     347            0 :   if (state) {
     348            0 :     ui->gitPath->setText(git);
     349              :   } else {
     350            0 :     useGit(false);
     351              :   }
     352              : 
     353            0 :   ui->checkBoxUseGit->setEnabled(state);
     354            0 : }
     355              : 
     356              : /**
     357              :  * @brief ConfigDialog::on_toolButtonGpg_clicked get gpg application.
     358              :  */
     359            0 : void ConfigDialog::on_toolButtonGpg_clicked() {
     360            0 :   QString gpg = selectExecutable();
     361            0 :   if (!gpg.isEmpty()) {
     362            0 :     ui->gpgPath->setText(gpg);
     363              :   }
     364            0 : }
     365              : 
     366              : /**
     367              :  * @brief ConfigDialog::on_toolButtonPass_clicked get pass application.
     368              :  */
     369            0 : void ConfigDialog::on_toolButtonPass_clicked() {
     370            0 :   QString pass = selectExecutable();
     371            0 :   if (!pass.isEmpty()) {
     372            0 :     ui->passPath->setText(pass);
     373              :   }
     374            0 : }
     375              : 
     376              : /**
     377              :  * @brief ConfigDialog::on_toolButtonStore_clicked get .password-store
     378              :  * location.s
     379              :  */
     380            0 : void ConfigDialog::on_toolButtonStore_clicked() {
     381            0 :   QString store = selectFolder();
     382            0 :   if (!store.isEmpty()) { // TODO(annejan): call check
     383            0 :     ui->storePath->setText(store);
     384              :   }
     385            0 : }
     386              : 
     387              : /**
     388              :  * @brief ConfigDialog::on_comboBoxClipboard_activated show and hide options.
     389              :  * @param index of selectbox (0 = no clipboard).
     390              :  */
     391            0 : void ConfigDialog::on_comboBoxClipboard_activated(int index) {
     392            0 :   bool state = index > 0;
     393              : 
     394            0 :   ui->checkBoxSelection->setEnabled(state);
     395            0 :   ui->checkBoxAutoclear->setEnabled(state);
     396            0 :   ui->checkBoxHidePassword->setEnabled(state);
     397            0 :   ui->checkBoxHideContent->setEnabled(state);
     398            0 :   if (state) {
     399            0 :     ui->spinBoxAutoclearSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
     400            0 :     ui->labelSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
     401              :   } else {
     402            0 :     ui->spinBoxAutoclearSeconds->setEnabled(false);
     403            0 :     ui->labelSeconds->setEnabled(false);
     404              :   }
     405            0 : }
     406              : 
     407              : /**
     408              :  * @brief ConfigDialog::on_checkBoxAutoclearPanel_clicked enable and disable
     409              :  * options based on autoclear use.
     410              :  */
     411            0 : void ConfigDialog::on_checkBoxAutoclearPanel_clicked() {
     412            0 :   bool state = ui->checkBoxAutoclearPanel->isChecked();
     413            0 :   ui->spinBoxAutoclearPanelSeconds->setEnabled(state);
     414            0 :   ui->labelPanelSeconds->setEnabled(state);
     415            0 : }
     416              : 
     417              : /**
     418              :  * @brief ConfigDialog::useSelection set the clipboard type use from
     419              :  * MainWindow.
     420              :  * @param useSelection
     421              :  */
     422            0 : void ConfigDialog::useSelection(bool useSelection) {
     423            0 :   ui->checkBoxSelection->setChecked(useSelection);
     424            0 :   on_checkBoxSelection_clicked();
     425            0 : }
     426              : 
     427              : /**
     428              :  * @brief ConfigDialog::useAutoclear set the clipboard autoclear use from
     429              :  * MainWindow.
     430              :  * @param useAutoclear
     431              :  */
     432            0 : void ConfigDialog::useAutoclear(bool useAutoclear) {
     433            0 :   ui->checkBoxAutoclear->setChecked(useAutoclear);
     434            0 :   on_checkBoxAutoclear_clicked();
     435            0 : }
     436              : 
     437              : /**
     438              :  * @brief ConfigDialog::useAutoclearPanel set the panel autoclear use from
     439              :  * MainWindow.
     440              :  * @param useAutoclearPanel
     441              :  */
     442            0 : void ConfigDialog::useAutoclearPanel(bool useAutoclearPanel) {
     443            0 :   ui->checkBoxAutoclearPanel->setChecked(useAutoclearPanel);
     444            0 :   on_checkBoxAutoclearPanel_clicked();
     445            0 : }
     446              : 
     447              : /**
     448              :  * @brief ConfigDialog::on_checkBoxSelection_clicked checkbox clicked, update
     449              :  * state via ConfigDialog::on_comboBoxClipboard_activated
     450              :  */
     451            0 : void ConfigDialog::on_checkBoxSelection_clicked() {
     452            0 :   on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
     453            0 : }
     454              : 
     455              : /**
     456              :  * @brief ConfigDialog::on_checkBoxAutoclear_clicked checkbox clicked, update
     457              :  * state via ConfigDialog::on_comboBoxClipboard_activated
     458              :  */
     459            0 : void ConfigDialog::on_checkBoxAutoclear_clicked() {
     460            0 :   on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
     461            0 : }
     462              : 
     463              : /**
     464              :  * @brief ConfigDialog::genKey tunnel function to make MainWindow generate a
     465              :  * gpg key pair.
     466              :  * @todo refactor the process to not be entangled so much.
     467              :  * @param batch
     468              :  * @param dialog
     469              :  */
     470            0 : void ConfigDialog::genKey(const QString &batch, QDialog *dialog) {
     471            0 :   mainWindow->generateKeyPair(batch, dialog);
     472            0 : }
     473              : 
     474              : /**
     475              :  * @brief ConfigDialog::setProfiles set the profiles and chosen profile from
     476              :  * MainWindow.
     477              :  * @param profiles
     478              :  * @param profile
     479              :  */
     480            0 : void ConfigDialog::setProfiles(QHash<QString, QHash<QString, QString>> profiles,
     481              :                                const QString &currentProfile) {
     482              :   // dbg()<< profiles;
     483            0 :   if (profiles.contains("")) {
     484            0 :     profiles.remove("");
     485              :     // remove weird "" key value pairs
     486              :   }
     487              : 
     488            0 :   ui->profileTable->setRowCount(profiles.count());
     489            0 :   QHashIterator<QString, QHash<QString, QString>> i(profiles);
     490              :   int n = 0;
     491            0 :   while (i.hasNext()) {
     492              :     i.next();
     493            0 :     if (!i.value().isEmpty() && !i.key().isEmpty()) {
     494            0 :       ui->profileTable->setItem(n, 0, new QTableWidgetItem(i.key()));
     495            0 :       ui->profileTable->setItem(n, 1,
     496            0 :                                 new QTableWidgetItem(i.value().value("path")));
     497            0 :       ui->profileTable->setItem(
     498            0 :           n, 2, new QTableWidgetItem(i.value().value("signingKey")));
     499              :       // dbg()<< "naam:" + i.key();
     500            0 :       if (i.key() == currentProfile) {
     501            0 :         ui->profileTable->selectRow(n);
     502              :       }
     503              :     }
     504            0 :     ++n;
     505              :   }
     506            0 : }
     507              : 
     508              : /**
     509              :  * @brief ConfigDialog::getProfiles return profile list.
     510              :  * @return
     511              :  */
     512            0 : auto ConfigDialog::getProfiles() -> QHash<QString, QHash<QString, QString>> {
     513            0 :   QHash<QString, QHash<QString, QString>> profiles;
     514              :   // Check?
     515            0 :   for (int i = 0; i < ui->profileTable->rowCount(); ++i) {
     516            0 :     QHash<QString, QString> profile;
     517            0 :     QTableWidgetItem *pathItem = ui->profileTable->item(i, 1);
     518            0 :     if (nullptr != pathItem) {
     519            0 :       QTableWidgetItem *item = ui->profileTable->item(i, 0);
     520            0 :       if (item == nullptr) {
     521              :         continue;
     522              :       }
     523            0 :       profile["path"] = pathItem->text();
     524            0 :       QTableWidgetItem *signingKeyItem = ui->profileTable->item(i, 2);
     525            0 :       if (nullptr != signingKeyItem) {
     526            0 :         profile["signingKey"] = signingKeyItem->text();
     527              :       }
     528            0 :       profiles.insert(item->text(), profile);
     529              :     }
     530            0 :   }
     531            0 :   return profiles;
     532            0 : }
     533              : 
     534              : /**
     535              :  * @brief ConfigDialog::on_addButton_clicked add a profile row.
     536              :  */
     537            0 : void ConfigDialog::on_addButton_clicked() {
     538            0 :   int n = ui->profileTable->rowCount();
     539            0 :   ui->profileTable->insertRow(n);
     540            0 :   ui->profileTable->setItem(n, 0, new QTableWidgetItem());
     541            0 :   ui->profileTable->setItem(n, 1, new QTableWidgetItem(ui->storePath->text()));
     542            0 :   ui->profileTable->setItem(n, 2, new QTableWidgetItem());
     543            0 :   ui->profileTable->selectRow(n);
     544            0 :   ui->deleteButton->setEnabled(true);
     545              : 
     546            0 :   validate();
     547            0 : }
     548              : 
     549              : /**
     550              :  * @brief ConfigDialog::on_deleteButton_clicked remove a profile row.
     551              :  */
     552            0 : void ConfigDialog::on_deleteButton_clicked() {
     553              :   QSet<int> selectedRows; //  we use a set to prevent doubles
     554            0 :   QList<QTableWidgetItem *> itemList = ui->profileTable->selectedItems();
     555            0 :   if (itemList.count() == 0) {
     556            0 :     QMessageBox::warning(this, tr("No profile selected"),
     557            0 :                          tr("No profile selected to delete"));
     558              :     return;
     559              :   }
     560              :   QTableWidgetItem *item;
     561            0 :   foreach (item, itemList)
     562            0 :     selectedRows.insert(item->row());
     563              :   // get a list, and sort it big to small
     564            0 :   QList<int> rows = selectedRows.values();
     565            0 :   std::sort(rows.begin(), rows.end());
     566              :   // now actually do the removing:
     567            0 :   foreach (int row, rows)
     568            0 :     ui->profileTable->removeRow(row);
     569            0 :   if (ui->profileTable->rowCount() < 1) {
     570            0 :     ui->deleteButton->setEnabled(false);
     571              :   }
     572              : 
     573            0 :   validate();
     574              : }
     575              : 
     576              : /**
     577              :  * @brief ConfigDialog::criticalMessage weapper for showing critical messages
     578              :  * in a popup.
     579              :  * @param title
     580              :  * @param text
     581              :  */
     582            0 : void ConfigDialog::criticalMessage(const QString &title, const QString &text) {
     583            0 :   QMessageBox::critical(this, title, text, QMessageBox::Ok, QMessageBox::Ok);
     584            0 : }
     585              : 
     586            0 : auto ConfigDialog::isQrencodeAvailable() -> bool {
     587              : #ifdef Q_OS_WIN
     588              :   return false;
     589              : #else
     590            0 :   QProcess which;
     591            0 :   which.start("which", QStringList() << "qrencode");
     592            0 :   which.waitForFinished();
     593            0 :   QtPassSettings::setQrencodeExecutable(
     594            0 :       which.readAllStandardOutput().trimmed());
     595            0 :   return which.exitCode() == 0;
     596              : #endif
     597            0 : }
     598              : 
     599            0 : auto ConfigDialog::isPassOtpAvailable() -> bool {
     600              : #ifdef Q_OS_WIN
     601              :   return false;
     602              : #else
     603            0 :   QProcess pass;
     604            0 :   pass.start(QtPassSettings::getPassExecutable(), QStringList() << "otp"
     605            0 :                                                                 << "--help");
     606            0 :   pass.waitForFinished(2000);
     607            0 :   return pass.exitCode() == 0;
     608              : #endif
     609            0 : }
     610              : 
     611              : /**
     612              :  * @brief ConfigDialog::wizard first-time use wizard.
     613              :  * @todo make this thing more reliable.
     614              :  */
     615            0 : void ConfigDialog::wizard() {
     616            0 :   Util::checkConfig();
     617            0 :   on_autodetectButton_clicked();
     618              : 
     619            0 :   if (!checkGpgExistence()) {
     620              :     return;
     621              :   }
     622            0 :   if (!checkSecretKeys()) {
     623              :     return;
     624              :   }
     625            0 :   if (!checkPasswordStore()) {
     626              :     return;
     627              :   }
     628            0 :   handleGpgIdFile();
     629              : 
     630            0 :   ui->checkBoxHidePassword->setCheckState(Qt::Checked);
     631              : }
     632              : 
     633            0 : auto ConfigDialog::checkGpgExistence() -> bool {
     634            0 :   QString gpg = ui->gpgPath->text();
     635            0 :   if (!gpg.startsWith("wsl ") && !QFile(gpg).exists()) {
     636            0 :     criticalMessage(
     637            0 :         tr("GnuPG not found"),
     638              : #ifdef Q_OS_WIN
     639              : #ifdef WINSTORE
     640              :         tr("Please install GnuPG on your system.<br>Install "
     641              :            "<strong>Ubuntu</strong> from the Microsoft Store to get it.<br>"
     642              :            "If you already did so, make sure you started it once and<br>"
     643              :            "click \"Autodetect\" in the next dialog.")
     644              : #else
     645              :         tr("Please install GnuPG on your system.<br>Install "
     646              :            "<strong>Ubuntu</strong> from the Microsoft Store<br>or <a "
     647              :            "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
     648              :            "from GnuPG.org")
     649              : #endif
     650              : #else
     651            0 :         tr("Please install GnuPG on your system.<br>Install "
     652              :            "<strong>gpg</strong> using your favorite package manager<br>or "
     653              :            "<a "
     654              :            "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
     655              :            "from GnuPG.org")
     656              : #endif
     657              :     );
     658            0 :     return false;
     659              :   }
     660              :   return true;
     661              : }
     662              : 
     663            0 : auto ConfigDialog::checkSecretKeys() -> bool {
     664            0 :   QString gpg = ui->gpgPath->text();
     665            0 :   QStringList names = getSecretKeys();
     666              : 
     667              : #ifdef QT_DEBUG
     668              :   dbg() << names;
     669              : #endif
     670              : 
     671            0 :   if ((gpg.startsWith("wsl ") || QFile(gpg).exists()) && names.empty()) {
     672            0 :     KeygenDialog d(this);
     673            0 :     return d.exec();
     674            0 :   }
     675              :   return true;
     676              : }
     677              : 
     678            0 : auto ConfigDialog::checkPasswordStore() -> bool {
     679            0 :   QString passStore = ui->storePath->text();
     680              : 
     681            0 :   if (!QFile(passStore).exists()) {
     682            0 :     if (QMessageBox::question(
     683            0 :             this, tr("Create password-store?"),
     684            0 :             tr("Would you like to create a password-store at %1?")
     685            0 :                 .arg(passStore),
     686              :             QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
     687            0 :       if (!QDir().mkdir(passStore)) {
     688            0 :         QMessageBox::warning(
     689            0 :             this, tr("Error"),
     690            0 :             tr("Failed to create password-store at: %1").arg(passStore));
     691            0 :         return false;
     692              :       }
     693              : #ifdef Q_OS_WIN
     694              :       SetFileAttributes(passStore.toStdWString().c_str(),
     695              :                         FILE_ATTRIBUTE_HIDDEN);
     696              : #endif
     697            0 :       if (ui->checkBoxUseGit->isChecked()) {
     698            0 :         emit mainWindow->passGitInitNeeded();
     699              :       }
     700            0 :       mainWindow->userDialog(passStore);
     701              :     }
     702              :   }
     703              :   return true;
     704              : }
     705              : 
     706            0 : void ConfigDialog::handleGpgIdFile() {
     707            0 :   QString passStore = ui->storePath->text();
     708            0 :   if (!QFile(QDir(passStore).filePath(".gpg-id")).exists()) {
     709              : #ifdef QT_DEBUG
     710              :     dbg() << ".gpg-id file does not exist";
     711              : #endif
     712            0 :     criticalMessage(tr("Password store not initialised"),
     713            0 :                     tr("The folder %1 doesn't seem to be a password store or "
     714              :                        "is not yet initialised.")
     715            0 :                         .arg(passStore));
     716              : 
     717            0 :     while (!QFile(passStore).exists()) {
     718            0 :       on_toolButtonStore_clicked();
     719            0 :       if (passStore == ui->storePath->text()) {
     720              :         return;
     721              :       }
     722            0 :       passStore = ui->storePath->text();
     723              :     }
     724            0 :     if (!QFile(passStore + ".gpg-id").exists()) {
     725              : #ifdef QT_DEBUG
     726              :       dbg() << ".gpg-id file still does not exist :/";
     727              : #endif
     728            0 :       mainWindow->userDialog(passStore);
     729              :     }
     730              :   }
     731              : }
     732              : 
     733              : /**
     734              :  * @brief ConfigDialog::useTrayIcon set preference for using trayicon.
     735              :  * Enable or disable related checkboxes accordingly.
     736              :  * @param useSystray
     737              :  */
     738            0 : void ConfigDialog::useTrayIcon(bool useSystray) {
     739            0 :   if (QSystemTrayIcon::isSystemTrayAvailable()) {
     740            0 :     ui->checkBoxUseTrayIcon->setChecked(useSystray);
     741            0 :     ui->checkBoxHideOnClose->setEnabled(useSystray);
     742            0 :     ui->checkBoxStartMinimized->setEnabled(useSystray);
     743              : 
     744            0 :     if (!useSystray) {
     745            0 :       ui->checkBoxHideOnClose->setChecked(false);
     746            0 :       ui->checkBoxStartMinimized->setChecked(false);
     747              :     }
     748              :   }
     749            0 : }
     750              : 
     751              : /**
     752              :  * @brief ConfigDialog::on_checkBoxUseTrayIcon_clicked enable and disable
     753              :  * related checkboxes.
     754              :  */
     755            0 : void ConfigDialog::on_checkBoxUseTrayIcon_clicked() {
     756            0 :   bool state = ui->checkBoxUseTrayIcon->isChecked();
     757            0 :   ui->checkBoxHideOnClose->setEnabled(state);
     758            0 :   ui->checkBoxStartMinimized->setEnabled(state);
     759            0 : }
     760              : 
     761              : /**
     762              :  * @brief ConfigDialog::closeEvent close this window.
     763              :  * @param event
     764              :  */
     765            0 : void ConfigDialog::closeEvent(QCloseEvent *event) {
     766              :   // TODO(annejan): save window size or something?
     767              :   event->accept();
     768            0 : }
     769              : 
     770              : /**
     771              :  * @brief ConfigDialog::useGit set preference for using git.
     772              :  * @param useGit
     773              :  */
     774            0 : void ConfigDialog::useGit(bool useGit) {
     775            0 :   ui->checkBoxUseGit->setChecked(useGit);
     776            0 :   on_checkBoxUseGit_clicked();
     777            0 : }
     778              : 
     779              : /**
     780              :  * @brief ConfigDialog::useOtp set preference for using otp plugin.
     781              :  * @param useOtp
     782              :  */
     783            0 : void ConfigDialog::useOtp(bool useOtp) {
     784            0 :   ui->checkBoxUseOtp->setChecked(useOtp);
     785            0 : }
     786              : 
     787              : /**
     788              :  * @brief ConfigDialog::useOtp set preference for using otp plugin.
     789              :  * @param useOtp
     790              :  */
     791            0 : void ConfigDialog::useQrencode(bool useQrencode) {
     792            0 :   ui->checkBoxUseQrencode->setChecked(useQrencode);
     793            0 : }
     794              : 
     795              : /**
     796              :  * @brief ConfigDialog::on_checkBoxUseGit_clicked enable or disable related
     797              :  * checkboxes.
     798              :  */
     799            0 : void ConfigDialog::on_checkBoxUseGit_clicked() {
     800            0 :   ui->checkBoxAddGPGId->setEnabled(ui->checkBoxUseGit->isChecked());
     801            0 :   ui->checkBoxAutoPull->setEnabled(ui->checkBoxUseGit->isChecked());
     802            0 :   ui->checkBoxAutoPush->setEnabled(ui->checkBoxUseGit->isChecked());
     803            0 : }
     804              : 
     805              : /**
     806              :  * @brief ConfigDialog::on_toolButtonPwgen_clicked enable or disable related
     807              :  * options in the interface.
     808              :  */
     809            0 : void ConfigDialog::on_toolButtonPwgen_clicked() {
     810            0 :   QString pwgen = selectExecutable();
     811            0 :   if (!pwgen.isEmpty()) {
     812            0 :     ui->pwgenPath->setText(pwgen);
     813            0 :     ui->checkBoxUsePwgen->setEnabled(true);
     814              :   } else {
     815            0 :     ui->checkBoxUsePwgen->setEnabled(false);
     816            0 :     ui->checkBoxUsePwgen->setChecked(false);
     817              :   }
     818            0 : }
     819              : 
     820              : /**
     821              :  * @brief ConfigDialog::setPwgenPath set pwgen executable path.
     822              :  * Enable or disable related options in the interface.
     823              :  * @param pwgen
     824              :  */
     825            0 : void ConfigDialog::setPwgenPath(const QString &pwgen) {
     826            0 :   ui->pwgenPath->setText(pwgen);
     827            0 :   if (pwgen.isEmpty()) {
     828            0 :     ui->checkBoxUsePwgen->setChecked(false);
     829            0 :     ui->checkBoxUsePwgen->setEnabled(false);
     830              :   }
     831            0 :   on_checkBoxUsePwgen_clicked();
     832            0 : }
     833              : 
     834              : /**
     835              :  * @brief ConfigDialog::on_checkBoxUsPwgen_clicked enable or disable related
     836              :  * options in the interface.
     837              :  */
     838            0 : void ConfigDialog::on_checkBoxUsePwgen_clicked() {
     839            0 :   bool usePwgen = ui->checkBoxUsePwgen->isChecked();
     840            0 :   ui->checkBoxAvoidCapitals->setEnabled(usePwgen);
     841            0 :   ui->checkBoxAvoidNumbers->setEnabled(usePwgen);
     842            0 :   ui->checkBoxLessRandom->setEnabled(usePwgen);
     843            0 :   ui->checkBoxUseSymbols->setEnabled(usePwgen);
     844            0 :   ui->lineEditPasswordChars->setEnabled(!usePwgen);
     845            0 :   ui->labelPasswordChars->setEnabled(!usePwgen);
     846            0 :   ui->passwordCharTemplateSelector->setEnabled(!usePwgen);
     847            0 : }
     848              : 
     849              : /**
     850              :  * @brief ConfigDialog::usePwgen set preference for using pwgen (can be
     851              :  * overruled buy empty pwgenPath).
     852              :  * enable or disable related options in the interface via
     853              :  * ConfigDialog::on_checkBoxUsePwgen_clicked
     854              :  * @param usePwgen
     855              :  */
     856            0 : void ConfigDialog::usePwgen(bool usePwgen) {
     857            0 :   if (ui->pwgenPath->text().isEmpty()) {
     858              :     usePwgen = false;
     859              :   }
     860            0 :   ui->checkBoxUsePwgen->setChecked(usePwgen);
     861            0 :   on_checkBoxUsePwgen_clicked();
     862            0 : }
     863              : 
     864            0 : void ConfigDialog::setPasswordConfiguration(
     865              :     const PasswordConfiguration &config) {
     866            0 :   ui->spinBoxPasswordLength->setValue(config.length);
     867            0 :   ui->passwordCharTemplateSelector->setCurrentIndex(config.selected);
     868            0 :   if (config.selected != PasswordConfiguration::CUSTOM) {
     869            0 :     ui->lineEditPasswordChars->setEnabled(false);
     870              :   }
     871            0 :   ui->lineEditPasswordChars->setText(config.Characters[config.selected]);
     872            0 : }
     873              : 
     874            0 : auto ConfigDialog::getPasswordConfiguration() -> PasswordConfiguration {
     875            0 :   PasswordConfiguration config;
     876            0 :   config.length = ui->spinBoxPasswordLength->value();
     877            0 :   config.selected = static_cast<PasswordConfiguration::characterSet>(
     878            0 :       ui->passwordCharTemplateSelector->currentIndex());
     879              :   config.Characters[PasswordConfiguration::CUSTOM] =
     880            0 :       ui->lineEditPasswordChars->text();
     881            0 :   return config;
     882            0 : }
     883              : 
     884              : /**
     885              :  * @brief ConfigDialog::on_passwordCharTemplateSelector_activated sets the
     886              :  * passwordChar Template
     887              :  * combo box to the desired entry
     888              :  * @param entry of
     889              :  */
     890            0 : void ConfigDialog::on_passwordCharTemplateSelector_activated(int index) {
     891            0 :   ui->lineEditPasswordChars->setText(
     892            0 :       QtPassSettings::getPasswordConfiguration().Characters[index]);
     893            0 :   if (index == 3) {
     894            0 :     ui->lineEditPasswordChars->setEnabled(true);
     895              :   } else {
     896            0 :     ui->lineEditPasswordChars->setEnabled(false);
     897              :   }
     898            0 : }
     899              : 
     900              : /**
     901              :  * @brief ConfigDialog::on_checkBoxUseTemplate_clicked enable or disable the
     902              :  * template field and options.
     903              :  */
     904            0 : void ConfigDialog::on_checkBoxUseTemplate_clicked() {
     905            0 :   ui->plainTextEditTemplate->setEnabled(ui->checkBoxUseTemplate->isChecked());
     906            0 :   ui->checkBoxTemplateAllFields->setEnabled(
     907            0 :       ui->checkBoxUseTemplate->isChecked());
     908            0 : }
     909              : 
     910            0 : void ConfigDialog::onProfileTableItemChanged(QTableWidgetItem *item) {
     911            0 :   validate(item);
     912            0 : }
     913              : 
     914              : /**
     915              :  * @brief ConfigDialog::useTemplate set preference for using templates.
     916              :  * @param useTemplate
     917              :  */
     918            0 : void ConfigDialog::useTemplate(bool useTemplate) {
     919            0 :   ui->checkBoxUseTemplate->setChecked(useTemplate);
     920            0 :   on_checkBoxUseTemplate_clicked();
     921            0 : }
        

Generated by: LCOV version 2.4-beta