kparts Library API Documentation

browserrun.cpp

00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 2002 David Faure <faure@kde.org> 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Library General Public 00006 * License version 2, as published by the Free Software Foundation. 00007 * 00008 * This library is distributed in the hope that it will be useful, 00009 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 * Library General Public License for more details. 00012 * 00013 * You should have received a copy of the GNU Library General Public License 00014 * along with this library; see the file COPYING.LIB. If not, write to 00015 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00016 * Boston, MA 02111-1307, USA. 00017 */ 00018 00019 #include "browserrun.h" 00020 #include <kmessagebox.h> 00021 #include <kfiledialog.h> 00022 #include <kio/job.h> 00023 #include <kio/scheduler.h> 00024 #include <klocale.h> 00025 #include <kprocess.h> 00026 #include <kstringhandler.h> 00027 #include <kuserprofile.h> 00028 #include <ktempfile.h> 00029 #include <kdebug.h> 00030 #include <kstandarddirs.h> 00031 #include <assert.h> 00032 00033 using namespace KParts; 00034 00035 class BrowserRun::BrowserRunPrivate 00036 { 00037 public: 00038 bool m_bHideErrorDialog; 00039 }; 00040 00041 BrowserRun::BrowserRun( const KURL& url, const KParts::URLArgs& args, 00042 KParts::ReadOnlyPart *part, QWidget* window, 00043 bool removeReferrer, bool trustedSource ) 00044 : KRun( url, window, 0 /*mode*/, false /*is_local_file known*/, false /* no GUI */ ), 00045 m_args( args ), m_part( part ), m_window( window ), 00046 m_bRemoveReferrer( removeReferrer ), m_bTrustedSource( trustedSource ) 00047 { 00048 d = new BrowserRunPrivate; 00049 d->m_bHideErrorDialog = false; 00050 } 00051 00052 // BIC: merge with above ctor 00053 BrowserRun::BrowserRun( const KURL& url, const KParts::URLArgs& args, 00054 KParts::ReadOnlyPart *part, QWidget* window, 00055 bool removeReferrer, bool trustedSource, bool hideErrorDialog ) 00056 : KRun( url, window, 0 /*mode*/, false /*is_local_file known*/, false /* no GUI */ ), 00057 m_args( args ), m_part( part ), m_window( window ), 00058 m_bRemoveReferrer( removeReferrer ), m_bTrustedSource( trustedSource ) 00059 { 00060 d = new BrowserRunPrivate; 00061 d->m_bHideErrorDialog = hideErrorDialog; 00062 } 00063 00064 BrowserRun::~BrowserRun() 00065 { 00066 delete d; 00067 } 00068 00069 void BrowserRun::init() 00070 { 00071 if ( d->m_bHideErrorDialog ) 00072 { 00073 // ### KRun doesn't call a virtual method when it finds out that the URL 00074 // is either malformed, or points to a non-existing local file... 00075 // So we need to reimplement some of the checks, to handle m_bHideErrorDialog 00076 if ( !m_strURL.isValid() ) { 00077 redirectToError( KIO::ERR_MALFORMED_URL, m_strURL.url() ); 00078 return; 00079 } 00080 if ( !m_bIsLocalFile && !m_bFault && m_strURL.isLocalFile() ) 00081 m_bIsLocalFile = true; 00082 00083 if ( m_bIsLocalFile ) { 00084 struct stat buff; 00085 if ( stat( QFile::encodeName(m_strURL.path()), &buff ) == -1 ) 00086 { 00087 kdDebug(1000) << "BrowserRun::init : " << m_strURL.prettyURL() << " doesn't exist." << endl; 00088 redirectToError( KIO::ERR_DOES_NOT_EXIST, m_strURL.path() ); 00089 return; 00090 } 00091 m_mode = buff.st_mode; // while we're at it, save it for KRun::init() to use it 00092 } 00093 } 00094 KRun::init(); 00095 } 00096 00097 void BrowserRun::scanFile() 00098 { 00099 kdDebug(1000) << "BrowserRun::scanfile " << m_strURL.prettyURL() << endl; 00100 00101 // Let's check for well-known extensions 00102 // Not when there is a query in the URL, in any case. 00103 // Optimization for http/https, findByURL doesn't trust extensions over http. 00104 if ( m_strURL.query().isEmpty() && !m_strURL.protocol().startsWith("http") ) 00105 { 00106 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL ); 00107 assert( mime != 0L ); 00108 if ( mime->name() != "application/octet-stream" || m_bIsLocalFile ) 00109 { 00110 kdDebug(1000) << "Scanfile: MIME TYPE is " << mime->name() << endl; 00111 foundMimeType( mime->name() ); 00112 return; 00113 } 00114 } 00115 00116 if ( m_part ) 00117 { 00118 QString proto = m_part->url().protocol().lower(); 00119 00120 if (proto == "https" || proto == "webdavs") { 00121 m_args.metaData().insert("main_frame_request", "TRUE" ); 00122 m_args.metaData().insert("ssl_was_in_use", "TRUE" ); 00123 m_args.metaData().insert("ssl_activate_warnings", "TRUE" ); 00124 } else if (proto == "http" || proto == "webdav") { 00125 m_args.metaData().insert("ssl_activate_warnings", "TRUE" ); 00126 m_args.metaData().insert("ssl_was_in_use", "FALSE" ); 00127 } 00128 00129 // Set the PropagateHttpHeader meta-data if it has not already been set... 00130 if (!m_args.metaData().contains("PropagateHttpHeader")) 00131 m_args.metaData().insert("PropagateHttpHeader", "TRUE"); 00132 } 00133 00134 KIO::TransferJob *job; 00135 if ( m_args.doPost() && m_strURL.protocol().startsWith("http")) 00136 { 00137 job = KIO::http_post( m_strURL, m_args.postData, false ); 00138 job->addMetaData( "content-type", m_args.contentType() ); 00139 } 00140 else 00141 job = KIO::get(m_strURL, m_args.reload, false); 00142 00143 if ( m_bRemoveReferrer ) 00144 m_args.metaData().remove("referrer"); 00145 00146 job->addMetaData( m_args.metaData() ); 00147 job->setWindow( m_window ); 00148 connect( job, SIGNAL( result( KIO::Job *)), 00149 this, SLOT( slotBrowserScanFinished(KIO::Job *))); 00150 connect( job, SIGNAL( mimetype( KIO::Job *, const QString &)), 00151 this, SLOT( slotBrowserMimetype(KIO::Job *, const QString &))); 00152 m_job = job; 00153 } 00154 00155 void BrowserRun::slotBrowserScanFinished(KIO::Job *job) 00156 { 00157 kdDebug(1000) << "BrowserRun::slotBrowserScanFinished" << endl; 00158 if ( job->error() == KIO::ERR_IS_DIRECTORY ) 00159 { 00160 // It is in fact a directory. This happens when HTTP redirects to FTP. 00161 // Due to the "protocol doesn't support listing" code in BrowserRun, we 00162 // assumed it was a file. 00163 kdDebug(1000) << "It is in fact a directory!" << endl; 00164 // Update our URL in case of a redirection 00165 m_strURL = static_cast<KIO::TransferJob *>(job)->url(); 00166 m_job = 0; 00167 foundMimeType( "inode/directory" ); 00168 } 00169 else 00170 { 00171 if ( job->error() ) 00172 handleError( job ); 00173 else 00174 KRun::slotScanFinished(job); 00175 } 00176 } 00177 00178 void BrowserRun::slotBrowserMimetype( KIO::Job *_job, const QString &type ) 00179 { 00180 Q_ASSERT( _job == m_job ); 00181 KIO::TransferJob *job = static_cast<KIO::TransferJob *>(m_job); 00182 // Update our URL in case of a redirection 00183 //kdDebug(1000) << "old URL=" << m_strURL.url() << endl; 00184 //kdDebug(1000) << "new URL=" << job->url().url() << endl; 00185 m_strURL = job->url(); 00186 kdDebug(1000) << "slotBrowserMimetype: found " << type << " for " << m_strURL.prettyURL() << endl; 00187 00188 m_suggestedFilename = job->queryMetaData("content-disposition"); 00189 //kdDebug(1000) << "m_suggestedFilename=" << m_suggestedFilename << endl; 00190 00191 // Make a copy to avoid a dead reference 00192 QString _type = type; 00193 job->putOnHold(); 00194 m_job = 0; 00195 00196 foundMimeType( _type ); 00197 } 00198 00199 BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable( const QString& _mimeType ) 00200 { 00201 QString mimeType( _mimeType ); 00202 Q_ASSERT( !m_bFinished ); // only come here if the mimetype couldn't be embedded 00203 // Support for saving remote files. 00204 if ( mimeType != "inode/directory" && // dirs can't be saved 00205 !m_strURL.isLocalFile() ) 00206 { 00207 if ( isTextExecutable(mimeType) ) 00208 mimeType = QString::fromLatin1("text/plain"); // view, don't execute 00209 kdDebug(1000) << "BrowserRun: ask for saving" << endl; 00210 KService::Ptr offer = KServiceTypeProfile::preferredService(mimeType, "Application"); 00211 // ... -> ask whether to save 00212 KParts::BrowserRun::AskSaveResult res = askSave( m_strURL, offer, mimeType, m_suggestedFilename ); 00213 if ( res == KParts::BrowserRun::Save ) { 00214 save( m_strURL, m_suggestedFilename ); 00215 kdDebug(1000) << "BrowserRun::handleNonEmbeddable: Save: returning Handled" << endl; 00216 m_bFinished = true; 00217 return Handled; 00218 } 00219 else if ( res == KParts::BrowserRun::Cancel ) { 00220 // saving done or canceled 00221 kdDebug(1000) << "BrowserRun::handleNonEmbeddable: Cancel: returning Handled" << endl; 00222 m_bFinished = true; 00223 return Handled; 00224 } 00225 else // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled) 00226 { 00227 // If we were in a POST, we can't just pass a URL to an external application. 00228 // We must save the data to a tempfile first. 00229 if ( m_args.doPost() ) 00230 { 00231 kdDebug(1000) << "BrowserRun: request comes from a POST, can't pass a URL to another app, need to save" << endl; 00232 m_sMimeType = mimeType; 00233 QString extension; 00234 QString fileName = m_suggestedFilename.isEmpty() ? m_strURL.fileName() : m_suggestedFilename; 00235 int extensionPos = fileName.findRev( '.' ); 00236 if ( extensionPos != -1 ) 00237 extension = fileName.mid( extensionPos ); // keep the '.' 00238 KTempFile tempFile( QString::null, extension ); 00239 KURL destURL; 00240 destURL.setPath( tempFile.name() ); 00241 KIO::Job *job = KIO::file_copy( m_strURL, destURL, 0600, true /*overwrite*/, false /*no resume*/, true /*progress info*/ ); 00242 job->setWindow (m_window); 00243 connect( job, SIGNAL( result( KIO::Job *)), 00244 this, SLOT( slotCopyToTempFileResult(KIO::Job *)) ); 00245 return Delayed; // We'll continue after the job has finished 00246 } 00247 } 00248 } 00249 00250 // Check if running is allowed 00251 if ( !m_bTrustedSource && // ... and untrusted source... 00252 !allowExecution( mimeType, m_strURL ) ) // ...and the user said no (for executables etc.) 00253 { 00254 m_bFinished = true; 00255 return Handled; 00256 } 00257 00258 KIO::SimpleJob::removeOnHold(); // Kill any slave that was put on hold. 00259 return NotHandled; 00260 } 00261 00262 //static 00263 bool BrowserRun::allowExecution( const QString &serviceType, const KURL &url ) 00264 { 00265 if ( !isExecutable( serviceType ) ) 00266 return true; 00267 00268 if ( !url.isLocalFile() ) // Don't permit to execute remote files 00269 return false; 00270 00271 return ( KMessageBox::warningYesNo( 0, i18n( "Do you really want to execute '%1'? " ).arg( url.prettyURL() ) ) == KMessageBox::Yes ); 00272 } 00273 00274 static QString makeQuestion( const KURL& url, const QString& mimeType, const QString& suggestedFilename ) 00275 { 00276 QString surl = KStringHandler::csqueeze( url.prettyURL() ); 00277 KMimeType::Ptr mime = KMimeType::mimeType( mimeType ); 00278 QString comment = mimeType; 00279 00280 // Test if the mimeType is not recognize as octet-stream. 00281 // If so then keep mime-type as comment 00282 if (mime->name() != KMimeType::defaultMimeType()) { 00283 // The mime-type is known so display the comment instead of mime-type 00284 comment = mime->comment(); 00285 } 00286 // The strange order in the i18n() calls below is due to the possibility 00287 // of surl containing a '%' 00288 if ( suggestedFilename.isEmpty() ) 00289 return i18n("Open '%2'?\nType: %1").arg(comment).arg(surl); 00290 else 00291 return i18n("Open '%3'?\nName: %2\nType: %1").arg(comment).arg(suggestedFilename).arg(surl); 00292 } 00293 00294 //static 00295 BrowserRun::AskSaveResult BrowserRun::askSave( const KURL & url, KService::Ptr offer, const QString& mimeType, const QString & suggestedFilename ) 00296 { 00297 QString question = makeQuestion( url, mimeType, suggestedFilename ); 00298 00299 // Text used for the open button 00300 QString openText = (offer && !offer->name().isEmpty()) 00301 ? i18n("&Open with '%1'").arg(offer->name()) 00302 : i18n("&Open with..."); 00303 00304 int choice = KMessageBox::questionYesNoCancel( 00305 0L, question, QString::null, 00306 KStdGuiItem::saveAs(), openText, 00307 QString::fromLatin1("askSave")+ mimeType ); // dontAskAgainName 00308 return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel ); 00309 } 00310 00311 //static 00312 BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave( const KURL & url, const QString& mimeType, const QString & suggestedFilename, int /*flags*/ ) 00313 { 00314 KMimeType::Ptr mime = KMimeType::mimeType( mimeType ); 00315 // Don't ask for: 00316 // - html (even new tabs would ask, due to about:blank!) 00317 // - dirs obviously (though not common over HTTP :), 00318 // - images (reasoning: no need to save, most of the time, because fast to see) 00319 // e.g. postscript is different, because takes longer to read, so 00320 // it's more likely that the user might want to save it. 00321 // - multipart/* ("server push", see kmultipart) 00322 // - other strange 'internal' mimetypes like print/manager... 00323 if ( mime->is( "text/html" ) || 00324 mime->is( "text/xml" ) || 00325 mime->is( "inode/directory" ) || 00326 mimeType.startsWith( "image" ) || 00327 mime->is( "multipart/x-mixed-replace" ) || 00328 mime->is( "multipart/replace" ) || 00329 mimeType.startsWith( "print" ) ) 00330 return Open; 00331 00332 QString question = makeQuestion( url, mimeType, suggestedFilename ); 00333 00334 int choice = KMessageBox::questionYesNoCancel( 00335 0L, question, QString::null, 00336 KStdGuiItem::saveAs(), KGuiItem( i18n( "&Open" ), "fileopen"), 00337 QString::fromLatin1("askEmbedOrSave")+ mimeType ); // dontAskAgainName 00338 return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel ); 00339 } 00340 00341 // Default implementation, overridden in KHTMLRun 00342 void BrowserRun::save( const KURL & url, const QString & suggestedFilename ) 00343 { 00344 simpleSave( url, suggestedFilename, m_window ); 00345 } 00346 00347 // static 00348 void BrowserRun::simpleSave( const KURL & url, const QString & suggestedFilename ) 00349 { 00350 simpleSave (url, suggestedFilename, 0); 00351 } 00352 00353 void BrowserRun::simpleSave( const KURL & url, const QString & suggestedFilename, 00354 QWidget* window ) 00355 { 00356 // DownloadManager <-> konqueror integration 00357 // find if the integration is enabled 00358 // the empty key means no integration 00359 KConfig cfg("konquerorrc", false, false); 00360 cfg.setGroup("HTML Settings"); 00361 QString downloadManger = cfg.readPathEntry("DownloadManager"); 00362 if (!downloadManger.isEmpty()) 00363 { 00364 // then find the download manager location 00365 kdDebug(1000) << "Using: "<<downloadManger <<" as Download Manager" <<endl; 00366 QString cmd=KStandardDirs::findExe(downloadManger); 00367 if (cmd.isEmpty()) 00368 { 00369 QString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ").arg(downloadManger); 00370 QString errMsgEx= i18n("Try to reinstall it \n\nThe integration with Konqueror will be disabled!"); 00371 KMessageBox::detailedSorry(0,errMsg,errMsgEx); 00372 cfg.writePathEntry("DownloadManager",QString::null); 00373 cfg.sync (); 00374 } 00375 else 00376 { 00377 // ### suggestedFilename not taken into account. Fix this (and 00378 // the duplicated code) with shiny new KDownload class for 3.2 (pfeiffer) 00379 // Until the shiny new class comes about, send the suggestedFilename 00380 // along with the actual URL to download. (DA) 00381 cmd += " " + KProcess::quote(url.url()) + " " + KProcess::quote(suggestedFilename); 00382 kdDebug(1000) << "Calling command " << cmd << endl; 00383 // slave is already on hold (slotBrowserMimetype()) 00384 KIO::Scheduler::publishSlaveOnHold(); 00385 KRun::runCommand(cmd); 00386 return; 00387 } 00388 } 00389 00390 // no download manager available, let's do it ourself 00391 KFileDialog *dlg = new KFileDialog( QString::null, QString::null /*all files*/, 00392 window , "filedialog", true ); 00393 dlg->setOperationMode( KFileDialog::Saving ); 00394 dlg->setCaption(i18n("Save As")); 00395 00396 dlg->setSelection( suggestedFilename.isEmpty() ? url.fileName() : suggestedFilename ); 00397 if ( dlg->exec() ) 00398 { 00399 KURL destURL( dlg->selectedURL() ); 00400 if ( destURL.isValid() ) 00401 { 00402 KIO::Job *job = KIO::copy( url, destURL ); 00403 job->setWindow (window); 00404 job->setAutoErrorHandlingEnabled( true ); 00405 } 00406 } 00407 delete dlg; 00408 } 00409 00410 void BrowserRun::slotStatResult( KIO::Job *job ) 00411 { 00412 if ( job->error() ) { 00413 kdDebug(1000) << "BrowserRun::slotStatResult : " << job->errorString() << endl; 00414 handleError( job ); 00415 } else 00416 KRun::slotStatResult( job ); 00417 } 00418 00419 void BrowserRun::handleError( KIO::Job * job ) 00420 { 00421 if ( !job ) { // Shouldn't happen, see docu. 00422 kdWarning(1000) << "BrowserRun::handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog << endl; 00423 return; 00424 } 00425 00426 if (d->m_bHideErrorDialog && job->error() != KIO::ERR_NO_CONTENT) 00427 { 00428 redirectToError( job->error(), job->errorText() ); 00429 return; 00430 } 00431 00432 // Reuse code in KRun, to benefit from d->m_showingError etc. 00433 KRun::slotStatResult( job ); 00434 } 00435 00436 void BrowserRun::redirectToError( int error, const QString& errorText ) 00437 { 00448 QString errText( errorText ); 00449 errText.replace( '#', "%23" ); // a # in the error string would really muck things up... 00450 KURL newURL(QString("error:/?error=%1&errText=%2") 00451 .arg( error ).arg( errText ), 106 ); 00452 m_strURL.setPass( QString::null ); // don't put the password in the error URL 00453 00454 KURL::List lst; 00455 lst << newURL << m_strURL; 00456 m_strURL = KURL::join( lst ); 00457 //kdDebug(1202) << "BrowserRun::handleError m_strURL=" << m_strURL.prettyURL() << endl; 00458 00459 m_job = 0; 00460 foundMimeType( "text/html" ); 00461 } 00462 00463 void BrowserRun::slotCopyToTempFileResult(KIO::Job *job) 00464 { 00465 if ( job->error() ) { 00466 job->showErrorDialog( m_window ); 00467 } else { 00468 // Same as KRun::foundMimeType but with a different URL 00469 (void) (KRun::runURL( static_cast<KIO::FileCopyJob *>(job)->destURL(), m_sMimeType )); 00470 } 00471 m_bFault = true; // see above 00472 m_bFinished = true; 00473 m_timer.start( 0, true ); 00474 } 00475 00476 bool BrowserRun::isTextExecutable( const QString &serviceType ) 00477 { 00478 return ( serviceType == "application/x-desktop" || 00479 serviceType == "application/x-shellscript" ); 00480 } 00481 00482 bool BrowserRun::isExecutable( const QString &serviceType ) 00483 { 00484 return KRun::isExecutable( serviceType ); 00485 } 00486 00487 bool BrowserRun::hideErrorDialog() const 00488 { 00489 return d->m_bHideErrorDialog; 00490 } 00491 00492 #include "browserrun.moc"
KDE Logo
This file is part of the documentation for kparts Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Aug 30 22:55:10 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003