Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions 3rdparty/interface/archiveinterface/archiveinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ ErrorType ReadOnlyArchiveInterface::errorType()
return m_eErrorType;
}

void ReadOnlyArchiveInterface::resetResult()
{
m_eErrorType = ET_NoError;
}

bool ReadOnlyArchiveInterface::doKill()
{
return false; // 修改默认为未取消
Expand Down
6 changes: 6 additions & 0 deletions 3rdparty/interface/archiveinterface/archiveinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ class ReadOnlyArchiveInterface : public QObject
*/
ErrorType errorType();

/**
* @brief resetResult forget the result of the previous operation; the interface is reused for
* later operations on the same archive, so a job starts with this
*/
virtual void resetResult();

/**
* @brief pauseOperation 暂停操作
*/
Expand Down
9 changes: 9 additions & 0 deletions 3rdparty/interface/archiveinterface/cliinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ CliInterface::~CliInterface()
deleteProcess();
}

void CliInterface::resetResult()
{
ReadOnlyArchiveInterface::resetResult();
m_finishType = PFT_Nomral;
}

PluginFinishType CliInterface::list()
{
setPassword(QString());
Expand Down Expand Up @@ -784,6 +790,9 @@ bool CliInterface::runProcess(const QString &programName, const QStringList &arg
[=](int exitCode, QProcess::ExitStatus) {
if (m_process) {
if (exitCode != 0) {
// Release the failed listing process: the interface is used again (e.g. to
// extract after asking for the password again), and runProcess() needs none
deleteProcess();
emit signalprogress(100);
emit signalFinished(PFT_Error);
return;
Expand Down
6 changes: 6 additions & 0 deletions 3rdparty/interface/archiveinterface/cliinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ class CliInterface : public ReadWriteArchiveInterface
explicit CliInterface(QObject *parent, const QVariantList &args);
~CliInterface() override;

/**
* @brief resetResult also forget the previous finish type: an operation that succeeds after a
* failed one on the same archive must not end as an error
*/
void resetResult() override;

// ReadOnlyArchiveInterface interface
public:
PluginFinishType list() override;
Expand Down
24 changes: 24 additions & 0 deletions 3rdparty/interface/queries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <DPasswordEdit>

#include <QApplication>
#include <QCoreApplication>
#include <QImageReader>
#include <QLayout>
#include <QUrl>
Expand Down Expand Up @@ -459,6 +460,18 @@ void ExtractToQuery::setWidgetType(QWidget *pWgt, DPalette::ColorType ct, double



bool PasswordNeededQuery::s_bPreviousPasswordWrong = false;

void PasswordNeededQuery::setPreviousPasswordWrong(bool bWrong)
{
s_bPreviousPasswordWrong = bWrong;
}

bool PasswordNeededQuery::previousPasswordWrong()
{
return s_bPreviousPasswordWrong;
}

PasswordNeededQuery::PasswordNeededQuery(const QString &strFileName, QObject *parent)
: Query(parent)
{
Expand Down Expand Up @@ -514,6 +527,17 @@ void PasswordNeededQuery::execute()
passwordedit->setMinimumHeight(36);
passwordedit->setFixedWidth(280);

// The previous password was wrong: say so and mark the field until the user types
if (s_bPreviousPasswordWrong) {
s_bPreviousPasswordWrong = false;
m_strDesText = QCoreApplication::translate("MainWindow", "Wrong password");
pTipLbl->setText(m_strDesText);
passwordedit->setAlert(true);
connect(passwordedit, &DPasswordEdit::textChanged, passwordedit, [passwordedit]() {
passwordedit->setAlert(false);
});
}

dialog->addButton(QObject::tr("Cancel", "button"), true, DDialog::ButtonNormal);
dialog->addButton(QObject::tr("OK", "button"), true, DDialog::ButtonRecommend);
dialog->getButton(1)->setEnabled(false);
Expand Down
12 changes: 12 additions & 0 deletions 3rdparty/interface/queries.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,19 @@ class PasswordNeededQuery : public Query
*/
QString password();

/**
* @brief setPreviousPasswordWrong the next password dialog says the previous password was wrong
* (set before an extraction or load is restarted after a wrong password)
*/
static void setPreviousPasswordWrong(bool bWrong);

/**
* @brief previousPasswordWrong true until a password dialog has shown the hint
*/
static bool previousPasswordWrong();

private:
static bool s_bPreviousPasswordWrong;
QString m_strDesText;
QString m_strFileName;
int m_iLabelOldHeight = 0;
Expand Down
8 changes: 8 additions & 0 deletions src/source/archivemanager/singlejob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ void SingleJob::start()
return;
}

// The interface is reused for later operations on the same archive: start without the result of
// the previous one (errors found during this job, e.g. while listing first, are kept)
m_pInterface->resetResult();

// 判断是否通过线程的方式调用
if (m_pInterface->waitForFinished()) {
qCDebug(appLog) << "Executing work directly";
Expand Down Expand Up @@ -532,6 +536,10 @@ void UpdateJob::start()
return;
}

// The interface is reused for later operations on the same archive: start without the result of
// the previous one (errors found during this job, e.g. while listing first, are kept)
m_pInterface->resetResult();

d->start(); // 开启线程,执行操作
}

Expand Down
68 changes: 66 additions & 2 deletions src/source/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,11 @@ void MainWindow::slotJobFinished(ArchiveJob::JobType eJobType, PluginFinishType
{
qCInfo(appLog) << "操作类型:" << eJobType << "****结束类型:" << eFinishType << "****错误类型" << eErrorType;

// A retry after a wrong password asks for the password again; if the job ended without showing the
// dialog, the hint is still pending: do not retry again, and do not leave the hint for a later dialog.
m_bWrongPasswordUnanswered = PasswordNeededQuery::previousPasswordWrong();
PasswordNeededQuery::setPreviousPasswordWrong(false);

switch (eFinishType) {
case PFT_Nomral:
handleJobNormalFinished(eJobType, eErrorType); // 处理job正常结束
Expand Down Expand Up @@ -1362,8 +1367,54 @@ void MainWindow::slotJobFinished(ArchiveJob::JobType eJobType, PluginFinishType
PERF_PRINT_END("POINT-05");
}

bool MainWindow::retryAfterWrongPassword(ArchiveJob::JobType eJobType)
{
if (m_bWrongPasswordUnanswered || m_stUnCompressParameter.bBatch) {
return false;
}

const QString strArchive = m_stUnCompressParameter.strFullPath;
if (strArchive.isEmpty()) {
return false;
}

if (ArchiveJob::JT_Load == eJobType) {
PasswordNeededQuery::setPreviousPasswordWrong(true);
QTimer::singleShot(0, this, [this, strArchive]() {
loadArchive(strArchive);
refreshPage();
});
return true;
}

if (StartupType::ST_ExtractHere == m_eStartupType || StartupType::ST_Extractto == m_eStartupType) {
// Started from the file manager: extract the same archive the same way again
PasswordNeededQuery::setPreviousPasswordWrong(true);
const StartupType eType = m_eStartupType;
QTimer::singleShot(0, this, [this, eType, strArchive]() {
rightExtract2Path(eType, QStringList() << strArchive);
Comment on lines +1394 to +1395

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Release the failed listing process before restarting extraction

For a file-manager extraction that first runs the preliminary tmpList process, such as a header-encrypted 7z/RAR on a non-LNFS target, a wrong password leaves m_process allocated: the nonzero-exit branch in CliInterface::runProcess() emits failure without calling deleteProcess(). This retry reuses that interface through ArchiveManager::extractFiles(), so the next runProcess() trips Q_ASSERT(!m_process) in assertion-enabled builds; release builds overwrite and leak the process pointer instead. Clean up the failed preliminary process or recreate the interface before restarting.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. When the preliminary tmpList listing fails, the finished handler now calls deleteProcess() before reporting PFT_Error, so the retry starts with no process left on the interface (no Q_ASSERT(!m_process) failure, no leak).

refreshPage();
});
return true;
}

// Opened in the window: extract again to the destination the user chose (strExtractPath may already
// include the folder named after the archive, which would be added a second time)
const QString strPath = m_strUncompressBasePath;
if (strPath.isEmpty() || m_pUnCompressPage->archiveFullPath().isEmpty()) {
return false;
}
PasswordNeededQuery::setPreviousPasswordWrong(true);
m_ePageID = PI_UnCompress;
QTimer::singleShot(0, this, [this, strPath]() {
slotUncompressClicked(strPath);
Comment on lines +1409 to +1410

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid adding the archive folder again on password retry

With automatic folder creation enabled (the default), m_stUnCompressParameter.strExtractPath already includes the archive-named folder added by slotUncompressClicked(). Passing that effective destination back into the same slot appends the folder again: extracting a.zip to /dest after one wrong password writes to /dest/a/a instead of /dest/a, and each subsequent wrong password adds another level. This can also separate files extracted before the password failure from those extracted afterward. Preserve the original base destination or restart with the saved extraction options rather than reapplying destination construction.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The retry now uses the destination the user chose (m_strUncompressBasePath, saved at the start of slotUncompressClicked()) instead of m_stUnCompressParameter.strExtractPath, so the archive-named folder is added once.

});
return true;
}

void MainWindow::slotUncompressClicked(const QString &strUncompressPath)
{
m_strUncompressBasePath = strUncompressPath;
qCDebug(appLog) << "Starting extraction to path:" << strUncompressPath;
m_operationtype = Operation_Extract; //解压操作

Expand Down Expand Up @@ -1934,8 +1985,11 @@ void MainWindow::handleJobErrorFinished(ArchiveJob::JobType eJobType, ErrorType
case ET_ArchiveDamaged:
showErrorMessage(FI_Load, EI_ArchiveDamaged);
break;
// 密码错误
// 密码错误:重新询问密码,不显示失败界面
case ET_WrongPassword:
if (retryAfterWrongPassword(eJobType)) {
break;
}
showErrorMessage(FI_Load, EI_WrongPassword, true);
break;
// ftp目录不支持seek操作
Expand Down Expand Up @@ -2004,8 +2058,11 @@ void MainWindow::handleJobErrorFinished(ArchiveJob::JobType eJobType, ErrorType
showErrorMessage(FI_Uncompress, EI_ArchiveDamaged,
!(StartupType::ST_ExtractHere == m_eStartupType || StartupType::ST_Extractto == m_eStartupType));
break;
// 密码错误
// 密码错误:重新询问密码,不显示失败界面
case ET_WrongPassword:
if (retryAfterWrongPassword(eJobType)) {
break;
}
showErrorMessage(FI_Uncompress, EI_WrongPassword,
!(StartupType::ST_ExtractHere == m_eStartupType || StartupType::ST_Extractto == m_eStartupType));
break;
Expand Down Expand Up @@ -3549,6 +3606,13 @@ void MainWindow::slotFailureReturn()
}
break;
case FI_Uncompress: {
// An archive opened in the window: go back to its file list instead of an empty home page
if (!(StartupType::ST_ExtractHere == m_eStartupType || StartupType::ST_Extractto == m_eStartupType)
&& !m_stUnCompressParameter.bBatch && !m_pUnCompressPage->archiveFullPath().isEmpty()) {
m_ePageID = PI_UnCompress;
refreshPage();
return;
}
m_pUnCompressPage->clear(); // 清空解压界面
}
break;
Expand Down
9 changes: 9 additions & 0 deletions src/source/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ public :
*/
void handleJobErrorFinished(ArchiveJob::JobType eJobType, ErrorType eErrorType);

/**
* @brief retryAfterWrongPassword after a wrong password, restart the same load or extraction so the
* password dialog asks again (with a "Wrong password" hint) instead of showing the failure page
* @return false when it does not apply (batch extraction, no dialog was shown since the last retry, ...)
*/
bool retryAfterWrongPassword(ArchiveJob::JobType eJobType);

/**
* @brief addFiles2Archive 向压缩包中添加文件
* @param listFiles 需要添加的文件
Expand Down Expand Up @@ -579,6 +586,8 @@ private Q_SLOTS:
DFileWatcher *m_pFileWatcher = nullptr; // 文件监控
QString m_strFinalConvertFile; // 格式转换最终的文件全路径
QString m_fileWriteErrorName; // 创建失败的文件名
bool m_bWrongPasswordUnanswered = false; // a retry after a wrong password ended before any password dialog
QString m_strUncompressBasePath; // the destination chosen on the file list page (before any folder is added)

StartupType m_eStartupType = StartupType::ST_Normal; // 操作方式
CalculateSizeThread *m_mywork = nullptr; // 计算文件(夹)大小线程
Expand Down
Loading