diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 475edf2..efeea09 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,152 +1,152 @@ set(KParts_LIB_SRCS partbase.cpp part.cpp openurlarguments.cpp readonlypart.cpp readwritepart.cpp plugin.cpp partmanager.cpp mainwindow.cpp event.cpp guiactivateevent.cpp partactivateevent.cpp partselectevent.cpp browserextension.cpp browserhostextension.cpp browserarguments.cpp liveconnectextension.cpp openurlevent.cpp windowargs.cpp historyprovider.cpp browserinterface.cpp browserrun.cpp browseropenorsavequestion.cpp statusbarextension.cpp scriptableextension.cpp textextension.cpp htmlextension.cpp htmlsettingsinterface.cpp selectorinterface.cpp fileinfoextension.cpp listingfilterextension.cpp listingnotificationextension.cpp ) include(ECMGenerateHeaders) ecm_generate_headers(KParts_CamelCase_HEADERS HEADER_NAMES BrowserArguments BrowserExtension BrowserHostExtension BrowserInterface BrowserOpenOrSaveQuestion BrowserRun Event FileInfoExtension GUIActivateEvent HistoryProvider HtmlExtension HtmlSettingsInterface ListingFilterExtension ListingNotificationExtension LiveConnectExtension MainWindow OpenUrlArguments OpenUrlEvent Part PartActivateEvent PartBase PartManager PartSelectEvent Plugin ReadOnlyPart ReadWritePart ScriptableExtension SelectorInterface StatusBarExtension TextExtension WindowArgs REQUIRED_HEADERS KParts_HEADERS PREFIX KParts ) install(FILES ${KParts_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KParts/KParts COMPONENT Devel) add_library(KF5Parts ${KParts_LIB_SRCS}) add_library(KF5::Parts ALIAS KF5Parts) ecm_generate_export_header(KF5Parts EXPORT_FILE_NAME ${KParts_BINARY_DIR}/kparts/kparts_export.h BASE_NAME KParts GROUP_BASE_NAME KF VERSION ${KF5_VERSION} DEPRECATED_BASE_VERSION 0 - DEPRECATION_VERSIONS 3.0 5.0 + DEPRECATION_VERSIONS 3.0 4.4 5.0 EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} ) set(KParts_BUILD_INCLUDE_DIRS ${KParts_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(KF5Parts PUBLIC "$") target_include_directories(KF5Parts INTERFACE "$" ) target_link_libraries(KF5Parts PUBLIC KF5::KIOWidgets #browserrun.h uses krun.h KF5::XmlGui # essential to the technology KF5::TextWidgets # needed for KFind, as interface PRIVATE KF5::I18n #few uses of i18n and i18nc, can be probably stripped down KF5::IconThemes #only used by KPart::iconLoader() ) set_target_properties(KF5Parts PROPERTIES VERSION ${KPARTS_VERSION_STRING} SOVERSION ${KPARTS_SOVERSION} EXPORT_NAME Parts ) install(TARGETS KF5Parts EXPORT KF5PartsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES kpart.desktop krop.desktop krwp.desktop browserview.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR} ) install(FILES ${KParts_BINARY_DIR}/kparts/kparts_export.h ${KParts_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KParts/kparts COMPONENT Devel ) install(FILES kde_terminal_interface.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KParts ) if(BUILD_QCH) ecm_add_qch( KF5Parts_QCH NAME KParts BASE_NAME KF5Parts VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KParts_HEADERS} kde_terminal_interface.h MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS KF5KIO_QCH KF5XmlGui_QCH KF5TextWidgets_QCH INCLUDE_DIRS ${KParts_BUILD_INCLUDE_DIRS} BLANK_MACROS KPARTS_EXPORT KPARTS_DEPRECATED KPARTS_DEPRECATED_EXPORT "KPARTS_DEPRECATED_VERSION(x, y, t)" TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KParts LIB_NAME KF5Parts DEPS "KIOWidgets KXmlGui KTextWidgets" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KParts) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/browserrun.cpp b/src/browserrun.cpp index 650a184..332b8fa 100644 --- a/src/browserrun.cpp +++ b/src/browserrun.cpp @@ -1,579 +1,581 @@ /* This file is part of the KDE project * * Copyright (C) 2002 David Faure * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "browserrun.h" #include "browserrun_p.h" #include "browseropenorsavequestion.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KParts; class Q_DECL_HIDDEN BrowserRun::BrowserRunPrivate { public: bool m_bHideErrorDialog; bool m_bRemoveReferrer; bool m_bTrustedSource; KParts::OpenUrlArguments m_args; KParts::BrowserArguments m_browserArgs; KParts::ReadOnlyPart *m_part; // QGuardedPtr? QPointer m_window; QString m_mimeType; QString m_contentDisposition; }; BrowserRun::BrowserRun(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, KParts::ReadOnlyPart *part, QWidget *window, bool removeReferrer, bool trustedSource, bool hideErrorDialog) : KRun(url, window, false /* no GUI */), d(new BrowserRunPrivate) { d->m_bHideErrorDialog = hideErrorDialog; d->m_bRemoveReferrer = removeReferrer; d->m_bTrustedSource = trustedSource; d->m_args = args; d->m_browserArgs = browserArgs; d->m_part = part; d->m_window = window; } BrowserRun::~BrowserRun() { delete d; } KParts::ReadOnlyPart *BrowserRun::part() const { return d->m_part; } QUrl BrowserRun::url() const { return KRun::url(); } void BrowserRun::init() { if (d->m_bHideErrorDialog) { // ### KRun doesn't call a virtual method when it finds out that the URL // is either malformed, or points to a non-existing local file... // So we need to reimplement some of the checks, to handle d->m_bHideErrorDialog if (!KRun::url().isValid()) { redirectToError(KIO::ERR_MALFORMED_URL, KRun::url().toString()); return; } if (isLocalFile()) { const QString localPath = KRun::url().toLocalFile(); if (!QFile::exists(localPath)) { // qDebug() << localPath << "doesn't exist."; redirectToError(KIO::ERR_DOES_NOT_EXIST, localPath); return; } } } KRun::init(); } void BrowserRun::scanFile() { const QUrl url = KRun::url(); // qDebug() << url; // Let's check for well-known extensions // Not when there is a query in the URL, in any case. // Optimization for http/https, findByURL doesn't trust extensions over http. QString protocol = url.scheme(); if (!KProtocolInfo::proxiedBy(protocol).isEmpty()) { QString dummy; protocol = KProtocolManager::slaveProtocol(url, dummy); } if (!url.hasQuery() && !protocol.startsWith(QLatin1String("http")) && (!url.path().endsWith(QLatin1Char('/')) || KProtocolManager::supportsListing(url))) { QMimeDatabase db; QMimeType mime = db.mimeTypeForUrl(url); if (!mime.isDefault() || isLocalFile()) { // qDebug() << "MIME TYPE is" << mime.name(); mimeTypeDetermined(mime.name()); return; } } QMap &metaData = d->m_args.metaData(); if (d->m_part) { const QString proto = d->m_part->url().scheme(); if (proto == QLatin1String("https") || proto == QLatin1String("webdavs")) { metaData.insert(QStringLiteral("main_frame_request"), QStringLiteral("TRUE")); metaData.insert(QStringLiteral("ssl_was_in_use"), QStringLiteral("TRUE")); // metaData.insert(QStringLiteral("ssl_activate_warnings"), QStringLiteral("TRUE")); } else if (proto == QLatin1String("http") || proto == QLatin1String("webdav")) { // metaData.insert(QStringLiteral("ssl_activate_warnings"), QStringLiteral("TRUE")); metaData.insert(QStringLiteral("ssl_was_in_use"), QStringLiteral("FALSE")); } // Set the PropagateHttpHeader meta-data if it has not already been set... if (!metaData.contains(QStringLiteral("PropagateHttpHeader"))) { metaData.insert(QStringLiteral("PropagateHttpHeader"), QStringLiteral("TRUE")); } } KIO::TransferJob *job; if (d->m_browserArgs.doPost() && url.scheme().startsWith(QLatin1String("http"))) { job = KIO::http_post(url, d->m_browserArgs.postData, KIO::HideProgressInfo); job->addMetaData(QStringLiteral("content-type"), d->m_browserArgs.contentType()); } else { job = KIO::get(url, d->m_args.reload() ? KIO::Reload : KIO::NoReload, KIO::HideProgressInfo); } if (d->m_bRemoveReferrer) { metaData.remove(QStringLiteral("referrer")); } job->addMetaData(metaData); KJobWidgets::setWindow(job, d->m_window); connect(job, &KIO::TransferJob::result, this, &BrowserRun::slotBrowserScanFinished); connect(job, static_cast(&KIO::TransferJob::mimetype), this, &BrowserRun::slotBrowserMimetype); setJob(job); } void BrowserRun::slotBrowserScanFinished(KJob *job) { // qDebug() << job->error(); if (job->error() == KIO::ERR_IS_DIRECTORY) { // It is in fact a directory. This happens when HTTP redirects to FTP. // Due to the "protocol doesn't support listing" code in BrowserRun, we // assumed it was a file. // qDebug() << "It is in fact a directory!"; // Update our URL in case of a redirection KRun::setUrl(static_cast(job)->url()); setJob(nullptr); mimeTypeDetermined(QStringLiteral("inode/directory")); } else { KRun::slotScanFinished(job); } } static QMimeType fixupMimeType(const QString &mimeType, const QString &fileName) { QMimeDatabase db; QMimeType mime = db.mimeTypeForName(mimeType); if ((!mime.isValid() || mime.isDefault()) && !fileName.isEmpty()) { mime = db.mimeTypeForFile(fileName, QMimeDatabase::MatchExtension); } return mime; } void BrowserRun::slotBrowserMimetype(KIO::Job *_job, const QString &type) { Q_ASSERT(_job == KRun::job()); Q_UNUSED(_job) KIO::TransferJob *job = static_cast(KRun::job()); // Update our URL in case of a redirection //qDebug() << "old URL=" << KRun::url(); //qDebug() << "new URL=" << job->url(); setUrl(job->url()); if (job->isErrorPage()) { d->m_mimeType = type; handleError(job); setJob(nullptr); } else { // qDebug() << "found" << type << "for" << KRun::url(); // Suggested filename given by the server (e.g. HTTP content-disposition) // When set, we should really be saving instead of embedding const QString suggestedFileName = job->queryMetaData(QStringLiteral("content-disposition-filename")); setSuggestedFileName(suggestedFileName); // store it (in KRun) //qDebug() << "suggestedFileName=" << suggestedFileName; d->m_contentDisposition = job->queryMetaData(QStringLiteral("content-disposition-type")); const QString modificationTime = job->queryMetaData(QStringLiteral("content-disposition-modification-date")); if (!modificationTime.isEmpty()) { d->m_args.metaData().insert(QStringLiteral("content-disposition-modification-date"), modificationTime); } QMapIterator it(job->metaData()); while (it.hasNext()) { it.next(); if (it.key().startsWith(QLatin1String("ssl_"), Qt::CaseInsensitive)) { d->m_args.metaData().insert(it.key(), it.value()); } } // Make a copy to avoid a dead reference QString _type = type; job->putOnHold(); setJob(nullptr); // If the current mime-type is the default mime-type, then attempt to // determine the "real" mimetype from the file name. QMimeType mime = fixupMimeType(_type, suggestedFileName.isEmpty() ? url().fileName() : suggestedFileName); if (mime.isValid() && mime.name() != _type) { _type = mime.name(); } mimeTypeDetermined(_type); } } BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString &mimeType) { return handleNonEmbeddable(mimeType, nullptr); } BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString &_mimeType, KService::Ptr *selectedService) { QString mimeType(_mimeType); Q_ASSERT(!hasFinished()); // only come here if the mimetype couldn't be embedded // Support for saving remote files. if (mimeType != QLatin1String("inode/directory") && // dirs can't be saved !KRun::url().isLocalFile()) { if (isTextExecutable(mimeType)) { mimeType = QStringLiteral("text/plain"); // view, don't execute } // ... -> ask whether to save BrowserOpenOrSaveQuestion question(d->m_window, KRun::url(), mimeType); question.setSuggestedFileName(suggestedFileName()); if (selectedService) { question.setFeatures(BrowserOpenOrSaveQuestion::ServiceSelection); } BrowserOpenOrSaveQuestion::Result res = question.askOpenOrSave(); if (res == BrowserOpenOrSaveQuestion::Save) { save(KRun::url(), suggestedFileName()); // qDebug() << "Save: returning Handled"; setFinished(true); return Handled; } else if (res == BrowserOpenOrSaveQuestion::Cancel) { // saving done or canceled // qDebug() << "Cancel: returning Handled"; setFinished(true); return Handled; } else { // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled) // If we were in a POST, we can't just pass a URL to an external application. // We must save the data to a tempfile first. if (d->m_browserArgs.doPost()) { // qDebug() << "request comes from a POST, can't pass a URL to another app, need to save"; d->m_mimeType = mimeType; QString extension; QString fileName = suggestedFileName().isEmpty() ? KRun::url().fileName() : suggestedFileName(); int extensionPos = fileName.lastIndexOf(QLatin1Char('.')); if (extensionPos != -1) { extension = fileName.mid(extensionPos); // keep the '.' } QTemporaryFile tempFile(QDir::tempPath() + QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1String("XXXXXX") + extension); tempFile.setAutoRemove(false); tempFile.open(); QUrl destURL = QUrl::fromLocalFile(tempFile.fileName()); KIO::Job *job = KIO::file_copy(KRun::url(), destURL, 0600, KIO::Overwrite); KJobWidgets::setWindow(job, d->m_window); connect(job, &KIO::Job::result, this, &BrowserRun::slotCopyToTempFileResult); return Delayed; // We'll continue after the job has finished } if (selectedService && question.selectedService()) { *selectedService = question.selectedService(); // KRun will use this when starting an app KRun::setPreferredService(question.selectedService()->desktopEntryName()); } } } // Check if running is allowed if (!d->m_bTrustedSource && // ... and untrusted source... !allowExecution(mimeType, KRun::url())) { // ...and the user said no (for executables etc.) setFinished(true); return Handled; } KIO::Scheduler::publishSlaveOnHold(); // publish any slave on hold so it can be reused. return NotHandled; } //static bool BrowserRun::allowExecution(const QString &mimeType, const QUrl &url) { if (!KRun::isExecutable(mimeType)) { return true; } if (!url.isLocalFile()) { // Don't permit to execute remote files return false; } return (KMessageBox::warningContinueCancel(nullptr, i18n("Do you really want to execute '%1'?", url.toDisplayString()), i18n("Execute File?"), KGuiItem(i18n("Execute"))) == KMessageBox::Continue); } //static, deprecated #if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) BrowserRun::AskSaveResult BrowserRun::askSave(const QUrl &url, KService::Ptr offer, const QString &mimeType, const QString &suggestedFileName) { Q_UNUSED(offer); BrowserOpenOrSaveQuestion question(nullptr, url, mimeType); question.setSuggestedFileName(suggestedFileName); const BrowserOpenOrSaveQuestion::Result result = question.askOpenOrSave(); return result == BrowserOpenOrSaveQuestion::Save ? Save : BrowserOpenOrSaveQuestion::Open ? Open : Cancel; } #endif //static, deprecated #if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave(const QUrl &url, const QString &mimeType, const QString &suggestedFileName, int flags) { BrowserOpenOrSaveQuestion question(nullptr, url, mimeType); question.setSuggestedFileName(suggestedFileName); const BrowserOpenOrSaveQuestion::Result result = question.askEmbedOrSave(flags); return result == BrowserOpenOrSaveQuestion::Save ? Save : result == BrowserOpenOrSaveQuestion::Embed ? Open : Cancel; } #endif // Default implementation, overridden in KHTMLRun void BrowserRun::save(const QUrl &url, const QString &suggestedFileName) { saveUrl(url, suggestedFileName, d->m_window, d->m_args); } +#if KPARTS_BUILD_DEPRECATED_SINCE(4, 4) // static void BrowserRun::simpleSave(const QUrl &url, const QString &suggestedFileName, QWidget *window) { saveUrl(url, suggestedFileName, window, KParts::OpenUrlArguments()); } +#endif void KParts::BrowserRun::saveUrl(const QUrl &url, const QString &suggestedFileName, QWidget *window, const KParts::OpenUrlArguments &args) { // DownloadManager <-> konqueror integration // find if the integration is enabled // the empty key means no integration // only use the downloadmanager for non-local urls if (!url.isLocalFile()) { KConfigGroup cfg = KSharedConfig::openConfig(QStringLiteral("konquerorrc"), KConfig::NoGlobals)->group("HTML Settings"); QString downloadManger = cfg.readPathEntry("DownloadManager", QString()); if (!downloadManger.isEmpty()) { // then find the download manager location // qDebug() << "Using: "<setAcceptMode(QFileDialog::AcceptSave); dlg->setWindowTitle(i18n("Save As")); dlg->setOption(QFileDialog::DontConfirmOverwrite, false); QString name; if (!suggestedFileName.isEmpty()) { name = suggestedFileName; } else { name = url.fileName(); // can be empty, e.g. in case http://www.kde.org/ } dlg->selectFile(name); if (dlg->exec()) { QUrl destURL(dlg->selectedUrls().at(0)); if (destURL.isValid()) { saveUrlUsingKIO(url, destURL, window, args.metaData()); } } delete dlg; } void BrowserRun::saveUrlUsingKIO(const QUrl &srcUrl, const QUrl &destUrl, QWidget *window, const QMap &metaData) { KIO::FileCopyJob *job = KIO::file_copy(srcUrl, destUrl, -1, KIO::Overwrite); const QString modificationTime = metaData[QStringLiteral("content-disposition-modification-date")]; if (!modificationTime.isEmpty()) { job->setModificationTime(QDateTime::fromString(modificationTime, Qt::RFC2822Date)); } job->setMetaData(metaData); job->addMetaData(QStringLiteral("MaxCacheSize"), QStringLiteral("0")); // Don't store in http cache. job->addMetaData(QStringLiteral("cache"), QStringLiteral("cache")); // Use entry from cache if available. KJobWidgets::setWindow(job, window); job->uiDelegate()->setAutoErrorHandlingEnabled(true); new DownloadJobWatcher(job, metaData); } void BrowserRun::handleError(KJob *job) { if (!job) { // Shouldn't happen qWarning() << "handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog; return; } KIO::TransferJob *tjob = qobject_cast(job); if (tjob && tjob->isErrorPage() && !job->error()) { // The default handling of error pages is to show them like normal pages // But this is done here in handleError so that KHTMLRun can reimplement it tjob->putOnHold(); setJob(nullptr); if (!d->m_mimeType.isEmpty()) { mimeTypeDetermined(d->m_mimeType); } return; } if (d->m_bHideErrorDialog && job->error() != KIO::ERR_NO_CONTENT) { redirectToError(job->error(), job->errorText()); return; } // Reuse code in KRun, to benefit from d->m_showingError etc. KRun::handleError(job); } // static QUrl BrowserRun::makeErrorUrl(int error, const QString &errorText, const QUrl &initialUrl) { /* * The format of the error:/ URL is error:/?query#url, * where two variables are passed in the query: * error = int kio error code, errText = QString error text from kio * The sub-url is the URL that we were trying to open. */ QUrl newURL(QStringLiteral("error:/?error=%1&errText=%2") .arg(error) .arg(QString::fromUtf8(QUrl::toPercentEncoding(errorText)))); QString cleanedOrigUrl = initialUrl.toString(); QUrl runURL(cleanedOrigUrl); if (runURL.isValid()) { runURL.setPassword(QString()); // don't put the password in the error URL cleanedOrigUrl = runURL.toString(); } newURL.setFragment(cleanedOrigUrl); return newURL; } void BrowserRun::redirectToError(int error, const QString &errorText) { /** * To display this error in KHTMLPart instead of inside a dialog box, * we tell konq that the mimetype is text/html, and we redirect to * an error:/ URL that sends the info to khtml. */ KRun::setUrl(makeErrorUrl(error, errorText, url())); setJob(nullptr); mimeTypeDetermined(QStringLiteral("text/html")); } void BrowserRun::slotCopyToTempFileResult(KJob *job) { if (job->error()) { job->uiDelegate()->showErrorMessage(); } else { // Same as KRun::foundMimeType but with a different URL (void)(KRun::runUrl(static_cast(job)->destUrl(), d->m_mimeType, d->m_window, KRun::RunFlags(KRun::RunExecutables))); } setError(true); // see above setFinished(true); } bool BrowserRun::isTextExecutable(const QString &mimeType) { return (mimeType == QLatin1String("application/x-desktop") || mimeType == QLatin1String("application/x-shellscript")); } bool BrowserRun::hideErrorDialog() const { return d->m_bHideErrorDialog; } QString BrowserRun::contentDisposition() const { return d->m_contentDisposition; } bool BrowserRun::serverSuggestsSave() const { // RfC 2183, section 2.8: // Unrecognized disposition types should be treated as `attachment'. return !contentDisposition().isEmpty() && (contentDisposition() != QLatin1String("inline")); } KParts::OpenUrlArguments &KParts::BrowserRun::arguments() { return d->m_args; } KParts::BrowserArguments &KParts::BrowserRun::browserArguments() { return d->m_browserArgs; } #include "moc_browserrun.cpp" #include "moc_browserrun_p.cpp" diff --git a/src/browserrun.h b/src/browserrun.h index 4784b03..fa31555 100644 --- a/src/browserrun.h +++ b/src/browserrun.h @@ -1,221 +1,228 @@ /* This file is part of the KDE project * * Copyright (C) 2002 David Faure * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef kparts_browserrun_h #define kparts_browserrun_h #include #include #include namespace KParts { /** * This class extends KRun to provide additional functionality for browsers: * - "save or open" dialog boxes * - "save" functionality * - support for HTTP POST (including saving the result to a temp file if * opening a separate application) * - warning before launching executables off the web * - custom error handling (i.e. treating errors as HTML pages) * - generation of SSL metadata depending on the previous URL shown by the part * @author David Faure */ class KPARTS_EXPORT BrowserRun : public KRun { Q_OBJECT public: /** * @param url the URL we're probing * @param args URL args - includes reload, metaData, etc. * @param browserArgs browser-related args - includes data for a HTTP POST, etc. * @param part the part going to open this URL - can be @c nullptr if not created yet * @param window the mainwindow - passed to KIO::Job::setWindow() * @param removeReferrer if true, the "referrer" metadata from @p args isn't passed on * @param trustedSource if false, a warning will be shown before launching an executable. Always pass false for @p trustedSource, except for local directory views. * @param hideErrorDialog if true, no dialog will be shown in case of errors. */ BrowserRun(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, KParts::ReadOnlyPart *part, QWidget *window, bool removeReferrer, bool trustedSource, bool hideErrorDialog = false); virtual ~BrowserRun(); KParts::OpenUrlArguments &arguments(); KParts::BrowserArguments &browserArguments(); KParts::ReadOnlyPart *part() const; QUrl url() const; bool hideErrorDialog() const; /** * @return Suggested disposition by the server (e.g. HTTP content-disposition) */ QString contentDisposition() const; /** * @return Whether the returned disposition suggests saving or opening inline */ bool serverSuggestsSave() const; #if KPARTS_ENABLE_DEPRECATED_SINCE(5, 0) enum AskSaveResult { Save, Open, Cancel }; /** * Ask the user whether to save or open a url in another application. * @param url the URL in question * @param offer the application that will be used to open the URL * @param mimeType the mimetype of the URL * @param suggestedFileName optional file name suggested by the server * @return Save, Open or Cancel. * @deprecated Since 5.0, use BrowserOpenOrSaveQuestion * @code * BrowserOpenOrSaveQuestion dlg(parent, url, mimeType, suggestedFileName); * const BrowserOpenOrSaveQuestion::Result res = dlg.askOpenOrSave(); * @endcode */ KPARTS_DEPRECATED_VERSION(5, 0, "Use KParts::BrowserOpenOrSaveQuestion") static AskSaveResult askSave(const QUrl &url, KService::Ptr offer, const QString &mimeType, const QString &suggestedFileName = QString()); #endif #if KPARTS_ENABLE_DEPRECATED_SINCE(5, 64) /** @deprecated Since 5.64, use BrowserOpenOrSaveQuestion::AskEmbedOrSaveFlags */ enum AskEmbedOrSaveFlags { InlineDisposition = 0, AttachmentDisposition = 1 }; #endif #if KPARTS_ENABLE_DEPRECATED_SINCE(5, 0) /** * Similar to askSave but for the case where the current application is * able to embed the url itself (instead of passing it to another app). * @param url the URL in question * @param mimeType the mimetype of the URL * @param suggestedFileName optional filename suggested by the server * @param flags set to AttachmentDisposition if suggested by the server * @return Save, Open or Cancel. * @deprecated Since 5.0, use BrowserOpenOrSaveQuestion * @code * BrowserOpenOrSaveQuestion dlg(parent, url, mimeType, suggestedFileName); * const BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave(flags); * // Important: returns Embed now, not Open! * @endcode */ KPARTS_DEPRECATED_VERSION(5, 0, "Use KParts::BrowserOpenOrSaveQuestion") static AskSaveResult askEmbedOrSave(const QUrl &url, const QString &mimeType, const QString &suggestedFileName = QString(), int flags = 0); #endif // virtual so that KHTML can implement differently (HTML cache) virtual void save(const QUrl &url, const QString &suggestedFileName); - // static so that it can be called from other classes +#if KPARTS_ENABLE_DEPRECATED_SINCE(4, 4) + /** + * static so that it can be called from other classes + * @deprecated Since 4.4, use saveUrl(const QUrl &, const QString &, QWidget *, const KParts::OpenUrlArguments &) + */ + KPARTS_DEPRECATED_VERSION(4, 4, "Use BrowserRun::saveUrl(const QUrl &, const QString &, QWidget *, const KParts::OpenUrlArguments &)") static void simpleSave(const QUrl &url, const QString &suggestedFileName, - QWidget *window = nullptr); // KDE5: remove + QWidget *window = nullptr); +#endif + /** * If kget integration is enabled, passes the url to kget. * Otherwise, asks the user for a destination url, and calls saveUrlUsingKIO. * @since 4.4 */ static void saveUrl(const QUrl &url, const QString &suggestedFileName, QWidget *window, const KParts::OpenUrlArguments &args); /** * Starts the KIO file copy job to download @p srcUrl into @p destUrl. * @since 4.4 */ static void saveUrlUsingKIO(const QUrl &srcUrl, const QUrl &destUrl, QWidget *window, const QMap &metaData); static bool allowExecution(const QString &mimeType, const QUrl &url); static bool isTextExecutable(const QString &mimeType); /** * KDE webbrowsing kparts support error urls to display errors in-line in the browser component. * This helper method creates the error URL from its parameters. * @param error the KIO error code (or KIO::ERR_SLAVE_DEFINED if not from KIO) * @param errorText the text of the error message * @param initialUrl the URL that we were trying to open (as a string, so that this can * support invalid URLs as well) (changed from QString to QUrl in KF5) * @since 4.6 */ static QUrl makeErrorUrl(int error, const QString &errorText, const QUrl &initialUrl); protected: /** * Reimplemented from KRun */ void scanFile() override; /** * Reimplemented from KRun */ void init() override; /** * Reimplemented from KRun */ void handleError(KJob *job) override; /** * NotHandled means that foundMimeType should call KRun::foundMimeType, * i.e. launch an external app. */ enum NonEmbeddableResult { Handled, NotHandled, Delayed }; /** * Helper for foundMimeType: call this if the mimetype couldn't be embedded */ NonEmbeddableResult handleNonEmbeddable(const QString &mimeType); // TODO KDE5: remove, and add =0 to the other overload /** * Helper for foundMimeType: call this if the mimetype couldn't be embedded * @param mimeType the mimetype found for the URL * @param pSelectedService Output variable: pointer to a KService::Ptr, which will be set * to the service selected in the BrowserOpenOrSaveQuestion dialog, if any. * * How to handle this properly: if pSelectedService is non-zero, then the dialog will show * additional "open with" buttons. In your code, you should write: * @code if (selectedService) { KRun::setPreferredService(selectedService->desktopEntryName()); // not necessary since 4.9.3 KRun::foundMimeType(mimeType); } else { // the user requested an open-with dialog KRun::displayOpenWithDialog(url(), m_window, false, suggestedFileName()); setFinished(true); } * @endcode * * @since 4.5 */ NonEmbeddableResult handleNonEmbeddable(const QString &mimeType, KService::Ptr *pSelectedService); protected Q_SLOTS: void slotBrowserScanFinished(KJob *job); void slotBrowserMimetype(KIO::Job *job, const QString &type); void slotCopyToTempFileResult(KJob *job); private: void redirectToError(int error, const QString &errorText); class BrowserRunPrivate; BrowserRunPrivate *const d; }; } #endif