diff options
author | wundrweapon <wundrweapon@users.noreply.github.com> | 2021-05-15 16:48:59 +0300 |
---|---|---|
committer | Jonathan White <support@dmapps.us> | 2021-05-30 15:44:09 +0300 |
commit | aaf8f188521a1742ded2fbd104cd594191d43a75 (patch) | |
tree | 569037f06f47f59a928b9dd2232c7596042bf67c | |
parent | 29de94b65674559b55102b8ec4ddbaf06364a274 (diff) |
Add command line option to lock open databases (#6511)
Closes #6126
-rw-r--r-- | src/gui/Application.cpp | 70 | ||||
-rw-r--r-- | src/gui/Application.h | 1 | ||||
-rw-r--r-- | src/main.cpp | 19 |
3 files changed, 79 insertions, 11 deletions
diff --git a/src/gui/Application.cpp b/src/gui/Application.cpp index 784528294..973e29032 100644 --- a/src/gui/Application.cpp +++ b/src/gui/Application.cpp @@ -286,13 +286,26 @@ void Application::socketReadyRead() } QStringList fileNames; - in >> fileNames; - for (const QString& fileName : asConst(fileNames)) { - const QFileInfo fInfo(fileName); - if (fInfo.isFile() && fInfo.suffix().toLower() == "kdbx") { - emit openFile(fileName); + quint32 id; + in >> id; + + // TODO: move constants to enum + switch (id) { + case 1: + in >> fileNames; + for (const QString& fileName : asConst(fileNames)) { + const QFileInfo fInfo(fileName); + if (fInfo.isFile() && fInfo.suffix().toLower() == "kdbx") { + emit openFile(fileName); + } } + + break; + case 2: + getMainWindow()->lockAllDatabases(); + break; } + socket->deleteLater(); } @@ -305,6 +318,12 @@ bool Application::isAlreadyRunning() const 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) { QLocalSocket client; @@ -317,13 +336,48 @@ bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames) QByteArray data; QDataStream out(&data, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_0); - out << quint32(0) << fileNames; + 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.device()->seek(0); + out << quint32(data.size() - sizeof(quint32)); // replace the previous constant 0 with block size + + const bool writeOk = client.write(data) != -1 && client.waitForBytesWritten(WaitTimeoutMSec); + client.disconnectFromServer(); + const bool disconnected = + client.state() == QLocalSocket::UnconnectedState || client.waitForDisconnected(WaitTimeoutMSec); + return writeOk && disconnected; +} + +/** + * Locks all open databases in the running instance + * + * @return true if the "please lock" signal was sent successfully + */ +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; + } + + // 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)); + 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.waitForDisconnected(WaitTimeoutMSec); + const bool disconnected = + client.state() == QLocalSocket::UnconnectedState || client.waitForConnected(WaitTimeoutMSec); return writeOk && disconnected; } diff --git a/src/gui/Application.h b/src/gui/Application.h index 9f694f8c3..f6c35a037 100644 --- a/src/gui/Application.h +++ b/src/gui/Application.h @@ -48,6 +48,7 @@ public: bool isDarkTheme() const; bool sendFileNamesToRunningInstance(const QStringList& fileNames); + bool sendLockToInstance(); void restart(); diff --git a/src/main.cpp b/src/main.cpp index b88dc41e0..43f9d0992 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,6 +64,7 @@ int main(int argc, char** argv) QCommandLineOption configOption("config", QObject::tr("path to a custom config file"), "config"); QCommandLineOption localConfigOption( "localconfig", QObject::tr("path to a custom local config file"), "localconfig"); + QCommandLineOption lockOption("lock", QObject::tr("lock all open databases")); QCommandLineOption keyfileOption("keyfile", QObject::tr("key file of the database"), "keyfile"); QCommandLineOption pwstdinOption("pw-stdin", QObject::tr("read password of the database from stdin")); @@ -72,6 +73,7 @@ int main(int argc, char** argv) QCommandLineOption debugInfoOption(QStringList() << "debug-info", QObject::tr("Displays debugging information.")); parser.addOption(configOption); parser.addOption(localConfigOption); + parser.addOption(lockOption); parser.addOption(keyfileOption); parser.addOption(pwstdinOption); parser.addOption(debugInfoOption); @@ -96,12 +98,23 @@ int main(int argc, char** argv) } // Process single instance and early exit if already running + // FIXME: this is a *mess* and it is entirely my fault. --wundrweapon const QStringList fileNames = parser.positionalArguments(); if (app.isAlreadyRunning()) { - if (!fileNames.isEmpty()) { - app.sendFileNamesToRunningInstance(fileNames); + if (parser.isSet(lockOption)) { + if (app.sendLockToInstance()) { + qInfo() << QObject::tr("Locked databases.").toUtf8().constData(); + } else { + qWarning() << QObject::tr("Database failed to lock.").toUtf8().constData(); + return EXIT_FAILURE; + } + } else { + if (!fileNames.isEmpty()) { + app.sendFileNamesToRunningInstance(fileNames); + } + + qWarning() << QObject::tr("Another instance of KeePassXC is already running.").toUtf8().constData(); } - qWarning() << QObject::tr("Another instance of KeePassXC is already running.").toUtf8().constData(); return EXIT_SUCCESS; } |