File indexing completed on 2024-04-21 05:50:21

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/SimpleJob>
0031 #include <KIO/TransferJob>
0032 #include <KParts/NavigationExtension>
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         auto partResult = KParts::PartLoader::instantiatePartForMimeType<KParts::ReadOnlyPart>(QStringLiteral("text/html"), nullptr, this);
0076         if (!partResult) {
0077             Q_EMIT done(false, i18n("%1; no HTML component found (%2)", currentError, partResult.errorString));
0078             return;
0079         }
0080 
0081         auto part = partResult.plugin;
0082         part->setProperty("pluginsEnabled", QVariant(false));
0083         part->setProperty("javaScriptEnabled", QVariant(false));
0084         part->setProperty("javaEnabled", QVariant(false));
0085         part->setProperty("autoloadImages", QVariant(false));
0086         KParts::NavigationExtension *ext = KParts::NavigationExtension::childObject(part);
0087         Q_ASSERT(ext);
0088 
0089         connect(ext, &KParts::NavigationExtension::setIconUrl, this, &FavIconUpdater::setIconUrl);
0090         m_part = part;
0091     }
0092 
0093     // The part isn't created by the webgrabber so that we can create the part
0094     // only once.
0095     delete m_webGrabber;
0096     m_webGrabber = new FavIconWebGrabber(m_part, bk.url());
0097     connect(m_webGrabber, &FavIconWebGrabber::done, this, &FavIconUpdater::done);
0098 }
0099 
0100 // khtml callback
0101 void FavIconUpdater::setIconUrl(const QUrl &iconURL)
0102 {
0103     KIO::FavIconRequestJob *job = new KIO::FavIconRequestJob(m_bk.url());
0104     job->setIconUrl(iconURL);
0105     connect(job, &KIO::FavIconRequestJob::result, this, &FavIconUpdater::slotResult);
0106 
0107     delete m_webGrabber;
0108     m_webGrabber = nullptr;
0109 }
0110 
0111 void FavIconUpdater::slotResult(KJob *job)
0112 {
0113     KIO::FavIconRequestJob *requestJob = static_cast<KIO::FavIconRequestJob *>(job);
0114     if (job->error()) {
0115         if (!webupdate) {
0116             qCDebug(KEDITBOOKMARKS_LOG) << "favicon job failed, going to downloadIconUsingWebBrowser";
0117             // no icon found, try webupdater
0118             downloadIconUsingWebBrowser(m_bk, job->errorString());
0119         } else {
0120             qCDebug(KEDITBOOKMARKS_LOG) << "favicon job failed, emit done";
0121             // already tried webupdater
0122             Q_EMIT done(false, job->errorString());
0123         }
0124         return;
0125     }
0126     m_bk.setIcon(requestJob->iconFile());
0127     Q_EMIT done(true, QString());
0128 }
0129 
0130 /* -------------------------- */
0131 
0132 FavIconWebGrabber::FavIconWebGrabber(KParts::ReadOnlyPart *part, const QUrl &url)
0133     : m_part(part)
0134     , m_url(url)
0135 {
0136     // FIXME only connect to result?
0137     //  connect(part, SIGNAL(result(KIO::Job*job)),
0138     //          this, SLOT(slotCompleted()));
0139     connect(part, &KParts::ReadOnlyPart::canceled, this, &FavIconWebGrabber::slotCanceled);
0140     // clang-format off
0141     connect(part, SIGNAL(completed(bool)), this, SLOT(slotCompleted()));
0142     // clang-format on
0143 
0144     // the use of KIO rather than directly using KHTML is to allow silently abort on error
0145     // TODO: an alternative would be to derive from KHTMLPart and reimplement showError(KJob*).
0146 
0147     // qCDebug(KEDITBOOKMARKS_LOG) << "starting KIO::get() on" << m_url;
0148     KIO::Job *job = KIO::get(m_url, KIO::NoReload, KIO::HideProgressInfo);
0149     job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none"));
0150     job->addMetaData(QStringLiteral("errorPage"), QStringLiteral("false"));
0151     connect(job, &KJob::result, this, &FavIconWebGrabber::slotFinished);
0152     // clang-format off
0153     connect(job, SIGNAL(mimetype(KIO::Job*,QString)), this, SLOT(slotMimetype(KIO::Job*,QString)));
0154     // clang-format on
0155 }
0156 
0157 void FavIconWebGrabber::slotMimetype(KIO::Job *job, const QString &type)
0158 {
0159     Q_ASSERT(!job->error()); // can't be set already, surely?
0160 
0161     KIO::SimpleJob *sjob = static_cast<KIO::SimpleJob *>(job);
0162     m_url = sjob->url(); // allow for redirection
0163     sjob->putOnHold();
0164 
0165     // QString typeLocal = typeUncopied; // local copy
0166     qCDebug(KEDITBOOKMARKS_LOG) << "slotMimetype " << type << "calling openUrl on" << m_url;
0167     // TODO - what to do if typeLocal is not text/html ??
0168 
0169     m_part->openUrl(m_url);
0170 }
0171 
0172 void FavIconWebGrabber::slotFinished(KJob *job)
0173 {
0174     if (job->error()) {
0175         qCDebug(KEDITBOOKMARKS_LOG) << job->errorString();
0176         Q_EMIT done(false, job->errorString());
0177         return;
0178     }
0179     // On success mimetype was emitted, so no need to do anything.
0180 }
0181 
0182 void FavIconWebGrabber::slotCompleted()
0183 {
0184     qCDebug(KEDITBOOKMARKS_LOG);
0185     Q_EMIT done(true, QString());
0186 }
0187 
0188 void FavIconWebGrabber::slotCanceled(const QString &errorString)
0189 {
0190     // qCDebug(KEDITBOOKMARKS_LOG) << errorString;
0191     Q_EMIT done(false, errorString);
0192 }
0193 
0194 #include "moc_faviconupdater.cpp"