00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "browserrun.h"
00020 #include <kmessagebox.h>
00021 #include <kfiledialog.h>
00022 #include <kio/job.h>
00023 #include <kio/jobuidelegate.h>
00024 #include <kio/scheduler.h>
00025 #include <kio/copyjob.h>
00026 #include <klocale.h>
00027 #include <kshell.h>
00028 #include <kstringhandler.h>
00029 #include <kmimetypetrader.h>
00030 #include <ktemporaryfile.h>
00031 #include <kdebug.h>
00032 #include <kde_file.h>
00033 #include <kstandarddirs.h>
00034 #include <assert.h>
00035
00036 using namespace KParts;
00037
00038 class BrowserRun::BrowserRunPrivate
00039 {
00040 public:
00041 bool m_bHideErrorDialog;
00042 bool m_bRemoveReferrer;
00043 bool m_bTrustedSource;
00044 KParts::OpenUrlArguments m_args;
00045 KParts::BrowserArguments m_browserArgs;
00046
00047 KParts::ReadOnlyPart *m_part;
00048 QPointer<QWidget> m_window;
00049 QString m_mimeType;
00050 QString m_contentDisposition;
00051 };
00052
00053 BrowserRun::BrowserRun( const KUrl& url, const KParts::OpenUrlArguments& args,
00054 const KParts::BrowserArguments& browserArgs,
00055 KParts::ReadOnlyPart *part, QWidget* window,
00056 bool removeReferrer, bool trustedSource, bool hideErrorDialog )
00057 : KRun( url, window, 0 , false , false ),
00058 d(new BrowserRunPrivate)
00059 {
00060 d->m_bHideErrorDialog = hideErrorDialog;
00061 d->m_bRemoveReferrer = removeReferrer;
00062 d->m_bTrustedSource = trustedSource;
00063 d->m_args = args;
00064 d->m_browserArgs = browserArgs;
00065 d->m_part = part;
00066 d->m_window = window;
00067 }
00068
00069 BrowserRun::~BrowserRun()
00070 {
00071 delete d;
00072 }
00073
00074 KParts::ReadOnlyPart* BrowserRun::part() const
00075 {
00076 return d->m_part;
00077 }
00078
00079 KUrl BrowserRun::url() const
00080 {
00081 return KRun::url();
00082 }
00083
00084 void BrowserRun::init()
00085 {
00086 if ( d->m_bHideErrorDialog )
00087 {
00088
00089
00090
00091 if ( !KRun::url().isValid() ) {
00092 redirectToError( KIO::ERR_MALFORMED_URL, KRun::url().url() );
00093 return;
00094 }
00095 if ( !isLocalFile() && !hasError() && KRun::url().isLocalFile() )
00096 setIsLocalFile( true );
00097
00098 if ( isLocalFile() ) {
00099 KDE_struct_stat buff;
00100 if ( KDE::stat( KRun::url().toLocalFile(), &buff ) == -1 )
00101 {
00102 kDebug(1000) << KRun::url().toLocalFile() << "doesn't exist.";
00103 redirectToError( KIO::ERR_DOES_NOT_EXIST, KRun::url().toLocalFile() );
00104 return;
00105 }
00106 setMode( buff.st_mode );
00107 }
00108 }
00109 KRun::init();
00110 }
00111
00112 void BrowserRun::scanFile()
00113 {
00114 kDebug(1000) << KRun::url();
00115
00116
00117
00118
00119 if ( KRun::url().query().isEmpty() && !KRun::url().protocol().startsWith("http") )
00120 {
00121 KMimeType::Ptr mime = KMimeType::findByUrl( KRun::url() );
00122 assert( mime );
00123 if ( mime->name() != "application/octet-stream" || isLocalFile() )
00124 {
00125 kDebug(1000) << "MIME TYPE is" << mime->name();
00126 mimeTypeDetermined( mime->name() );
00127 return;
00128 }
00129 }
00130
00131 QMap<QString, QString>& metaData = d->m_args.metaData();
00132 if ( d->m_part ) {
00133 const QString proto = d->m_part->url().protocol().toLower();
00134
00135 if (proto == "https" || proto == "webdavs") {
00136 metaData.insert("main_frame_request", "TRUE" );
00137 metaData.insert("ssl_was_in_use", "TRUE" );
00138
00139 } else if (proto == "http" || proto == "webdav") {
00140
00141 metaData.insert("ssl_was_in_use", "FALSE" );
00142 }
00143
00144
00145 if (!metaData.contains("PropagateHttpHeader"))
00146 metaData.insert("PropagateHttpHeader", "TRUE");
00147 }
00148
00149 KIO::TransferJob *job;
00150 if ( d->m_browserArgs.doPost() && KRun::url().protocol().startsWith("http")) {
00151 job = KIO::http_post( KRun::url(), d->m_browserArgs.postData, KIO::HideProgressInfo );
00152 job->addMetaData( "content-type", d->m_browserArgs.contentType() );
00153 } else {
00154 job = KIO::get(KRun::url(),
00155 d->m_args.reload() ? KIO::Reload : KIO::NoReload,
00156 KIO::HideProgressInfo);
00157 }
00158
00159 if ( d->m_bRemoveReferrer )
00160 metaData.remove("referrer");
00161
00162 job->addMetaData( metaData );
00163 job->ui()->setWindow( d->m_window );
00164 connect( job, SIGNAL( result( KJob *)),
00165 this, SLOT( slotBrowserScanFinished(KJob *)));
00166 connect( job, SIGNAL( mimetype( KIO::Job *, const QString &)),
00167 this, SLOT( slotBrowserMimetype(KIO::Job *, const QString &)));
00168 setJob( job );
00169 }
00170
00171 void BrowserRun::slotBrowserScanFinished(KJob *job)
00172 {
00173 kDebug(1000) << job->error();
00174 if ( job->error() == KIO::ERR_IS_DIRECTORY )
00175 {
00176
00177
00178
00179 kDebug(1000) << "It is in fact a directory!";
00180
00181 KRun::setUrl( static_cast<KIO::TransferJob *>(job)->url() );
00182 setJob( 0 );
00183 mimeTypeDetermined( "inode/directory" );
00184 }
00185 else
00186 {
00187 if ( job->error() )
00188 handleError( job );
00189 else
00190 KRun::slotScanFinished(job);
00191 }
00192 }
00193
00194 void BrowserRun::slotBrowserMimetype( KIO::Job *_job, const QString &type )
00195 {
00196 Q_ASSERT( _job == KRun::job() );
00197 KIO::TransferJob *job = static_cast<KIO::TransferJob *>(KRun::job());
00198
00199
00200
00201 setUrl( job->url() );
00202
00203 if (job->isErrorPage()) {
00204 d->m_mimeType = type;
00205 handleError(job);
00206 setJob( 0 );
00207 } else {
00208 kDebug(1000) << "found" << type << "for" << KRun::url();
00209
00210
00211
00212 const QString suggestedFileName = job->queryMetaData("content-disposition-filename");
00213 setSuggestedFileName(suggestedFileName);
00214
00215 d->m_contentDisposition = job->queryMetaData("content-disposition-type");
00216
00217
00218 QMapIterator<QString,QString> it (job->metaData());
00219 while (it.hasNext()) {
00220 it.next();
00221 if (it.key().startsWith(QLatin1String("ssl_"), Qt::CaseInsensitive))
00222 d->m_args.metaData().insert(it.key(), it.value());
00223 }
00224
00225
00226 QString _type = type;
00227 job->putOnHold();
00228 setJob( 0 );
00229
00230 mimeTypeDetermined( _type );
00231 }
00232 }
00233
00234 BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable( const QString& _mimeType )
00235 {
00236 QString mimeType( _mimeType );
00237 Q_ASSERT( !hasFinished() );
00238
00239 if ( mimeType != "inode/directory" &&
00240 !KRun::url().isLocalFile() )
00241 {
00242 if ( isTextExecutable(mimeType) )
00243 mimeType = QLatin1String("text/plain");
00244 kDebug(1000) << "ask for saving";
00245 KService::Ptr offer = KMimeTypeTrader::self()->preferredService(mimeType, "Application");
00246
00247 KParts::BrowserRun::AskSaveResult res = askSave( KRun::url(), offer, mimeType, suggestedFileName() );
00248 if ( res == KParts::BrowserRun::Save ) {
00249 save( KRun::url(), suggestedFileName() );
00250 kDebug(1000) << "Save: returning Handled";
00251 setFinished( true );
00252 return Handled;
00253 }
00254 else if ( res == KParts::BrowserRun::Cancel ) {
00255
00256 kDebug(1000) << "Cancel: returning Handled";
00257 setFinished( true );
00258 return Handled;
00259 }
00260 else
00261 {
00262
00263
00264 if ( d->m_browserArgs.doPost() )
00265 {
00266 kDebug(1000) << "request comes from a POST, can't pass a URL to another app, need to save";
00267 d->m_mimeType = mimeType;
00268 QString extension;
00269 QString fileName = suggestedFileName().isEmpty() ? KRun::url().fileName() : suggestedFileName();
00270 int extensionPos = fileName.lastIndexOf( '.' );
00271 if ( extensionPos != -1 )
00272 extension = fileName.mid( extensionPos );
00273 KTemporaryFile tempFile;
00274 tempFile.setSuffix(extension);
00275 tempFile.setAutoRemove(false);
00276 tempFile.open();
00277 KUrl destURL;
00278 destURL.setPath( tempFile.fileName() );
00279 KIO::Job *job = KIO::file_copy( KRun::url(), destURL, 0600, KIO::Overwrite );
00280 job->ui()->setWindow(d->m_window);
00281 connect( job, SIGNAL(result(KJob *)),
00282 this, SLOT(slotCopyToTempFileResult(KJob *)) );
00283 return Delayed;
00284 }
00285 }
00286 }
00287
00288
00289 if ( !d->m_bTrustedSource &&
00290 !allowExecution( mimeType, KRun::url() ) )
00291 {
00292 setFinished( true );
00293 return Handled;
00294 }
00295
00296 KIO::SimpleJob::removeOnHold();
00297 return NotHandled;
00298 }
00299
00300
00301 bool BrowserRun::allowExecution( const QString &mimeType, const KUrl &url )
00302 {
00303 if ( !KRun::isExecutable( mimeType ) )
00304 return true;
00305
00306 if ( !url.isLocalFile() )
00307 return false;
00308
00309 return ( KMessageBox::warningContinueCancel( 0,
00310 i18n( "Do you really want to execute '%1'?", url.prettyUrl() ),
00311 i18n("Execute File?"), KGuiItem(i18n("Execute")) ) == KMessageBox::Continue );
00312 }
00313
00314 static QString makeQuestion( const KUrl& url, const QString& mimeType, const QString& suggestedFileName )
00315 {
00316 QString surl = url.prettyUrl();
00317 KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
00318 QString comment = mimeType;
00319
00320
00321
00322 if (mime && mime->name() != KMimeType::defaultMimeType()) {
00323
00324 comment = mime->comment();
00325 }
00326
00327
00328 if ( suggestedFileName.isEmpty() )
00329 return i18n("Open '%2'?\nType: %1", comment, surl);
00330 else
00331 return i18n("Open '%3'?\nName: %2\nType: %1", comment, suggestedFileName, surl);
00332 }
00333
00334
00335
00336 BrowserRun::AskSaveResult BrowserRun::askSave( const KUrl & url, KService::Ptr offer, const QString& mimeType, const QString & suggestedFileName )
00337 {
00338
00339
00340
00341
00342 QString question = makeQuestion( url, mimeType, suggestedFileName );
00343
00344
00345 KGuiItem openItem;
00346 if (offer && !offer->name().isEmpty())
00347 openItem = KGuiItem(i18n("&Open with '%1'", offer->name()), offer->icon());
00348 else
00349 openItem = KGuiItem(i18n("&Open with..."), "system-run");
00350
00351 int choice = KMessageBox::questionYesNoCancel(
00352 0, question, url.host(),
00353 KStandardGuiItem::saveAs(), openItem, KStandardGuiItem::cancel(),
00354 QLatin1String("askSave")+ mimeType );
00355
00356 return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel );
00357
00358 }
00359
00360
00361
00362 BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave( const KUrl & url, const QString& mimeType, const QString & suggestedFileName, int flags )
00363 {
00364
00365
00366
00367
00368
00369 KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 if (flags != (int)AttachmentDisposition && mime && (
00380 mime->is( "text/html" ) ||
00381 mime->is( "application/xml" ) ||
00382 mime->is( "inode/directory" ) ||
00383 mimeType.startsWith( "image" ) ||
00384 mime->is( "multipart/x-mixed-replace" ) ||
00385 mime->is( "multipart/replace" ) ||
00386 mimeType.startsWith( "print" ) ) )
00387 return Open;
00388
00389 QString question = makeQuestion( url, mimeType, suggestedFileName );
00390
00391
00392 int choice = KMessageBox::questionYesNoCancel(
00393 0, question, url.host(),
00394 KStandardGuiItem::saveAs(), KGuiItem( i18n( "&Open" ), "document-open"), KStandardGuiItem::cancel(),
00395 QLatin1String("askEmbedOrSave")+ mimeType );
00396 return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel );
00397
00398 }
00399
00400
00401 void BrowserRun::save( const KUrl & url, const QString & suggestedFileName )
00402 {
00403 simpleSave( url, suggestedFileName, d->m_window );
00404 }
00405
00406
00407 void BrowserRun::simpleSave( const KUrl & url, const QString & suggestedFileName,
00408 QWidget* window )
00409 {
00410
00411
00412
00413
00414 if ( !url.isLocalFile() )
00415 {
00416 KConfigGroup cfg = KSharedConfig::openConfig("konquerorrc", KConfig::NoGlobals)->group("HTML Settings");
00417 QString downloadManger = cfg.readPathEntry("DownloadManager", QString());
00418 if (!downloadManger.isEmpty())
00419 {
00420
00421 kDebug(1000) << "Using: "<<downloadManger <<" as Download Manager";
00422 QString cmd=KStandardDirs::findExe(downloadManger);
00423 if (cmd.isEmpty())
00424 {
00425 QString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ", downloadManger);
00426 QString errMsgEx= i18n("Try to reinstall it \n\nThe integration with Konqueror will be disabled.");
00427 KMessageBox::detailedSorry(0,errMsg,errMsgEx);
00428 cfg.writePathEntry("DownloadManager",QString());
00429 cfg.sync ();
00430 }
00431 else
00432 {
00433
00434
00435
00436
00437 cmd += " " + KShell::quoteArg(url.url());
00438 if ( !suggestedFileName.isEmpty() )
00439 cmd +=" " + KShell::quoteArg(suggestedFileName);
00440
00441 kDebug(1000) << "Calling command" << cmd;
00442
00443 KIO::Scheduler::publishSlaveOnHold();
00444 KRun::runCommand(cmd, window);
00445 return;
00446 }
00447 }
00448 }
00449
00450
00451 KFileDialog *dlg = new KFileDialog( QString(), QString() ,
00452 window);
00453 dlg->setOperationMode( KFileDialog::Saving );
00454 dlg->setCaption(i18n("Save As"));
00455
00456 dlg->setSelection( suggestedFileName.isEmpty() ? url.fileName() : suggestedFileName );
00457 if ( dlg->exec() )
00458 {
00459 KUrl destURL( dlg->selectedUrl() );
00460 if ( destURL.isValid() )
00461 {
00462 KIO::Job *job = KIO::copy( url, destURL );
00463 job->ui()->setWindow (window);
00464 job->ui()->setAutoErrorHandlingEnabled( true );
00465 }
00466 }
00467 delete dlg;
00468 }
00469
00470 void BrowserRun::slotStatResult( KJob *job )
00471 {
00472 if ( job->error() ) {
00473 kDebug(1000) << job->errorString();
00474 handleError( job );
00475 } else
00476 KRun::slotStatResult( job );
00477 }
00478
00479 void BrowserRun::handleError( KJob * job )
00480 {
00481 if ( !job ) {
00482 kWarning(1000) << "handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog;
00483 return;
00484 }
00485
00486 KIO::TransferJob *tjob = qobject_cast<KIO::TransferJob *>(job);
00487 if (tjob && tjob->isErrorPage() && !job->error()) {
00488
00489
00490 tjob->putOnHold();
00491 setJob(0);
00492 if (!d->m_mimeType.isEmpty())
00493 mimeTypeDetermined(d->m_mimeType);
00494 return;
00495 }
00496
00497 if (d->m_bHideErrorDialog && job->error() != KIO::ERR_NO_CONTENT)
00498 {
00499 redirectToError( job->error(), job->errorText() );
00500 return;
00501 }
00502
00503
00504 KRun::slotStatResult( job );
00505 }
00506
00507 void BrowserRun::redirectToError( int error, const QString& errorText )
00508 {
00519 KUrl newURL(QString("error:/?error=%1&errText=%2")
00520 .arg( error )
00521 .arg( QString::fromUtf8( QUrl::toPercentEncoding( errorText ) ) ) );
00522 KUrl runURL = KRun::url();
00523 runURL.setPass( QString() );
00524
00525 KUrl::List lst;
00526 lst << newURL << runURL;
00527 KRun::setUrl( KUrl::join( lst ) );
00528
00529 setJob( 0 );
00530 mimeTypeDetermined( "text/html" );
00531 }
00532
00533 void BrowserRun::slotCopyToTempFileResult(KJob *job)
00534 {
00535 if ( job->error() ) {
00536 job->uiDelegate()->showErrorMessage();
00537 } else {
00538
00539 (void) (KRun::runUrl( static_cast<KIO::FileCopyJob *>(job)->destUrl(), d->m_mimeType, d->m_window ));
00540 }
00541 setError( true );
00542 setFinished( true );
00543 timer().start( 0 );
00544 }
00545
00546 bool BrowserRun::isTextExecutable( const QString &mimeType )
00547 {
00548 return ( mimeType == "application/x-desktop" ||
00549 mimeType == "application/x-shellscript" );
00550 }
00551
00552 bool BrowserRun::hideErrorDialog() const
00553 {
00554 return d->m_bHideErrorDialog;
00555 }
00556
00557 QString BrowserRun::contentDisposition() const {
00558 return d->m_contentDisposition;
00559 }
00560
00561 KParts::OpenUrlArguments& KParts::BrowserRun::arguments()
00562 {
00563 return d->m_args;
00564 }
00565
00566 KParts::BrowserArguments& KParts::BrowserRun::browserArguments()
00567 {
00568 return d->m_browserArgs;
00569 }
00570
00571 #include "browserrun.moc"