diff options
| author | Mikaël Capelle <capelle.mikael@gmail.com> | 2020-06-01 21:06:52 +0200 |
|---|---|---|
| committer | Mikaël Capelle <capelle.mikael@gmail.com> | 2020-06-01 21:06:52 +0200 |
| commit | 2c20a4115d0fdc4ce81787d8d78bd06fbf838b25 (patch) | |
| tree | 25d60bd64d079764190852a44caac8584e6904ec /src | |
| parent | af0c0dc33e639f116aaa5c0ac4f2541a80106099 (diff) | |
Fix opening and extraction of archives with passwords and/or encrypted filenames.
Diffstat (limited to 'src')
| -rw-r--r-- | src/installationmanager.cpp | 33 | ||||
| -rw-r--r-- | src/installationmanager.h | 13 |
2 files changed, 37 insertions, 9 deletions
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 639dc88a..d2262d13 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -105,6 +105,12 @@ InstallationManager::InstallationManager() break; } }); + + // Connect the query password slot - This is the only way I found to be able to query user + // from a separate thread. We use a BlockingQueuedConnection so that calling passwordRequested() + // will block until the end of the slot. + connect(this, &InstallationManager::passwordRequested, + this, &InstallationManager::queryPassword, Qt::BlockingQueuedConnection); } InstallationManager::~InstallationManager() @@ -125,6 +131,11 @@ void InstallationManager::setURL(QString const &url) m_URL = url; } +void InstallationManager::queryPassword() { + m_Password = QInputDialog::getText(m_ParentWidget, tr("Password required"), + tr("Password"), QLineEdit::Password); +} + bool InstallationManager::extractFiles(QString extractPath, QString title, bool showFilenames) { QProgressDialog *installationProgress = new QProgressDialog(m_ParentWidget); @@ -625,11 +636,22 @@ IPluginInstaller::EInstallResult InstallationManager::install(const QString &fil m_ArchiveHandler->close(); // open the archive and construct the directory tree the installers work on + bool archiveOpen = m_ArchiveHandler->open( - fileName.toStdWString(), [this]() { - QString password = QInputDialog::getText(m_ParentWidget, tr("Password required"), - tr("Password"), QLineEdit::Password); - return password.toStdWString(); + fileName.toStdWString(), [this]() -> std::wstring { + m_Password = QString(); + + // Note: If we are not in the Qt event thread, we cannot use queryPassword() directly, + // so we emit passwordRequested() that is connected to queryPassword(). The connection is + // made using Qt::BlockingQueuedConnection, so the emit "call" is actually blocking. We + // cannot use emit if we are in the even thread, otherwize we have a deadlock. + if (QThread::currentThread() != QApplication::instance()->thread()) { + emit passwordRequested(); + } + else { + queryPassword(); + } + return m_Password.toStdWString(); }); if (!archiveOpen) { log::debug("integrated archiver can't open {}: {} ({})", @@ -755,8 +777,6 @@ IPluginInstaller::EInstallResult InstallationManager::install(const QString &fil return installResult; } - - QString InstallationManager::getErrorString(Archive::Error errorCode) { switch (errorCode) { @@ -791,7 +811,6 @@ QString InstallationManager::getErrorString(Archive::Error errorCode) } } - void InstallationManager::registerInstaller(IPluginInstaller *installer) { m_Installers.push_back(installer); diff --git a/src/installationmanager.h b/src/installationmanager.h index 67e58356..328272e1 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -204,10 +204,16 @@ private: void postInstallCleanup(); +private slots: + + /** + * @brief Query user for password and update the m_Password field. + */ + void queryPassword(); + signals: - void progressUpdate(float percentage); - void progressUpdate(QString const fileName); + void passwordRequested(); private: @@ -253,6 +259,9 @@ private: Archive *m_ArchiveHandler; QString m_CurrentFile; + // Current password: + QString m_Password; + // Map from entries in the tree that is used by the installer and absolute // paths to temporary files: std::map<std::shared_ptr<const MOBase::FileTreeEntry>, QString> m_CreatedFiles; |
