#include "./downloadinteraction.h" #include "./settings.h" #include "../network/download.h" #include "../network/permissionstatus.h" #include #include #include #include #include #include using namespace Network; using namespace QtUtilities; namespace QtGui { DownloadInteraction::DownloadInteraction(QObject *parent) : QObject(parent) , m_parentWidget(nullptr) { } DownloadInteraction::DownloadInteraction(QWidget *parent) : QObject(parent) , m_parentWidget(parent) { } void DownloadInteraction::connectDownload(Download *download) { connect(download, &Download::outputDeviceRequired, this, static_cast(&DownloadInteraction::downloadRequiresOutputDevice)); connect(download, &Download::overwriteingPermissionRequired, this, &DownloadInteraction::downloadRequriesOverwritePermission); connect(download, &Download::appendingPermissionRequired, this, &DownloadInteraction::downloadRequriesAppendingPermission); connect(download, &Download::redirectionPermissonRequired, this, &DownloadInteraction::downloadRequiresRedirectionPermission); connect(download, &Download::authenticationRequired, this, &DownloadInteraction::downloadRequiresAuthentication); connect(download, &Download::sslErrors, this, &DownloadInteraction::downloadHasSslErrors); } void DownloadInteraction::disconnectDownload(Download *download) { download->disconnect(this); } void DownloadInteraction::downloadRequiresOutputDevice(Download *download, size_t optionIndex) { downloadRequiresOutputDevice(download, optionIndex, false); } void DownloadInteraction::downloadRequiresOutputDevice(Download *download, size_t optionIndex, bool forceFileDialog) { QString fileName = download->suitableFilename(); // use default directory and the "suitable file name" to determine the target path if (TargetPage::determineTargetFileWithoutAsking() // if correspondent option is set && !forceFileDialog // and the caller don't wants to force the file dialog && (TargetPage::targetDirectory().isEmpty() || QDir(TargetPage::targetDirectory()).exists()) // and the default directory exists or is empty && !fileName.isEmpty()) { // and the file name is not empty download->provideOutputDevice(optionIndex, new QFile(TargetPage::targetDirectory() % QChar('/') % fileName), true); } else { // ask the user for the target path otherwise QFileDialog *dlg = new QFileDialog(m_parentWidget); #ifndef Q_OS_WIN // the native dialog can only be shown modal under Windows dlg->setModal(false); #endif dlg->setFileMode(QFileDialog::AnyFile); dlg->setAcceptMode(QFileDialog::AcceptSave); dlg->setDirectory(TargetPage::targetDirectory()); dlg->selectFile(fileName); dlg->setOption(QFileDialog::DontConfirmOverwrite, true); if (!download->title().isEmpty()) { dlg->setWindowTitle(tr("Where to save »%1«?").arg(download->title())); } connect(dlg, &QFileDialog::finished, [download, optionIndex, dlg](int result) { if (result == QFileDialog::Accepted && dlg->selectedFiles().size() == 1) { download->provideOutputDevice(optionIndex, new QFile(dlg->selectedFiles().front()), true); } else { download->provideOutputDevice(optionIndex, nullptr); } dlg->deleteLater(); }); dlg->show(); } } void DownloadInteraction::downloadRequriesOverwritePermission(Download *download, size_t optionIndex, const QString &file) { if (TargetPage::overwriteWithoutAsking()) { download->setOverwritePermission(optionIndex, PermissionStatus::Allowed); } else { QString message = tr("

The output file %1 already exists.

Do you want to overwrite the existing file?

").arg(file); QMessageBox *dlg = new QMessageBox(m_parentWidget); dlg->setModal(false); dlg->setTextFormat(Qt::RichText); dlg->setText(message); dlg->setIcon(QMessageBox::Warning); QPushButton *overwriteButton = dlg->addButton(tr("Overwrite (only this time)"), QMessageBox::YesRole); QPushButton *overwriteAlwaysButton = dlg->addButton(tr("Overwrite (always)"), QMessageBox::YesRole); QPushButton *selectOtherButton = dlg->addButton(tr("Select other download target"), QMessageBox::ActionRole); QPushButton *abortButton = dlg->addButton(tr("Abort"), QMessageBox::NoRole); dlg->setEscapeButton(abortButton); // show warning message connect(dlg, &QMessageBox::finished, [download, optionIndex, dlg, overwriteButton, overwriteAlwaysButton, selectOtherButton, abortButton, this](int) { if (dlg->clickedButton() == overwriteAlwaysButton) { // set dontAskBeforeOverwriting to true if the user clicked yes to all TargetPage::overwriteWithoutAsking() = true; } if (dlg->clickedButton() == overwriteButton || dlg->clickedButton() == overwriteAlwaysButton) { download->setOverwritePermission(optionIndex, PermissionStatus::Allowed); } else if (dlg->clickedButton() == selectOtherButton) { downloadRequiresOutputDevice(download, optionIndex, true); } else { download->setOverwritePermission(optionIndex, PermissionStatus::Refused); } dlg->deleteLater(); }); dlg->show(); } } void DownloadInteraction::downloadRequriesAppendingPermission( Download *download, size_t optionIndex, const QString &file, quint64 offset, quint64 fileSize) { if (TargetPage::overwriteWithoutAsking()) { download->setAppendPermission(optionIndex, PermissionStatus::Allowed); } else { QString message = tr("

The output file %1 already exists. The downloader assumes it contains previously downloaded data.

Do " "you want to append the received data to the existing file?

") .arg(file); if (offset != fileSize) { message.append( tr("

The current download offset (%1) does not match the size of the existing file (%2).

").arg(offset).arg(fileSize)); } QMessageBox *dlg = new QMessageBox(m_parentWidget); dlg->setModal(false); dlg->setTextFormat(Qt::RichText); dlg->setText(message); dlg->setIcon(QMessageBox::Warning); QPushButton *appendButton = dlg->addButton(tr("Append"), QMessageBox::YesRole); QPushButton *abortButton = dlg->addButton(tr("Abort"), QMessageBox::NoRole); dlg->setEscapeButton(abortButton); // show warning message connect(dlg, &QMessageBox::finished, [download, optionIndex, dlg, appendButton, abortButton, this](int) { if (dlg->clickedButton() == appendButton) { download->setAppendPermission(optionIndex, PermissionStatus::Allowed); } else { download->setAppendPermission(optionIndex, PermissionStatus::Refused); } dlg->deleteLater(); }); dlg->show(); } } void DownloadInteraction::downloadRequiresRedirectionPermission(Download *download, size_t optionIndex) { if (MiscPage::redirectWithoutAsking()) { download->setRedirectPermission(optionIndex, PermissionStatus::Allowed); } else { const QUrl &originalUrl = download->downloadUrl(download->options().at(optionIndex).redirectionOf()); const QUrl &newUrl = download->downloadUrl(optionIndex); QString message = tr( "

Do you want to redirect form %1 to %2?

The redirection URL will be added to the options so you can it select " "later, too.

") .arg(originalUrl.toString(), newUrl.toString()); QMessageBox *dlg = new QMessageBox(m_parentWidget); dlg->setModal(false); dlg->setTextFormat(Qt::RichText); dlg->setText(message); dlg->setIcon(QMessageBox::Question); dlg->setStandardButtons(QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No); connect(dlg, &QMessageBox::finished, [download, optionIndex, dlg, this](int result) { switch (result) { case QMessageBox::YesToAll: MiscPage::redirectWithoutAsking() = true; download->setRedirectPermission(optionIndex, PermissionStatus::AlwaysAllowed); break; case QMessageBox::Yes: download->setRedirectPermission(optionIndex, PermissionStatus::Allowed); break; default: download->setRedirectPermission(optionIndex, PermissionStatus::Refused); } dlg->deleteLater(); }); connect(download, &Download::destroyed, dlg, &QMessageBox::deleteLater); dlg->show(); } } void DownloadInteraction::downloadRequiresAuthentication(Download *download, size_t optionIndex, const QString &realm) { auto *const dlg = new EnterPasswordDialog(m_parentWidget); QString downloadName = download->downloadUrl().isEmpty() ? download->id() : download->downloadUrl().toString(); dlg->setModal(false); dlg->setPromptForUserName(true); dlg->setPasswordRequired(true); dlg->setInstruction(tr("

Enter authentication credentials for the download %1.

").arg(downloadName)); if (!realm.isEmpty()) { dlg->setDescription(tr("Realm: %1").arg(realm)); } connect(dlg, &EnterPasswordDialog::accepted, [download, optionIndex, dlg] { download->provideAuthenticationCredentials(optionIndex, AuthenticationCredentials(dlg->userName(), dlg->password())); dlg->deleteLater(); }); connect(download, &Download::destroyed, dlg, &QMessageBox::deleteLater); dlg->adjustSize(); dlg->show(); } void DownloadInteraction::downloadHasSslErrors(Download *download, size_t optionIndex, const QList &sslErrors) { QString downloadName = download->downloadUrl().isEmpty() ? download->id() : download->downloadUrl().toString(); QString details; for (const QSslError &error : sslErrors) { if (!details.isEmpty()) { details.append(QStringLiteral("\n\n")); } details.append(error.errorString()); if (!error.certificate().isNull()) { details.append(QChar('\n')); details.append(error.certificate().toText()); } } auto *dlg = new QMessageBox(m_parentWidget); dlg->setModal(false); dlg->setWindowTitle(tr("SSL errors occurred") % QStringLiteral(" - ") % QCoreApplication::applicationName()); dlg->setTextFormat(Qt::RichText); dlg->setText(tr("The download %1 has SSL errors.").arg(downloadName)); dlg->setInformativeText(tr("Do you want to ignore the SSL errors for this download?")); dlg->setDetailedText(details); dlg->setIcon(QMessageBox::Warning); dlg->setStandardButtons(QMessageBox::Yes | QMessageBox::No); connect(dlg, &QMessageBox::finished, [download, optionIndex, dlg](int result) { switch (result) { case QMessageBox::Yes: download->setIgnoreSslErrorsPermission(optionIndex, PermissionStatus::Allowed); break; default: download->setIgnoreSslErrorsPermission(optionIndex, PermissionStatus::Refused); } dlg->deleteLater(); }); connect(download, &Download::destroyed, dlg, &QMessageBox::deleteLater); dlg->show(); } } // namespace QtGui