File indexing completed on 2024-06-16 06:57:00

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2020 Ahmad Samir <a.samirh78@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "widgetsaskuseractionhandler.h"
0009 
0010 #include <KConfig>
0011 #include <KConfigGroup>
0012 #include <KGuiItem>
0013 #include <KIO/WorkerBase>
0014 #include <KJob>
0015 #include <KJobWidgets>
0016 #include <KLocalizedString>
0017 #include <KMessageDialog>
0018 #include <KSharedConfig>
0019 #include <KSslInfoDialog>
0020 #include <KStandardGuiItem>
0021 #include <kio_widgets_debug.h>
0022 
0023 #include <QApplication>
0024 #include <QDialogButtonBox>
0025 #include <QPointer>
0026 #include <QRegularExpression>
0027 #include <QUrl>
0028 
0029 class KIO::WidgetsAskUserActionHandlerPrivate
0030 {
0031 public:
0032     explicit WidgetsAskUserActionHandlerPrivate(WidgetsAskUserActionHandler *qq)
0033         : q(qq)
0034     {
0035     }
0036 
0037     // Creates a KSslInfoDialog or falls back to a generic Information dialog
0038     void sslMessageBox(const QString &text, const KIO::MetaData &metaData, QWidget *parent);
0039 
0040     bool gotPersistentUserReply(KIO::AskUserActionInterface::MessageDialogType type, const KConfigGroup &cg, const QString &dontAskAgainName);
0041     void savePersistentUserReply(KIO::AskUserActionInterface::MessageDialogType type, KConfigGroup &cg, const QString &dontAskAgainName, int result);
0042 
0043     WidgetsAskUserActionHandler *const q;
0044     QPointer<QWidget> m_parentWidget = nullptr;
0045 
0046     QWidget *getParentWidget(KJob *job);
0047     QWidget *getParentWidget(QWidget *widget);
0048 };
0049 
0050 bool KIO::WidgetsAskUserActionHandlerPrivate::gotPersistentUserReply(KIO::AskUserActionInterface::MessageDialogType type,
0051                                                                      const KConfigGroup &cg,
0052                                                                      const QString &dontAskAgainName)
0053 {
0054     // storage values matching the logic of FrameworkIntegration's KMessageBoxDontAskAgainConfigStorage
0055     switch (type) {
0056     case KIO::AskUserActionInterface::QuestionTwoActions:
0057     case KIO::AskUserActionInterface::QuestionTwoActionsCancel:
0058     case KIO::AskUserActionInterface::WarningTwoActions:
0059     case KIO::AskUserActionInterface::WarningTwoActionsCancel: {
0060         // storage holds "true" if persistent reply is "Yes", "false" for persistent "No",
0061         // otherwise no persistent reply is present
0062         const QString value = cg.readEntry(dontAskAgainName, QString());
0063         if ((value.compare(QLatin1String("yes"), Qt::CaseInsensitive) == 0) || (value.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0)) {
0064             Q_EMIT q->messageBoxResult(KIO::WorkerBase::PrimaryAction);
0065             return true;
0066         }
0067         if ((value.compare(QLatin1String("no"), Qt::CaseInsensitive) == 0) || (value.compare(QLatin1String("false"), Qt::CaseInsensitive) == 0)) {
0068             Q_EMIT q->messageBoxResult(KIO::WorkerBase::SecondaryAction);
0069             return true;
0070         }
0071         break;
0072     }
0073     case KIO::AskUserActionInterface::WarningContinueCancel: {
0074         // storage holds "false" if persistent reply is "Continue"
0075         // otherwise no persistent reply is present
0076         const bool value = cg.readEntry(dontAskAgainName, true);
0077         if (value == false) {
0078             Q_EMIT q->messageBoxResult(KIO::WorkerBase::Continue);
0079             return true;
0080         }
0081         break;
0082     }
0083     default:
0084         break;
0085     }
0086 
0087     return false;
0088 }
0089 
0090 void KIO::WidgetsAskUserActionHandlerPrivate::savePersistentUserReply(KIO::AskUserActionInterface::MessageDialogType type,
0091                                                                       KConfigGroup &cg,
0092                                                                       const QString &dontAskAgainName,
0093                                                                       int result)
0094 {
0095     // see gotPersistentUserReply for values stored and why
0096     switch (type) {
0097     case KIO::AskUserActionInterface::QuestionTwoActions:
0098     case KIO::AskUserActionInterface::QuestionTwoActionsCancel:
0099     case KIO::AskUserActionInterface::WarningTwoActions:
0100     case KIO::AskUserActionInterface::WarningTwoActionsCancel:
0101         cg.writeEntry(dontAskAgainName, result == KIO::WorkerBase::PrimaryAction);
0102         cg.sync();
0103         break;
0104     case KIO::AskUserActionInterface::WarningContinueCancel:
0105         cg.writeEntry(dontAskAgainName, false);
0106         cg.sync();
0107         break;
0108     default:
0109         break;
0110     }
0111 }
0112 
0113 QWidget *KIO::WidgetsAskUserActionHandlerPrivate::getParentWidget(KJob *job)
0114 {
0115     // This needs to be in qpointer, otherwise copying process
0116     // will crash if done in background and dolphin is closed
0117     QPointer<QWidget> parentWidget = nullptr;
0118 
0119     if (job) {
0120         parentWidget = KJobWidgets::window(job);
0121     }
0122 
0123     return getParentWidget(parentWidget);
0124 }
0125 
0126 QWidget *KIO::WidgetsAskUserActionHandlerPrivate::getParentWidget(QWidget *widget)
0127 {
0128     // This needs to be in qpointer, otherwise copying process
0129     // will crash if done in background and dolphin is closed
0130     QPointer<QWidget> parentWidget = widget;
0131 
0132     if (!parentWidget) {
0133         parentWidget = this->m_parentWidget;
0134     }
0135 
0136     if (!parentWidget) {
0137         parentWidget = qApp->activeWindow();
0138     }
0139 
0140     return parentWidget;
0141 }
0142 
0143 KIO::WidgetsAskUserActionHandler::WidgetsAskUserActionHandler(QObject *parent)
0144     : KIO::AskUserActionInterface(parent)
0145     , d(new WidgetsAskUserActionHandlerPrivate(this))
0146 {
0147 }
0148 
0149 KIO::WidgetsAskUserActionHandler::~WidgetsAskUserActionHandler()
0150 {
0151 }
0152 
0153 void KIO::WidgetsAskUserActionHandler::askUserRename(KJob *job,
0154                                                      const QString &title,
0155                                                      const QUrl &src,
0156                                                      const QUrl &dest,
0157                                                      KIO::RenameDialog_Options options,
0158                                                      KIO::filesize_t sizeSrc,
0159                                                      KIO::filesize_t sizeDest,
0160                                                      const QDateTime &ctimeSrc,
0161                                                      const QDateTime &ctimeDest,
0162                                                      const QDateTime &mtimeSrc,
0163                                                      const QDateTime &mtimeDest)
0164 {
0165     QMetaObject::invokeMethod(qGuiApp, [=] {
0166         auto *dlg = new KIO::RenameDialog(d->getParentWidget(job), title, src, dest, options, sizeSrc, sizeDest, ctimeSrc, ctimeDest, mtimeSrc, mtimeDest);
0167 
0168         dlg->setAttribute(Qt::WA_DeleteOnClose);
0169         dlg->setWindowModality(Qt::WindowModal);
0170 
0171         connect(job, &KJob::finished, dlg, &QDialog::reject);
0172         connect(dlg, &QDialog::finished, this, [this, job, dlg](const int exitCode) {
0173             KIO::RenameDialog_Result result = static_cast<RenameDialog_Result>(exitCode);
0174             const QUrl newUrl = result == Result_AutoRename ? dlg->autoDestUrl() : dlg->newDestUrl();
0175             Q_EMIT askUserRenameResult(result, newUrl, job);
0176         });
0177 
0178         dlg->show();
0179     });
0180 }
0181 
0182 void KIO::WidgetsAskUserActionHandler::askUserSkip(KJob *job, KIO::SkipDialog_Options options, const QString &errorText)
0183 {
0184     QMetaObject::invokeMethod(qGuiApp, [=] {
0185         auto *dlg = new KIO::SkipDialog(d->getParentWidget(job), options, errorText);
0186         dlg->setAttribute(Qt::WA_DeleteOnClose);
0187         dlg->setWindowModality(Qt::WindowModal);
0188 
0189         connect(job, &KJob::finished, dlg, &QDialog::reject);
0190         connect(dlg, &QDialog::finished, this, [this, job](const int exitCode) {
0191             Q_EMIT askUserSkipResult(static_cast<KIO::SkipDialog_Result>(exitCode), job);
0192         });
0193 
0194         dlg->show();
0195     });
0196 }
0197 
0198 struct ProcessAskDeleteResult {
0199     QStringList prettyList;
0200     KMessageDialog::Type dialogType = KMessageDialog::QuestionTwoActions;
0201     KGuiItem acceptButton;
0202     QString text;
0203     QIcon icon;
0204     QString title = i18n("Delete Permanently");
0205     bool isSingleUrl = false;
0206 };
0207 
0208 using AskIface = KIO::AskUserActionInterface;
0209 static ProcessAskDeleteResult processAskDelete(const QList<QUrl> &urls, AskIface::DeletionType deletionType)
0210 {
0211     ProcessAskDeleteResult res;
0212     res.prettyList.reserve(urls.size());
0213     std::transform(urls.cbegin(), urls.cend(), std::back_inserter(res.prettyList), [](const auto &url) {
0214         if (url.scheme() == QLatin1String("trash")) {
0215             QString path = url.path();
0216             // HACK (#98983): remove "0-foo". Note that it works better than
0217             // displaying KFileItem::name(), for files under a subdir.
0218             static const QRegularExpression re(QStringLiteral("^/[0-9]+-"));
0219             path.remove(re);
0220             return path;
0221         } else {
0222             return url.toDisplayString(QUrl::PreferLocalFile);
0223         }
0224     });
0225 
0226     const int urlCount = res.prettyList.size();
0227     res.isSingleUrl = urlCount == 1;
0228 
0229     switch (deletionType) {
0230     case AskIface::Delete: {
0231         res.dialogType = KMessageDialog::QuestionTwoActions; // Using Question* so the Delete button is pre-selected. Bug 462845
0232         res.icon = QIcon::fromTheme(QStringLiteral("dialog-warning"));
0233         if (res.isSingleUrl) {
0234             res.text = xi18nc("@info",
0235                               "Do you really want to permanently delete this item?<nl/><nl/>"
0236                               "<filename>%1</filename><nl/><nl/>"
0237                               "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0238                               res.prettyList.at(0));
0239         } else {
0240             res.text = xi18ncp("@info",
0241                                "Do you really want to permanently delete this %1 item?<nl/><nl/>"
0242                                "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0243                                "Do you really want to permanently delete these %1 items?<nl/><nl/>"
0244                                "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0245                                urlCount);
0246         }
0247         res.acceptButton = KGuiItem(i18nc("@action:button", "Delete Permanently"), QStringLiteral("edit-delete"));
0248         break;
0249     }
0250     case AskIface::DeleteInsteadOfTrash: {
0251         res.dialogType = KMessageDialog::WarningTwoActions;
0252         if (res.isSingleUrl) {
0253             res.text = xi18nc("@info",
0254                               "Moving this item to Trash failed as it is too large."
0255                               " Permanently delete it instead?<nl/><nl/>"
0256                               "<filename>%1</filename><nl/><nl/>"
0257                               "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0258                               res.prettyList.at(0));
0259         } else {
0260             res.text = xi18ncp("@info",
0261                                "Moving this %1 item to Trash failed as it is too large."
0262                                " Permanently delete it instead?<nl/>"
0263                                "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0264                                "Moving these %1 items to Trash failed as they are too large."
0265                                " Permanently delete them instead?<nl/><nl/>"
0266                                "<emphasis strong='true'>This action cannot be undone.</emphasis>",
0267                                urlCount);
0268         }
0269         res.acceptButton = KGuiItem(i18nc("@action:button", "Delete Permanently"), QStringLiteral("edit-delete"));
0270         break;
0271     }
0272     case AskIface::EmptyTrash: {
0273         res.dialogType = KMessageDialog::QuestionTwoActions; // Using Question* so the Delete button is pre-selected.
0274         res.icon = QIcon::fromTheme(QStringLiteral("dialog-warning"));
0275         res.text = xi18nc("@info",
0276                           "Do you want to permanently delete all items from the Trash?<nl/><nl/>"
0277                           "<emphasis strong='true'>This action cannot be undone.</emphasis>");
0278         res.acceptButton = KGuiItem(i18nc("@action:button", "Empty Trash"), QStringLiteral("user-trash"));
0279         break;
0280     }
0281     case AskIface::Trash: {
0282         if (res.isSingleUrl) {
0283             res.text = xi18nc("@info",
0284                               "Do you really want to move this item to the Trash?<nl/>"
0285                               "<filename>%1</filename>",
0286                               res.prettyList.at(0));
0287         } else {
0288             res.text =
0289                 xi18ncp("@info", "Do you really want to move this %1 item to the Trash?", "Do you really want to move these %1 items to the Trash?", urlCount);
0290         }
0291         res.title = i18n("Move to Trash");
0292         res.acceptButton = KGuiItem(res.title, QStringLiteral("user-trash"));
0293         break;
0294     }
0295     default:
0296         break;
0297     }
0298     return res;
0299 }
0300 
0301 void KIO::WidgetsAskUserActionHandler::askUserDelete(const QList<QUrl> &urls, DeletionType deletionType, ConfirmationType confirmationType, QWidget *parent)
0302 {
0303     QString keyName;
0304     bool ask = (confirmationType == ForceConfirmation);
0305     if (!ask) {
0306         // The default value for confirmations is true for delete and false
0307         // for trash. If you change this, please also update:
0308         //      dolphin/src/settings/general/confirmationssettingspage.cpp
0309         bool defaultValue = true;
0310 
0311         switch (deletionType) {
0312         case DeleteInsteadOfTrash:
0313         case Delete:
0314             keyName = QStringLiteral("ConfirmDelete");
0315             break;
0316         case Trash:
0317             keyName = QStringLiteral("ConfirmTrash");
0318             defaultValue = false;
0319             break;
0320         case EmptyTrash:
0321             keyName = QStringLiteral("ConfirmEmptyTrash");
0322             break;
0323         }
0324 
0325         KSharedConfigPtr kioConfig = KSharedConfig::openConfig(QStringLiteral("kiorc"), KConfig::NoGlobals);
0326         ask = kioConfig->group(QStringLiteral("Confirmations")).readEntry(keyName, defaultValue);
0327     }
0328 
0329     if (!ask) {
0330         Q_EMIT askUserDeleteResult(true, urls, deletionType, parent);
0331         return;
0332     }
0333 
0334     QMetaObject::invokeMethod(qGuiApp, [=] {
0335         const auto &[prettyList, dialogType, acceptButton, text, icon, title, singleUrl] = processAskDelete(urls, deletionType);
0336         KMessageDialog *dlg = new KMessageDialog(dialogType, text, parent);
0337         dlg->setAttribute(Qt::WA_DeleteOnClose);
0338         dlg->setCaption(title);
0339         dlg->setIcon(icon);
0340         dlg->setButtons(acceptButton, KStandardGuiItem::cancel());
0341         if (!singleUrl) {
0342             dlg->setListWidgetItems(prettyList);
0343         }
0344         dlg->setDontAskAgainText(i18nc("@option:checkbox", "Do not ask again"));
0345         // If we get here, !ask must be false
0346         dlg->setDontAskAgainChecked(!ask);
0347 
0348         connect(dlg, &QDialog::finished, this, [=](const int buttonCode) {
0349             const bool isDelete = (buttonCode == KMessageDialog::PrimaryAction);
0350 
0351             Q_EMIT askUserDeleteResult(isDelete, urls, deletionType, parent);
0352 
0353             if (isDelete) {
0354                 KSharedConfigPtr kioConfig = KSharedConfig::openConfig(QStringLiteral("kiorc"), KConfig::NoGlobals);
0355                 KConfigGroup cg = kioConfig->group(QStringLiteral("Confirmations"));
0356                 cg.writeEntry(keyName, !dlg->isDontAskAgainChecked());
0357                 cg.sync();
0358             }
0359         });
0360 
0361         dlg->setWindowModality(Qt::WindowModal);
0362         dlg->show();
0363     });
0364 }
0365 
0366 void KIO::WidgetsAskUserActionHandler::requestUserMessageBox(MessageDialogType type,
0367                                                              const QString &text,
0368                                                              const QString &title,
0369                                                              const QString &primaryActionText,
0370                                                              const QString &secondaryActionText,
0371                                                              const QString &primaryActionIconName,
0372                                                              const QString &secondaryActionIconName,
0373                                                              const QString &dontAskAgainName,
0374                                                              const QString &details,
0375                                                              QWidget *parent)
0376 {
0377     if (d->gotPersistentUserReply(type,
0378                                   KSharedConfig::openConfig(QStringLiteral("kioslaverc"))->group(QStringLiteral("Notification Messages")),
0379                                   dontAskAgainName)) {
0380         return;
0381     }
0382 
0383     const KGuiItem primaryActionButton(primaryActionText, primaryActionIconName);
0384     const KGuiItem secondaryActionButton(secondaryActionText, secondaryActionIconName);
0385 
0386     // It's "Do not ask again" every where except with Information
0387     QString dontAskAgainText = i18nc("@option:check", "Do not ask again");
0388 
0389     KMessageDialog::Type dlgType;
0390     bool hasCancelButton = false;
0391 
0392     switch (type) {
0393     case AskUserActionInterface::QuestionTwoActions:
0394         dlgType = KMessageDialog::QuestionTwoActions;
0395         break;
0396     case AskUserActionInterface::QuestionTwoActionsCancel:
0397         dlgType = KMessageDialog::QuestionTwoActionsCancel;
0398         hasCancelButton = true;
0399         break;
0400     case AskUserActionInterface::WarningTwoActions:
0401         dlgType = KMessageDialog::WarningTwoActions;
0402         break;
0403     case AskUserActionInterface::WarningTwoActionsCancel:
0404         dlgType = KMessageDialog::WarningTwoActionsCancel;
0405         hasCancelButton = true;
0406         break;
0407     case AskUserActionInterface::WarningContinueCancel:
0408         dlgType = KMessageDialog::WarningContinueCancel;
0409         hasCancelButton = true;
0410         break;
0411     case AskUserActionInterface::Information:
0412         dlgType = KMessageDialog::Information;
0413         dontAskAgainText = i18nc("@option:check", "Do not show this message again");
0414         break;
0415     case AskUserActionInterface::Error:
0416         dlgType = KMessageDialog::Error;
0417         dontAskAgainText = QString{}; // No dontAskAgain checkbox
0418         break;
0419     default:
0420         qCWarning(KIO_WIDGETS) << "Unknown message dialog type" << type;
0421         return;
0422     }
0423 
0424     QMetaObject::invokeMethod(qGuiApp, [=]() {
0425         auto cancelButton = hasCancelButton ? KStandardGuiItem::cancel() : KGuiItem();
0426         auto *dialog = new KMessageDialog(dlgType, text, d->getParentWidget(parent));
0427 
0428         dialog->setAttribute(Qt::WA_DeleteOnClose);
0429         dialog->setCaption(title);
0430         dialog->setIcon(QIcon{});
0431         dialog->setButtons(primaryActionButton, secondaryActionButton, cancelButton);
0432         dialog->setDetails(details);
0433         dialog->setDontAskAgainText(dontAskAgainText);
0434         dialog->setDontAskAgainChecked(false);
0435         dialog->setOpenExternalLinks(true); // Allow opening external links in the text labels
0436 
0437         connect(dialog, &QDialog::finished, this, [=](const int result) {
0438             KIO::WorkerBase::ButtonCode btnCode;
0439             switch (result) {
0440             case KMessageDialog::PrimaryAction:
0441                 if (dlgType == KMessageDialog::WarningContinueCancel) {
0442                     btnCode = KIO::WorkerBase::Continue;
0443                 } else {
0444                     btnCode = KIO::WorkerBase::PrimaryAction;
0445                 }
0446                 break;
0447             case KMessageDialog::SecondaryAction:
0448                 btnCode = KIO::WorkerBase::SecondaryAction;
0449                 break;
0450             case KMessageDialog::Cancel:
0451                 btnCode = KIO::WorkerBase::Cancel;
0452                 break;
0453             case KMessageDialog::Ok:
0454                 btnCode = KIO::WorkerBase::Ok;
0455                 break;
0456             default:
0457                 qCWarning(KIO_WIDGETS) << "Unknown message dialog result" << result;
0458                 return;
0459             }
0460 
0461             Q_EMIT messageBoxResult(btnCode);
0462 
0463             if ((result != KMessageDialog::Cancel) && dialog->isDontAskAgainChecked()) {
0464                 KSharedConfigPtr reqMsgConfig = KSharedConfig::openConfig(QStringLiteral("kioslaverc"));
0465                 KConfigGroup cg = reqMsgConfig->group(QStringLiteral("Notification Messages"));
0466                 d->savePersistentUserReply(type, cg, dontAskAgainName, result);
0467             }
0468         });
0469 
0470         dialog->show();
0471     });
0472 }
0473 
0474 void KIO::WidgetsAskUserActionHandler::setWindow(QWidget *window)
0475 {
0476     d->m_parentWidget = window;
0477 }
0478 
0479 void KIO::WidgetsAskUserActionHandler::askIgnoreSslErrors(const QVariantMap &sslErrorData, QWidget *parent)
0480 {
0481     QWidget *parentWidget = d->getParentWidget(parent);
0482 
0483     QString message = i18n("The server failed the authenticity check (%1).\n\n", sslErrorData[QLatin1String("hostname")].toString());
0484 
0485     message += sslErrorData[QLatin1String("sslError")].toString();
0486 
0487     auto *dialog = new KMessageDialog(KMessageDialog::WarningTwoActionsCancel, message, parentWidget);
0488 
0489     dialog->setAttribute(Qt::WA_DeleteOnClose);
0490     dialog->setCaption(i18n("Server Authentication"));
0491     dialog->setIcon(QIcon{});
0492     dialog->setButtons(KGuiItem{i18n("&Details"), QStringLiteral("documentinfo")}, KStandardGuiItem::cont(), KStandardGuiItem::cancel());
0493 
0494     connect(dialog, &KMessageDialog::finished, this, [this, parentWidget, sslErrorData](int result) {
0495         if (result == KMessageDialog::PrimaryAction) {
0496             showSslDetails(sslErrorData, parentWidget);
0497         } else if (result == KMessageDialog::SecondaryAction) {
0498             // continue();
0499             Q_EMIT askIgnoreSslErrorsResult(1);
0500         } else if (result == KMessageDialog::Cancel) {
0501             // cancel();
0502             Q_EMIT askIgnoreSslErrorsResult(0);
0503         } else {
0504             Q_UNREACHABLE();
0505         }
0506     });
0507 
0508     dialog->show();
0509 }
0510 
0511 void KIO::WidgetsAskUserActionHandler::showSslDetails(const QVariantMap &sslErrorData, QWidget *parentWidget)
0512 {
0513     const QStringList sslList = sslErrorData[QLatin1String("peerCertChain")].toStringList();
0514 
0515     QList<QSslCertificate> certChain;
0516     bool decodedOk = true;
0517     for (const QString &str : sslList) {
0518         certChain.append(QSslCertificate(str.toUtf8()));
0519         if (certChain.last().isNull()) {
0520             decodedOk = false;
0521             break;
0522         }
0523     }
0524 
0525     QMetaObject::invokeMethod(qGuiApp, [=] {
0526         if (decodedOk) { // Use KSslInfoDialog
0527             KSslInfoDialog *ksslDlg = new KSslInfoDialog(parentWidget);
0528             ksslDlg->setSslInfo(
0529                 certChain,
0530                 QString(),
0531                 sslErrorData[QLatin1String("hostname")].toString(),
0532                 sslErrorData[QLatin1String("protocol")].toString(),
0533                 sslErrorData[QLatin1String("cipher")].toString(),
0534                 sslErrorData[QLatin1String("usedBits")].toInt(),
0535                 sslErrorData[QLatin1String("bits")].toInt(),
0536                 KSslInfoDialog::certificateErrorsFromString(sslErrorData[QLatin1String("certificateErrors")].toStringList().join(QLatin1Char('\n'))));
0537 
0538             // KSslInfoDialog deletes itself by setting Qt::WA_DeleteOnClose
0539 
0540             QObject::connect(ksslDlg, &QDialog::finished, this, [this, sslErrorData, parentWidget]() {
0541                 // KSslInfoDialog only has one button, QDialogButtonBox::Close
0542                 askIgnoreSslErrors(sslErrorData, parentWidget);
0543             });
0544 
0545             ksslDlg->show();
0546             return;
0547         }
0548 
0549         // Fallback to a generic message box
0550         auto *dialog = new KMessageDialog(KMessageDialog::Information, i18n("The peer SSL certificate chain appears to be corrupt."), parentWidget);
0551 
0552         dialog->setAttribute(Qt::WA_DeleteOnClose);
0553         dialog->setCaption(i18n("SSL"));
0554         dialog->setButtons(KStandardGuiItem::ok());
0555 
0556         QObject::connect(dialog, &QDialog::finished, this, [this](const int result) {
0557             Q_EMIT askIgnoreSslErrorsResult(result == KMessageDialog::Ok ? 1 : 0);
0558         });
0559 
0560         dialog->show();
0561     });
0562 }
0563 
0564 #include "moc_widgetsaskuseractionhandler.cpp"