QtPass  1.2.0-pre
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 <QFileInfo>
6 #include <QInputDialog>
7 #include <QLabel>
8 #include <QMessageBox>
9 #include <QQueue>
10 #include <QShortcut>
11 #include <QTextCodec>
12 #include <QTimer>
13 #ifdef Q_OS_WIN
14 #define WIN32_LEAN_AND_MEAN /*_KILLING_MACHINE*/
15 #define WIN32_EXTRA_LEAN
16 #include <windows.h>
17 #include <winnetwk.h>
18 #undef DELETE
19 #endif
20 #include "configdialog.h"
21 #include "keygendialog.h"
22 #include "passworddialog.h"
24 #include "qtpasssettings.h"
25 #include "settingsconstants.h"
26 #include "ui_mainwindow.h"
27 #include "usersdialog.h"
28 #include "util.h"
29 
35 MainWindow::MainWindow(QWidget *parent)
36  : QMainWindow(parent), ui(new Ui::MainWindow), fusedav(this), keygen(NULL),
37  tray(NULL) {
38 #ifdef __APPLE__
39  // extra treatment for mac os
40  // see http://doc.qt.io/qt-5/qkeysequence.html#qt_set_sequence_auto_mnemonic
41  qt_set_sequence_auto_mnemonic(true);
42 #endif
43  // register shortcut ctrl/cmd + Q to close the main window
44  new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this, SLOT(close()));
45 
46  // TODO(bezet): this should be reconnected dynamically when pass changes
47  connectPassSignalHandlers(QtPassSettings::getRealPass());
48  connectPassSignalHandlers(QtPassSettings::getImitatePass());
49 
50  // only for ipass
51  connect(QtPassSettings::getImitatePass(), SIGNAL(startReencryptPath()), this,
52  SLOT(startReencryptPath()));
53  connect(QtPassSettings::getImitatePass(), SIGNAL(endReencryptPath()), this,
54  SLOT(endReencryptPath()));
55 
56  ui->setupUi(this);
57  enableUiElements(true);
58  ui->statusBar->showMessage(tr("Welcome to QtPass %1").arg(VERSION), 2000);
59  freshStart = true;
60  startupPhase = true;
61  clearPanelTimer.setSingleShot(true);
62  connect(&clearPanelTimer, SIGNAL(timeout()), this, SLOT(clearPanel()));
63  clearClipboardTimer.setSingleShot(true);
64  connect(&clearClipboardTimer, SIGNAL(timeout()), this,
65  SLOT(clearClipboard()));
67  if (!checkConfig()) {
68  // no working config
69  QApplication::quit();
70  }
71  clippedText = "";
72  QtPass = NULL;
73  QTimer::singleShot(10, this, SLOT(focusInput()));
74 
75  // Add a Actions to the Add-Button
76  QIcon addFileIcon = QIcon::fromTheme("file_new");
77  QIcon addFolderIcon = QIcon::fromTheme("folder_new");
78  actionAddPassword = new QAction(addFileIcon, tr("Add Password"), this);
79  actionAddFolder = new QAction(addFolderIcon, tr("Add Folder"), this);
80 
81  ui->addButton->addAction(actionAddPassword);
82  ui->addButton->addAction(actionAddFolder);
83 
84  connect(actionAddPassword, SIGNAL(triggered()), this,
85  SLOT(on_addButton_clicked()));
86  connect(actionAddFolder, SIGNAL(triggered()), this, SLOT(addFolder()));
87  qsrand(static_cast<uint>(QTime::currentTime().msec()));
88 
89 #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
90  ui->lineEdit->setClearButtonEnabled(true);
91 #endif
92 }
93 
100 void MainWindow::focusInput() {
101  ui->lineEdit->selectAll();
102  ui->lineEdit->setFocus();
103 }
104 
109 #ifdef Q_OS_WIN
111  WNetCancelConnection2A(QtPassSettings::getPassStore().toUtf8().constData(),
112  0, 1);
113 #else
114  if (fusedav.state() == QProcess::Running) {
115  fusedav.terminate();
116  fusedav.waitForFinished(2000);
117  }
118 #endif
119 }
120 
125 void MainWindow::changeEvent(QEvent *event) {
126  QWidget::changeEvent(event);
127  if (event->type() == QEvent::ActivationChange) {
128  if (this->isActiveWindow()) {
129  ui->lineEdit->selectAll();
130  ui->lineEdit->setFocus();
131  }
132  }
133 }
134 
142 void MainWindow::connectPassSignalHandlers(Pass *pass) {
143 
144  // TODO(bezet): this is never emitted(should be), also naming(see
145  // critical())
146  connect(pass, &Pass::error, this, &MainWindow::processError);
147  connect(pass, &Pass::startingExecuteWrapper, this,
148  &MainWindow::executeWrapperStarted);
149  connect(pass, &Pass::critical, this, &MainWindow::critical);
150  connect(pass, &Pass::statusMsg, this, &MainWindow::showStatusMessage);
151  connect(pass, &Pass::processErrorExit, this, &MainWindow::processErrorExit);
152 
153  connect(pass, &Pass::finishedGitInit, this, &MainWindow::passStoreChanged);
154  connect(pass, &Pass::finishedGitPull, this, &MainWindow::processFinished);
155  connect(pass, &Pass::finishedGitPush, this, &MainWindow::processFinished);
156  connect(pass, &Pass::finishedShow, this, &MainWindow::passShowHandler);
157  connect(pass, &Pass::finishedInsert, this, &MainWindow::finishedInsert);
158  connect(pass, &Pass::finishedRemove, this, &MainWindow::passStoreChanged);
159  connect(pass, &Pass::finishedInit, this, &MainWindow::passStoreChanged);
160  connect(pass, &Pass::finishedMove, this, &MainWindow::passStoreChanged);
161  connect(pass, &Pass::finishedCopy, this, &MainWindow::passStoreChanged);
162 
163  connect(pass, &Pass::finishedGenerateGPGKeys, this,
164  &MainWindow::keyGenerationComplete);
165 }
166 
170 void MainWindow::mountWebDav() {
171 #ifdef Q_OS_WIN
172  char dst[20] = {0};
173  NETRESOURCEA netres;
174  memset(&netres, 0, sizeof(netres));
175  netres.dwType = RESOURCETYPE_DISK;
176  netres.lpLocalName = 0;
177  netres.lpRemoteName = QtPassSettings::getWebDavUrl().toUtf8().data();
178  DWORD size = sizeof(dst);
179  DWORD r = WNetUseConnectionA(
180  reinterpret_cast<HWND>(effectiveWinId()), &netres,
181  QtPassSettings::getWebDavPassword().toUtf8().constData(),
182  QtPassSettings::getWebDavUser().toUtf8().constData(),
183  CONNECT_TEMPORARY | CONNECT_INTERACTIVE | CONNECT_REDIRECT, dst, &size,
184  0);
185  if (r == NO_ERROR) {
187  } else {
188  char message[256] = {0};
189  FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, r, 0, message,
190  sizeof(message), 0);
191  ui->textBrowser->setTextColor(Qt::red);
192  ui->textBrowser->setText(tr("Failed to connect WebDAV:\n") + message +
193  " (0x" + QString::number(r, 16) + ")");
194  ui->textBrowser->setTextColor(Qt::black);
195  }
196 #else
197  fusedav.start("fusedav -o nonempty -u \"" + QtPassSettings::getWebDavUser() +
198  "\" " + QtPassSettings::getWebDavUrl() + " \"" +
200  fusedav.waitForStarted();
201  if (fusedav.state() == QProcess::Running) {
202  QString pwd = QtPassSettings::getWebDavPassword();
203  bool ok = true;
204  if (pwd.isEmpty()) {
205  pwd = QInputDialog::getText(this, tr("QtPass WebDAV password"),
206  tr("Enter password to connect to WebDAV:"),
207  QLineEdit::Password, "", &ok);
208  }
209  if (ok && !pwd.isEmpty()) {
210  fusedav.write(pwd.toUtf8() + '\n');
211  fusedav.closeWriteChannel();
212  fusedav.waitForFinished(2000);
213  } else {
214  fusedav.terminate();
215  }
216  }
217  QString error = fusedav.readAllStandardError();
218  int prompt = error.indexOf("Password:");
219  if (prompt >= 0)
220  error.remove(0, prompt + 10);
221  if (fusedav.state() != QProcess::Running)
222  error = tr("fusedav exited unexpectedly\n") + error;
223  if (error.size() > 0) {
224  ui->textBrowser->setTextColor(Qt::red);
225  ui->textBrowser->setText(
226  tr("Failed to start fusedav to connect WebDAV:\n") + error);
227  ui->textBrowser->setTextColor(Qt::black);
228  }
229 #endif
230 }
231 
237  QString version = QtPassSettings::getVersion();
238 
239  if (freshStart) {
240  QByteArray geometry = QtPassSettings::getGeometry(saveGeometry());
241  restoreGeometry(geometry);
242  QByteArray savestate = QtPassSettings::getSavestate(saveState());
243  restoreState(savestate);
244  QPoint position = QtPassSettings::getPos(pos());
245  move(position);
246  QSize newSize = QtPassSettings::getSize(size());
247  resize(newSize);
248  QList<int> splitter = ui->splitter->sizes();
249  int left = QtPassSettings::getSplitterLeft(splitter[0]);
250  int right = QtPassSettings::getSplitterRight(splitter[1]);
251  if (left > 0 || right > 0) {
252  splitter[0] = left;
253  splitter[1] = right;
254  ui->splitter->setSizes(splitter);
255  }
256  if (QtPassSettings::isMaximized(isMaximized())) {
257  showMaximized();
258  }
259  }
260 
262  QtPassSettings::setPassStore(passStore);
263 
264  QString passExecutable =
266  QtPassSettings::setPassExecutable(passExecutable);
267 
268  QString gitExecutable =
270  QtPassSettings::setGitExecutable(gitExecutable);
271 
272  QString gpgExecutable =
274  QtPassSettings::setGpgExecutable(gpgExecutable);
275 
276  QString pwgenExecutable =
278  QtPassSettings::setPwgenExecutable(pwgenExecutable);
279 
285 
287  Qt::WindowFlags flags = windowFlags();
288  this->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
289  this->show();
290  }
291 
292  if (QtPassSettings::isUseTrayIcon() && tray == NULL) {
293  initTrayIcon();
294  if (freshStart && QtPassSettings::isStartMinimized()) {
295  // since we are still in constructor, can't directly hide
296  QTimer::singleShot(10, this, SLOT(hide()));
297  }
298  } else if (!QtPassSettings::isUseTrayIcon() && tray != NULL) {
299  destroyTrayIcon();
300  }
301 
302  // dbg()<< version;
303 
304  // Config updates
305  if (version.isEmpty()) {
306  dbg() << "assuming fresh install";
311  if (!QtPassSettings::getPwgenExecutable().isEmpty())
313  else
315  QtPassSettings::setPassTemplate("login\nurl");
316  } else {
317  // QStringList ver = version.split(".");
318  // dbg()<< ver;
319  // if (ver[0] == "0" && ver[1] == "8") {
321  // }
322  if (QtPassSettings::getPassTemplate().isEmpty())
323  QtPassSettings::setPassTemplate("login\nurl");
324  }
325 
327 
328  if (Util::checkConfig()) {
329  config();
330  if (freshStart && Util::checkConfig())
331  return false;
332  }
333 
334  freshStart = false;
335 
336  // TODO(annejan): this needs to be before we try to access the store,
337  // but it would be better to do it after the Window is shown,
338  // as the long delay it can cause is irritating otherwise.
340  mountWebDav();
341 
342  model.setNameFilters(QStringList() << "*.gpg");
343  model.setNameFilterDisables(false);
344 
345  proxyModel.setSourceModel(&model);
346  proxyModel.setModelAndStore(&model, QtPassSettings::getPassStore());
347  selectionModel.reset(new QItemSelectionModel(&proxyModel));
348  model.fetchMore(model.setRootPath(QtPassSettings::getPassStore()));
349  model.sort(0, Qt::AscendingOrder);
350 
351  ui->treeView->setModel(&proxyModel);
352  ui->treeView->setRootIndex(proxyModel.mapFromSource(
353  model.setRootPath(QtPassSettings::getPassStore())));
354  ui->treeView->setColumnHidden(1, true);
355  ui->treeView->setColumnHidden(2, true);
356  ui->treeView->setColumnHidden(3, true);
357  ui->treeView->setHeaderHidden(true);
358  ui->treeView->setIndentation(15);
359  ui->treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
360  ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
361  connect(ui->treeView, SIGNAL(customContextMenuRequested(const QPoint &)),
362  this, SLOT(showContextMenu(const QPoint &)));
363  connect(ui->treeView, SIGNAL(emptyClicked()), this, SLOT(deselect()));
364  ui->textBrowser->setOpenExternalLinks(true);
365  ui->textBrowser->setContextMenuPolicy(Qt::CustomContextMenu);
366  connect(ui->textBrowser, SIGNAL(customContextMenuRequested(const QPoint &)),
367  this, SLOT(showBrowserContextMenu(const QPoint &)));
368 
369  updateProfileBox();
371  clearPanelTimer.setInterval(1000 *
373  clearClipboardTimer.setInterval(1000 * QtPassSettings::getAutoclearSeconds());
374  if (!QtPassSettings::isUseGit() ||
375  (QtPassSettings::getGitExecutable().isEmpty() &&
376  QtPassSettings::getPassExecutable().isEmpty())) {
377  ui->pushButton->hide();
378  ui->updateButton->hide();
379  ui->horizontalSpacer->changeSize(0, 20, QSizePolicy::Maximum,
380  QSizePolicy::Minimum);
381  } else {
382  ui->pushButton->show();
383  ui->updateButton->show();
384  ui->horizontalSpacer->changeSize(24, 24, QSizePolicy::Minimum,
385  QSizePolicy::Minimum);
386  }
387 
388  startupPhase = false;
389  return true;
390 }
391 
397  QScopedPointer<ConfigDialog> d(new ConfigDialog(this));
398  d->setModal(true);
399  // Automatically default to pass if it's available
400  if (freshStart && QFile(QtPassSettings::getPassExecutable()).exists()) {
402  }
403 
404  d->setPassPath(QtPassSettings::getPassExecutable());
405  d->setGitPath(QtPassSettings::getGitExecutable());
406  d->setGpgPath(QtPassSettings::getGpgExecutable());
407  d->setStorePath(QtPassSettings::getPassStore());
408  d->usePass(QtPassSettings::isUsePass());
409  d->useClipboard(QtPassSettings::getClipBoardType());
410  d->useSelection(QtPassSettings::isUseSelection());
411  d->useAutoclear(QtPassSettings::isUseAutoclear());
412  d->setAutoclear(QtPassSettings::getAutoclearSeconds());
413  d->useAutoclearPanel(QtPassSettings::isUseAutoclearPanel());
414  d->setAutoclearPanel(QtPassSettings::getAutoclearPanelSeconds());
415  d->hidePassword(QtPassSettings::isHidePassword());
416  d->hideContent(QtPassSettings::isHideContent());
417  d->addGPGId(QtPassSettings::isAddGPGId(true));
418  d->useTrayIcon(QtPassSettings::isUseTrayIcon());
419  d->hideOnClose(QtPassSettings::isHideOnClose());
420  d->startMinimized(QtPassSettings::isStartMinimized());
422  d->useGit(QtPassSettings::isUseGit());
423  d->setPwgenPath(QtPassSettings::getPwgenExecutable());
424  d->usePwgen(QtPassSettings::isUsePwgen());
425  d->avoidCapitals(QtPassSettings::isAvoidCapitals());
426  d->avoidNumbers(QtPassSettings::isAvoidNumbers());
427  d->lessRandom(QtPassSettings::isLessRandom());
428  d->useSymbols(QtPassSettings::isUseSymbols());
429  d->setPasswordLength(pwdConfig.length);
430  d->setPwdTemplateSelector(pwdConfig.selected);
432  d->setLineEditEnabled(false);
433  d->setPasswordChars(pwdConfig.Characters[pwdConfig.selected]);
434  d->useTemplate(QtPassSettings::isUseTemplate());
435  d->setTemplate(QtPassSettings::getPassTemplate());
436  d->templateAllFields(QtPassSettings::isTemplateAllFields());
437  d->autoPull(QtPassSettings::isAutoPull());
438  d->autoPush(QtPassSettings::isAutoPush());
439  d->alwaysOnTop(QtPassSettings::isAlwaysOnTop());
440  if (startupPhase)
441  d->wizard(); // does shit
442  if (d->exec()) {
443  if (d->result() == QDialog::Accepted) {
444  QtPassSettings::setPassExecutable(d->getPassPath());
445  QtPassSettings::setGitExecutable(d->getGitPath());
446  QtPassSettings::setGpgExecutable(d->getGpgPath());
448  Util::normalizeFolderPath(d->getStorePath()));
449  QtPassSettings::setUsePass(d->usePass());
450  QtPassSettings::setClipBoardType(d->useClipboard());
451  QtPassSettings::setUseSelection(d->useSelection());
452  QtPassSettings::setUseAutoclear(d->useAutoclear());
453  QtPassSettings::setAutoclearSeconds(d->getAutoclear());
454  QtPassSettings::setUseAutoclearPanel(d->useAutoclearPanel());
455  QtPassSettings::setAutoclearPanelSeconds(d->getAutoclearPanel());
456  QtPassSettings::setHidePassword(d->hidePassword());
457  QtPassSettings::setHideContent(d->hideContent());
458  QtPassSettings::setAddGPGId(d->addGPGId());
459  QtPassSettings::setUseTrayIcon(d->useTrayIcon());
460  QtPassSettings::setHideOnClose(d->hideOnClose());
461  QtPassSettings::setStartMinimized(d->startMinimized());
462  QtPassSettings::setProfiles(d->getProfiles());
463  QtPassSettings::setUseGit(d->useGit());
464  QtPassSettings::setPwgenExecutable(d->getPwgenPath());
465  QtPassSettings::setUsePwgen(d->usePwgen());
466  QtPassSettings::setAvoidCapitals(d->avoidCapitals());
467  QtPassSettings::setAvoidNumbers(d->avoidNumbers());
468  QtPassSettings::setLessRandom(d->lessRandom());
469  QtPassSettings::setUseSymbols(d->useSymbols());
470  pwdConfig.length = d->getPasswordLength();
472  d->getPwdTemplateSelector());
474  d->getPasswordChars();
475  QtPassSettings::setUseTemplate(d->useTemplate());
476  QtPassSettings::setPassTemplate(d->getTemplate());
477  QtPassSettings::setTemplateAllFields(d->templateAllFields());
478  QtPassSettings::setAutoPush(d->autoPush());
479  QtPassSettings::setAutoPull(d->autoPull());
480  QtPassSettings::setAlwaysOnTop(d->alwaysOnTop());
481 
487 
489  Qt::WindowFlags flags = windowFlags();
490  this->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
491  this->show();
492  } else {
493  this->setWindowFlags(Qt::Window);
494  this->show();
495  }
496 
497  updateProfileBox();
498  ui->treeView->setRootIndex(proxyModel.mapFromSource(
499  model.setRootPath(QtPassSettings::getPassStore())));
500 
501  if (freshStart && Util::checkConfig())
502  config();
504  clearPanelTimer.setInterval(1000 *
506  clearClipboardTimer.setInterval(1000 *
508 
509  if (!QtPassSettings::isUseGit() ||
510  (QtPassSettings::getGitExecutable().isEmpty() &&
511  QtPassSettings::getPassExecutable().isEmpty())) {
512  ui->pushButton->hide();
513  ui->updateButton->hide();
514  ui->horizontalSpacer->changeSize(0, 20, QSizePolicy::Maximum,
515  QSizePolicy::Minimum);
516  } else {
517  ui->pushButton->show();
518  ui->updateButton->show();
519  ui->horizontalSpacer->changeSize(24, 24, QSizePolicy::Minimum,
520  QSizePolicy::Minimum);
521  }
522  if (QtPassSettings::isUseTrayIcon() && tray == NULL)
523  initTrayIcon();
524  else if (!QtPassSettings::isUseTrayIcon() && tray != NULL)
525  destroyTrayIcon();
526  }
527  freshStart = false;
528  }
529 }
530 
534 void MainWindow::on_updateButton_clicked(bool block) {
535  ui->statusBar->showMessage(tr("Updating password-store"), 2000);
536  if (block)
538  else
540 }
541 
545 void MainWindow::on_pushButton_clicked() {
546  if (QtPassSettings::isUseGit()) {
547  ui->statusBar->showMessage(tr("Updating password-store"), 2000);
549  }
550 }
551 
559 QString MainWindow::getFile(const QModelIndex &index, bool forPass) {
560  if (!index.isValid() ||
561  !model.fileInfo(proxyModel.mapToSource(index)).isFile())
562  return QString();
563  QString filePath = model.filePath(proxyModel.mapToSource(index));
564  if (forPass) {
565  filePath = QDir(QtPassSettings::getPassStore()).relativeFilePath(filePath);
566  filePath.replace(QRegExp("\\.gpg$"), "");
567  }
568  return filePath;
569 }
570 
575 void MainWindow::on_treeView_clicked(const QModelIndex &index) {
576  bool cleared = ui->treeView->currentIndex().flags() == Qt::NoItemFlags;
577  currentDir =
578  Util::getDir(ui->treeView->currentIndex(), false, model, proxyModel);
579  // TODO(bezet): "Could not decrypt";
580  clippedText = "";
581  QString file = getFile(index, true);
582  ui->passwordName->setText(getFile(index, true));
583  if (!file.isEmpty() && !cleared) {
584  QtPassSettings::getPass()->Show(file);
585  } else {
586  clearPanel(false);
587  ui->editButton->setEnabled(false);
588  ui->deleteButton->setEnabled(true);
589  }
590 }
591 
597 void MainWindow::on_treeView_doubleClicked(const QModelIndex &index) {
598  QFileInfo fileOrFolder =
599  model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
600 
601  if (fileOrFolder.isFile()) {
602  editPassword(getFile(index, true));
603  }
604 }
605 
610  currentDir = "/";
611  clearClipboard();
612  ui->passwordName->setText("");
613  clearPanel(false);
614 }
615 
620  dbg() << "Pass git init called";
622 }
623 
624 void MainWindow::executeWrapperStarted() {
625  clearTemplateWidgets();
626  ui->textBrowser->clear();
627  enableUiElements(false);
628  clearPanelTimer.stop();
629 }
630 
631 void MainWindow::keyGenerationComplete(const QString &p_output,
632  const QString &p_errout) {
633  // qDebug() << p_output;
634  // qDebug() << p_errout;
635  if (0 != keygen) {
636  qDebug() << "Keygen Done";
637  keygen->close();
638  keygen = 0;
639  // TODO(annejan) some sanity checking ?
640  }
641  processFinished(p_output, p_errout);
642 }
643 
644 void MainWindow::passShowHandler(const QString &p_output) {
645  QString output = p_output;
646  {
647  QStringList tokens = p_output.split("\n");
648  QString password = tokens.at(0);
649  tokens.erase(tokens.begin());
650 
652  !p_output.isEmpty()) {
653  clippedText = password;
655  copyTextToClipboard(password);
657  clearPanelTimer.start();
658  }
661  output = "***" + tr("Password hidden") + "***";
662  output += tokens.join("\n");
663  }
665  output = "***" + tr("Content hidden") + "***";
666  }
667 
668  clearTemplateWidgets();
670  QStringList remainingTokens;
671  for (int j = 0; j < tokens.length(); ++j) {
672  QString token = tokens.at(j);
673  if (token.contains(':')) {
674  int colon = token.indexOf(':');
675  QString field = token.left(colon);
677  QtPassSettings::getPassTemplate().contains(field)) {
678  QString value = token.right(token.length() - colon - 1);
679  if (!QtPassSettings::getPassTemplate().contains(field) &&
680  value.startsWith("//")) {
681  remainingTokens.append(token);
682  continue; // colon is probably from a url
683  }
684  addToGridLayout(j + 1, field, value);
685  }
686  } else {
687  remainingTokens.append(token);
688  }
689  }
690  if (ui->gridLayout->count() == 0)
691  ui->verticalLayoutPassword->setSpacing(0);
692  else
693  ui->verticalLayoutPassword->setSpacing(6);
694  output = remainingTokens.join("\n");
695  } else if (!QtPassSettings::isHideContent()) {
696  output = tokens.join("\n");
697  }
698  if (!QtPassSettings::isHideContent() && !password.isEmpty()) {
699  // now set the password. If we set it earlier, the layout will be
700  // cleared
701  addToGridLayout(0, tr("Password"), password);
702  }
704  clearPanelTimer.start();
705  }
706  }
707 
708  DisplayInTextBrowser(output);
709  enableUiElements(true);
710 }
711 
712 void MainWindow::passStoreChanged(const QString &p_out, const QString &p_err) {
713  processFinished(p_out, p_err);
714  doGitPush();
715 }
716 
717 void MainWindow::doGitPush() {
719  on_pushButton_clicked();
720 }
721 
722 void MainWindow::finishedInsert(const QString &p_output,
723  const QString &p_errout) {
724  processFinished(p_output, p_errout);
725  doGitPush();
726  on_treeView_clicked(ui->treeView->currentIndex());
727 }
728 
729 void MainWindow::DisplayInTextBrowser(QString output, QString prefix,
730  QString postfix) {
731 
732  output.replace(QRegExp("<"), "&lt;");
733  output.replace(QRegExp(">"), "&gt;");
734  output.replace(QRegExp(" "), "&nbsp;");
735 
736  output.replace(QRegExp("((?:https?|ftp|ssh)://\\S+)"),
737  "<a href=\"\\1\">\\1</a>");
738  output.replace(QRegExp("\n"), "<br />");
739  output = prefix + output + postfix;
740  if (!ui->textBrowser->toPlainText().isEmpty())
741  output = ui->textBrowser->toHtml() + output;
742  ui->textBrowser->setHtml(output);
743 }
744 
745 void MainWindow::processErrorExit(int exitCode, const QString &p_error) {
746  if (!p_error.isEmpty()) {
747  QString output;
748  QString error = p_error;
749  error.replace(QRegExp("<"), "&lt;");
750  error.replace(QRegExp(">"), "&gt;");
751  error.replace(QRegExp(" "), "&nbsp;");
752  if (exitCode == 0) {
753  // https://github.com/IJHack/qtpass/issues/111
754  output = "<span style=\"color: darkgray;\">" + error + "</span><br />";
755  } else {
756  output = "<span style=\"color: red;\">" + error + "</span><br />";
757  }
758 
759  output.replace(QRegExp("((?:https?|ftp|ssh)://\\S+)"),
760  "<a href=\"\\1\">\\1</a>");
761  output.replace(QRegExp("\n"), "<br />");
762  if (!ui->textBrowser->toPlainText().isEmpty())
763  output = ui->textBrowser->toHtml() + output;
764  ui->textBrowser->setHtml(output);
765  }
766  enableUiElements(true);
767 }
768 
772 void MainWindow::clearClipboard() {
773  QClipboard *clipboard = QApplication::clipboard();
775  QString clippedText = clipboard->text(QClipboard::Clipboard);
776  } else {
777  QString clippedText = clipboard->text(QClipboard::Selection);
778  }
779  if (clippedText == this->clippedText) {
781  clipboard->clear(QClipboard::Clipboard);
782  } else {
783  clipboard->clear(QClipboard::Selection);
784  }
785  ui->statusBar->showMessage(tr("Clipboard cleared"), 2000);
786  } else {
787  ui->statusBar->showMessage(tr("Clipboard not cleared"), 2000);
788  }
789 }
790 
794 void MainWindow::clearPanel(bool notify) {
795  while (ui->gridLayout->count() > 0) {
796  QLayoutItem *item = ui->gridLayout->takeAt(0);
797  delete item->widget();
798  delete item;
799  }
800  if (notify) {
801  QString output = "***" + tr("Password and Content hidden") + "***";
802  ui->textBrowser->setHtml(output);
803  } else {
804  ui->textBrowser->setHtml("");
805  }
806 }
807 
815 void MainWindow::processFinished(const QString &p_output,
816  const QString &p_errout) {
817  DisplayInTextBrowser(p_output);
818  // Sometimes there is error output even with 0 exit code, which is
819  // assumed in this function
820  processErrorExit(0, p_errout);
821  enableUiElements(true);
822 }
823 
829 void MainWindow::enableUiElements(bool state) {
830  ui->updateButton->setEnabled(state);
831  ui->treeView->setEnabled(state);
832  ui->lineEdit->setEnabled(state);
833  ui->lineEdit->installEventFilter(this);
834  ui->addButton->setEnabled(state);
835  ui->usersButton->setEnabled(state);
836  ui->configButton->setEnabled(state);
837  // is a file selected?
838  state &= ui->treeView->currentIndex().isValid();
839  ui->deleteButton->setEnabled(state);
840  ui->editButton->setEnabled(state);
841  ui->pushButton->setEnabled(state);
842 }
843 
848 void MainWindow::processError(QProcess::ProcessError error) {
849  QString errorString;
850  switch (error) {
851  case QProcess::FailedToStart:
852  errorString = tr("QProcess::FailedToStart");
853  break;
854  case QProcess::Crashed:
855  errorString = tr("QProcess::Crashed");
856  break;
857  case QProcess::Timedout:
858  errorString = tr("QProcess::Timedout");
859  break;
860  case QProcess::ReadError:
861  errorString = tr("QProcess::ReadError");
862  break;
863  case QProcess::WriteError:
864  errorString = tr("QProcess::WriteError");
865  break;
866  case QProcess::UnknownError:
867  errorString = tr("QProcess::UnknownError");
868  break;
869  }
870  ui->textBrowser->setTextColor(Qt::red);
871  ui->textBrowser->setText(errorString);
872  ui->textBrowser->setTextColor(Qt::black);
873  enableUiElements(true);
874 }
875 
879 void MainWindow::on_configButton_clicked() { config(); }
880 
886 void MainWindow::on_lineEdit_textChanged(const QString &arg1) {
887  ui->treeView->expandAll();
888  ui->statusBar->showMessage(tr("Looking for: %1").arg(arg1), 1000);
889  QString query = arg1;
890  query.replace(QRegExp(" "), ".*");
891  QRegExp regExp(query, Qt::CaseInsensitive);
892  proxyModel.setFilterRegExp(regExp);
893  ui->treeView->setRootIndex(proxyModel.mapFromSource(
894  model.setRootPath(QtPassSettings::getPassStore())));
895  selectFirstFile();
896 }
897 
903 void MainWindow::on_lineEdit_returnPressed() {
904  dbg() << "on_lineEdit_returnPressed";
905  selectFirstFile();
906  on_treeView_clicked(ui->treeView->currentIndex());
907 }
908 
913 void MainWindow::selectFirstFile() {
914  QModelIndex index = proxyModel.mapFromSource(
915  model.setRootPath(QtPassSettings::getPassStore()));
916  index = firstFile(index);
917  ui->treeView->setCurrentIndex(index);
918 }
919 
925 QModelIndex MainWindow::firstFile(QModelIndex parentIndex) {
926  QModelIndex index = parentIndex;
927  int numRows = proxyModel.rowCount(parentIndex);
928  for (int row = 0; row < numRows; ++row) {
929  index = proxyModel.index(row, 0, parentIndex);
930  if (model.fileInfo(proxyModel.mapToSource(index)).isFile())
931  return index;
932  if (proxyModel.hasChildren(index))
933  return firstFile(index);
934  }
935  return index;
936 }
937 
945 void MainWindow::setPassword(QString file, bool isNew) {
946  PasswordDialog d(pwdConfig, this);
949  // TODO(bezet): add error handling
950  QtPassSettings::getPass()->Show(file);
951  d.setFile(file);
956  if (!d.exec()) {
957  d.setPassword(QString());
958  return;
959  }
960  QString newValue = d.getPassword();
961  if (newValue.isEmpty())
962  return;
963 
964  if (newValue.right(1) != "\n")
965  newValue += "\n";
966 
967  QtPassSettings::getPass()->Insert(file, newValue, !isNew);
968 }
969 
974 void MainWindow::on_addButton_clicked() {
975  bool ok;
976  QString dir =
977  Util::getDir(ui->treeView->currentIndex(), true, model, proxyModel);
978  QString file =
979  QInputDialog::getText(this, tr("New file"),
980  tr("New password file: \n(Will be placed in %1 )")
982  Util::getDir(ui->treeView->currentIndex(),
983  true, model, proxyModel)),
984  QLineEdit::Normal, "", &ok);
985  if (!ok || file.isEmpty())
986  return;
987  file = dir + file;
988  setPassword(file);
989 }
990 
995 void MainWindow::on_deleteButton_clicked() {
996  QFileInfo fileOrFolder =
997  model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
998  QString file = "";
999  bool isDir = false;
1000 
1001  if (fileOrFolder.isFile()) {
1002  file = getFile(ui->treeView->currentIndex(), true);
1003  } else {
1004  file = Util::getDir(ui->treeView->currentIndex(), true, model, proxyModel);
1005  isDir = true;
1006  }
1007 
1008  if (QMessageBox::question(
1009  this, isDir ? tr("Delete folder?") : tr("Delete password?"),
1010  tr("Are you sure you want to delete %1%2?")
1011  .arg(QDir::separator() + file)
1012  .arg(isDir ? tr(" and whole content") : ""),
1013  QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
1014  return;
1015 
1016  QtPassSettings::getPass()->Remove(file, isDir);
1017 }
1018 
1022 void MainWindow::on_editButton_clicked() {
1023  QString file = getFile(ui->treeView->currentIndex(), true);
1024  editPassword(file);
1025 }
1026 
1031 void MainWindow::userDialog(QString dir) {
1032  if (!dir.isEmpty())
1033  currentDir = dir;
1034  on_usersButton_clicked();
1035 }
1036 
1042 void MainWindow::on_usersButton_clicked() {
1043  QList<UserInfo> users = QtPassSettings::getPass()->listKeys();
1044  if (users.size() == 0) {
1045  QMessageBox::critical(this, tr("Can not get key list"),
1046  tr("Unable to get list of available gpg keys"));
1047  return;
1048  }
1049  QList<UserInfo> secret_keys = QtPassSettings::getPass()->listKeys("", true);
1050  foreach (const UserInfo &sec, secret_keys) {
1051  for (QList<UserInfo>::iterator it = users.begin(); it != users.end(); ++it)
1052  if (sec.key_id == it->key_id)
1053  it->have_secret = true;
1054  }
1055  QList<UserInfo> selected_users;
1056  QString dir =
1057  currentDir.isEmpty()
1058  ? Util::getDir(ui->treeView->currentIndex(), false, model, proxyModel)
1059  : currentDir;
1060  int count = 0;
1061  QString recipients = QtPassSettings::getPass()->getRecipientString(
1062  dir.isEmpty() ? "" : dir, " ", &count);
1063  if (!recipients.isEmpty())
1064  selected_users = QtPassSettings::getPass()->listKeys(recipients);
1065  foreach (const UserInfo &sel, selected_users) {
1066  for (QList<UserInfo>::iterator it = users.begin(); it != users.end(); ++it)
1067  if (sel.key_id == it->key_id)
1068  it->enabled = true;
1069  }
1070  if (count > selected_users.size()) {
1071  // Some keys seem missing from keyring, add them separately
1072  QStringList recipients =
1073  QtPassSettings::getPass()->getRecipientList(dir.isEmpty() ? "" : dir);
1074  foreach (const QString recipient, recipients) {
1075  if (QtPassSettings::getPass()->listKeys(recipient).size() < 1) {
1076  UserInfo i;
1077  i.enabled = true;
1078  i.key_id = recipient;
1079  i.name = " ?? " + tr("Key not found in keyring");
1080  users.append(i);
1081  }
1082  }
1083  }
1084  UsersDialog d(this);
1085  d.setUsers(&users);
1086  if (!d.exec()) {
1087  d.setUsers(NULL);
1088  return;
1089  }
1090  d.setUsers(NULL);
1091 
1092  QtPassSettings::getPass()->Init(dir, users);
1093 }
1094 
1100 #if SINGLE_APP
1101  connect(app, SIGNAL(messageAvailable(QString)), this,
1102  SLOT(messageAvailable(QString)));
1103 #endif
1104 }
1105 
1110 void MainWindow::messageAvailable(QString message) {
1111  if (message.isEmpty()) {
1112  focusInput();
1113  } else {
1114  ui->treeView->expandAll();
1115  ui->lineEdit->setText(message);
1116  on_lineEdit_returnPressed();
1117  }
1118  show();
1119  raise();
1120 }
1121 
1127 void MainWindow::setText(QString text) { ui->lineEdit->setText(text); }
1128 
1134  QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
1135  QStringList names;
1136 
1137  if (keys.size() == 0)
1138  return names;
1139 
1140  foreach (const UserInfo &sec, keys)
1141  names << sec.name;
1142 
1143  return names;
1144 }
1145 
1151 void MainWindow::generateKeyPair(QString batch, QDialog *keygenWindow) {
1152  keygen = keygenWindow;
1153  ui->statusBar->showMessage(tr("Generating GPG key pair"), 60000);
1155 }
1156 
1161 void MainWindow::updateProfileBox() {
1162  // dbg()<< profiles.size();
1163  if (QtPassSettings::getProfiles().isEmpty()) {
1164  ui->profileBox->hide();
1165  } else {
1166  ui->profileBox->show();
1167  if (QtPassSettings::getProfiles().size() < 2)
1168  ui->profileBox->setEnabled(false);
1169  else
1170  ui->profileBox->setEnabled(true);
1171  ui->profileBox->clear();
1172  QHashIterator<QString, QString> i(QtPassSettings::getProfiles());
1173  while (i.hasNext()) {
1174  i.next();
1175  if (!i.key().isEmpty())
1176  ui->profileBox->addItem(i.key());
1177  }
1178  }
1179  int index = ui->profileBox->findText(QtPassSettings::getProfile());
1180  if (index != -1) // -1 for not found
1181  ui->profileBox->setCurrentIndex(index);
1182 }
1183 
1189 void MainWindow::on_profileBox_currentIndexChanged(QString name) {
1190  if (startupPhase || name == QtPassSettings::getProfile())
1191  return;
1193 
1195  ui->statusBar->showMessage(tr("Profile changed to %1").arg(name), 2000);
1196 
1198 
1199  ui->treeView->setRootIndex(proxyModel.mapFromSource(
1200  model.setRootPath(QtPassSettings::getPassStore())));
1201 }
1202 
1208 void MainWindow::initTrayIcon() {
1209  if (tray != NULL) {
1210  dbg() << "Creating tray icon again?";
1211  return;
1212  }
1213  if (QSystemTrayIcon::isSystemTrayAvailable() == true) {
1214  // Setup tray icon
1215  this->tray = new TrayIcon(this);
1216  if (tray == NULL)
1217  dbg() << "Allocating tray icon failed.";
1218  } else {
1219  dbg() << "No tray icon for this OS possibly also not show options?";
1220  }
1221 }
1222 
1226 void MainWindow::destroyTrayIcon() {
1227  if (tray == NULL) {
1228  dbg() << "Destroy non existing tray icon?";
1229  return;
1230  }
1231  delete this->tray;
1232  tray = NULL;
1233 }
1234 
1239 void MainWindow::closeEvent(QCloseEvent *event) {
1241  this->hide();
1242  event->ignore();
1243  } else {
1244  clearClipboard();
1245  QtPassSettings::setGeometry(saveGeometry());
1246  QtPassSettings::setSavestate(saveState());
1247  QtPassSettings::setMaximized(isMaximized());
1248  if (!isMaximized()) {
1249  QtPassSettings::setPos(pos());
1250  QtPassSettings::setSize(size());
1251  }
1252  QtPassSettings::setSplitterLeft(ui->splitter->sizes()[0]);
1253  QtPassSettings::setSplitterRight(ui->splitter->sizes()[1]);
1254  event->accept();
1255  }
1256 }
1257 
1265 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
1266  if (obj == ui->lineEdit && event->type() == QEvent::KeyPress) {
1267  QKeyEvent *key = static_cast<QKeyEvent *>(event);
1268  if (key->key() == Qt::Key_Down) {
1269  ui->treeView->setFocus();
1270  }
1271  }
1272  return QObject::eventFilter(obj, event);
1273 }
1274 
1279 void MainWindow::keyPressEvent(QKeyEvent *event) {
1280  switch (event->key()) {
1281  case Qt::Key_Delete:
1282  on_deleteButton_clicked();
1283  break;
1284  case Qt::Key_Return:
1285  case Qt::Key_Enter:
1286  on_treeView_clicked(ui->treeView->currentIndex());
1287  break;
1288  case Qt::Key_Escape:
1289  ui->lineEdit->clear();
1290  break;
1291  default:
1292  break;
1293  }
1294 }
1295 
1301 void MainWindow::showContextMenu(const QPoint &pos) {
1302  QModelIndex index = ui->treeView->indexAt(pos);
1303  bool selected = true;
1304  if (!index.isValid()) {
1305  ui->treeView->clearSelection();
1306  ui->deleteButton->setEnabled(false);
1307  ui->editButton->setEnabled(false);
1308  currentDir = "";
1309  selected = false;
1310  }
1311 
1312  ui->treeView->setCurrentIndex(index);
1313 
1314  QPoint globalPos = ui->treeView->viewport()->mapToGlobal(pos);
1315 
1316  QFileInfo fileOrFolder =
1317  model.fileInfo(proxyModel.mapToSource(ui->treeView->currentIndex()));
1318 
1319  QMenu contextMenu;
1320  if (!selected || fileOrFolder.isDir()) {
1321  QAction *addFolder = contextMenu.addAction(tr("Add folder"));
1322  QAction *addPassword = contextMenu.addAction(tr("Add password"));
1323  QAction *users = contextMenu.addAction(tr("Users"));
1324  connect(addFolder, SIGNAL(triggered()), this, SLOT(addFolder()));
1325  connect(addPassword, SIGNAL(triggered()), this,
1326  SLOT(on_addButton_clicked()));
1327  connect(users, SIGNAL(triggered()), this, SLOT(on_usersButton_clicked()));
1328  } else if (fileOrFolder.isFile()) {
1329  QAction *edit = contextMenu.addAction(tr("Edit"));
1330  connect(edit, SIGNAL(triggered()), this, SLOT(on_editButton_clicked()));
1331  }
1332  if (selected) {
1333  // if (useClipboard != CLIPBOARD_NEVER) {
1334  // contextMenu.addSeparator();
1335  // QAction* copyItem = contextMenu.addAction(tr("Copy Password"));
1336  // if (getClippedPassword().length() == 0) copyItem->setEnabled(false);
1337  // connect(copyItem, SIGNAL(triggered()), this,
1338  // SLOT(copyPasswordToClipboard()));
1339  // }
1340  contextMenu.addSeparator();
1341  QAction *deleteItem = contextMenu.addAction(tr("Delete"));
1342  connect(deleteItem, SIGNAL(triggered()), this,
1343  SLOT(on_deleteButton_clicked()));
1344  }
1345  contextMenu.exec(globalPos);
1346 }
1347 
1353 void MainWindow::showBrowserContextMenu(const QPoint &pos) {
1354  QMenu *contextMenu = ui->textBrowser->createStandardContextMenu(pos);
1355  QPoint globalPos = ui->textBrowser->viewport()->mapToGlobal(pos);
1356 
1357  contextMenu->exec(globalPos);
1358 }
1359 
1363 void MainWindow::addFolder() {
1364  bool ok;
1365  QString dir =
1366  Util::getDir(ui->treeView->currentIndex(), false, model, proxyModel);
1367  QString newdir =
1368  QInputDialog::getText(this, tr("New file"),
1369  tr("New Folder: \n(Will be placed in %1 )")
1371  Util::getDir(ui->treeView->currentIndex(),
1372  true, model, proxyModel)),
1373  QLineEdit::Normal, "", &ok);
1374  if (!ok || newdir.isEmpty())
1375  return;
1376  newdir.prepend(dir);
1377  // dbg()<< newdir;
1378  QDir().mkdir(newdir);
1379 }
1380 
1385 void MainWindow::editPassword(const QString &file) {
1386  if (!file.isEmpty()) {
1388  on_updateButton_clicked(true);
1389  setPassword(file, false);
1390  }
1391 }
1392 
1397 void MainWindow::clearTemplateWidgets() {
1398  while (ui->gridLayout->count() > 0) {
1399  QLayoutItem *item = ui->gridLayout->takeAt(0);
1400  delete item->widget();
1401  delete item;
1402  }
1403  ui->verticalLayoutPassword->setSpacing(0);
1404 }
1405 
1410 void MainWindow::copyTextToClipboard(const QString &text) {
1411  QClipboard *clip = QApplication::clipboard();
1413  clip->setText(text, QClipboard::Clipboard);
1414  } else {
1415  clip->setText(text, QClipboard::Selection);
1416  }
1417  clippedText = text;
1418  ui->statusBar->showMessage(tr("Copied to clipboard"), 2000);
1420  clearClipboardTimer.start();
1421  }
1422 }
1423 
1430 void MainWindow::addToGridLayout(int position, const QString &field,
1431  const QString &value) {
1432  QString trimmedField = field.trimmed();
1433  QString trimmedValue = value.trimmed();
1434 
1435  // Combine the Copy button and the line edit in one widget
1436  QFrame *frame = new QFrame();
1437  QLayout *ly = new QHBoxLayout();
1438  ly->setContentsMargins(5, 2, 2, 2);
1439  frame->setLayout(ly);
1441  QPushButtonWithClipboard *fieldLabel =
1442  new QPushButtonWithClipboard(trimmedValue, this);
1443  connect(fieldLabel, SIGNAL(clicked(QString)), this,
1444  SLOT(copyTextToClipboard(QString)));
1445 
1446  fieldLabel->setStyleSheet("border-style: none ; background: transparent;");
1447  // fieldLabel->setContentsMargins(0,5,5,0);
1448  frame->layout()->addWidget(fieldLabel);
1449  }
1450 
1451  // set the echo mode to password, if the field is "password"
1452  if (QtPassSettings::isHidePassword() && trimmedField == tr("Password")) {
1453  QLineEdit *line = new QLineEdit();
1454  line->setObjectName(trimmedField);
1455  line->setText(trimmedValue);
1456  line->setReadOnly(true);
1457  line->setStyleSheet("border-style: none ; background: transparent;");
1458  line->setContentsMargins(0, 0, 0, 0);
1459  line->setEchoMode(QLineEdit::Password);
1460  frame->layout()->addWidget(line);
1461  } else {
1462  QTextBrowser *line = new QTextBrowser();
1463  line->setOpenExternalLinks(true);
1464  line->setOpenLinks(true);
1465  line->setMaximumHeight(26);
1466  line->setMinimumHeight(26);
1467  line->setSizePolicy(
1468  QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));
1469  line->setObjectName(trimmedField);
1470  trimmedValue.replace(QRegExp("((?:https?|ftp|ssh)://\\S+)"),
1471  "<a href=\"\\1\">\\1</a>");
1472  line->setText(trimmedValue);
1473  line->setReadOnly(true);
1474  line->setStyleSheet("border-style: none ; background: transparent;");
1475  line->setContentsMargins(0, 0, 0, 0);
1476  frame->layout()->addWidget(line);
1477  }
1478 
1479  frame->setStyleSheet(
1480  ".QFrame{border: 1px solid lightgrey; border-radius: 5px;}");
1481 
1482  // set into the layout
1483  ui->gridLayout->addWidget(new QLabel(trimmedField), position, 0);
1484  ui->gridLayout->addWidget(frame, position, 1);
1485 }
1486 
1493 void MainWindow::showStatusMessage(QString msg, int timeout) {
1494  ui->statusBar->showMessage(msg, timeout);
1495 }
1496 
1500 void MainWindow::startReencryptPath() {
1501  enableUiElements(false);
1502  ui->treeView->setDisabled(true);
1503 }
1504 
1508 void MainWindow::endReencryptPath() { enableUiElements(true); }
1509 
1515 void MainWindow::critical(QString title, QString msg) {
1516  QMessageBox::critical(this, title, msg);
1517 }
static void setPwgenExecutable(const QString &pwgenExecutable)
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())
void setFile(QString)
Sets the file (name) in the interface.
static void setPassExecutable(const QString &passExecutable)
void GenerateGPGKeys(QString batch)
Pass::GenerateGPGKeys internal gpg keypair generator . .
Definition: pass.cpp:112
passwordConfiguration pwdConfig
MainWindow::pwdConfig instance of passwordConfiguration.
Definition: mainwindow.h:61
void setText(QString)
MainWindow::setText do a search from an external source (eg: commandline)
int length
passwordConfiguration::length of password.
Definition: datahelpers.h:25
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: datahelpers.h:85
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:126
static void setPasswordChars(const QString &passwordChars)
static QString findBinaryInPath(QString binary)
Util::findBinaryInPath search for executables.
Definition: util.cpp:78
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: datahelpers.h:71
static void setPassTemplate(const QString &passTemplate)
void usePwgen(bool usePwgen)
PasswordDialog::usePwgen PasswordDialog::usePwgen don&#39;t use own password generator.
void finishedInsert(const QString &, const QString &)
~MainWindow()
MainWindow::~MainWindow destroy!
Definition: mainwindow.cpp:108
static QString getPasswordChars(const QString &defaultValue=QVariant().toString())
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 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)
void templateAll(bool templateAll)
PasswordDialog::templateAll basic setter for use in PasswordDialog::setPassword templating all tokeni...
static void setSplitterRight(const int &splitterRight)
QString Characters[CHARSETS_COUNT]
passwordConfiguration::Characters the different character sets.
Definition: datahelpers.h:29
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:396
Acts as an abstraction for pass or pass imitation.
Definition: pass.h:18
static QString getPassStore(const QString &defaultValue=QVariant().toString())
void setTemplate(QString)
Sets content in the template for the interface.
static void setProfile(const QString &profile)
void userDialog(QString="")
MainWindow::userDialog see MainWindow::on_usersButton_clicked()
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:79
static void setUseAutoclearPanel(const bool &useAutoclearPanel)
enum passwordConfiguration::characterSet selected
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.
void setUsers(QList< UserInfo > *)
UsersDialog::setUsers update all the users.
Definition: usersdialog.cpp:48
static QString getRecipientString(QString for_file, QString separator=" ", int *count=NULL)
Pass::getRecipientString formated string for use with GPG.
Definition: pass.cpp:275
Handles listing and editing of GPG users.
Definition: usersdialog.h:23
virtual void GitPull_b()=0
void changeEvent(QEvent *event)
MainWindow::changeEvent sets focus to the search box.
Definition: mainwindow.cpp:125
static void setAvoidNumbers(const bool &avoidNumbers)
static QString getPassExecutable(const QString &defaultValue=QVariant().toString())
void setPassword(QString password)
Sets content in the password field in the interface.
Handles the systemtray icon and menu.
Definition: trayicon.h:15
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:619
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:239
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
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:35
void finishedInit(const QString &, const QString &)
static bool isUsePwgen(const bool &defaultValue=QVariant().toBool())
static void setSavestate(const QByteArray &saveState)
void useTemplate(bool useTemplate)
PasswordDialog::useTemplate basic setter for use in PasswordDialog::useTemplate templating.
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())
QString getPassword()
Returns the password as set in the password field in the interface.
void updateEnv()
Pass::updateEnv update the execution environment (used when switching profiles)
Definition: pass.cpp:218
The ConfigDialog handles the configuration interface.
Definition: configdialog.h:22
QString name
UserInfo::name full name.
Definition: datahelpers.h:67
bool checkConfig()
MainWindow::checkConfig make sure we are ready to go as soon as possible.
Definition: mainwindow.cpp:236
Stores key info lines including validity, creation date and more.
Definition: datahelpers.h:46
static void setUseTemplate(const bool &useTemplate)
static QByteArray getGeometry(const QByteArray &defaultValue=QVariant().toByteArray())
static void setPasswordCharsselection(const int &passwordCharsselection)
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 QString getDir(const QModelIndex &index, bool forPass, const QFileSystemModel &model, const StoreModel &storeModel)
Util::getDir get selectd folder path.
Definition: util.cpp:149
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:609
static void setUseTrayIcon(const bool &useTrayIcon)
static void setGeometry(const QByteArray &geometry)
static int getSplitterLeft(const int &defaultValue=QVariant().toInt())
void generateKeyPair(QString, QDialog *)
MainWindow::generateKeyPair internal gpg keypair generator . .
characterSet
passwordConfiguration::selected character set.
Definition: datahelpers.h:15
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:42
static RealPass * getRealPass()
static bool isHidePassword(const bool &defaultValue=QVariant().toBool())
static QString findPasswordStore()
Util::findPasswordStore look for common .password-store folder location.
Definition: util.cpp:44
static bool isHideContent(const bool &defaultValue=QVariant().toBool())
static bool checkConfig()
Util::checkConfig do we have prequisite settings?
Definition: util.cpp:121
static QString getProfile(const QString &defaultValue=QVariant().toString())
static void setVersion(const QString &version)
static void setHidePassword(const bool &hidePassword)
static void setPassStore(const QString &passStore)
static void setUseSelection(const bool &useSelection)
static void setPasswordLength(const int &passwordLength)
static int getPasswordCharsselection(const int &defaultValue=QVariant().toInt())
static int getPasswordLength(const int &defaultValue=QVariant().toInt())
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:67
static bool isAutoPush(const bool &defaultValue=QVariant().toBool())
static void setAvoidCapitals(const bool &avoidCapitals)