QtPass  1.2.1
Multi-platform GUI for pass, the standard unix password manager.
mainwindow.cpp
Go to the documentation of this file.
1 #include "mainwindow.h"
2 #include "debughelper.h"
3 #include <QClipboard>
4 #include <QCloseEvent>
5 #include <QDesktopServices>
6 #include <QFileInfo>
7 #include <QInputDialog>
8 #include <QLabel>
9 #include <QMenu>
10 #include <QMessageBox>
11 #include <QQueue>
12 #include <QShortcut>
13 #include <QSystemTrayIcon>
14 #include <QTextCodec>
15 #ifdef Q_OS_WIN
16 #define WIN32_LEAN_AND_MEAN /*_KILLING_MACHINE*/
17 #define WIN32_EXTRA_LEAN
18 #include <windows.h>
19 #include <winnetwk.h>
20 #undef DELETE
21 #endif
22 #include "configdialog.h"
23 #include "filecontent.h"
24 #include "keygendialog.h"
25 #include "passworddialog.h"
27 #include "qtpasssettings.h"
28 #include "settingsconstants.h"
29 #include "trayicon.h"
30 #include "ui_mainwindow.h"
31 #include "usersdialog.h"
32 #include "util.h"
33 
34 #if SINGLE_APP
35 #include "singleapplication.h"
36 #endif
37 
43 MainWindow::MainWindow(QWidget *parent)
44  : QMainWindow(parent), ui(new Ui::MainWindow), fusedav(this), keygen(NULL),
45  tray(NULL) {
46 #ifdef __APPLE__
47  // extra treatment for mac os
48  // see http://doc.qt.io/qt-5/qkeysequence.html#qt_set_sequence_auto_mnemonic
49  qt_set_sequence_auto_mnemonic(true);
50 #endif
51  // register shortcut ctrl/cmd + Q to close the main window
52  new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this, SLOT(close()));
53  // register shortcut ctrl/cmd + C to copy the currently selected password
54  new QShortcut(QKeySequence(QKeySequence::StandardKey::Copy), this,
55  SLOT(copyPasswordFromTreeview()));
56 
57  // TODO(bezet): this should be reconnected dynamically when pass changes
58  connectPassSignalHandlers(QtPassSettings::getRealPass());
59  connectPassSignalHandlers(QtPassSettings::getImitatePass());
60 
61  // only for ipass
62  connect(QtPassSettings::getImitatePass(), SIGNAL(startReencryptPath()), this,
63  SLOT(startReencryptPath()));
64  connect(QtPassSettings::getImitatePass(), SIGNAL(endReencryptPath()), this,
65  SLOT(endReencryptPath()));
66 
67  ui->setupUi(this);
68  enableUiElements(true);
69  ui->statusBar->showMessage(tr("Welcome to QtPass %1").arg(VERSION), 2000);
70  freshStart = true;
71  startupPhase = true;
72  clearPanelTimer.setSingleShot(true);
73  connect(&clearPanelTimer, SIGNAL(timeout()), this, SLOT(clearPanel()));
74  clearClipboardTimer.setSingleShot(true);
75  connect(&clearClipboardTimer, SIGNAL(timeout()), this,
76  SLOT(clearClipboard()));
77  if (!checkConfig()) {
78  // no working config
79  QApplication::quit();
80  }
81  clippedText = "";
82  QTimer::singleShot(10, this, SLOT(focusInput()));
83 
84  initAddButton();
85 
86  qsrand(static_cast<uint>(QTime::currentTime().msec()));
87 
88 #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
89  ui->lineEdit->setClearButtonEnabled(true);
90 #endif
91 }
92 
99 void MainWindow::focusInput() {
100  ui->lineEdit->selectAll();
101  ui->lineEdit->setFocus();
102 }
103 
108 #ifdef Q_OS_WIN
110  WNetCancelConnection2A(QtPassSettings::getPassStore().toUtf8().constData(),
111  0, 1);
112 #else
113  if (fusedav.state() == QProcess::Running) {
114  fusedav.terminate();
115  fusedav.waitForFinished(2000);
116  }
117 #endif
118 }
119 
124 void MainWindow::changeEvent(QEvent *event) {
125  QWidget::changeEvent(event);
126  if (event->type() == QEvent::ActivationChange) {
127  if (this->isActiveWindow()) {
128  ui->lineEdit->selectAll();
129  ui->lineEdit->setFocus();
130  }
131  }
132 }
133 
141 void MainWindow::connectPassSignalHandlers(Pass *pass) {
142 
143  // TODO(bezet): this is never emitted(should be), also naming(see
144  // critical())
145  connect(pass, &Pass::error, this, &MainWindow::processError);
146  connect(pass, &Pass::startingExecuteWrapper, this,
147  &MainWindow::executeWrapperStarted);
148  connect(pass, &Pass::critical, this, &MainWindow::critical);
149  connect(pass, &Pass::statusMsg, this, &MainWindow::showStatusMessage);
150  connect(pass, &Pass::processErrorExit, this, &MainWindow::processErrorExit);
151 
152  connect(pass, &Pass::finishedGitInit, this, &MainWindow::passStoreChanged);
153  connect(pass, &Pass::finishedGitPull, this, &MainWindow::processFinished);
154  connect(pass, &Pass::finishedGitPush, this, &MainWindow::processFinished);
155  connect(pass, &Pass::finishedShow, this, &MainWindow::passShowHandler);
156  connect(pass, &Pass::finishedInsert, this, &MainWindow::finishedInsert);
157  connect(pass, &Pass::finishedRemove, this, &MainWindow::passStoreChanged);
158  connect(pass, &Pass::finishedInit, this, &MainWindow::passStoreChanged);
159  connect(pass, &Pass::finishedMove, this, &MainWindow::passStoreChanged);
160  connect(pass, &Pass::finishedCopy, this, &MainWindow::passStoreChanged);
161 
162  connect(pass, &Pass::finishedGenerateGPGKeys, this,
163  &MainWindow::keyGenerationComplete);
164 }
165 
169 void MainWindow::mountWebDav() {
170 #ifdef Q_OS_WIN
171  char dst[20] = {0};
172  NETRESOURCEA netres;
173  memset(&netres, 0, sizeof(netres));
174  netres.dwType = RESOURCETYPE_DISK;
175  netres.lpLocalName = 0;
176  netres.lpRemoteName = QtPassSettings::getWebDavUrl().toUtf8().data();
177  DWORD size = sizeof(dst);
178  DWORD r = WNetUseConnectionA(
179  reinterpret_cast<HWND>(effectiveWinId()), &netres,
180  QtPassSettings::getWebDavPassword().toUtf8().constData(),
181  QtPassSettings::getWebDavUser().toUtf8().constData(),
182  CONNECT_TEMPORARY | CONNECT_INTERACTIVE | CONNECT_REDIRECT, dst, &size,
183  0);
184  if (r == NO_ERROR) {
186  } else {
187  char message[256] = {0};
188  FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, r, 0, message,
189  sizeof(message), 0);
190  ui->textBrowser->setTextColor(Qt::red);
191  ui->textBrowser->setText(tr("Failed to connect WebDAV:\n") + message +
192  " (0x" + QString::number(r, 16) + ")");
193  ui->textBrowser->setTextColor(Qt::black);
194  }
195 #else
196  fusedav.start("fusedav -o nonempty -u \"" + QtPassSettings::getWebDavUser() +
197  "\" " + QtPassSettings::getWebDavUrl() + " \"" +
199  fusedav.waitForStarted();
200  if (fusedav.state() == QProcess::Running) {
201  QString pwd = QtPassSettings::getWebDavPassword();
202  bool ok = true;
203  if (pwd.isEmpty()) {
204  pwd = QInputDialog::getText(this, tr("QtPass WebDAV password"),
205  tr("Enter password to connect to WebDAV:"),
206  QLineEdit::Password, "", &ok);
207  }
208  if (ok && !pwd.isEmpty()) {
209  fusedav.write(pwd.toUtf8() + '\n');
210  fusedav.closeWriteChannel();
211  fusedav.waitForFinished(2000);
212  } else {
213  fusedav.terminate();
214  }
215  }
216  QString error = fusedav.readAllStandardError();
217  int prompt = error.indexOf("Password:");
218  if (prompt >= 0)
219  error.remove(0, prompt + 10);
220  if (fusedav.state() != QProcess::Running)
221  error = tr("fusedav exited unexpectedly\n") + error;
222  if (error.size() > 0) {
223  ui->textBrowser->setTextColor(Qt::red);
224  ui->textBrowser->setText(
225  tr("Failed to start fusedav to connect WebDAV:\n") + error);
226  ui->textBrowser->setTextColor(Qt::black);
227  }
228 #endif
229 }
230 
236  QString version = QtPassSettings::getVersion();
237 
238  if (freshStart) {
239  restoreWindow();
240  }
241 
243  QtPassSettings::setPassStore(passStore);
244 
246 
248  Qt::WindowFlags flags = windowFlags();
249  this->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
250  this->show();
251  }
252 
253  if (QtPassSettings::isUseTrayIcon() && tray == NULL) {
254  initTrayIcon();
255  if (freshStart && QtPassSettings::isStartMinimized()) {
256  // since we are still in constructor, can't directly hide
257  QTimer::singleShot(10, this, SLOT(hide()));
258  }
259  } else if (!QtPassSettings::isUseTrayIcon() && tray != NULL) {
260  destroyTrayIcon();
261  }
262 
263  // dbg()<< version;
264 
265  // Config updates
266  if (version.isEmpty()) {
267  dbg() << "assuming fresh install";
272  if (!QtPassSettings::getPwgenExecutable().isEmpty())
274  else
276  QtPassSettings::setPassTemplate("login\nurl");
277  } else {
278  // QStringList ver = version.split(".");
279  // dbg()<< ver;
280  // if (ver[0] == "0" && ver[1] == "8") {
282  // }
283  if (QtPassSettings::getPassTemplate().isEmpty())
284  QtPassSettings::setPassTemplate("login\nurl");
285  }
286 
288 
289  if (Util::checkConfig()) {
290  config();
291  if (freshStart && Util::checkConfig())
292  return false;
293  }
294 
295  freshStart = false;
296 
297  // TODO(annejan): this needs to be before we try to access the store,
298  // but it would be better to do it after the Window is shown,
299  // as the long delay it can cause is irritating otherwise.
301  mountWebDav();
302 
303  model.setNameFilters(QStringList() << "*.gpg");
304  model.setNameFilterDisables(false);
305 
306  proxyModel.setSourceModel(&model);
307  proxyModel.setModelAndStore(&model, QtPassSettings::getPassStore());
308  selectionModel.reset(new QItemSelectionModel(&proxyModel));
309  model.fetchMore(model.setRootPath(QtPassSettings::getPassStore()));
310  model.sort(0, Qt::AscendingOrder);
311 
312  ui->treeView->setModel(&proxyModel);
313  ui->treeView->setRootIndex(proxyModel.mapFromSource(
314  model.setRootPath(QtPassSettings::getPassStore())));
315  ui->treeView->setColumnHidden(1, true);
316  ui->treeView->setColumnHidden(2, true);
317  ui->treeView->setColumnHidden(3, true);
318  ui->treeView->setHeaderHidden(true);
319  ui->treeView->setIndentation(15);
320  ui->treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
321  ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
322  connect(ui->treeView, SIGNAL(customContextMenuRequested(const QPoint &)),
323  this, SLOT(showContextMenu(const QPoint &)));
324  connect(ui->treeView, SIGNAL(emptyClicked()), this, SLOT(deselect()));
325  ui->textBrowser->setOpenExternalLinks(true);
326  ui->textBrowser->setContextMenuPolicy(Qt::CustomContextMenu);
327  connect(ui->textBrowser, SIGNAL(customContextMenuRequested(const QPoint &)),
328  this, SLOT(showBrowserContextMenu(const QPoint &)));
329 
330  updateProfileBox();
332  clearPanelTimer.setInterval(1000 *
334  clearClipboardTimer.setInterval(1000 * QtPassSettings::getAutoclearSeconds());
335  updateGitButtonVisibility();
336 
337  startupPhase = false;
338  return true;
339 }
340 
346  QScopedPointer<ConfigDialog> d(new ConfigDialog(this));
347  d->setModal(true);
348  // Automatically default to pass if it's available
349  if (freshStart && QFile(QtPassSettings::getPassExecutable()).exists()) {
351  }
352 
353  d->setPassPath(QtPassSettings::getPassExecutable());
354  d->setGitPath(QtPassSettings::getGitExecutable());
355  d->setGpgPath(QtPassSettings::getGpgExecutable());
356  d->setStorePath(QtPassSettings::getPassStore());
357  d->usePass(QtPassSettings::isUsePass());
358  d->useClipboard(QtPassSettings::getClipBoardType());
359  d->useSelection(QtPassSettings::isUseSelection());
360  d->useAutoclear(QtPassSettings::isUseAutoclear());
361  d->setAutoclear(QtPassSettings::getAutoclearSeconds());
362  d->useAutoclearPanel(QtPassSettings::isUseAutoclearPanel());
363  d->setAutoclearPanel(QtPassSettings::getAutoclearPanelSeconds());
364  d->hidePassword(QtPassSettings::isHidePassword());
365  d->hideContent(QtPassSettings::isHideContent());
366  d->addGPGId(QtPassSettings::isAddGPGId(true));
367  d->useTrayIcon(QtPassSettings::isUseTrayIcon());
368  d->hideOnClose(QtPassSettings::isHideOnClose());
369  d->startMinimized(QtPassSettings::isStartMinimized());
371  d->useGit(QtPassSettings::isUseGit());
372  d->setPwgenPath(QtPassSettings::getPwgenExecutable());
373  d->usePwgen(QtPassSettings::isUsePwgen());
374  d->avoidCapitals(QtPassSettings::isAvoidCapitals());
375  d->avoidNumbers(QtPassSettings::isAvoidNumbers());
376  d->lessRandom(QtPassSettings::isLessRandom());
377  d->useSymbols(QtPassSettings::isUseSymbols());
378  d->setPasswordConfiguration(QtPassSettings::getPasswordConfiguration());
379  d->useTemplate(QtPassSettings::isUseTemplate());
380  d->setTemplate(QtPassSettings::getPassTemplate());
381  d->templateAllFields(QtPassSettings::isTemplateAllFields());
382  d->autoPull(QtPassSettings::isAutoPull());
383  d->autoPush(QtPassSettings::isAutoPush());
384  d->alwaysOnTop(QtPassSettings::isAlwaysOnTop());
385  if (startupPhase)
386  d->wizard(); // does shit
387  if (d->exec()) {
388  if (d->result() == QDialog::Accepted) {
389  QtPassSettings::setPassExecutable(d->getPassPath());
390  QtPassSettings::setGitExecutable(d->getGitPath());
391  QtPassSettings::setGpgExecutable(d->getGpgPath());
393  Util::normalizeFolderPath(d->getStorePath()));
394  QtPassSettings::setUsePass(d->usePass());
395  QtPassSettings::setClipBoardType(d->useClipboard());
396  QtPassSettings::setUseSelection(d->useSelection());
397  QtPassSettings::setUseAutoclear(d->useAutoclear());
398  QtPassSettings::setAutoclearSeconds(d->getAutoclear());
399  QtPassSettings::setUseAutoclearPanel(d->useAutoclearPanel());
400  QtPassSettings::setAutoclearPanelSeconds(d->getAutoclearPanel());
401  QtPassSettings::setHidePassword(d->hidePassword());
402  QtPassSettings::setHideContent(d->hideContent());
403  QtPassSettings::setAddGPGId(d->addGPGId());
404  QtPassSettings::setUseTrayIcon(d->useTrayIcon());
405  QtPassSettings::setHideOnClose(d->hideOnClose());
406  QtPassSettings::setStartMinimized(d->startMinimized());
407  QtPassSettings::setProfiles(d->getProfiles());
408  QtPassSettings::setUseGit(d->useGit());
409  QtPassSettings::setPwgenExecutable(d->getPwgenPath());
410  QtPassSettings::setUsePwgen(d->usePwgen());
411  QtPassSettings::setAvoidCapitals(d->avoidCapitals());
412  QtPassSettings::setAvoidNumbers(d->avoidNumbers());
413  QtPassSettings::setLessRandom(d->lessRandom());
414  QtPassSettings::setUseSymbols(d->useSymbols());
415  QtPassSettings::setPasswordConfiguration(d->getPasswordConfiguration());
416  QtPassSettings::setUseTemplate(d->useTemplate());
417  QtPassSettings::setPassTemplate(d->getTemplate());
418  QtPassSettings::setTemplateAllFields(d->templateAllFields());
419  QtPassSettings::setAutoPush(d->autoPush());
420  QtPassSettings::setAutoPull(d->autoPull());
421  QtPassSettings::setAlwaysOnTop(d->alwaysOnTop());
422 
424 
426  Qt::WindowFlags flags = windowFlags();
427  this->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
428  this->show();
429  } else {
430  this->setWindowFlags(Qt::Window);
431  this->show();
432  }
433 
434  updateProfileBox();
435  ui->treeView->setRootIndex(proxyModel.mapFromSource(
436  model.setRootPath(QtPassSettings::getPassStore())));
437 
438  if (freshStart && Util::checkConfig())
439  config();
441  clearPanelTimer.setInterval(1000 *
443  clearClipboardTimer.setInterval(1000 *
445 
446  updateGitButtonVisibility();
447  if (QtPassSettings::isUseTrayIcon() && tray == NULL)
448  initTrayIcon();
449  else if (!QtPassSettings::isUseTrayIcon() && tray != NULL)
450  destroyTrayIcon();
451  }
452  freshStart = false;
453  }
454 }
455 
459 void MainWindow::on_updateButton_clicked(bool block) {
460  ui->statusBar->showMessage(tr("Updating password-store"), 2000);
461  if (block)
463  else
465 }
466 
470 void MainWindow::on_pushButton_clicked() {
471  if (QtPassSettings::isUseGit()) {
472  ui->statusBar->showMessage(tr("Updating password-store"), 2000);
474  }
475 }
476 
484 QString MainWindow::getFile(const QModelIndex &index, bool forPass) {
485  if (!index.isValid() ||
486  !model.fileInfo(proxyModel.mapToSource(index)).isFile())
487  return QString();
488  QString filePath = model.filePath(proxyModel.mapToSource(index));
489  if (forPass) {
490  filePath = QDir(QtPassSettings::getPassStore()).relativeFilePath(filePath);
491  filePath.replace(QRegExp("\\.gpg$"), "");
492  }
493  return filePath;
494 }
495 
500 void MainWindow::on_treeView_clicked(const QModelIndex &index) {
501  bool cleared = ui->treeView->currentIndex().flags() == Qt::NoItemFlags;
502  currentDir =
503  Util::getDir(ui->treeView->currentIndex(), false, model, proxyModel);
504  // TODO(bezet): "Could not decrypt";
505  clippedText = "";
506  QString file = getFile(index, true);
507  ui->passwordName->setText(getFile(index, true));
508  if (!file.isEmpty() && !cleared) {
509  QtPassSettings::getPass()->Show(file);
510  } else {
511  clearPanel(false);
512  ui->editButton->setEnabled(false);
513  ui->deleteButton->setEnabled(true);
514  }
515 }
516 
522 void MainWindow::on_treeView_doubleClicked(const QModelIndex &index) {
523  QFileInfo fileOrFolder =
524  model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
525 
526  if (fileOrFolder.isFile()) {
527  editPassword(getFile(index, true));
528  }
529 }
530 
535  currentDir = "/";
536  clearClipboard();
537  ui->passwordName->setText("");
538  clearPanel(false);
539 }
540 
545  dbg() << "Pass git init called";
547 }
548 
549 void MainWindow::executeWrapperStarted() {
550  clearTemplateWidgets();
551  ui->textBrowser->clear();
552  enableUiElements(false);
553  clearPanelTimer.stop();
554 }
555 
556 void MainWindow::keyGenerationComplete(const QString &p_output,
557  const QString &p_errout) {
558  // qDebug() << p_output;
559  // qDebug() << p_errout;
560  if (0 != keygen) {
561  qDebug() << "Keygen Done";
562  keygen->close();
563  keygen = 0;
564  // TODO(annejan) some sanity checking ?
565  }
566  processFinished(p_output, p_errout);
567 }
568 
569 void MainWindow::initAddButton() {
570  // Add a Actions to the Add-Button
571  QIcon addFileIcon = QIcon::fromTheme("file_new");
572  QIcon addFolderIcon = QIcon::fromTheme("folder_new");
573  QAction *actionAddPassword =
574  new QAction(addFileIcon, tr("Add Password"), this);
575  QAction *actionAddFolder = new QAction(addFolderIcon, tr("Add Folder"), this);
576 
577  ui->addButton->addAction(actionAddPassword);
578  ui->addButton->addAction(actionAddFolder);
579 
580  connect(actionAddPassword, SIGNAL(triggered()), this,
581  SLOT(on_addButton_clicked()));
582  connect(actionAddFolder, SIGNAL(triggered()), this, SLOT(addFolder()));
583 }
584 
585 void MainWindow::passShowHandler(const QString &p_output) {
586  QStringList templ = QtPassSettings::isUseTemplate()
587  ? QtPassSettings::getPassTemplate().split("\n")
588  : QStringList();
589  bool allFields =
591  FileContent fileContent = FileContent::parse(p_output, templ, allFields);
592  QString output = p_output;
593  QString password = fileContent.getPassword();
594 
595  // handle clipboard
597  !p_output.isEmpty()) {
598  clippedText = password;
600  copyTextToClipboard(password);
601  }
602 
603  // first clear the current view:
604  clearTemplateWidgets();
605 
606  // show what is needed:
608  output = "***" + tr("Content hidden") + "***";
609  } else {
610  if (!password.isEmpty()) {
611  // set the password, it is hidden if needed in addToGridLayout
612  addToGridLayout(0, tr("Password"), password);
613  }
614 
615  NamedValues namedValues = fileContent.getNamedValues();
616  for (int j = 0; j < namedValues.length(); ++j) {
617  NamedValue nv = namedValues.at(j);
618  addToGridLayout(j + 1, nv.name, nv.value);
619  }
620  if (ui->gridLayout->count() == 0)
621  ui->verticalLayoutPassword->setSpacing(0);
622  else
623  ui->verticalLayoutPassword->setSpacing(6);
624  output = fileContent.getRemainingData();
625  }
626 
628  clearPanelTimer.start();
629  }
630 
631  DisplayInTextBrowser(output);
632  enableUiElements(true);
633 }
634 
635 void MainWindow::passStoreChanged(const QString &p_out, const QString &p_err) {
636  processFinished(p_out, p_err);
637  doGitPush();
638 }
639 
640 void MainWindow::doGitPush() {
642  on_pushButton_clicked();
643 }
644 
645 void MainWindow::finishedInsert(const QString &p_output,
646  const QString &p_errout) {
647  processFinished(p_output, p_errout);
648  doGitPush();
649  on_treeView_clicked(ui->treeView->currentIndex());
650 }
651 
652 void MainWindow::DisplayInTextBrowser(QString output, QString prefix,
653  QString postfix) {
654 
655  output.replace(QRegExp("<"), "&lt;");
656  output.replace(QRegExp(">"), "&gt;");
657  output.replace(QRegExp(" "), "&nbsp;");
658 
659  output.replace(
660  QRegExp("((?:https?|ftp|ssh|sftp|ftps|webdav|webdavs)://\\S+)"),
661  "<a href=\"\\1\">\\1</a>");
662  output.replace(QRegExp("\n"), "<br />");
663  output = prefix + output + postfix;
664  if (!ui->textBrowser->toPlainText().isEmpty())
665  output = ui->textBrowser->toHtml() + output;
666  ui->textBrowser->setHtml(output);
667 }
668 
669 void MainWindow::processErrorExit(int exitCode, const QString &p_error) {
670  if (!p_error.isEmpty()) {
671  QString output;
672  QString error = p_error;
673  error.replace(QRegExp("<"), "&lt;");
674  error.replace(QRegExp(">"), "&gt;");
675  error.replace(QRegExp(" "), "&nbsp;");
676  if (exitCode == 0) {
677  // https://github.com/IJHack/qtpass/issues/111
678  output = "<span style=\"color: darkgray;\">" + error + "</span><br />";
679  } else {
680  output = "<span style=\"color: red;\">" + error + "</span><br />";
681  }
682 
683  output.replace(
684  QRegExp("((?:https?|ftp|ssh|sftp|ftps|webdav|webdavs)://\\S+)"),
685  "<a href=\"\\1\">\\1</a>");
686  output.replace(QRegExp("\n"), "<br />");
687  if (!ui->textBrowser->toPlainText().isEmpty())
688  output = ui->textBrowser->toHtml() + output;
689  ui->textBrowser->setHtml(output);
690  }
691  enableUiElements(true);
692 }
693 
697 void MainWindow::clearClipboard() {
698  QClipboard *clipboard = QApplication::clipboard();
699  bool cleared = false;
700  if (this->clippedText == clipboard->text(QClipboard::Selection)) {
701  clipboard->clear(QClipboard::Clipboard);
702  cleared = true;
703  }
704  if (this->clippedText == clipboard->text(QClipboard::Clipboard)) {
705  clipboard->clear(QClipboard::Clipboard);
706  cleared = true;
707  }
708  if (cleared) {
709  ui->statusBar->showMessage(tr("Clipboard cleared"), 2000);
710  } else {
711  ui->statusBar->showMessage(tr("Clipboard not cleared"), 2000);
712  }
713  this->clippedText.clear();
714 }
715 
719 void MainWindow::clearPanel(bool notify) {
720  while (ui->gridLayout->count() > 0) {
721  QLayoutItem *item = ui->gridLayout->takeAt(0);
722  delete item->widget();
723  delete item;
724  }
725  if (notify) {
726  QString output = "***" + tr("Password and Content hidden") + "***";
727  ui->textBrowser->setHtml(output);
728  } else {
729  ui->textBrowser->setHtml("");
730  }
731 }
732 
740 void MainWindow::processFinished(const QString &p_output,
741  const QString &p_errout) {
742  DisplayInTextBrowser(p_output);
743  // Sometimes there is error output even with 0 exit code, which is
744  // assumed in this function
745  processErrorExit(0, p_errout);
746  enableUiElements(true);
747 }
748 
754 void MainWindow::enableUiElements(bool state) {
755  ui->updateButton->setEnabled(state);
756  ui->treeView->setEnabled(state);
757  ui->lineEdit->setEnabled(state);
758  ui->lineEdit->installEventFilter(this);
759  ui->addButton->setEnabled(state);
760  ui->usersButton->setEnabled(state);
761  ui->configButton->setEnabled(state);
762  // is a file selected?
763  state &= ui->treeView->currentIndex().isValid();
764  ui->deleteButton->setEnabled(state);
765  ui->editButton->setEnabled(state);
766  ui->pushButton->setEnabled(state);
767 }
768 
769 void MainWindow::restoreWindow() {
770  QByteArray geometry = QtPassSettings::getGeometry(saveGeometry());
771  restoreGeometry(geometry);
772  QByteArray savestate = QtPassSettings::getSavestate(saveState());
773  restoreState(savestate);
774  QPoint position = QtPassSettings::getPos(pos());
775  move(position);
776  QSize newSize = QtPassSettings::getSize(size());
777  resize(newSize);
778  QList<int> splitter = ui->splitter->sizes();
779  int left = QtPassSettings::getSplitterLeft(splitter[0]);
780  int right = QtPassSettings::getSplitterRight(splitter[1]);
781  if (left > 0 || right > 0) {
782  splitter[0] = left;
783  splitter[1] = right;
784  ui->splitter->setSizes(splitter);
785  }
786  if (QtPassSettings::isMaximized(isMaximized())) {
787  showMaximized();
788  }
789 }
790 
795 void MainWindow::processError(QProcess::ProcessError error) {
796  QString errorString;
797  switch (error) {
798  case QProcess::FailedToStart:
799  errorString = tr("QProcess::FailedToStart");
800  break;
801  case QProcess::Crashed:
802  errorString = tr("QProcess::Crashed");
803  break;
804  case QProcess::Timedout:
805  errorString = tr("QProcess::Timedout");
806  break;
807  case QProcess::ReadError:
808  errorString = tr("QProcess::ReadError");
809  break;
810  case QProcess::WriteError:
811  errorString = tr("QProcess::WriteError");
812  break;
813  case QProcess::UnknownError:
814  errorString = tr("QProcess::UnknownError");
815  break;
816  }
817  ui->textBrowser->setTextColor(Qt::red);
818  ui->textBrowser->setText(errorString);
819  ui->textBrowser->setTextColor(Qt::black);
820  enableUiElements(true);
821 }
822 
826 void MainWindow::on_configButton_clicked() { config(); }
827 
833 void MainWindow::on_lineEdit_textChanged(const QString &arg1) {
834  ui->treeView->expandAll();
835  ui->statusBar->showMessage(tr("Looking for: %1").arg(arg1), 1000);
836  QString query = arg1;
837  query.replace(QRegExp(" "), ".*");
838  QRegExp regExp(query, Qt::CaseInsensitive);
839  proxyModel.setFilterRegExp(regExp);
840  ui->treeView->setRootIndex(proxyModel.mapFromSource(
841  model.setRootPath(QtPassSettings::getPassStore())));
842  selectFirstFile();
843 }
844 
850 void MainWindow::on_lineEdit_returnPressed() {
851  dbg() << "on_lineEdit_returnPressed";
852  selectFirstFile();
853  on_treeView_clicked(ui->treeView->currentIndex());
854 }
855 
860 void MainWindow::selectFirstFile() {
861  QModelIndex index = proxyModel.mapFromSource(
862  model.setRootPath(QtPassSettings::getPassStore()));
863  index = firstFile(index);
864  ui->treeView->setCurrentIndex(index);
865 }
866 
872 QModelIndex MainWindow::firstFile(QModelIndex parentIndex) {
873  QModelIndex index = parentIndex;
874  int numRows = proxyModel.rowCount(parentIndex);
875  for (int row = 0; row < numRows; ++row) {
876  index = proxyModel.index(row, 0, parentIndex);
877  if (model.fileInfo(proxyModel.mapToSource(index)).isFile())
878  return index;
879  if (proxyModel.hasChildren(index))
880  return firstFile(index);
881  }
882  return index;
883 }
884 
892 void MainWindow::setPassword(QString file, bool isNew) {
896  // TODO(bezet): add error handling
897  QtPassSettings::getPass()->Show(file);
898  d.setFile(file);
899  d.usePwgen(QtPassSettings::isUsePwgen());
900  d.setTemplate(QtPassSettings::getPassTemplate(),
902  d.templateAll(QtPassSettings::isTemplateAllFields());
903  if (!d.exec()) {
904  d.setPassword(QString());
905  return;
906  }
907  QString newValue = d.getPassword();
908  if (newValue.isEmpty())
909  return;
910 
911  if (newValue.right(1) != "\n")
912  newValue += "\n";
913 
914  QtPassSettings::getPass()->Insert(file, newValue, !isNew);
915 }
916 
921 void MainWindow::on_addButton_clicked() {
922  bool ok;
923  QString dir =
924  Util::getDir(ui->treeView->currentIndex(), true, model, proxyModel);
925  QString file =
926  QInputDialog::getText(this, tr("New file"),
927  tr("New password file: \n(Will be placed in %1 )")
929  Util::getDir(ui->treeView->currentIndex(),
930  true, model, proxyModel)),
931  QLineEdit::Normal, "", &ok);
932  if (!ok || file.isEmpty())
933  return;
934  file = dir + file;
935  setPassword(file);
936 }
937 
942 void MainWindow::on_deleteButton_clicked() {
943  QFileInfo fileOrFolder =
944  model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
945  QString file = "";
946  bool isDir = false;
947 
948  if (fileOrFolder.isFile()) {
949  file = getFile(ui->treeView->currentIndex(), true);
950  } else {
951  file = Util::getDir(ui->treeView->currentIndex(), true, model, proxyModel);
952  isDir = true;
953  }
954 
955  QString dirMessage = tr(" and the whole content?");
956  if (isDir) {
957  QDirIterator it(model.rootPath() + "/" + file,
958  QDirIterator::Subdirectories);
959  bool okDir = true;
960  while (it.hasNext() && okDir) {
961  it.next();
962  if (QFileInfo(it.filePath()).isFile()) {
963  if (QFileInfo(it.filePath()).suffix() != "gpg") {
964  okDir = false;
965  dirMessage = tr(" and the whole content? <br><strong>Attention: "
966  "there are unexpected files in the given folder, "
967  "check them before continue.</strong>");
968  }
969  }
970  }
971  }
972 
973  if (QMessageBox::question(
974  this, isDir ? tr("Delete folder?") : tr("Delete password?"),
975  tr("Are you sure you want to delete %1%2")
976  .arg(QDir::separator() + file)
977  .arg(isDir ? dirMessage : "?"),
978  QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
979  return;
980 
981  QtPassSettings::getPass()->Remove(file, isDir);
982 }
983 
987 void MainWindow::on_editButton_clicked() {
988  QString file = getFile(ui->treeView->currentIndex(), true);
989  editPassword(file);
990 }
991 
996 void MainWindow::userDialog(QString dir) {
997  if (!dir.isEmpty())
998  currentDir = dir;
999  on_usersButton_clicked();
1000 }
1001 
1007 void MainWindow::on_usersButton_clicked() {
1008  QList<UserInfo> users = QtPassSettings::getPass()->listKeys();
1009  if (users.size() == 0) {
1010  QMessageBox::critical(this, tr("Can not get key list"),
1011  tr("Unable to get list of available gpg keys"));
1012  return;
1013  }
1014  QList<UserInfo> secret_keys = QtPassSettings::getPass()->listKeys("", true);
1015  foreach (const UserInfo &sec, secret_keys) {
1016  for (QList<UserInfo>::iterator it = users.begin(); it != users.end(); ++it)
1017  if (sec.key_id == it->key_id)
1018  it->have_secret = true;
1019  }
1020  QList<UserInfo> selected_users;
1021  QString dir =
1022  currentDir.isEmpty()
1023  ? Util::getDir(ui->treeView->currentIndex(), false, model, proxyModel)
1024  : currentDir;
1025  int count = 0;
1026  QString recipients = QtPassSettings::getPass()->getRecipientString(
1027  dir.isEmpty() ? "" : dir, " ", &count);
1028  if (!recipients.isEmpty())
1029  selected_users = QtPassSettings::getPass()->listKeys(recipients);
1030  foreach (const UserInfo &sel, selected_users) {
1031  for (QList<UserInfo>::iterator it = users.begin(); it != users.end(); ++it)
1032  if (sel.key_id == it->key_id)
1033  it->enabled = true;
1034  }
1035  if (count > selected_users.size()) {
1036  // Some keys seem missing from keyring, add them separately
1037  QStringList recipients =
1038  QtPassSettings::getPass()->getRecipientList(dir.isEmpty() ? "" : dir);
1039  foreach (const QString recipient, recipients) {
1040  if (QtPassSettings::getPass()->listKeys(recipient).size() < 1) {
1041  UserInfo i;
1042  i.enabled = true;
1043  i.key_id = recipient;
1044  i.name = " ?? " + tr("Key not found in keyring");
1045  users.append(i);
1046  }
1047  }
1048  }
1049  UsersDialog d(this);
1050  d.setUsers(&users);
1051  if (!d.exec()) {
1052  d.setUsers(NULL);
1053  return;
1054  }
1055  d.setUsers(NULL);
1056 
1057  QtPassSettings::getPass()->Init(dir, users);
1058 }
1059 
1065 #if SINGLE_APP
1066  connect(app, SIGNAL(messageAvailable(QString)), this,
1067  SLOT(messageAvailable(QString)));
1068 #endif
1069 }
1070 
1075 void MainWindow::messageAvailable(QString message) {
1076  if (message.isEmpty()) {
1077  focusInput();
1078  } else {
1079  ui->treeView->expandAll();
1080  ui->lineEdit->setText(message);
1081  on_lineEdit_returnPressed();
1082  }
1083  show();
1084  raise();
1085 }
1086 
1092 void MainWindow::setText(QString text) { ui->lineEdit->setText(text); }
1093 
1099  QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
1100  QStringList names;
1101 
1102  if (keys.size() == 0)
1103  return names;
1104 
1105  foreach (const UserInfo &sec, keys)
1106  names << sec.name;
1107 
1108  return names;
1109 }
1110 
1116 void MainWindow::generateKeyPair(QString batch, QDialog *keygenWindow) {
1117  keygen = keygenWindow;
1118  ui->statusBar->showMessage(tr("Generating GPG key pair"), 60000);
1120 }
1121 
1126 void MainWindow::updateProfileBox() {
1127  // dbg()<< profiles.size();
1128  if (QtPassSettings::getProfiles().isEmpty()) {
1129  ui->profileBox->hide();
1130  } else {
1131  ui->profileBox->show();
1132  if (QtPassSettings::getProfiles().size() < 2)
1133  ui->profileBox->setEnabled(false);
1134  else
1135  ui->profileBox->setEnabled(true);
1136  ui->profileBox->clear();
1137  QHashIterator<QString, QString> i(QtPassSettings::getProfiles());
1138  while (i.hasNext()) {
1139  i.next();
1140  if (!i.key().isEmpty())
1141  ui->profileBox->addItem(i.key());
1142  }
1143  }
1144  int index = ui->profileBox->findText(QtPassSettings::getProfile());
1145  if (index != -1) // -1 for not found
1146  ui->profileBox->setCurrentIndex(index);
1147 }
1148 
1154 void MainWindow::on_profileBox_currentIndexChanged(QString name) {
1155  if (startupPhase || name == QtPassSettings::getProfile())
1156  return;
1158 
1160  ui->statusBar->showMessage(tr("Profile changed to %1").arg(name), 2000);
1161 
1163 
1164  ui->treeView->setRootIndex(proxyModel.mapFromSource(
1165  model.setRootPath(QtPassSettings::getPassStore())));
1166 }
1167 
1173 void MainWindow::initTrayIcon() {
1174  if (tray != NULL) {
1175  dbg() << "Creating tray icon again?";
1176  return;
1177  }
1178  if (QSystemTrayIcon::isSystemTrayAvailable() == true) {
1179  // Setup tray icon
1180  this->tray = new TrayIcon(this);
1181  if (tray == NULL)
1182  dbg() << "Allocating tray icon failed.";
1183  } else {
1184  dbg() << "No tray icon for this OS possibly also not show options?";
1185  }
1186 }
1187 
1191 void MainWindow::destroyTrayIcon() {
1192  if (tray == NULL) {
1193  dbg() << "Destroy non existing tray icon?";
1194  return;
1195  }
1196  delete this->tray;
1197  tray = NULL;
1198 }
1199 
1204 void MainWindow::closeEvent(QCloseEvent *event) {
1206  this->hide();
1207  event->ignore();
1208  } else {
1209  clearClipboard();
1210  QtPassSettings::setGeometry(saveGeometry());
1211  QtPassSettings::setSavestate(saveState());
1212  QtPassSettings::setMaximized(isMaximized());
1213  if (!isMaximized()) {
1214  QtPassSettings::setPos(pos());
1215  QtPassSettings::setSize(size());
1216  }
1217  QtPassSettings::setSplitterLeft(ui->splitter->sizes()[0]);
1218  QtPassSettings::setSplitterRight(ui->splitter->sizes()[1]);
1219  event->accept();
1220  }
1221 }
1222 
1230 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
1231  if (obj == ui->lineEdit && event->type() == QEvent::KeyPress) {
1232  QKeyEvent *key = static_cast<QKeyEvent *>(event);
1233  if (key->key() == Qt::Key_Down) {
1234  ui->treeView->setFocus();
1235  }
1236  }
1237  return QObject::eventFilter(obj, event);
1238 }
1239 
1244 void MainWindow::keyPressEvent(QKeyEvent *event) {
1245  switch (event->key()) {
1246  case Qt::Key_Delete:
1247  on_deleteButton_clicked();
1248  break;
1249  case Qt::Key_Return:
1250  case Qt::Key_Enter:
1251  on_treeView_clicked(ui->treeView->currentIndex());
1252  break;
1253  case Qt::Key_Escape:
1254  ui->lineEdit->clear();
1255  break;
1256  default:
1257  break;
1258  }
1259 }
1260 
1266 void MainWindow::showContextMenu(const QPoint &pos) {
1267  QModelIndex index = ui->treeView->indexAt(pos);
1268  bool selected = true;
1269  if (!index.isValid()) {
1270  ui->treeView->clearSelection();
1271  ui->deleteButton->setEnabled(false);
1272  ui->editButton->setEnabled(false);
1273  currentDir = "";
1274  selected = false;
1275  }
1276 
1277  ui->treeView->setCurrentIndex(index);
1278 
1279  QPoint globalPos = ui->treeView->viewport()->mapToGlobal(pos);
1280 
1281  QFileInfo fileOrFolder =
1282  model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
1283 
1284  QMenu contextMenu;
1285  if (!selected || fileOrFolder.isDir()) {
1286  QAction *openFolder =
1287  contextMenu.addAction(tr("Open folder with file manager"));
1288  QAction *addFolder = contextMenu.addAction(tr("Add folder"));
1289  QAction *addPassword = contextMenu.addAction(tr("Add password"));
1290  QAction *users = contextMenu.addAction(tr("Users"));
1291  connect(openFolder, SIGNAL(triggered()), this, SLOT(openFolder()));
1292  connect(addFolder, SIGNAL(triggered()), this, SLOT(addFolder()));
1293  connect(addPassword, SIGNAL(triggered()), this,
1294  SLOT(on_addButton_clicked()));
1295  connect(users, SIGNAL(triggered()), this, SLOT(on_usersButton_clicked()));
1296  } else if (fileOrFolder.isFile()) {
1297  QAction *edit = contextMenu.addAction(tr("Edit"));
1298  connect(edit, SIGNAL(triggered()), this, SLOT(on_editButton_clicked()));
1299  }
1300  if (selected) {
1301  // if (useClipboard != CLIPBOARD_NEVER) {
1302  // contextMenu.addSeparator();
1303  // QAction* copyItem = contextMenu.addAction(tr("Copy Password"));
1304  // if (getClippedPassword().length() == 0) copyItem->setEnabled(false);
1305  // connect(copyItem, SIGNAL(triggered()), this,
1306  // SLOT(copyPasswordToClipboard()));
1307  // }
1308  contextMenu.addSeparator();
1309  QAction *deleteItem = contextMenu.addAction(tr("Delete"));
1310  connect(deleteItem, SIGNAL(triggered()), this,
1311  SLOT(on_deleteButton_clicked()));
1312  }
1313  contextMenu.exec(globalPos);
1314 }
1315 
1321 void MainWindow::showBrowserContextMenu(const QPoint &pos) {
1322  QMenu *contextMenu = ui->textBrowser->createStandardContextMenu(pos);
1323  QPoint globalPos = ui->textBrowser->viewport()->mapToGlobal(pos);
1324 
1325  contextMenu->exec(globalPos);
1326 }
1327 
1331 void MainWindow::openFolder() {
1332  QString dir =
1333  Util::getDir(ui->treeView->currentIndex(), false, model, proxyModel);
1334 
1335  QString path = QDir::toNativeSeparators(dir);
1336  QDesktopServices::openUrl(QUrl::fromLocalFile(path));
1337 }
1338 
1342 void MainWindow::addFolder() {
1343  bool ok;
1344  QString dir =
1345  Util::getDir(ui->treeView->currentIndex(), false, model, proxyModel);
1346  QString newdir =
1347  QInputDialog::getText(this, tr("New file"),
1348  tr("New Folder: \n(Will be placed in %1 )")
1350  Util::getDir(ui->treeView->currentIndex(),
1351  true, model, proxyModel)),
1352  QLineEdit::Normal, "", &ok);
1353  if (!ok || newdir.isEmpty())
1354  return;
1355  newdir.prepend(dir);
1356  // dbg()<< newdir;
1357  QDir().mkdir(newdir);
1358 }
1359 
1364 void MainWindow::editPassword(const QString &file) {
1365  if (!file.isEmpty()) {
1367  on_updateButton_clicked(true);
1368  setPassword(file, false);
1369  }
1370 }
1371 
1376 void MainWindow::clearTemplateWidgets() {
1377  while (ui->gridLayout->count() > 0) {
1378  QLayoutItem *item = ui->gridLayout->takeAt(0);
1379  delete item->widget();
1380  delete item;
1381  }
1382  ui->verticalLayoutPassword->setSpacing(0);
1383 }
1384 
1389 void MainWindow::copyTextToClipboard(const QString &text) {
1390  QClipboard *clip = QApplication::clipboard();
1392  clip->setText(text, QClipboard::Clipboard);
1393  } else {
1394  clip->setText(text, QClipboard::Selection);
1395  }
1396  clippedText = text;
1397  ui->statusBar->showMessage(tr("Copied to clipboard"), 2000);
1399  clearClipboardTimer.start();
1400  }
1401 }
1402 
1403 void MainWindow::copyPasswordFromTreeview() {
1404  QFileInfo fileOrFolder =
1405  model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
1406 
1407  if (fileOrFolder.isFile()) {
1408  QString file = getFile(ui->treeView->currentIndex(), true);
1409  connect(QtPassSettings::getPass(), &Pass::finishedShow, this,
1410  &MainWindow::passwordFromFileToClipboard);
1411  QtPassSettings::getPass()->Show(file);
1412  }
1413 }
1414 
1415 void MainWindow::passwordFromFileToClipboard(const QString &text) {
1416  QStringList tokens = text.split('\n');
1417  copyTextToClipboard(tokens[0]);
1418 }
1419 
1426 void MainWindow::addToGridLayout(int position, const QString &field,
1427  const QString &value) {
1428  QString trimmedField = field.trimmed();
1429  QString trimmedValue = value.trimmed();
1430 
1431  // Combine the Copy button and the line edit in one widget
1432  QFrame *frame = new QFrame();
1433  QLayout *ly = new QHBoxLayout();
1434  ly->setContentsMargins(5, 2, 2, 2);
1435  frame->setLayout(ly);
1437  QPushButtonWithClipboard *fieldLabel =
1438  new QPushButtonWithClipboard(trimmedValue, this);
1439  connect(fieldLabel, SIGNAL(clicked(QString)), this,
1440  SLOT(copyTextToClipboard(QString)));
1441 
1442  fieldLabel->setStyleSheet("border-style: none ; background: transparent;");
1443  // fieldLabel->setContentsMargins(0,5,5,0);
1444  frame->layout()->addWidget(fieldLabel);
1445  }
1446 
1447  // set the echo mode to password, if the field is "password"
1448  if (QtPassSettings::isHidePassword() && trimmedField == tr("Password")) {
1449  QLineEdit *line = new QLineEdit();
1450  line->setObjectName(trimmedField);
1451  line->setText(trimmedValue);
1452  line->setReadOnly(true);
1453  line->setStyleSheet("border-style: none ; background: transparent;");
1454  line->setContentsMargins(0, 0, 0, 0);
1455  line->setEchoMode(QLineEdit::Password);
1456  frame->layout()->addWidget(line);
1457  } else {
1458  QTextBrowser *line = new QTextBrowser();
1459  line->setOpenExternalLinks(true);
1460  line->setOpenLinks(true);
1461  line->setMaximumHeight(26);
1462  line->setMinimumHeight(26);
1463  line->setSizePolicy(
1464  QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
1465  line->setObjectName(trimmedField);
1466  trimmedValue.replace(
1467  QRegExp("((?:https?|ftp|ssh|sftp|ftps|webdav|webdavs)://\\S+)"),
1468  "<a href=\"\\1\">\\1</a>");
1469  line->setText(trimmedValue);
1470  line->setReadOnly(true);
1471  line->setStyleSheet("border-style: none ; background: transparent;");
1472  line->setContentsMargins(0, 0, 0, 0);
1473  frame->layout()->addWidget(line);
1474  }
1475 
1476  frame->setStyleSheet(
1477  ".QFrame{border: 1px solid lightgrey; border-radius: 5px;}");
1478 
1479  // set into the layout
1480  ui->gridLayout->addWidget(new QLabel(trimmedField), position, 0);
1481  ui->gridLayout->addWidget(frame, position, 1);
1482 }
1483 
1490 void MainWindow::showStatusMessage(QString msg, int timeout) {
1491  ui->statusBar->showMessage(msg, timeout);
1492 }
1493 
1497 void MainWindow::startReencryptPath() {
1498  enableUiElements(false);
1499  ui->treeView->setDisabled(true);
1500 }
1501 
1505 void MainWindow::endReencryptPath() { enableUiElements(true); }
1506 
1512 void MainWindow::critical(QString title, QString msg) {
1513  QMessageBox::critical(this, title, msg);
1514 }
1515 
1516 void MainWindow::updateGitButtonVisibility() {
1517  if (!QtPassSettings::isUseGit() ||
1518  (QtPassSettings::getGitExecutable().isEmpty() &&
1519  QtPassSettings::getPassExecutable().isEmpty())) {
1520  hideGitButtons();
1521  } else {
1522  showGitButtons();
1523  }
1524 }
1525 
1526 void MainWindow::hideGitButtons() {
1527  ui->pushButton->hide();
1528  ui->updateButton->hide();
1529  ui->horizontalSpacer->changeSize(0, 20, QSizePolicy::Maximum,
1530  QSizePolicy::Minimum);
1531 }
1532 
1533 void MainWindow::showGitButtons() {
1534  ui->pushButton->show();
1535  ui->updateButton->show();
1536  ui->horizontalSpacer->changeSize(24, 24, QSizePolicy::Minimum,
1537  QSizePolicy::Minimum);
1538 }
static void setPwgenExecutable(const QString &pwgenExecutable)
The NamedValues class is mostly a list of but also has a method to take a specific NamedValue pair ou...
Definition: filecontent.h:16
void finishedMove(const QString &, const QString &)
static void setAutoclearSeconds(const int &autoClearSeconds)
static int getAutoclearSeconds(const int &defaultValue=QVariant().toInt())
static void setUsePwgen(const bool &usePwgen)
static bool isStartMinimized(const bool &defaultValue=QVariant().toBool())
static bool isMaximized(const bool &defaultValue=QVariant().toBool())
static void setUsePass(const bool &usePass)
void finishedCopy(const QString &, const QString &)
static bool isLessRandom(const bool &defaultValue=QVariant().toBool())
static void setPassExecutable(const QString &passExecutable)
void GenerateGPGKeys(QString batch)
Pass::GenerateGPGKeys internal gpg keypair generator . .
Definition: pass.cpp:106
void setText(QString)
MainWindow::setText do a search from an external source (eg: commandline)
void finishedGenerateGPGKeys(const QString &, const QString &)
static void setSplitterLeft(const int &splitterLeft)
Stylish widget to allow copying of password and account details.
bool enabled
UserInfo::enabled.
Definition: userinfo.h:50
void finishedGitPush(const QString &, const QString &)
void error(QProcess::ProcessError)
#define dbg()
Definition: debughelper.h:7
static bool isAlwaysOnTop(const bool &defaultValue=QVariant().toBool())
static QPoint getPos(const QPoint &defaultValue=QVariant().toPoint())
QList< UserInfo > listKeys(QString keystring="", bool secret=false)
Pass::listKeys list users.
Definition: pass.cpp:120
NamedValues getNamedValues() const
Definition: filecontent.cpp:30
Definition: configdialog.h:9
static void setAutoPush(const bool &autoPush)
static void setGitExecutable(const QString &gitExecutable)
static void setAlwaysOnTop(const bool &alwaysOnTop)
static bool isUseSelection(const bool &defaultValue=QVariant().toBool())
QString key_id
UserInfo::key_id hexadecimal representation.
Definition: userinfo.h:36
static void setPassTemplate(const QString &passTemplate)
void finishedInsert(const QString &, const QString &)
~MainWindow()
MainWindow::~MainWindow destroy!
Definition: mainwindow.cpp:107
static void setUseGit(const bool &useGit)
static void setClipBoardType(const Enums::clipBoardType &clipBoardType)
static void setPos(const QPoint &pos)
static bool isAvoidNumbers(const bool &defaultValue=QVariant().toBool())
static ImitatePass * getImitatePass()
static void setPasswordConfiguration(const PasswordConfiguration &config)
static void setHideContent(const bool &hideContent)
static bool isUseAutoclearPanel(const bool &defaultValue=QVariant().toBool())
static bool isUseWebDav(const bool &defaultValue=QVariant().toBool())
static void setSize(const QSize &size)
static void setLessRandom(const bool &lessRandom)
void finishedRemove(const QString &, const QString &)
static void setAutoPull(const bool &autoPull)
static void setSplitterRight(const int &splitterRight)
QString value
Definition: filecontent.h:9
static bool isAddGPGId(const bool &defaultValue=QVariant().toBool())
static bool isUseAutoclear(const bool &defaultValue=QVariant().toBool())
virtual void GitInit()=0
static bool isHideOnClose(const bool &defaultValue=QVariant().toBool())
bool eventFilter(QObject *obj, QEvent *event)
MainWindow::eventFilter filter out some events and focus the treeview.
static void setProfiles(const QHash< QString, QString > &profiles)
static bool isUseGit(const bool &defaultValue=QVariant().toBool())
void config()
MainWindow::config pops up the configuration screen and handles all inter-window communication.
Definition: mainwindow.cpp:345
Acts as an abstraction for pass or pass imitation.
Definition: pass.h:25
static FileContent parse(const QString &fileContent, const QStringList &templateFields, bool allFields)
parse parses the given fileContent in a FileContent object. The password is accessible through getPas...
Definition: filecontent.cpp:3
static QString getPassStore(const QString &defaultValue=QVariant().toString())
static void setProfile(const QString &profile)
void userDialog(QString="")
MainWindow::userDialog see MainWindow::on_usersButton_clicked()
Definition: mainwindow.cpp:996
virtual void Remove(QString file, bool isDir)=0
static void setMaximized(const bool &maximized)
static QString getGitExecutable(const QString &defaultValue=QVariant().toString())
void finishedGitPull(const QString &, const QString &)
virtual void Show(QString file)=0
static void setAutoclearPanelSeconds(const int &autoClearPanelSeconds)
void critical(QString, QString)
void setModelAndStore(QFileSystemModel *sourceModel, QString passStore)
StoreModel::setModelAndStore update the source model and store.
Definition: storemodel.cpp:80
static void setUseAutoclearPanel(const bool &useAutoclearPanel)
PasswordDialog Handles the inserting and editing of passwords.
static bool isUseTrayIcon(const bool &defaultValue=QVariant().toBool())
void closeEvent(QCloseEvent *event)
MainWindow::closeEvent hide or quit.
static QString getRecipientString(QString for_file, QString separator=" ", int *count=NULL)
Pass::getRecipientString formated string for use with GPG.
Definition: pass.cpp:267
Handles listing and editing of GPG users.
Definition: usersdialog.h:22
virtual void GitPull_b()=0
void changeEvent(QEvent *event)
MainWindow::changeEvent sets focus to the search box.
Definition: mainwindow.cpp:124
static void setAvoidNumbers(const bool &avoidNumbers)
static QString getPassExecutable(const QString &defaultValue=QVariant().toString())
Handles the systemtray icon and menu.
Definition: trayicon.h:14
void keyPressEvent(QKeyEvent *event)
MainWindow::keyPressEvent did anyone press return, enter or escape?
static QString getVersion(const QString &defaultValue=QVariant().toString())
void executePassGitInit()
MainWindow::executePassGitInit git init wrapper.
Definition: mainwindow.cpp:544
static void setHideOnClose(const bool &hideOnClose)
static QStringList getRecipientList(QString for_file)
Pass::getRecipientList return list of gpg-id&#39;s to encrypt for.
Definition: pass.cpp:231
static bool isAvoidCapitals(const bool &defaultValue=QVariant().toBool())
static QByteArray getSavestate(const QByteArray &defaultValue=QVariant().toByteArray())
static QSize getSize(const QSize &defaultValue=QVariant().toSize())
virtual void GitPush()=0
QString getRemainingData() const
Definition: filecontent.cpp:32
void setApp(SingleApplication *app)
MainWindow::setApp make sure we know what/who/where we are.
The SingleApplication class is used for commandline intergration.
static Pass * getPass()
void statusMsg(QString, int)
virtual void GitPull()=0
static void setGpgExecutable(const QString &gpgExecutable)
static QString getWebDavUser(const QString &defaultValue=QVariant().toString())
static void setStartMinimized(const bool &startMinimized)
MainWindow(QWidget *parent=0)
MainWindow::MainWindow handles all of the main functionality and also the main window.
Definition: mainwindow.cpp:43
void finishedInit(const QString &, const QString &)
static bool isUsePwgen(const bool &defaultValue=QVariant().toBool())
static void setSavestate(const QByteArray &saveState)
static void setUseAutoclear(const bool &useAutoclear)
static QString getPassTemplate(const QString &defaultValue=QVariant().toString())
static Enums::clipBoardType getClipBoardType(const Enums::clipBoardType &defaultvalue=Enums::CLIPBOARD_NEVER)
static QString getWebDavUrl(const QString &defaultValue=QVariant().toString())
static QString getPwgenExecutable(const QString &defaultValue=QVariant().toString())
static bool isUseSymbols(const bool &defaultValue=QVariant().toBool())
void updateEnv()
Pass::updateEnv update the execution environment (used when switching profiles)
Definition: pass.cpp:210
The ConfigDialog handles the configuration interface.
Definition: configdialog.h:23
QString name
UserInfo::name full name.
Definition: userinfo.h:32
bool checkConfig()
MainWindow::checkConfig make sure we are ready to go as soon as possible.
Definition: mainwindow.cpp:235
Stores key info lines including validity, creation date and more.
Definition: userinfo.h:11
static void setUseTemplate(const bool &useTemplate)
static QByteArray getGeometry(const QByteArray &defaultValue=QVariant().toByteArray())
static int getSplitterRight(const int &defaultValue=QVariant().toInt())
static int getAutoclearPanelSeconds(const int &defaultValue=QVariant().toInt())
static void setAddGPGId(const bool &addGPGId)
static QString getGpgExecutable(const QString &defaultValue=QVariant().toString())
void finishedShow(const QString &)
static bool isUseTemplate(const bool &defaultValue=QVariant().toBool())
static QString getWebDavPassword(const QString &defaultValue=QVariant().toString())
static bool isTemplateAllFields(const bool &defaultValue=QVariant().toBool())
static void setUseSymbols(const bool &useSymbols)
QStringList getSecretKeys()
MainWindow::getSecretKeys get list of secret/private keys.
static void initExecutables()
static QString getDir(const QModelIndex &index, bool forPass, const QFileSystemModel &model, const StoreModel &storeModel)
Util::getDir get selectd folder path.
Definition: util.cpp:133
virtual void Insert(QString file, QString value, bool force)=0
void finishedGitInit(const QString &, const QString &)
static void setTemplateAllFields(const bool &templateAllFields)
static QHash< QString, QString > getProfiles()
void deselect()
MainWindow::deselect clear the selection, password and copy buffer.
Definition: mainwindow.cpp:534
static void setUseTrayIcon(const bool &useTrayIcon)
static PasswordConfiguration getPasswordConfiguration()
static void setGeometry(const QByteArray &geometry)
static int getSplitterLeft(const int &defaultValue=QVariant().toInt())
void generateKeyPair(QString, QDialog *)
MainWindow::generateKeyPair internal gpg keypair generator . .
virtual void Init(QString path, const QList< UserInfo > &users)=0
void startingExecuteWrapper()
void processErrorExit(int exitCode, const QString &err)
void setPass(const QString &output)
The MainWindow class does way too much, not only is it a switchboard, configuration handler and more...
Definition: mainwindow.h:38
static RealPass * getRealPass()
static bool isHidePassword(const bool &defaultValue=QVariant().toBool())
QString getPassword() const
Definition: filecontent.cpp:28
static QString findPasswordStore()
Util::findPasswordStore look for common .password-store folder location.
Definition: util.cpp:41
static bool isHideContent(const bool &defaultValue=QVariant().toBool())
static bool checkConfig()
Util::checkConfig do we have prequisite settings?
Definition: util.cpp:118
static QString getProfile(const QString &defaultValue=QVariant().toString())
static void setVersion(const QString &version)
static void setHidePassword(const bool &hidePassword)
QString name
Definition: filecontent.h:8
static void setPassStore(const QString &passStore)
static void setUseSelection(const bool &useSelection)
static bool isAutoPull(const bool &defaultValue=QVariant().toBool())
static bool isUsePass(const bool &defaultValue=QVariant().toBool())
static QString normalizeFolderPath(QString path)
Util::normalizeFolderPath let&#39;s always end folders with a QDir::separator()
Definition: util.cpp:64
static bool isAutoPush(const bool &defaultValue=QVariant().toBool())
static void setAvoidCapitals(const bool &avoidCapitals)