• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KParts

browserrun.cpp

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

KParts

Skip menu "KParts"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal