diff --git a/src/gui/Application.cpp b/src/gui/Application.cpp index 402b50c3d..969f623d7 100644 --- a/src/gui/Application.cpp +++ b/src/gui/Application.cpp @@ -51,6 +51,7 @@ enum Application::SocketCmd : quint32 { OpenFiles = 1, LockAll, + Unlock, }; Application::Application(int& argc, char** argv) @@ -327,8 +328,7 @@ void Application::socketReadyRead() } SocketCmd id; - // manual reinterpret_cast not needed for Qt 5.14+ - in >> reinterpret_cast::type&>(id); + in >> id; switch (id) { case SocketCmd::OpenFiles: { @@ -345,6 +345,11 @@ void Application::socketReadyRead() case SocketCmd::LockAll: getMainWindow()->lockAllDatabases(); break; + case SocketCmd::Unlock: + QString filename, password, keyfile; + in >> filename >> password >> keyfile; + emit openFile(filename, password, keyfile); + break; } socket->deleteLater(); @@ -352,10 +357,6 @@ void Application::socketReadyRead() bool Application::isAlreadyRunning() const { -#ifdef QT_DEBUG - // In DEBUG mode we can run unlimited instances - return false; -#endif return config()->get(Config::SingleInstance).toBool() && m_alreadyRunning; } @@ -392,7 +393,7 @@ bool Application::sendSocketCommand(SocketCmd id, const std::functionsendSocketCommand(SocketCmd::OpenFiles, [fileNames](QDataStream& out) { out << fileNames; }); + return this->sendSocketCommand(SocketCmd::OpenFiles, [&](QDataStream& out) { out << fileNames; }); } /** @@ -405,6 +406,17 @@ bool Application::sendLockToInstance() return this->sendSocketCommand(SocketCmd::LockAll, [](QDataStream&) { /* No Data */ }); } +/** + * Open and unlock a database file in the running instance + * + * @return true if the instance receives the request + */ +bool Application::sendUnlockToInstance(const QString& filename, const QString& password, const QString& keyfile) +{ + return this->sendSocketCommand(SocketCmd::Unlock, + [&](QDataStream& out) { out << filename << password << keyfile; }); +} + bool Application::isDarkTheme() const { return m_darkTheme; diff --git a/src/gui/Application.h b/src/gui/Application.h index 4d7a87fca..b00f8ce99 100644 --- a/src/gui/Application.h +++ b/src/gui/Application.h @@ -53,11 +53,12 @@ public: bool sendFileNamesToRunningInstance(const QStringList& fileNames); bool sendLockToInstance(); + bool sendUnlockToInstance(const QString& filename, const QString& password = {}, const QString& keyfile = {}); void restart(); signals: - void openFile(const QString& filename); + void openFile(const QString& filename, const QString& password = {}, const QString& keyfile = {}); void anotherInstanceStarted(); void applicationActivated(); void quitSignalReceived(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index a051187d6..067f7250c 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -661,8 +661,8 @@ MainWindow::MainWindow() connect(qApp, SIGNAL(anotherInstanceStarted()), this, SLOT(bringToFront())); connect(qApp, SIGNAL(applicationActivated()), this, SLOT(bringToFront())); - connect(qApp, SIGNAL(openFile(QString)), this, SLOT(openDatabase(QString))); connect(qApp, SIGNAL(quitSignalReceived()), this, SLOT(appExit()), Qt::DirectConnection); + connect(static_cast(qApp), &Application::openFile, this, &MainWindow::openDatabase); // Setup the status bar statusBar()->setFixedHeight(24); diff --git a/src/main.cpp b/src/main.cpp index 2c4da4c1f..f9af22ecc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,18 @@ Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) #include #endif +namespace +{ + QString promptPassword() + { + // we always need consume a line of STDIN if --pw-stdin is set to clear out the + // buffer for native messaging, even if the specified file does not exist + QTextStream out(stdout, QIODevice::WriteOnly); + out << QObject::tr("Database password: ") << Qt::flush; + return Utils::getPassword(); + } +} // namespace + int main(int argc, char** argv) { QT_REQUIRE_VERSION(argc, argv, QT_VERSION_STR) @@ -140,9 +152,14 @@ int main(int argc, char** argv) } } #endif + Utils::setDefaultTextStreams(); + + const bool pwstdin = parser.isSet(pwstdinOption); + const QString keyfile = parser.value(keyfileOption); // Process single instance and early exit if already running if (app.isAlreadyRunning()) { + qWarning() << QObject::tr("Another instance of KeePassXC is already running.").toUtf8().constData(); if (parser.isSet(lockOption)) { if (app.sendLockToInstance()) { qInfo() << QObject::tr("Databases have been locked.").toUtf8().constData(); @@ -151,11 +168,13 @@ int main(int argc, char** argv) return EXIT_FAILURE; } } else { - if (!fileNames.isEmpty()) { - app.sendFileNamesToRunningInstance(fileNames); + for (const QString& filename : fileNames) { + QString password; + if (pwstdin) { + password = promptPassword(); + } + app.sendUnlockToInstance(filename, password, keyfile); } - - qWarning() << QObject::tr("Another instance of KeePassXC is already running.").toUtf8().constData(); } return EXIT_SUCCESS; } @@ -176,8 +195,6 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - Utils::setDefaultTextStreams(); - // Apply the configured theme before creating any GUI elements app.applyTheme(); @@ -195,17 +212,12 @@ int main(int argc, char** argv) // This ensures any top-level windows (Main Window, Modal Dialogs, etc.) are excluded from screenshots mainWindow.setAllowScreenCapture(parser.isSet(allowScreenCaptureOption)); - const bool pwstdin = parser.isSet(pwstdinOption); for (const QString& filename : fileNames) { QString password; if (pwstdin) { - // we always need consume a line of STDIN if --pw-stdin is set to clear out the - // buffer for native messaging, even if the specified file does not exist - QTextStream out(stdout, QIODevice::WriteOnly); - out << QObject::tr("Database password: ") << Qt::flush; - password = Utils::getPassword(); + password = promptPassword(); } - mainWindow.openDatabase(filename, password, parser.value(keyfileOption)); + mainWindow.openDatabase(filename, password, keyfile); } // start minimized if configured