File indexing completed on 2024-04-28 08:34:09

0001 /*
0002     SPDX-FileCopyrightText: 2007 Trolltech ASA
0003     SPDX-FileCopyrightText: 2008-2010 Urs Wolfer <uwolfer@kde.org>
0004     SPDX-FileCopyrightText: 2008 Laurent Montel <montel@kde.org>
0005     SPDX-FileCopyrightText: 2009 Dawit Alemayehu <adawit@kde.org>
0006     SPDX-FileCopyrightText: 2013 Allan Sandfeld Jensen <sandfeld@kde.org>
0007 
0008     SPDX-License-Identifier: LGPL-2.1-or-later
0009 */
0010 
0011 #include "kwebkitpart.h"
0012 
0013 #include <QWebElement>
0014 #include <QWebHistoryItem>
0015 
0016 #include "kwebkitpart_debug.h"
0017 #include "kwebkitpart_ext.h"
0018 #include "webview.h"
0019 #include "webpage.h"
0020 #include "websslinfo.h"
0021 #include "webhistoryinterface.h"
0022 
0023 #include "ui/searchbar.h"
0024 #include "ui/passwordbar.h"
0025 #include "ui/featurepermissionbar.h"
0026 #include "settings/webkitsettings.h"
0027 
0028 #include <KCodecAction>
0029 #include <KSslInfoDialog>
0030 
0031 #include <KActionCollection>
0032 #include <KUrlLabel>
0033 #include <KIconLoader>
0034 #include <KLocalizedString>
0035 #include <KMessageBox>
0036 #include <KStringHandler>
0037 #include <KWebWallet>
0038 #include <KToolInvocation>
0039 #include <KAcceleratorManager>
0040 #include <KFileItem>
0041 #include <KProtocolInfo>
0042 #include <KParts/StatusBarExtension>
0043 #include <KParts/GUIActivateEvent>
0044 #include <KSharedConfig>
0045 #include <KConfigGroup>
0046 #include <KParts/BrowserRun>
0047 
0048 #include <QUrl>
0049 #include <QUrlQuery>
0050 #include <QIcon>
0051 #include <QMenu>
0052 #include <QTextCodec>
0053 #include <QCoreApplication>
0054 #include <QVBoxLayout>
0055 #include <QDBusInterface>
0056 #include <QStatusBar>
0057 
0058 #define QL1S(x)  QLatin1String(x)
0059 #define QL1C(x)  QLatin1Char(x)
0060 
0061 Q_GLOBAL_STATIC_WITH_ARGS(QUrl, globalBlankUrl, ("about:blank"))
0062 
0063 
0064 KWebKitPart::KWebKitPart(QWidget *parentWidget, QObject *parent,
0065                          const KPluginMetaData& metaData,
0066                          const QByteArray& cachedHistory, const QStringList& /*args*/)
0067             :KParts::ReadOnlyPart(parent),
0068              m_emitOpenUrlNotify(true),
0069              m_hasCachedFormData(false),
0070              m_doLoadFinishedActions(false),
0071              m_statusBarWalletLabel(nullptr),
0072              m_searchBar(nullptr),
0073              m_passwordBar(nullptr),
0074              m_featurePermissionBar(nullptr)
0075 {
0076     setMetaData(metaData);
0077 
0078     setXMLFile(QL1S("kwebkitpart.rc"));
0079 
0080     // Create this KPart's widget
0081     QWidget *mainWidget = new QWidget (parentWidget);
0082     mainWidget->setObjectName("kwebkitpart");
0083 
0084     // Create the WebView...
0085     m_webView = new WebView (this, parentWidget);
0086 
0087     // Create the browser extension.
0088     m_browserExtension = new WebKitBrowserExtension(this, cachedHistory);
0089 
0090     // Add status bar extension...
0091     m_statusBarExtension = new KParts::StatusBarExtension(this);
0092 
0093     // Add a web history interface for storing visited links.
0094     if (!QWebHistoryInterface::defaultInterface())
0095         QWebHistoryInterface::setDefaultInterface(new WebHistoryInterface(this));
0096 
0097     // Add text and html extensions...
0098     new KWebKitTextExtension(this);
0099     new KWebKitHtmlExtension(this);
0100     new KWebKitScriptableExtension(this);
0101 
0102 
0103     // Layout the GUI...
0104     QVBoxLayout* l = new QVBoxLayout(mainWidget);
0105     l->setContentsMargins(0, 0, 0, 0);
0106     l->setSpacing(0);
0107     l->addWidget(m_webView);
0108     mainWidget->setLayout(l);
0109 
0110     // Set the part's widget
0111     setWidget(mainWidget);
0112 
0113     // Set the web view as the focus object
0114     mainWidget->setFocusProxy(m_webView);
0115 
0116     // Connect the signals from the webview
0117     connect(m_webView, SIGNAL(titleChanged(QString)),
0118             this, SIGNAL(setWindowCaption(QString)));
0119     connect(m_webView, SIGNAL(urlChanged(QUrl)),
0120             this, SLOT(slotUrlChanged(QUrl)));
0121     connect(m_webView, SIGNAL(linkMiddleOrCtrlClicked(QUrl)),
0122             this, SLOT(slotLinkMiddleOrCtrlClicked(QUrl)));
0123     connect(m_webView, SIGNAL(selectionClipboardUrlPasted(QUrl,QString)),
0124             this, SLOT(slotSelectionClipboardUrlPasted(QUrl,QString)));
0125     connect(m_webView, SIGNAL(loadFinished(bool)),
0126             this, SLOT(slotLoadFinished(bool)));
0127 
0128     // Connect the signals from the page...
0129     connectWebPageSignals(page());
0130 
0131     // Init the QAction we are going to use...
0132     initActions();
0133 
0134     // Load plugins once we are fully ready
0135     loadPlugins();
0136 }
0137 
0138 KWebKitPart::~KWebKitPart()
0139 {
0140 }
0141 
0142 WebPage* KWebKitPart::page()
0143 {
0144     if (m_webView)
0145         return qobject_cast<WebPage*>(m_webView->page());
0146     return nullptr;
0147 }
0148 
0149 const WebPage* KWebKitPart::page() const
0150 {
0151     if (m_webView)
0152         return qobject_cast<const WebPage*>(m_webView->page());
0153     return nullptr;
0154 }
0155 
0156 void KWebKitPart::initActions()
0157 {
0158     actionCollection()->addAction(KStandardAction::SaveAs, "saveDocument",
0159                                   m_browserExtension, SLOT(slotSaveDocument()));
0160 
0161     QAction* action = new QAction(i18n("Save &Frame As..."), this);
0162     actionCollection()->addAction("saveFrame", action);
0163     connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(slotSaveFrame()));
0164 
0165     action = new QAction(QIcon::fromTheme(QStringLiteral("document-print-preview")), i18n("Print Preview"), this);
0166     actionCollection()->addAction("printPreview", action);
0167     connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(slotPrintPreview()));
0168 
0169     action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-in")), i18nc("zoom in action", "Zoom In"), this);
0170     actionCollection()->addAction("zoomIn", action);
0171     actionCollection()->setDefaultShortcuts(action,
0172                                             QList<QKeySequence>() << QKeySequence(Qt::CTRL+Qt::Key_Plus)
0173                                                                   << QKeySequence(Qt::CTRL+Qt::Key_Equal));
0174     connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(zoomIn()));
0175 
0176     action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-out")), i18nc("zoom out action", "Zoom Out"), this);
0177     actionCollection()->addAction("zoomOut", action);
0178     actionCollection()->setDefaultShortcuts(action,
0179                                             QList<QKeySequence>() << QKeySequence(Qt::CTRL+Qt::Key_Minus)
0180                                                                   << QKeySequence(Qt::CTRL+Qt::Key_Underscore));
0181     connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(zoomOut()));
0182 
0183     action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-original")), i18nc("reset zoom action", "Actual Size"), this);
0184     actionCollection()->addAction("zoomNormal", action);
0185     actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL+Qt::Key_0));
0186     connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(zoomNormal()));
0187 
0188     action = new QAction(i18n("Zoom Text Only"), this);
0189     action->setCheckable(true);
0190     KConfigGroup cgHtml(KSharedConfig::openConfig(), "HTML Settings");
0191     bool zoomTextOnly = cgHtml.readEntry("ZoomTextOnly", false);
0192     action->setChecked(zoomTextOnly);
0193     actionCollection()->addAction("zoomTextOnly", action);
0194     connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(toogleZoomTextOnly()));
0195 
0196     action = new QAction(i18n("Zoom To DPI"), this);
0197     action->setCheckable(true);
0198     bool zoomToDPI = cgHtml.readEntry("ZoomToDPI", false);
0199     action->setChecked(zoomToDPI);
0200     actionCollection()->addAction("zoomToDPI", action);
0201     connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(toogleZoomToDPI()));
0202 
0203     action = actionCollection()->addAction(KStandardAction::SelectAll, "selectAll",
0204                                            m_browserExtension, SLOT(slotSelectAll()));
0205     action->setShortcutContext(Qt::WidgetShortcut);
0206     m_webView->addAction(action);
0207 
0208     KCodecAction *codecAction = new KCodecAction( QIcon::fromTheme(QStringLiteral("character-set")), i18n( "Set &Encoding" ), this, true );
0209     actionCollection()->addAction( "setEncoding", codecAction );
0210     connect(codecAction, &KCodecAction::codecTriggered, this, &KWebKitPart::slotSetTextEncoding);
0211 
0212     action = new QAction(i18n("View Do&cument Source"), this);
0213     actionCollection()->addAction("viewDocumentSource", action);
0214     actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL+Qt::Key_U));
0215     connect(action, SIGNAL(triggered(bool)), m_browserExtension, SLOT(slotViewDocumentSource()));
0216 
0217     action = new QAction(i18nc("Secure Sockets Layer", "View SSL Information"), this);
0218     actionCollection()->addAction("security", action);
0219     connect(action, SIGNAL(triggered(bool)), SLOT(slotShowSecurity()));
0220 
0221     action = new KToggleAction(i18n("Toggle Caret Mode"), this);
0222     actionCollection()->addAction("caretMode", action);
0223     actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::Key_F7));
0224     action->setChecked(isCaretMode());
0225     connect(action, SIGNAL(triggered(bool)), SLOT(slotToggleCaretMode()));
0226     
0227     action = actionCollection()->addAction(KStandardAction::Find, "find", this, SLOT(slotShowSearchBar()));
0228     action->setWhatsThis(i18nc("find action \"whats this\" text", "<h3>Find text</h3>"
0229                               "Shows a dialog that allows you to find text on the displayed page."));
0230 }
0231 
0232 void KWebKitPart::updateActions()
0233 {
0234     m_browserExtension->updateActions();
0235 
0236     QAction* action = actionCollection()->action(QL1S("saveDocument"));
0237     if (action) {
0238         const QString protocol (url().scheme());
0239         action->setEnabled(protocol != QL1S("about") && protocol != QL1S("error"));
0240     }
0241 
0242     action = actionCollection()->action(QL1S("printPreview"));
0243     if (action) {
0244         action->setEnabled(m_browserExtension->isActionEnabled("print"));
0245     }
0246 
0247     action = actionCollection()->action(QL1S("saveFrame"));
0248     if (action) {
0249         action->setEnabled((view()->page()->currentFrame() != view()->page()->mainFrame()));
0250     }
0251 }
0252 
0253 void KWebKitPart::connectWebPageSignals(WebPage* page)
0254 {
0255     if (!page)
0256         return;
0257 
0258     connect(page, SIGNAL(loadStarted()),
0259             this, SLOT(slotLoadStarted()));
0260     connect(page, SIGNAL(loadAborted(QUrl)),
0261             this, SLOT(slotLoadAborted(QUrl)));
0262     connect(page, SIGNAL(linkHovered(QString,QString,QString)),
0263             this, SLOT(slotLinkHovered(QString,QString,QString)));
0264     connect(page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*)),
0265             this, SLOT(slotSaveFrameState(QWebFrame*,QWebHistoryItem*)));
0266     connect(page, SIGNAL(restoreFrameStateRequested(QWebFrame*)),
0267             this, SLOT(slotRestoreFrameState(QWebFrame*)));
0268     connect(page, SIGNAL(statusBarMessage(QString)),
0269             this, SLOT(slotSetStatusBarText(QString)));
0270     connect(page, SIGNAL(windowCloseRequested()),
0271             this, SLOT(slotWindowCloseRequested()));
0272     connect(page, SIGNAL(printRequested(QWebFrame*)),
0273             m_browserExtension, SLOT(slotPrintRequested(QWebFrame*)));
0274     connect(page, SIGNAL(frameCreated(QWebFrame*)),
0275             this, SLOT(slotFrameCreated(QWebFrame*)));
0276 
0277     connect(m_webView, SIGNAL(linkShiftClicked(QUrl)),
0278             page, SLOT(downloadUrl(QUrl)));
0279 
0280     connect(page, SIGNAL(loadProgress(int)),
0281             m_browserExtension, SIGNAL(loadingProgress(int)));
0282     connect(page, SIGNAL(selectionChanged()),
0283             m_browserExtension, SLOT(updateEditActions()));
0284     connect(m_browserExtension, SIGNAL(saveUrl(QUrl)),
0285             page, SLOT(downloadUrl(QUrl)));
0286 
0287     connect(page->mainFrame(), SIGNAL(loadFinished(bool)),
0288             this, SLOT(slotMainFrameLoadFinished(bool)));
0289 
0290 
0291     KWebWallet *wallet = page->wallet();
0292     if (wallet) {
0293         connect(wallet, SIGNAL(saveFormDataRequested(QString,QUrl)),
0294                 this, SLOT(slotSaveFormDataRequested(QString,QUrl)));
0295         connect(wallet, SIGNAL(fillFormRequestCompleted(bool)),
0296                 this, SLOT(slotFillFormRequestCompleted(bool)));
0297         connect(wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed()));
0298     }
0299 }
0300 
0301 bool KWebKitPart::openUrl(const QUrl &_u)
0302 {
0303     QUrl u (_u);
0304 
0305     qCDebug(KWEBKITPART_LOG) << u;
0306 
0307     // Ignore empty requests...
0308     if (u.isEmpty())
0309         return false;
0310 
0311     // If the URL given is a supported local protocol, e.g. "bookmark" but lacks
0312     // a path component, we set the path to "/" here so that the security context
0313     // will properly allow access to local resources.
0314     if (u.host().isEmpty() && u.path().isEmpty()
0315         && KProtocolInfo::protocolClass(u.scheme()) == QL1S(":local")) {
0316         u.setPath(QL1S("/"));
0317     }
0318 
0319     // Do not emit update history when url is typed in since the embedding part
0320     // should handle that automatically itself. At least Konqueror does that.
0321     m_emitOpenUrlNotify = false;
0322 
0323     // Pointer to the page object...
0324     WebPage* p = page();
0325     Q_ASSERT(p);
0326     
0327     //The new konq protocol used by Konqueror is not implemented using an ioslave
0328     //and it isn't (currently) supported by kwebkitpart.
0329     //If support for the konq protocol is added to kwebkitpart, remove the following
0330     //if statement
0331     if (u.scheme() == "konq") {
0332         u = KParts::BrowserRun::makeErrorUrl(KIO::ERR_UNSUPPORTED_PROTOCOL, u.url(), u);
0333     }
0334 
0335     // Handle error conditions...
0336     if (u.scheme() == QL1S("error")) {
0337         /**
0338          * The format of the error url is that two variables are passed in the query:
0339          * error = int kio error code, errText = QString error text from kio
0340          * and the URL where the error happened is passed as a sub URL.
0341          */
0342         const QUrl mainUrl(u.fragment());
0343 
0344         if (mainUrl.isValid()) {
0345             QString query = u.query(QUrl::FullyDecoded);
0346             QRegularExpression pattern("error=(\\d+)&errText=(.*)");
0347             QRegularExpressionMatch match = pattern.match(query);
0348             int error = match.captured(1).toInt();
0349             // error=0 isn't a valid error code, so 0 means it's missing from the URL
0350             if (error == 0) {
0351                 error = KIO::ERR_UNKNOWN;
0352             }
0353             const QString errorText = match.captured(2);
0354 
0355             emit m_browserExtension->setLocationBarUrl(mainUrl.toDisplayString());
0356             if (p) {
0357                 m_webView->setHtml(p->errorPage(error, errorText, mainUrl));
0358                 return true;
0359             }
0360         }
0361 
0362         return false;
0363     }
0364 
0365     KParts::BrowserArguments bargs (m_browserExtension->browserArguments());
0366     KParts::OpenUrlArguments args (arguments());
0367 
0368     if (u != *globalBlankUrl) {
0369         // Get the SSL information sent, if any...
0370         if (args.metaData().contains(QL1S("ssl_in_use"))) {
0371             WebSslInfo sslInfo;
0372             sslInfo.restoreFrom(KIO::MetaData(args.metaData()).toVariant());
0373             sslInfo.setUrl(u);
0374             p->setSslInfo(sslInfo);
0375         }
0376     }
0377 
0378     // Set URL in KParts before emitting started; konq plugins rely on that.
0379     setUrl(u);
0380     m_doLoadFinishedActions = true;
0381     m_webView->loadUrl(u, args, bargs);
0382     return true;
0383 }
0384 
0385 bool KWebKitPart::isCaretMode() const
0386 {
0387     return page()->settings()->testAttribute(QWebSettings::CaretBrowsingEnabled);
0388 }
0389 
0390 void KWebKitPart::slotToggleCaretMode()
0391 {
0392     page()->settings()->setAttribute(QWebSettings::CaretBrowsingEnabled, !isCaretMode());
0393 }
0394 
0395 bool KWebKitPart::closeUrl()
0396 {
0397     m_webView->triggerPageAction(QWebPage::StopScheduledPageRefresh);
0398     m_webView->stop();
0399     return true;
0400 }
0401 
0402 QWebView* KWebKitPart::view() const
0403 {
0404     return m_webView;
0405 }
0406 
0407 bool KWebKitPart::isModified() const
0408 {
0409     return m_webView->isModified();
0410 }
0411 
0412 void KWebKitPart::guiActivateEvent(KParts::GUIActivateEvent *event)
0413 {
0414     if (event && event->activated() && m_webView) {
0415         emit setWindowCaption(m_webView->title());
0416     }
0417 }
0418 
0419 bool KWebKitPart::openFile()
0420 {
0421     // never reached
0422     return false;
0423 }
0424 
0425 
0426 /// slots...
0427 
0428 void KWebKitPart::slotLoadStarted()
0429 {
0430     emit started(nullptr);
0431     updateActions();
0432 }
0433 
0434 void KWebKitPart::slotFrameLoadFinished(bool ok)
0435 {
0436     QWebFrame* frame = (sender() ? qobject_cast<QWebFrame*>(sender()) : page()->mainFrame());
0437 
0438     if (ok) {
0439         const QUrl currentUrl (frame->baseUrl().resolved(frame->url()));
0440         // qCDebug(KWEBKITPART_LOG) << "mainframe:" << m_webView->page()->mainFrame() << "frame:" << sender();
0441         // qCDebug(KWEBKITPART_LOG) << "url:" << frame->url() << "base url:" << frame->baseUrl() << "request url:" << frame->requestedUrl();
0442         if (currentUrl != *globalBlankUrl) {
0443             m_hasCachedFormData = false;
0444 
0445             if (WebKitSettings::self()->isNonPasswordStorableSite(currentUrl.host())) {
0446                 addWalletStatusBarIcon();
0447             } else {
0448                 // Attempt to fill the web form...
0449                 KWebWallet *webWallet = page() ? page()->wallet() : nullptr;
0450                 if (webWallet) {
0451                     webWallet->fillFormData(frame, false);
0452                 }
0453             }
0454         }
0455     }
0456 }
0457 
0458 void KWebKitPart::slotMainFrameLoadFinished (bool ok)
0459 {
0460     if (!ok || !m_doLoadFinishedActions)
0461         return;
0462 
0463     m_doLoadFinishedActions = false;
0464 
0465     if (!m_emitOpenUrlNotify) {
0466         m_emitOpenUrlNotify = true; // Save history once page loading is done.
0467     }
0468 
0469     // If the document contains no <title> tag, then set it to the current url.
0470     if (m_webView->title().trimmed().isEmpty()) {
0471         // If the document title is empty, then set it to the current url
0472         const QUrl url (m_webView->url());
0473         const QString caption (url.toString((QUrl::RemoveQuery|QUrl::RemoveFragment)));
0474         emit setWindowCaption(caption);
0475 
0476         // The urlChanged signal is emitted if and only if the main frame
0477         // receives the title of the page so we manually invoke the slot as a
0478         // work around here for pages that do not contain it, such as text
0479         // documents...
0480         slotUrlChanged(url);
0481     }
0482 
0483    QWebFrame* frame = page()->mainFrame();
0484 
0485     if (!frame || frame->url() == *globalBlankUrl)
0486         return;
0487 
0488     // Set the favicon specified through the <link> tag...
0489     if (WebKitSettings::self()->favIconsEnabled()
0490         && !frame->page()->settings()->testAttribute(QWebSettings::PrivateBrowsingEnabled)) {
0491         const QWebElement element = frame->findFirstElement(QL1S("head>link[rel=icon], "
0492                                                                  "head>link[rel=\"shortcut icon\"]"));
0493         QUrl shortcutIconUrl;
0494         if (!element.isNull()) {
0495             shortcutIconUrl = frame->baseUrl().resolved(QUrl(element.attribute("href")));
0496             //qCDebug(KWEBKITPART_LOG) << "setting favicon to" << shortcutIconUrl;
0497             m_browserExtension->setIconUrl(shortcutIconUrl);
0498         }
0499     }
0500 
0501     slotFrameLoadFinished(ok);
0502 }
0503 
0504 void KWebKitPart::slotLoadFinished(bool ok)
0505 {
0506     bool pending = false;
0507 
0508     if (m_doLoadFinishedActions) {
0509         updateActions();
0510         QWebFrame* frame = (page() ? page()->currentFrame() : nullptr);
0511         if (ok &&
0512             frame == page()->mainFrame() &&
0513             !frame->findFirstElement(QL1S("head>meta[http-equiv=refresh]")).isNull()) {
0514             if (WebKitSettings::self()->autoPageRefresh()) {
0515                 pending = true;
0516             } else {
0517                 frame->page()->triggerAction(QWebPage::StopScheduledPageRefresh);
0518             }
0519         }
0520     }
0521 
0522     emit completed ((ok && pending));
0523 }
0524 
0525 void KWebKitPart::slotLoadAborted(const QUrl & url)
0526 {
0527     closeUrl();
0528     m_doLoadFinishedActions = false;
0529     if (url.isValid())
0530         emit m_browserExtension->openUrlRequest(url);
0531     else
0532         setUrl(m_webView->url());
0533 }
0534 
0535 void KWebKitPart::slotUrlChanged(const QUrl& url)
0536 {
0537     // Ignore if empty
0538     if (url.isEmpty())
0539         return;
0540 
0541     // Ignore if error url
0542     if (url.scheme().compare(QL1S("error"), Qt::CaseInsensitive) == 0)
0543         return;
0544 
0545     const QUrl u (url);
0546 
0547     // Ignore if url has not changed!
0548     if (this->url() == u)
0549       return;
0550 
0551     m_doLoadFinishedActions = true;
0552     setUrl(u);
0553 
0554     // Do not update the location bar with about:blank
0555     if (url != *globalBlankUrl) {
0556         //qCDebug(KWEBKITPART_LOG) << "Setting location bar to" << u.prettyUrl() << "current URL:" << this->url();
0557         emit m_browserExtension->setLocationBarUrl(u.toDisplayString());
0558     }
0559 }
0560 
0561 void KWebKitPart::slotShowSecurity()
0562 {
0563     if (!page())
0564         return;
0565 
0566     const WebSslInfo& sslInfo = page()->sslInfo();
0567     if (!sslInfo.isValid()) {
0568         KMessageBox::information(nullptr, i18n("This site is not secured with SSL, or its SSL information is not valid."),
0569                             i18nc("Secure Sockets Layer", "SSL"));
0570         return;
0571     }
0572 
0573     KSslInfoDialog *dlg = new KSslInfoDialog (widget());
0574     dlg->setSslInfo(sslInfo.certificateChain(),
0575                     sslInfo.peerAddress().toString(),
0576                     url().host(),
0577                     sslInfo.protocol(),
0578                     sslInfo.ciphers(),
0579                     sslInfo.usedChiperBits(),
0580                     sslInfo.supportedChiperBits(),
0581                     KSslInfoDialog::certificateErrorsFromString(sslInfo.certificateErrors()));
0582     dlg->open();
0583 }
0584 
0585 void KWebKitPart::slotSaveFrameState(QWebFrame *frame, QWebHistoryItem *item)
0586 {
0587     if (!frame || !item) {
0588         return;
0589     }
0590 
0591     // Handle actions that apply only to the mainframe...
0592     if (frame == view()->page()->mainFrame()) {
0593         slotWalletClosed();
0594 
0595         // If "NoEmitOpenUrlNotification" property is set to true, do not
0596         // emit the open url notification. Property is set by this part's
0597         // extension to prevent openUrl notification being sent when
0598         // handling history navigation requests.
0599         const bool doNotEmitOpenUrl = property("NoEmitOpenUrlNotification").toBool();
0600         if (doNotEmitOpenUrl) {
0601             setProperty("NoEmitOpenUrlNotification", QVariant());
0602         }
0603 
0604         // Only emit open url notify for the main frame. Do not
0605         if (m_emitOpenUrlNotify && !doNotEmitOpenUrl) {
0606             // qCDebug(KWEBKITPART_LOG) << "***** EMITTING openUrlNotify" << item->url();
0607             emit m_browserExtension->openUrlNotify();
0608         }
0609     }
0610 
0611     // For some reason, QtWebKit does not restore scroll position when
0612     // QWebHistory is restored from persistent storage. Therefore, we
0613     // preserve that information and restore it as needed. See
0614     // slotRestoreFrameState.
0615     const QPoint scrollPos (frame->scrollPosition());
0616     if (!scrollPos.isNull()) {
0617         // qCDebug(KWEBKITPART_LOG) << "Saving scroll position:" << scrollPos;
0618         item->setUserData(scrollPos);
0619     }
0620 }
0621 
0622 void KWebKitPart::slotRestoreFrameState(QWebFrame *frame)
0623 {
0624     QWebPage* page = (frame ? frame->page() : nullptr);
0625     QWebHistory* history = (page ? page->history() : nullptr);
0626 
0627     // No history item...
0628     if (!history || history->count() < 1)
0629         return;
0630 
0631     QWebHistoryItem currentHistoryItem (history->currentItem());
0632 
0633     // Update the scroll position if needed. See comment in slotSaveFrameState above.
0634     if (frame->baseUrl().resolved(frame->url()) == currentHistoryItem.url()) {
0635         const QPoint currentPos (frame->scrollPosition());
0636         const QPoint desiredPos (currentHistoryItem.userData().toPoint());
0637         if (currentPos.isNull() && !desiredPos.isNull()) {
0638             frame->setScrollPosition(desiredPos);
0639         }
0640     }
0641 }
0642 
0643 void KWebKitPart::slotLinkHovered(const QString& _link, const QString& /*title*/, const QString& /*content*/)
0644 {
0645     QString message;
0646 
0647     if (_link.isEmpty()) {
0648         message = QL1S("");
0649         emit m_browserExtension->mouseOverInfo(KFileItem());
0650     } else {
0651         QUrl linkUrl (_link);
0652         const QString scheme = linkUrl.scheme();
0653 
0654         // Protect the user against URL spoofing!
0655         linkUrl.setUserName(QString());
0656         const QString link (linkUrl.toString());
0657 
0658         if (scheme == QL1S("mailto")) {
0659             message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", "Email: ");
0660 
0661             // Workaround: for QUrl's parsing deficiencies of "mailto:foo@bar.com".
0662             if (!linkUrl.hasQuery())
0663               linkUrl = QUrl(scheme + '?' + linkUrl.path());
0664 
0665             QMap<QString, QStringList> fields;
0666             QList<QPair<QString, QString> > queryItems = QUrlQuery(linkUrl).queryItems();
0667             const int count = queryItems.count();
0668 
0669             for(int i = 0; i < count; ++i) {
0670                 const QPair<QString, QString> queryItem (queryItems.at(i));
0671                 //qCDebug(KWEBKITPART_LOG) << "query: " << queryItem.first << queryItem.second;
0672                 if (queryItem.first.contains(QL1C('@')) && queryItem.second.isEmpty())
0673                     fields["to"] << queryItem.first;
0674                 if (QString::compare(queryItem.first, QL1S("to"), Qt::CaseInsensitive) == 0)
0675                     fields["to"] << queryItem.second;
0676                 if (QString::compare(queryItem.first, QL1S("cc"), Qt::CaseInsensitive) == 0)
0677                     fields["cc"] << queryItem.second;
0678                 if (QString::compare(queryItem.first, QL1S("bcc"), Qt::CaseInsensitive) == 0)
0679                     fields["bcc"] << queryItem.second;
0680                 if (QString::compare(queryItem.first, QL1S("subject"), Qt::CaseInsensitive) == 0)
0681                     fields["subject"] << queryItem.second;
0682             }
0683 
0684             if (fields.contains(QL1S("to")))
0685                 message += fields.value(QL1S("to")).join(QL1S(", "));
0686             if (fields.contains(QL1S("cc")))
0687                 message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - CC: ") + fields.value(QL1S("cc")).join(QL1S(", "));
0688             if (fields.contains(QL1S("bcc")))
0689                 message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - BCC: ") + fields.value(QL1S("bcc")).join(QL1S(", "));
0690             if (fields.contains(QL1S("subject")))
0691                 message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - Subject: ") + fields.value(QL1S("subject")).join(QL1S(" "));
0692         } else if (scheme == QL1S("javascript")) {
0693             message = KStringHandler::rsqueeze(link, 150);
0694             if (link.startsWith(QL1S("javascript:window.open")))
0695                 message += i18n(" (In new window)");
0696         } else {
0697             message = link;
0698             QWebFrame* frame = page() ? page()->currentFrame() : nullptr;
0699             if (frame) {
0700                 QWebHitTestResult result = frame->hitTestContent(page()->view()->mapFromGlobal(QCursor::pos()));
0701                 QWebFrame* target = result.linkTargetFrame();
0702                 if (frame->parentFrame() && target == frame->parentFrame()) {
0703                     message += i18n(" (In parent frame)");
0704                 } else if (!target || target != frame) {
0705                     message += i18n(" (In new window)");
0706                 }
0707             }
0708             KFileItem item (linkUrl, QString(), KFileItem::Unknown);
0709             emit m_browserExtension->mouseOverInfo(item);
0710         }
0711     }
0712 
0713     emit setStatusBarText(message);
0714 }
0715 
0716 void KWebKitPart::slotSearchForText(const QString &text, bool backward)
0717 {
0718     QWebPage::FindFlags flags = QWebPage::FindWrapsAroundDocument;
0719 
0720     if (backward)
0721         flags |= QWebPage::FindBackward;
0722 
0723     if (m_searchBar->caseSensitive())
0724         flags |= QWebPage::FindCaseSensitively;
0725 
0726     if (m_searchBar->highlightMatches())
0727         flags |= QWebPage::HighlightAllOccurrences;
0728 
0729     //qCDebug(KWEBKITPART_LOG) << "search for text:" << text << ", backward ?" << backward;
0730     m_searchBar->setFoundMatch(page()->findText(text, flags));
0731 }
0732 
0733 void KWebKitPart::slotShowSearchBar()
0734 {
0735     if (!m_searchBar) {
0736         // Create the search bar...
0737         m_searchBar = new SearchBar(widget());
0738         connect(m_searchBar, SIGNAL(searchTextChanged(QString,bool)),
0739                 this, SLOT(slotSearchForText(QString,bool)));
0740 
0741         actionCollection()->addAction(KStandardAction::FindNext, "findnext",
0742                                       m_searchBar, SLOT(findNext()));
0743         actionCollection()->addAction(KStandardAction::FindPrev, "findprev",
0744                                       m_searchBar, SLOT(findPrevious()));
0745 
0746         QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout());
0747         if (lay) {
0748           lay->addWidget(m_searchBar);
0749         }
0750     }
0751     const QString text = m_webView->selectedText();
0752     m_searchBar->setSearchText(text.left(150));
0753 }
0754 
0755 void KWebKitPart::slotLinkMiddleOrCtrlClicked(const QUrl& linkUrl)
0756 {
0757     emit m_browserExtension->createNewWindow(linkUrl);
0758 }
0759 
0760 void KWebKitPart::slotSelectionClipboardUrlPasted(const QUrl& selectedUrl, const QString& searchText)
0761 {
0762     if (!WebKitSettings::self()->isOpenMiddleClickEnabled())
0763         return;
0764 
0765     if (!searchText.isEmpty() &&
0766         KMessageBox::questionYesNo(m_webView,
0767                                    i18n("<qt>Do you want to search for <b>%1</b>?</qt>", searchText),
0768                                    i18n("Internet Search"), KGuiItem(i18n("&Search"), "edit-find"),
0769                                    KStandardGuiItem::cancel(), "MiddleClickSearch") != KMessageBox::Yes)
0770         return;
0771 
0772     emit m_browserExtension->openUrlRequest(selectedUrl);
0773 }
0774 
0775 void KWebKitPart::slotWalletClosed()
0776 {
0777     if (!m_statusBarWalletLabel)
0778        return;
0779 
0780     m_statusBarExtension->removeStatusBarItem(m_statusBarWalletLabel);
0781     delete m_statusBarWalletLabel;
0782     m_statusBarWalletLabel = nullptr;
0783     m_hasCachedFormData = false;
0784 }
0785 
0786 void KWebKitPart::slotShowWalletMenu()
0787 {
0788     QMenu *menu = new QMenu;
0789 
0790     if (m_webView && WebKitSettings::self()->isNonPasswordStorableSite(m_webView->url().host()))
0791       menu->addAction(i18n("&Allow password caching for this site"), this, SLOT(slotDeleteNonPasswordStorableSite()));
0792 
0793     if (m_hasCachedFormData)
0794       menu->addAction(i18n("Remove all cached passwords for this site"), this, SLOT(slotRemoveCachedPasswords()));
0795 
0796     menu->addSeparator();
0797     menu->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed()));
0798 
0799     KAcceleratorManager::manage(menu);
0800     menu->popup(QCursor::pos());
0801 }
0802 
0803 void KWebKitPart::slotLaunchWalletManager()
0804 {
0805     QDBusInterface r("org.kde.kwalletmanager", "/kwalletmanager/MainWindow_1");
0806     if (r.isValid())
0807         r.call(QDBus::NoBlock, "show");
0808     else
0809         KToolInvocation::startServiceByDesktopName("kwalletmanager_show");
0810 }
0811 
0812 void KWebKitPart::slotDeleteNonPasswordStorableSite()
0813 {
0814     if (m_webView)
0815         WebKitSettings::self()->removeNonPasswordStorableSite(m_webView->url().host());
0816 }
0817 
0818 void KWebKitPart::slotRemoveCachedPasswords()
0819 {
0820     if (!page() || !page()->wallet())
0821         return;
0822 
0823     page()->wallet()->removeFormData(page()->mainFrame(), true);
0824     m_hasCachedFormData = false;
0825 }
0826 
0827 void KWebKitPart::slotSetTextEncoding(QTextCodec * codec)
0828 {
0829     // FIXME: The code below that sets the text encoding has been reported not to work.
0830     if (!page())
0831         return;
0832 
0833     QWebSettings *localSettings = page()->settings();
0834     if (!localSettings)
0835         return;
0836 
0837     qCDebug(KWEBKITPART_LOG) << "Encoding: new=>" << localSettings->defaultTextEncoding() << ", old=>" << codec->name();
0838 
0839     localSettings->setDefaultTextEncoding(codec->name());
0840     page()->triggerAction(QWebPage::Reload);
0841 }
0842 
0843 void KWebKitPart::slotSetStatusBarText(const QString& text)
0844 {
0845     const QString host (page() ? page()->currentFrame()->url().host() : QString());
0846     if (WebKitSettings::self()->windowStatusPolicy(host) == KParts::HtmlSettingsInterface::JSWindowStatusAllow)
0847         emit setStatusBarText(text);
0848 }
0849 
0850 void KWebKitPart::slotWindowCloseRequested()
0851 {
0852     emit m_browserExtension->requestFocus(this);
0853 #if 0
0854     if (KMessageBox::questionYesNo(m_webView,
0855                                    i18n("Close window?"), i18n("Confirmation Required"),
0856                                    KStandardGuiItem::close(), KStandardGuiItem::cancel())
0857         != KMessageBox::Yes)
0858         return;
0859 #endif
0860     this->deleteLater();
0861 }
0862 
0863 void KWebKitPart::slotShowFeaturePermissionBar(QWebPage::Feature feature)
0864 {
0865     // FIXME: Allow multiple concurrent feature permission requests.
0866     if (m_featurePermissionBar && m_featurePermissionBar->isVisible())
0867         return;
0868 
0869     if (!m_featurePermissionBar) {
0870         m_featurePermissionBar = new FeaturePermissionBar(widget());
0871 
0872         connect(m_featurePermissionBar, SIGNAL(permissionGranted(QWebPage::Feature)),
0873                 this, SLOT(slotFeaturePermissionGranted(QWebPage::Feature)));
0874         connect(m_featurePermissionBar, SIGNAL(permissionDenied(QWebPage::Feature)),
0875                 this, SLOT(slotFeaturePermissionDenied(QWebPage::Feature)));
0876 //         connect(m_passwordBar, SIGNAL(done()),
0877 //                 this, SLOT(slotSaveFormDataDone()));
0878         QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout());
0879         if (lay)
0880             lay->insertWidget(0, m_featurePermissionBar);
0881     }
0882     m_featurePermissionBar->setFeature(feature);
0883 //     m_featurePermissionBar->setText(i18n("<html>Do you want to grant the site <b>%1</b> "
0884 //                                     "access to information about your current physical location?",
0885 //                                     url.host()));
0886     m_featurePermissionBar->setText(i18n("<html>Do you want to grant the site "
0887                                     "access to information about your current physical location?"));
0888     m_featurePermissionBar->animatedShow();
0889 }
0890 
0891 void KWebKitPart::slotFeaturePermissionGranted(QWebPage::Feature feature)
0892 {
0893     Q_ASSERT(m_featurePermissionBar && m_featurePermissionBar->feature() == feature);
0894     page()->setFeaturePermission(page()->mainFrame(), feature, QWebPage::PermissionGrantedByUser);
0895 }
0896 
0897 void KWebKitPart::slotFeaturePermissionDenied(QWebPage::Feature feature)
0898 {
0899     Q_ASSERT(m_featurePermissionBar && m_featurePermissionBar->feature() == feature);
0900     page()->setFeaturePermission(page()->mainFrame(), feature, QWebPage::PermissionDeniedByUser);
0901 }
0902 
0903 void KWebKitPart::slotSaveFormDataRequested (const QString& key, const QUrl& url)
0904 {
0905     if (WebKitSettings::self()->isNonPasswordStorableSite(url.host()))
0906         return;
0907 
0908     if (!WebKitSettings::self()->askToSaveSitePassword())
0909         return;
0910 
0911     if (m_passwordBar && m_passwordBar->isVisible())
0912         return;
0913 
0914     if (!m_passwordBar) {
0915         m_passwordBar = new PasswordBar(widget());
0916         KWebWallet* wallet = page()->wallet();
0917         if (!wallet) {
0918             qCWarning(KWEBKITPART_LOG) << "No wallet instance found! This should never happen!";
0919             return;
0920         }
0921         connect(m_passwordBar, SIGNAL(saveFormDataAccepted(QString)),
0922                 wallet, SLOT(acceptSaveFormDataRequest(QString)));
0923         connect(m_passwordBar, SIGNAL(saveFormDataRejected(QString)),
0924                 wallet, SLOT(rejectSaveFormDataRequest(QString)));
0925         connect(m_passwordBar, SIGNAL(done()),
0926                 this, SLOT(slotSaveFormDataDone()));
0927     }
0928 
0929     Q_ASSERT(m_passwordBar);
0930 
0931     m_passwordBar->setUrl(url);
0932     m_passwordBar->setRequestKey(key);
0933     m_passwordBar->setText(i18n("<html>Do you want %1 to remember the login "
0934                                 "information for <b>%2</b>?</html>",
0935                                 QCoreApplication::applicationName(),
0936                                 url.host()));
0937 
0938     QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout());
0939     if (lay)
0940         lay->insertWidget(0, m_passwordBar);
0941 
0942     m_passwordBar->animatedShow();
0943 }
0944 
0945 void KWebKitPart::slotSaveFormDataDone()
0946 {
0947     if (!m_passwordBar)
0948         return;
0949 
0950     QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout());
0951     if (lay)
0952         lay->removeWidget(m_passwordBar);
0953 }
0954 
0955 void KWebKitPart::addWalletStatusBarIcon ()
0956 {
0957     if (m_statusBarWalletLabel) {
0958         m_statusBarExtension->removeStatusBarItem(m_statusBarWalletLabel);
0959     } else {
0960         m_statusBarWalletLabel = new KUrlLabel(m_statusBarExtension->statusBar());
0961         m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum));
0962         m_statusBarWalletLabel->setUseCursor(false);
0963         m_statusBarWalletLabel->setPixmap(QIcon::fromTheme("wallet-open").pixmap(KIconLoader::SizeSmall));
0964         connect(m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(slotLaunchWalletManager()));
0965         connect(m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(slotShowWalletMenu()));
0966     }
0967     m_statusBarExtension->addStatusBarItem(m_statusBarWalletLabel, 0, false);
0968 }
0969 
0970 void KWebKitPart::slotFillFormRequestCompleted (bool ok)
0971 {
0972     if ((m_hasCachedFormData = ok))
0973         addWalletStatusBarIcon();
0974 }
0975 
0976 void KWebKitPart::slotFrameCreated (QWebFrame* frame)
0977 {
0978     if (frame != page()->mainFrame()) {
0979         connect(frame, SIGNAL(loadFinished(bool)), this, SLOT(slotFrameLoadFinished(bool)), Qt::UniqueConnection);
0980     }
0981 }