File indexing completed on 2024-04-28 15:29:20
0001 /* 0002 This file is part of the KDE project 0003 0004 SPDX-FileCopyrightText: 2002 David Faure <faure@kde.org> 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "browserrun.h" 0009 0010 #include "browseropenorsavequestion.h" 0011 0012 #include "kparts_logging.h" 0013 0014 #include <KConfigGroup> 0015 #include <KIO/CommandLauncherJob> 0016 #include <KIO/FileCopyJob> 0017 #include <KIO/JobUiDelegate> 0018 #include <KIO/OpenUrlJob> 0019 #include <KIO/Scheduler> 0020 #include <KIO/TransferJob> 0021 #include <KJobWidgets> 0022 #include <KLocalizedString> 0023 #include <KMessageBox> 0024 #include <KProtocolManager> 0025 #include <KSharedConfig> 0026 #include <KShell> 0027 0028 #include <QFileDialog> 0029 #include <QMimeDatabase> 0030 #include <QStandardPaths> 0031 #include <QTemporaryFile> 0032 0033 #if KIOWIDGETS_ENABLE_DEPRECATED_SINCE(5, 71) 0034 0035 using namespace KParts; 0036 0037 class KParts::BrowserRunPrivate 0038 { 0039 public: 0040 bool m_bHideErrorDialog; 0041 bool m_bRemoveReferrer; 0042 bool m_bTrustedSource; 0043 KParts::OpenUrlArguments m_args; 0044 KParts::BrowserArguments m_browserArgs; 0045 0046 KParts::ReadOnlyPart *m_part; // QGuardedPtr? 0047 QPointer<QWidget> m_window; 0048 QString m_mimeType; 0049 QString m_contentDisposition; 0050 }; 0051 0052 BrowserRun::BrowserRun(const QUrl &url, 0053 const KParts::OpenUrlArguments &args, 0054 const KParts::BrowserArguments &browserArgs, 0055 KParts::ReadOnlyPart *part, 0056 QWidget *window, 0057 bool removeReferrer, 0058 bool trustedSource, 0059 bool hideErrorDialog) 0060 : KRun(url, window, false /* no GUI */) 0061 , d(new BrowserRunPrivate) 0062 { 0063 d->m_bHideErrorDialog = hideErrorDialog; 0064 d->m_bRemoveReferrer = removeReferrer; 0065 d->m_bTrustedSource = trustedSource; 0066 d->m_args = args; 0067 d->m_browserArgs = browserArgs; 0068 d->m_part = part; 0069 d->m_window = window; 0070 } 0071 0072 BrowserRun::~BrowserRun() = default; 0073 0074 KParts::ReadOnlyPart *BrowserRun::part() const 0075 { 0076 return d->m_part; 0077 } 0078 0079 QUrl BrowserRun::url() const 0080 { 0081 return KRun::url(); 0082 } 0083 0084 void BrowserRun::init() 0085 { 0086 if (d->m_bHideErrorDialog) { 0087 // ### KRun doesn't call a virtual method when it finds out that the URL 0088 // is either malformed, or points to a non-existing local file... 0089 // So we need to reimplement some of the checks, to handle d->m_bHideErrorDialog 0090 if (!KRun::url().isValid()) { 0091 redirectToError(KIO::ERR_MALFORMED_URL, KRun::url().toString()); 0092 return; 0093 } 0094 0095 if (isLocalFile()) { 0096 const QString localPath = KRun::url().toLocalFile(); 0097 if (!QFile::exists(localPath)) { 0098 // qDebug() << localPath << "doesn't exist."; 0099 redirectToError(KIO::ERR_DOES_NOT_EXIST, localPath); 0100 return; 0101 } 0102 } 0103 } 0104 KRun::init(); 0105 } 0106 0107 void BrowserRun::scanFile() 0108 { 0109 const QUrl url = KRun::url(); 0110 // qDebug() << url; 0111 0112 // Let's check for well-known extensions 0113 // Not when there is a query in the URL, in any case. 0114 // Optimization for http/https, findByURL doesn't trust extensions over http. 0115 QString protocol = url.scheme(); 0116 0117 if (!KProtocolInfo::proxiedBy(protocol).isEmpty()) { 0118 QString dummy; 0119 protocol = KProtocolManager::workerProtocol(url, dummy); 0120 } 0121 0122 if (!url.hasQuery() && !protocol.startsWith(QLatin1String("http")) && (!url.path().endsWith(QLatin1Char('/')) || KProtocolManager::supportsListing(url))) { 0123 QMimeDatabase db; 0124 QMimeType mime = db.mimeTypeForUrl(url); 0125 if (!mime.isDefault() || isLocalFile()) { 0126 // qDebug() << "MIME TYPE is" << mime.name(); 0127 mimeTypeDetermined(mime.name()); 0128 return; 0129 } 0130 } 0131 0132 QMap<QString, QString> &metaData = d->m_args.metaData(); 0133 if (d->m_part) { 0134 const QString proto = d->m_part->url().scheme(); 0135 0136 if (proto == QLatin1String("https") || proto == QLatin1String("webdavs")) { 0137 metaData.insert(QStringLiteral("main_frame_request"), QStringLiteral("TRUE")); 0138 metaData.insert(QStringLiteral("ssl_was_in_use"), QStringLiteral("TRUE")); 0139 // metaData.insert(QStringLiteral("ssl_activate_warnings"), QStringLiteral("TRUE")); 0140 } else if (proto == QLatin1String("http") || proto == QLatin1String("webdav")) { 0141 // metaData.insert(QStringLiteral("ssl_activate_warnings"), QStringLiteral("TRUE")); 0142 metaData.insert(QStringLiteral("ssl_was_in_use"), QStringLiteral("FALSE")); 0143 } 0144 0145 // Set the PropagateHttpHeader meta-data if it has not already been set... 0146 if (!metaData.contains(QStringLiteral("PropagateHttpHeader"))) { 0147 metaData.insert(QStringLiteral("PropagateHttpHeader"), QStringLiteral("TRUE")); 0148 } 0149 } 0150 0151 KIO::TransferJob *job; 0152 if (d->m_browserArgs.doPost() && url.scheme().startsWith(QLatin1String("http"))) { 0153 job = KIO::http_post(url, d->m_browserArgs.postData, KIO::HideProgressInfo); 0154 job->addMetaData(QStringLiteral("content-type"), d->m_browserArgs.contentType()); 0155 } else { 0156 job = KIO::get(url, d->m_args.reload() ? KIO::Reload : KIO::NoReload, KIO::HideProgressInfo); 0157 } 0158 0159 if (d->m_bRemoveReferrer) { 0160 metaData.remove(QStringLiteral("referrer")); 0161 } 0162 0163 job->addMetaData(metaData); 0164 KJobWidgets::setWindow(job, d->m_window); 0165 connect(job, &KIO::TransferJob::result, this, &BrowserRun::slotBrowserScanFinished); 0166 connect(job, &KIO::TransferJob::mimeTypeFound, this, &BrowserRun::slotBrowserMimetype); 0167 setJob(job); 0168 } 0169 0170 void BrowserRun::slotBrowserScanFinished(KJob *job) 0171 { 0172 // qDebug() << job->error(); 0173 if (job->error() == KIO::ERR_IS_DIRECTORY) { 0174 // It is in fact a directory. This happens when HTTP redirects to FTP. 0175 // Due to the "protocol doesn't support listing" code in BrowserRun, we 0176 // assumed it was a file. 0177 // qDebug() << "It is in fact a directory!"; 0178 // Update our URL in case of a redirection 0179 KRun::setUrl(static_cast<KIO::TransferJob *>(job)->url()); 0180 setJob(nullptr); 0181 mimeTypeDetermined(QStringLiteral("inode/directory")); 0182 } else { 0183 KRun::slotScanFinished(job); 0184 } 0185 } 0186 0187 static QMimeType fixupMimeType(const QString &mimeType, const QString &fileName) 0188 { 0189 QMimeDatabase db; 0190 QMimeType mime = db.mimeTypeForName(mimeType); 0191 if ((!mime.isValid() || mime.isDefault()) && !fileName.isEmpty()) { 0192 mime = db.mimeTypeForFile(fileName, QMimeDatabase::MatchExtension); 0193 } 0194 return mime; 0195 } 0196 0197 void BrowserRun::slotBrowserMimetype(KIO::Job *_job, const QString &type) 0198 { 0199 Q_ASSERT(_job == KRun::job()); 0200 Q_UNUSED(_job) 0201 KIO::TransferJob *job = static_cast<KIO::TransferJob *>(KRun::job()); 0202 // Update our URL in case of a redirection 0203 // qDebug() << "old URL=" << KRun::url(); 0204 // qDebug() << "new URL=" << job->url(); 0205 setUrl(job->url()); 0206 0207 if (job->isErrorPage()) { 0208 d->m_mimeType = type; 0209 handleError(job); 0210 setJob(nullptr); 0211 } else { 0212 // qDebug() << "found" << type << "for" << KRun::url(); 0213 0214 // Suggested filename given by the server (e.g. HTTP content-disposition) 0215 // When set, we should really be saving instead of embedding 0216 const QString suggestedFileName = job->queryMetaData(QStringLiteral("content-disposition-filename")); 0217 setSuggestedFileName(suggestedFileName); // store it (in KRun) 0218 // qDebug() << "suggestedFileName=" << suggestedFileName; 0219 d->m_contentDisposition = job->queryMetaData(QStringLiteral("content-disposition-type")); 0220 0221 const QString modificationTime = job->queryMetaData(QStringLiteral("content-disposition-modification-date")); 0222 if (!modificationTime.isEmpty()) { 0223 d->m_args.metaData().insert(QStringLiteral("content-disposition-modification-date"), modificationTime); 0224 } 0225 0226 QMapIterator<QString, QString> it(job->metaData()); 0227 while (it.hasNext()) { 0228 it.next(); 0229 if (it.key().startsWith(QLatin1String("ssl_"), Qt::CaseInsensitive)) { 0230 d->m_args.metaData().insert(it.key(), it.value()); 0231 } 0232 } 0233 0234 // Make a copy to avoid a dead reference 0235 QString _type = type; 0236 job->putOnHold(); 0237 setJob(nullptr); 0238 0239 // If the current mime-type is the default mime-type, then attempt to 0240 // determine the "real" mimetype from the file name. 0241 QMimeType mime = fixupMimeType(_type, suggestedFileName.isEmpty() ? url().fileName() : suggestedFileName); 0242 if (mime.isValid() && mime.name() != _type) { 0243 _type = mime.name(); 0244 } 0245 0246 mimeTypeDetermined(_type); 0247 } 0248 } 0249 0250 BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString &mimeType) 0251 { 0252 return handleNonEmbeddable(mimeType, nullptr); 0253 } 0254 0255 BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString &_mimeType, KService::Ptr *selectedService) 0256 { 0257 QString mimeType(_mimeType); 0258 Q_ASSERT(!hasFinished()); // only come here if the mimetype couldn't be embedded 0259 // Support for saving remote files. 0260 if (mimeType != QLatin1String("inode/directory") && // dirs can't be saved 0261 !KRun::url().isLocalFile()) { 0262 if (isTextExecutable(mimeType)) { 0263 mimeType = QStringLiteral("text/plain"); // view, don't execute 0264 } 0265 // ... -> ask whether to save 0266 BrowserOpenOrSaveQuestion question(d->m_window, KRun::url(), mimeType); 0267 question.setSuggestedFileName(suggestedFileName()); 0268 if (selectedService) { 0269 question.setFeatures(BrowserOpenOrSaveQuestion::ServiceSelection); 0270 } 0271 BrowserOpenOrSaveQuestion::Result res = question.askOpenOrSave(); 0272 if (res == BrowserOpenOrSaveQuestion::Save) { 0273 save(KRun::url(), suggestedFileName()); 0274 // qDebug() << "Save: returning Handled"; 0275 setFinished(true); 0276 return Handled; 0277 } else if (res == BrowserOpenOrSaveQuestion::Cancel) { 0278 // saving done or canceled 0279 // qDebug() << "Cancel: returning Handled"; 0280 setFinished(true); 0281 return Handled; 0282 } else { // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled) 0283 // If we were in a POST, we can't just pass a URL to an external application. 0284 // We must save the data to a tempfile first. 0285 if (d->m_browserArgs.doPost()) { 0286 // qDebug() << "request comes from a POST, can't pass a URL to another app, need to save"; 0287 d->m_mimeType = mimeType; 0288 QString extension; 0289 QString fileName = suggestedFileName().isEmpty() ? KRun::url().fileName() : suggestedFileName(); 0290 int extensionPos = fileName.lastIndexOf(QLatin1Char('.')); 0291 if (extensionPos != -1) { 0292 extension = fileName.mid(extensionPos); // keep the '.' 0293 } 0294 QTemporaryFile tempFile(QDir::tempPath() + QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1String("XXXXXX") + extension); 0295 tempFile.setAutoRemove(false); 0296 tempFile.open(); 0297 QUrl destURL = QUrl::fromLocalFile(tempFile.fileName()); 0298 KIO::Job *job = KIO::file_copy(KRun::url(), destURL, 0600, KIO::Overwrite); 0299 KJobWidgets::setWindow(job, d->m_window); 0300 connect(job, &KIO::Job::result, this, &BrowserRun::slotCopyToTempFileResult); 0301 return Delayed; // We'll continue after the job has finished 0302 } 0303 if (selectedService && question.selectedService()) { 0304 *selectedService = question.selectedService(); 0305 // KRun will use this when starting an app 0306 KRun::setPreferredService(question.selectedService()->desktopEntryName()); 0307 } 0308 } 0309 } 0310 0311 // Check if running is allowed 0312 if (!d->m_bTrustedSource && // ... and untrusted source... 0313 !allowExecution(mimeType, KRun::url())) { // ...and the user said no (for executables etc.) 0314 setFinished(true); 0315 return Handled; 0316 } 0317 0318 return NotHandled; 0319 } 0320 0321 // static 0322 bool BrowserRun::allowExecution(const QString &mimeType, const QUrl &url) 0323 { 0324 if (!KRun::isExecutable(mimeType)) { 0325 return true; 0326 } 0327 0328 if (!url.isLocalFile()) { // Don't permit to execute remote files 0329 return false; 0330 } 0331 0332 return (KMessageBox::warningContinueCancel(nullptr, 0333 i18n("Do you really want to execute '%1'?", url.toDisplayString()), 0334 i18n("Execute File?"), 0335 KGuiItem(i18n("Execute"))) 0336 == KMessageBox::Continue); 0337 } 0338 0339 // static, deprecated 0340 #if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) 0341 BrowserRun::AskSaveResult BrowserRun::askSave(const QUrl &url, KService::Ptr offer, const QString &mimeType, const QString &suggestedFileName) 0342 { 0343 Q_UNUSED(offer); 0344 BrowserOpenOrSaveQuestion question(nullptr, url, mimeType); 0345 question.setSuggestedFileName(suggestedFileName); 0346 const BrowserOpenOrSaveQuestion::Result result = question.askOpenOrSave(); 0347 // clang-format off 0348 return result == BrowserOpenOrSaveQuestion::Save ? Save 0349 : (result == BrowserOpenOrSaveQuestion::Open ? Open 0350 : Cancel); 0351 // clang-format on 0352 } 0353 #endif 0354 0355 // static, deprecated 0356 #if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) 0357 BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave(const QUrl &url, const QString &mimeType, const QString &suggestedFileName, int flags) 0358 { 0359 BrowserOpenOrSaveQuestion question(nullptr, url, mimeType); 0360 question.setSuggestedFileName(suggestedFileName); 0361 const BrowserOpenOrSaveQuestion::Result result = question.askEmbedOrSave(flags); 0362 // clang-format off 0363 return result == BrowserOpenOrSaveQuestion::Save ? Save 0364 : result == BrowserOpenOrSaveQuestion::Embed ? Open 0365 : Cancel; 0366 // clang-format on 0367 } 0368 #endif 0369 0370 // Default implementation, overridden in KHTMLRun 0371 void BrowserRun::save(const QUrl &url, const QString &suggestedFileName) 0372 { 0373 saveUrl(url, suggestedFileName, d->m_window, d->m_args); 0374 } 0375 0376 #if KPARTS_BUILD_DEPRECATED_SINCE(4, 4) 0377 // static 0378 void BrowserRun::simpleSave(const QUrl &url, const QString &suggestedFileName, QWidget *window) 0379 { 0380 saveUrl(url, suggestedFileName, window, KParts::OpenUrlArguments()); 0381 } 0382 #endif 0383 0384 void KParts::BrowserRun::saveUrl(const QUrl &url, const QString &suggestedFileName, QWidget *window, const KParts::OpenUrlArguments &args) 0385 { 0386 // DownloadManager <-> konqueror integration 0387 // find if the integration is enabled 0388 // the empty key means no integration 0389 // only use the downloadmanager for non-local urls 0390 if (!url.isLocalFile()) { 0391 KConfigGroup cfg = KSharedConfig::openConfig(QStringLiteral("konquerorrc"), KConfig::NoGlobals)->group("HTML Settings"); 0392 QString downloadManager = cfg.readPathEntry("DownloadManager", QString()); 0393 if (!downloadManager.isEmpty()) { 0394 // then find the download manager location 0395 // qDebug() << "Using: "<<downloadManager <<" as Download Manager"; 0396 if (QStandardPaths::findExecutable(downloadManager).isEmpty()) { 0397 QString errMsg = i18n("The Download Manager (%1) could not be found in your $PATH ", downloadManager); 0398 QString errMsgEx = i18n("Try to reinstall it \n\nThe integration with Konqueror will be disabled."); 0399 KMessageBox::detailedError(nullptr, errMsg, errMsgEx); 0400 cfg.writePathEntry("DownloadManager", QString()); 0401 cfg.sync(); 0402 } else { 0403 QStringList args; 0404 args << url.toString(); 0405 if (!suggestedFileName.isEmpty()) { 0406 args << suggestedFileName; 0407 } 0408 0409 // qDebug() << "Calling command" << downloadManager << args; 0410 0411 auto *job = new KIO::CommandLauncherJob(downloadManager, args); 0412 job->setExecutable(downloadManager); 0413 job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, window)); 0414 job->start(); 0415 return; 0416 } 0417 } 0418 } 0419 0420 // no download manager available, let's do it ourself 0421 QFileDialog *dlg = new QFileDialog(window); 0422 dlg->setAcceptMode(QFileDialog::AcceptSave); 0423 dlg->setWindowTitle(i18n("Save As")); 0424 dlg->setOption(QFileDialog::DontConfirmOverwrite, false); 0425 dlg->setAttribute(Qt::WA_DeleteOnClose); 0426 0427 QString name; 0428 if (!suggestedFileName.isEmpty()) { 0429 name = suggestedFileName; 0430 } else { 0431 name = url.fileName(); // can be empty, e.g. in case http://www.kde.org/ 0432 } 0433 0434 dlg->selectFile(name); 0435 connect(dlg, &QDialog::accepted, dlg, [dlg, url, window, args]() { 0436 const QUrl destURL = dlg->selectedUrls().value(0); 0437 if (destURL.isValid()) { 0438 saveUrlUsingKIO(url, destURL, window, args.metaData()); 0439 } 0440 }); 0441 0442 dlg->show(); 0443 } 0444 0445 void BrowserRun::saveUrlUsingKIO(const QUrl &srcUrl, const QUrl &destUrl, QWidget *window, const QMap<QString, QString> &metaData) 0446 { 0447 KIO::FileCopyJob *job = KIO::file_copy(srcUrl, destUrl, -1, KIO::Overwrite); 0448 0449 const QString modificationTime = metaData[QStringLiteral("content-disposition-modification-date")]; 0450 if (!modificationTime.isEmpty()) { 0451 job->setModificationTime(QDateTime::fromString(modificationTime, Qt::RFC2822Date)); 0452 } 0453 job->setMetaData(metaData); 0454 job->addMetaData(QStringLiteral("MaxCacheSize"), QStringLiteral("0")); // Don't store in http cache. 0455 job->addMetaData(QStringLiteral("cache"), QStringLiteral("cache")); // Use entry from cache if available. 0456 KJobWidgets::setWindow(job, window); 0457 job->uiDelegate()->setAutoErrorHandlingEnabled(true); 0458 } 0459 0460 void BrowserRun::handleError(KJob *job) 0461 { 0462 if (!job) { // Shouldn't happen 0463 qCWarning(KPARTSLOG) << "handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog; 0464 return; 0465 } 0466 0467 KIO::TransferJob *tjob = qobject_cast<KIO::TransferJob *>(job); 0468 if (tjob && tjob->isErrorPage() && !job->error()) { 0469 // The default handling of error pages is to show them like normal pages 0470 // But this is done here in handleError so that KHTMLRun can reimplement it 0471 tjob->putOnHold(); 0472 setJob(nullptr); 0473 if (!d->m_mimeType.isEmpty()) { 0474 mimeTypeDetermined(d->m_mimeType); 0475 } 0476 return; 0477 } 0478 0479 if (d->m_bHideErrorDialog && job->error() != KIO::ERR_NO_CONTENT) { 0480 redirectToError(job->error(), job->errorText()); 0481 return; 0482 } 0483 0484 // Reuse code in KRun, to benefit from d->m_showingError etc. 0485 KRun::handleError(job); 0486 } 0487 0488 // static 0489 QUrl BrowserRun::makeErrorUrl(int error, const QString &errorText, const QUrl &initialUrl) 0490 { 0491 /* 0492 * The format of the error:/ URL is error:/?query#url, 0493 * where two variables are passed in the query: 0494 * error = int kio error code, errText = QString error text from kio 0495 * The sub-url is the URL that we were trying to open. 0496 */ 0497 QUrl newURL(QStringLiteral("error:/?error=%1&errText=%2").arg(error).arg(QString::fromUtf8(QUrl::toPercentEncoding(errorText)))); 0498 0499 QString cleanedOrigUrl = initialUrl.toString(); 0500 QUrl runURL(cleanedOrigUrl); 0501 if (runURL.isValid()) { 0502 runURL.setPassword(QString()); // don't put the password in the error URL 0503 cleanedOrigUrl = runURL.toString(); 0504 } 0505 0506 newURL.setFragment(cleanedOrigUrl); 0507 return newURL; 0508 } 0509 0510 void BrowserRun::redirectToError(int error, const QString &errorText) 0511 { 0512 /** 0513 * To display this error in KHTMLPart instead of inside a dialog box, 0514 * we tell konq that the mimetype is text/html, and we redirect to 0515 * an error:/ URL that sends the info to khtml. 0516 */ 0517 KRun::setUrl(makeErrorUrl(error, errorText, url())); 0518 setJob(nullptr); 0519 mimeTypeDetermined(QStringLiteral("text/html")); 0520 } 0521 0522 void BrowserRun::slotCopyToTempFileResult(KJob *job) 0523 { 0524 if (job->error()) { 0525 job->uiDelegate()->showErrorMessage(); 0526 } else { 0527 // Same as KRun::foundMimeType but with a different URL 0528 const QUrl destUrl = static_cast<KIO::FileCopyJob *>(job)->destUrl(); 0529 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(destUrl, d->m_mimeType); 0530 job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, d->m_window)); 0531 job->setRunExecutables(true); 0532 job->start(); 0533 } 0534 setError(true); // see above 0535 setFinished(true); 0536 } 0537 0538 bool BrowserRun::isTextExecutable(const QString &mimeType) 0539 { 0540 return (mimeType == QLatin1String("application/x-desktop") || mimeType == QLatin1String("application/x-shellscript")); 0541 } 0542 0543 bool BrowserRun::hideErrorDialog() const 0544 { 0545 return d->m_bHideErrorDialog; 0546 } 0547 0548 QString BrowserRun::contentDisposition() const 0549 { 0550 return d->m_contentDisposition; 0551 } 0552 0553 bool BrowserRun::serverSuggestsSave() const 0554 { 0555 // RfC 2183, section 2.8: 0556 // Unrecognized disposition types should be treated as `attachment'. 0557 return !contentDisposition().isEmpty() && (contentDisposition() != QLatin1String("inline")); 0558 } 0559 0560 KParts::OpenUrlArguments &KParts::BrowserRun::arguments() 0561 { 0562 return d->m_args; 0563 } 0564 0565 KParts::BrowserArguments &KParts::BrowserRun::browserArguments() 0566 { 0567 return d->m_browserArgs; 0568 } 0569 0570 #include "moc_browserrun.cpp" 0571 0572 #endif