File indexing completed on 2022-11-29 20:24:09

0001 // -*- indent-tabs-mode:nil -*-
0002 // vim: set ts=4 sts=4 sw=4 et:
0003 /* This file is part of the KDE project
0004    Copyright (C) 2003 Alexander Kellett <lypanov@kde.org>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public
0008    License version 2 or at your option version 3 as published by
0009    the Free Software Foundation.
0010 
0011    This program is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    General Public License for more details.
0015 
0016    You should have received a copy of the GNU General Public License
0017    along with this program; see the file COPYING.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019    Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "faviconupdater.h"
0023 
0024 #include "toplevel.h"
0025 
0026 #include "keditbookmarks_debug.h"
0027 #include <KLocalizedString>
0028 
0029 #include <KIO/FavIconRequestJob>
0030 #include <kio/job.h>
0031 
0032 #include <KParts/BrowserExtension>
0033 #include <KParts/PartLoader>
0034 
0035 FavIconUpdater::FavIconUpdater(QObject *parent)
0036     : QObject(parent)
0037 {
0038     m_part = nullptr;
0039     m_webGrabber = nullptr;
0040 }
0041 
0042 void FavIconUpdater::downloadIcon(const KBookmark &bk)
0043 {
0044     m_bk = bk;
0045     const QUrl url = bk.url();
0046     const QString favicon = KIO::favIconForUrl(url);
0047     if (!favicon.isEmpty()) {
0048         // qCDebug(KEDITBOOKMARKS_LOG) << "got favicon" << favicon;
0049         m_bk.setIcon(favicon);
0050         KEBApp::self()->notifyCommandExecuted();
0051         // //qCDebug(KEDITBOOKMARKS_LOG) << "emit done(true)";
0052         Q_EMIT done(true, QString());
0053 
0054     } else {
0055         // qCDebug(KEDITBOOKMARKS_LOG) << "no favicon found";
0056         webupdate = false;
0057         KIO::FavIconRequestJob *job = new KIO::FavIconRequestJob(url, KIO::Reload);
0058         connect(job, &KIO::FavIconRequestJob::result, this, &FavIconUpdater::slotResult);
0059     }
0060 }
0061 
0062 FavIconUpdater::~FavIconUpdater()
0063 {
0064     delete m_webGrabber;
0065     delete m_part;
0066 }
0067 
0068 void FavIconUpdater::downloadIconUsingWebBrowser(const KBookmark &bk, const QString &currentError)
0069 {
0070     // qCDebug(KEDITBOOKMARKS_LOG);
0071     m_bk = bk;
0072     webupdate = true;
0073 
0074     if (!m_part) {
0075         QString partLoadingError;
0076         KParts::ReadOnlyPart *part =
0077             KParts::PartLoader::createPartInstanceForMimeType<KParts::ReadOnlyPart>(QStringLiteral("text/html"), nullptr, this, &partLoadingError);
0078         if (!part) {
0079             Q_EMIT done(false, i18n("%1; no HTML component found (%2)", currentError, partLoadingError));
0080             return;
0081         }
0082 
0083         part->setProperty("pluginsEnabled", QVariant(false));
0084         part->setProperty("javaScriptEnabled", QVariant(false));
0085         part->setProperty("javaEnabled", QVariant(false));
0086         part->setProperty("autoloadImages", QVariant(false));
0087 
0088         KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject(part);
0089         Q_ASSERT(ext);
0090 
0091         connect(ext, &KParts::BrowserExtension::setIconUrl, this, &FavIconUpdater::setIconUrl);
0092 
0093         m_part = part;
0094     }
0095 
0096     // The part isn't created by the webgrabber so that we can create the part
0097     // only once.
0098     delete m_webGrabber;
0099     m_webGrabber = new FavIconWebGrabber(m_part, bk.url());
0100     connect(m_webGrabber, &FavIconWebGrabber::done, this, &FavIconUpdater::done);
0101 }
0102 
0103 // khtml callback
0104 void FavIconUpdater::setIconUrl(const QUrl &iconURL)
0105 {
0106     KIO::FavIconRequestJob *job = new KIO::FavIconRequestJob(m_bk.url());
0107     job->setIconUrl(iconURL);
0108     connect(job, &KIO::FavIconRequestJob::result, this, &FavIconUpdater::slotResult);
0109 
0110     delete m_webGrabber;
0111     m_webGrabber = nullptr;
0112 }
0113 
0114 void FavIconUpdater::slotResult(KJob *job)
0115 {
0116     KIO::FavIconRequestJob *requestJob = static_cast<KIO::FavIconRequestJob *>(job);
0117     if (job->error()) {
0118         if (!webupdate) {
0119             qCDebug(KEDITBOOKMARKS_LOG) << "favicon job failed, going to downloadIconUsingWebBrowser";
0120             // no icon found, try webupdater
0121             downloadIconUsingWebBrowser(m_bk, job->errorString());
0122         } else {
0123             qCDebug(KEDITBOOKMARKS_LOG) << "favicon job failed, emit done";
0124             // already tried webupdater
0125             Q_EMIT done(false, job->errorString());
0126         }
0127         return;
0128     }
0129     m_bk.setIcon(requestJob->iconFile());
0130     Q_EMIT done(true, QString());
0131 }
0132 
0133 /* -------------------------- */
0134 
0135 FavIconWebGrabber::FavIconWebGrabber(KParts::ReadOnlyPart *part, const QUrl &url)
0136     : m_part(part)
0137     , m_url(url)
0138 {
0139     // FIXME only connect to result?
0140     //  connect(part, SIGNAL(result(KIO::Job*job)),
0141     //          this, SLOT(slotCompleted()));
0142     connect(part, &KParts::ReadOnlyPart::canceled, this, &FavIconWebGrabber::slotCanceled);
0143     // clang-format off
0144     connect(part, SIGNAL(completed(bool)), this, SLOT(slotCompleted()));
0145     // clang-format on
0146 
0147     // the use of KIO rather than directly using KHTML is to allow silently abort on error
0148     // TODO: an alternative would be to derive from KHTMLPart and reimplement showError(KJob*).
0149 
0150     // qCDebug(KEDITBOOKMARKS_LOG) << "starting KIO::get() on" << m_url;
0151     KIO::Job *job = KIO::get(m_url, KIO::NoReload, KIO::HideProgressInfo);
0152     job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none"));
0153     job->addMetaData(QStringLiteral("errorPage"), QStringLiteral("false"));
0154     connect(job, &KJob::result, this, &FavIconWebGrabber::slotFinished);
0155     // clang-format off
0156     connect(job, SIGNAL(mimetype(KIO::Job*,QString)), this, SLOT(slotMimetype(KIO::Job*,QString)));
0157     // clang-format on
0158 }
0159 
0160 void FavIconWebGrabber::slotMimetype(KIO::Job *job, const QString &type)
0161 {
0162     Q_ASSERT(!job->error()); // can't be set already, surely?
0163 
0164     KIO::SimpleJob *sjob = static_cast<KIO::SimpleJob *>(job);
0165     m_url = sjob->url(); // allow for redirection
0166     sjob->putOnHold();
0167 
0168     // QString typeLocal = typeUncopied; // local copy
0169     qCDebug(KEDITBOOKMARKS_LOG) << "slotMimetype " << type << "calling openUrl on" << m_url;
0170     // TODO - what to do if typeLocal is not text/html ??
0171 
0172     m_part->openUrl(m_url);
0173 }
0174 
0175 void FavIconWebGrabber::slotFinished(KJob *job)
0176 {
0177     if (job->error()) {
0178         qCDebug(KEDITBOOKMARKS_LOG) << job->errorString();
0179         Q_EMIT done(false, job->errorString());
0180         return;
0181     }
0182     // On success mimetype was emitted, so no need to do anything.
0183 }
0184 
0185 void FavIconWebGrabber::slotCompleted()
0186 {
0187     qCDebug(KEDITBOOKMARKS_LOG);
0188     Q_EMIT done(true, QString());
0189 }
0190 
0191 void FavIconWebGrabber::slotCanceled(const QString &errorString)
0192 {
0193     // qCDebug(KEDITBOOKMARKS_LOG) << errorString;
0194     Q_EMIT done(false, errorString);
0195 }