mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2026-03-11 08:54:48 +00:00
Merge 4132a7efac into 56521023b8
This commit is contained in:
commit
246ca20f9b
4 changed files with 75 additions and 60 deletions
|
|
@ -49,6 +49,13 @@ namespace
|
|||
int g_OriginalFontSize = 0;
|
||||
} // namespace
|
||||
|
||||
enum Application::SocketCmd : quint32
|
||||
{
|
||||
OpenFiles = 1,
|
||||
LockAll,
|
||||
Unlock,
|
||||
};
|
||||
|
||||
Application::Application(int& argc, char** argv)
|
||||
: QApplication(argc, argv)
|
||||
#ifdef Q_OS_UNIX
|
||||
|
|
@ -56,11 +63,7 @@ Application::Application(int& argc, char** argv)
|
|||
#endif
|
||||
, m_alreadyRunning(false)
|
||||
, m_lockFile(nullptr)
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
|
||||
{
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
#if defined(Q_OS_UNIX)
|
||||
registerUnixSignals();
|
||||
#endif
|
||||
|
|
@ -324,13 +327,12 @@ void Application::socketReadyRead()
|
|||
return;
|
||||
}
|
||||
|
||||
QStringList fileNames;
|
||||
quint32 id;
|
||||
SocketCmd id;
|
||||
in >> id;
|
||||
|
||||
// TODO: move constants to enum
|
||||
switch (id) {
|
||||
case 1:
|
||||
case SocketCmd::OpenFiles: {
|
||||
QStringList fileNames;
|
||||
in >> fileNames;
|
||||
for (const QString& fileName : asConst(fileNames)) {
|
||||
const QFileInfo fInfo(fileName);
|
||||
|
|
@ -338,11 +340,16 @@ void Application::socketReadyRead()
|
|||
emit openFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
}
|
||||
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();
|
||||
|
|
@ -350,20 +357,10 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to-open file names to the running UI instance
|
||||
*
|
||||
* @param fileNames - list of file names to open
|
||||
* @return true if all operations succeeded (connection made, data sent, connection closed)
|
||||
*/
|
||||
bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames)
|
||||
bool Application::sendSocketCommand(SocketCmd id, const std::function<void(QDataStream&)>& caller)
|
||||
{
|
||||
QLocalSocket client;
|
||||
client.connectToServer(m_socketName);
|
||||
|
|
@ -376,8 +373,8 @@ bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames)
|
|||
QDataStream out(&data, QIODevice::WriteOnly);
|
||||
out.setVersion(QDataStream::Qt_5_0);
|
||||
out << quint32(0); // reserve space for block size
|
||||
out << quint32(1); // ID for file name send. TODO: move to enum
|
||||
out << fileNames; // send file names to be opened
|
||||
out << id; // ID of command being sent.
|
||||
caller(out); // Pass to caller to add any additional data
|
||||
out.device()->seek(0);
|
||||
out << quint32(data.size() - sizeof(quint32)); // replace the previous constant 0 with block size
|
||||
|
||||
|
|
@ -388,6 +385,17 @@ bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames)
|
|||
return writeOk && disconnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send to-open file names to the running UI instance
|
||||
*
|
||||
* @param fileNames - list of file names to open
|
||||
* @return true if all operations succeeded (connection made, data sent, connection closed)
|
||||
*/
|
||||
bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames)
|
||||
{
|
||||
return this->sendSocketCommand(SocketCmd::OpenFiles, [&](QDataStream& out) { out << fileNames; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks all open databases in the running instance
|
||||
*
|
||||
|
|
@ -395,29 +403,18 @@ bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames)
|
|||
*/
|
||||
bool Application::sendLockToInstance()
|
||||
{
|
||||
// Make a connection to avoid SIGSEGV
|
||||
QLocalSocket client;
|
||||
client.connectToServer(m_socketName);
|
||||
const bool connected = client.waitForConnected(WaitTimeoutMSec);
|
||||
if (!connected) {
|
||||
return false;
|
||||
}
|
||||
return this->sendSocketCommand(SocketCmd::LockAll, [](QDataStream&) { /* No Data */ });
|
||||
}
|
||||
|
||||
// Send lock signal
|
||||
QByteArray data;
|
||||
QDataStream out(&data, QIODevice::WriteOnly);
|
||||
out.setVersion(QDataStream::Qt_5_0);
|
||||
out << quint32(0); // reserve space for block size
|
||||
out << quint32(2); // ID for database lock. TODO: move to enum
|
||||
out.device()->seek(0);
|
||||
out << quint32(data.size() - sizeof(quint32)); // replace the previous constant 0 with block size
|
||||
|
||||
// Finish gracefully
|
||||
const bool writeOk = client.write(data) != -1 && client.waitForBytesWritten(WaitTimeoutMSec);
|
||||
client.disconnectFromServer();
|
||||
const bool disconnected =
|
||||
client.state() == QLocalSocket::UnconnectedState || client.waitForConnected(WaitTimeoutMSec);
|
||||
return writeOk && disconnected;
|
||||
/**
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <QApplication>
|
||||
#include <QString>
|
||||
#include <QtNetwork/qlocalserver.h>
|
||||
#include <functional>
|
||||
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
|
||||
|
||||
|
|
@ -52,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();
|
||||
|
|
@ -78,6 +80,10 @@ private:
|
|||
static void handleUnixSignal(int sig);
|
||||
static int unixSignalSocket[2];
|
||||
#endif
|
||||
|
||||
enum SocketCmd : quint32;
|
||||
bool sendSocketCommand(SocketCmd id, const std::function<void(QDataStream&)>&);
|
||||
|
||||
bool m_alreadyRunning;
|
||||
bool m_darkTheme = false;
|
||||
QLockFile* m_lockFile;
|
||||
|
|
|
|||
|
|
@ -671,8 +671,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<Application*>(qApp), &Application::openFile, this, &MainWindow::openDatabase);
|
||||
|
||||
// Setup the status bar
|
||||
statusBar()->setFixedHeight(24);
|
||||
|
|
|
|||
38
src/main.cpp
38
src/main.cpp
|
|
@ -49,6 +49,18 @@ Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
|
|||
#include <windows.h>
|
||||
#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
|
||||
|
|
|
|||
Loading…
Reference in a new issue