browserrun.cpp Source File (kparts Library)

| # kparts Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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, 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, 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     m_bFault = !m_strURL.isValid();
    00077     if ( !m_bIsLocalFile && !m_bFault && m_strURL.isLocalFile() )
    00078       m_bIsLocalFile = true;
    00079
    00080     if ( m_bIsLocalFile )  {
    00081       struct stat buff;
    00082       if ( stat( QFile::encodeName(m_strURL.path()), &buff ) == -1 )
    00083       {
    00084         m_bFault = true;
    00085         kdDebug(1000) << "BrowserRun::init : " << m_strURL.prettyURL() << " doesn't exist." << endl;
    00086       }
    00087       m_mode = buff.st_mode; // while we're at it, save it for KRun::init() to use it
    00088     }
    00089
    00090     if ( m_bFault )
    00091     {
    00092       m_bFinished = true;
    00093       m_timer.start( 0, true );
    00094       handleError( 0 );
    00095       return;
    00096     }
    00097   }
    00098   KRun::init();
    00099 }
    00100
    00101 void BrowserRun::scanFile()
    00102 {
    00103   kdDebug(1000) << "BrowserRun::scanfile " << m_strURL.prettyURL() << endl;
    00104
    00105   // Let's check for well-known extensions
    00106   // Not when there is a query in the URL, in any case.
    00107   // Optimization for http/https, findByURL doesn't trust extensions over http.
    00108   if ( m_strURL.query().isEmpty() && !m_strURL.protocol().startsWith("http") )
    00109   {
    00110     KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
    00111     assert( mime != 0L );
    00112     if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
    00113     {
    00114       kdDebug(1000) << "Scanfile: MIME TYPE is " << mime->name() << endl;
    00115       foundMimeType( mime->name() );
    00116       return;
    00117     }
    00118   }
    00119
    00120   if ( m_part )
    00121   {
    00122       QString proto = m_part->url().protocol();
    00123       if (proto.find("https", 0, false) == 0) {
    00124           m_args.metaData().insert("main_frame_request", "TRUE" );
    00125           m_args.metaData().insert("ssl_was_in_use", "TRUE" );
    00126           m_args.metaData().insert("ssl_activate_warnings", "TRUE" );
    00127       } else if (proto.find("http", 0, false) == 0) {
    00128           m_args.metaData().insert("ssl_activate_warnings", "TRUE" );
    00129           m_args.metaData().insert("ssl_was_in_use", "FALSE" );
    00130       }
    00131   }
    00132
    00133   KIO::TransferJob *job;
    00134   if ( m_args.doPost() && m_strURL.protocol().startsWith("http"))
    00135   {
    00136       job = KIO::http_post( m_strURL, m_args.postData, false );
    00137       job->addMetaData( "content-type", m_args.contentType() );
    00138   }
    00139   else
    00140       job = KIO::get(m_strURL, m_args.reload, false);
    00141
    00142   if ( m_bRemoveReferrer )
    00143      m_args.metaData().remove("referrer");
    00144
    00145   job->addMetaData( m_args.metaData() );
    00146   job->setWindow( m_window );
    00147   connect( job, SIGNAL( result( KIO::Job *)),
    00148            this, SLOT( slotBrowserScanFinished(KIO::Job *)));
    00149   connect( job, SIGNAL( mimetype( KIO::Job *, const QString &)),
    00150            this, SLOT( slotBrowserMimetype(KIO::Job *, const QString &)));
    00151   m_job = job;
    00152 }
    00153
    00154 void BrowserRun::slotBrowserScanFinished(KIO::Job *job)
    00155 {
    00156   kdDebug(1000) << "BrowserRun::slotBrowserScanFinished" << endl;
    00157   if ( job->error() == KIO::ERR_IS_DIRECTORY )
    00158   {
    00159       // It is in fact a directory. This happens when HTTP redirects to FTP.
    00160       // Due to the "protocol doesn't support listing" code in BrowserRun, we
    00161       // assumed it was a file.
    00162       kdDebug(1000) << "It is in fact a directory!" << endl;
    00163       // Update our URL in case of a redirection
    00164       m_strURL = static_cast<KIO::TransferJob *>(job)->url();
    00165       m_job = 0;
    00166       foundMimeType( "inode/directory" );
    00167   }
    00168   else
    00169   {
    00170       if ( job->error() )
    00171           handleError( job );
    00172       else
    00173           KRun::slotScanFinished(job);
    00174   }
    00175 }
    00176
    00177 void BrowserRun::slotBrowserMimetype( KIO::Job *_job, const QString &type )
    00178 {
    00179   Q_ASSERT( _job == m_job );
    00180   KIO::TransferJob *job = (KIO::TransferJob *) m_job;
    00181   // Update our URL in case of a redirection
    00182   //kdDebug(1000) << "old URL=" << m_strURL.url() << endl;
    00183   //kdDebug(1000) << "new URL=" << job->url().url() << endl;
    00184   m_strURL = job->url();
    00185   kdDebug(1000) << "slotBrowserMimetype: found " << type << " for " << m_strURL.prettyURL() << endl;
    00186
    00187   m_suggestedFilename = job->queryMetaData("content-disposition");
    00188   //kdDebug(1000) << "m_suggestedFilename=" << m_suggestedFilename << endl;
    00189
    00190   // Make a copy to avoid a dead reference
    00191   QString _type = type;
    00192   job->putOnHold();
    00193   m_job = 0;
    00194
    00195   foundMimeType( _type );
    00196 }
    00197
    00198 BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable( const QString& _mimeType )
    00199 {
    00200     QString mimeType( _mimeType );
    00201     Q_ASSERT( !m_bFinished ); // only come here if the mimetype couldn't be embedded
    00202     // Support for saving remote files.
    00203     if ( mimeType != "inode/directory" && // dirs can't be saved
    00204          !m_strURL.isLocalFile() )
    00205     {
    00206         if ( isTextExecutable(mimeType) )
    00207             mimeType = QString::fromLatin1("text/plain"); // view, don't execute
    00208         kdDebug(1000) << "BrowserRun: ask for saving" << endl;
    00209         KService::Ptr offer = KServiceTypeProfile::preferredService(mimeType, "Application");
    00210         // ... -> ask whether to save
    00211         KParts::BrowserRun::AskSaveResult res = askSave( m_strURL, offer, mimeType, m_suggestedFilename );
    00212         if ( res == KParts::BrowserRun::Save ) {
    00213             save( m_strURL, m_suggestedFilename );
    00214             kdDebug(1000) << "BrowserRun::handleNonEmbeddable: Save: returning Handled" << endl;
    00215             m_bFinished = true;
    00216             return Handled;
    00217         }
    00218         else if ( res == KParts::BrowserRun::Cancel ) {
    00219             // saving done or canceled
    00220             kdDebug(1000) << "BrowserRun::handleNonEmbeddable: Cancel: returning Handled" << endl;
    00221             m_bFinished = true;
    00222             return Handled;
    00223         }
    00224         else // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled)
    00225         {
    00226             // If we were in a POST, we can't just pass a URL to an external application.
    00227             // We must save the data to a tempfile first.
    00228             if ( m_args.doPost() )
    00229             {
    00230                 kdDebug(1000) << "BrowserRun: request comes from a POST, can't pass a URL to another app, need to save" << endl;
    00231                 m_sMimeType = mimeType;
    00232                 QString extension;
    00233                 QString fileName = m_suggestedFilename.isEmpty() ? m_strURL.fileName() : m_suggestedFilename;
    00234                 int extensionPos = fileName.findRev( '.' );
    00235                 if ( extensionPos != -1 )
    00236                     extension = fileName.mid( extensionPos ); // keep the '.'
    00237                 KTempFile tempFile( QString::null, extension );
    00238                 KURL destURL;
    00239                 destURL.setPath( tempFile.name() );
    00240                 KIO::Job *job = KIO::file_copy( m_strURL, destURL, 0600, true /*overwrite*/, false /*no resume*/, true /*progress info*/ );
    00241                 connect( job, SIGNAL( result( KIO::Job *)),
    00242                          this, SLOT( slotCopyToTempFileResult(KIO::Job *)) );
    00243                 return Delayed; // We'll continue after the job has finished
    00244             }
    00245         }
    00246     }
    00247
    00248     // Check if running is allowed
    00249     if ( !m_bTrustedSource && // ... and untrusted source...
    00250          !allowExecution( mimeType, m_strURL ) ) // ...and the user said no (for executables etc.)
    00251     {
    00252         m_bFinished = true;
    00253         return Handled;
    00254     }
    00255
    00256     KIO::SimpleJob::removeOnHold(); // Kill any slave that was put on hold.
    00257     return NotHandled;
    00258 }
    00259
    00260 //static
    00261 bool BrowserRun::allowExecution( const QString &serviceType, const KURL &url )
    00262 {
    00263     if ( !isExecutable( serviceType ) )
    00264       return true;
    00265
    00266     if ( !url.isLocalFile() ) // Don't permit to execute remote files
    00267         return false;
    00268
    00269     return ( KMessageBox::warningYesNo( 0, i18n( "Do you really want to execute '%1'? " ).arg( url.prettyURL() ) ) == KMessageBox::Yes );
    00270 }
    00271
    00272 //static
    00273 BrowserRun::AskSaveResult BrowserRun::askSave( const KURL & url, KService::Ptr offer, const QString& mimeType, const QString & suggestedFilename )
    00274 {
    00275     QString surl = KStringHandler::csqueeze( url.prettyURL() );
    00276     QString question;
    00277     if ( suggestedFilename.isEmpty() )
    00278     {
    00279         question = (offer && !offer->name().isEmpty())
    00280                    ? i18n("Open '%1' using '%2'?").arg(surl).arg(offer->name())
    00281                    : i18n("Open '%1'?").arg(surl);
    00282     } else {
    00283         question = (offer && !offer->name().isEmpty())
    00284                    ? i18n("Open '%1' (%2) using '%3'?").
    00285                      arg( surl ).arg(suggestedFilename).arg(offer->name())
    00286                    : i18n("Open '%1' (%2)?").arg( surl ).arg(suggestedFilename);
    00287     }
    00288     int choice = KMessageBox::questionYesNoCancel(
    00289         0L, question, QString::null,
    00290         KStdGuiItem::saveAs(), i18n("&Open"),
    00291         QString::fromLatin1("askSave")+ mimeType ); // dontAskAgainName
    00292     return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel );
    00293 }
    00294 // Default implementation, overriden in KHTMLRun
    00295 void BrowserRun::save( const KURL & url, const QString & suggestedFilename )
    00296 {
    00297     simpleSave( url, suggestedFilename );
    00298 }
    00299
    00300 // static
    00301 void BrowserRun::simpleSave( const KURL & url, const QString & suggestedFilename )
    00302 {
    00303     // DownloadManager <-> konqueror integration
    00304     // find if the integration is enabled
    00305     // the empty key  means no integration
    00306     KConfig cfg("konquerorrc", false, false);
    00307     cfg.setGroup("HTML Settings");
    00308     QString downloadManger = cfg.readPathEntry("DownloadManager");
    00309     if (!downloadManger.isEmpty())
    00310     {
    00311         // then find the download manager location
    00312         kdDebug(1000) << "Using: "<<downloadManger <<" as Download Manager" <<endl;
    00313         QString cmd=KStandardDirs::findExe(downloadManger);
    00314         if (cmd.isEmpty())
    00315         {
    00316             QString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ").arg(downloadManger);
    00317             QString errMsgEx= i18n("Try to reinstall it  \n\nThe integration with Konqueror will be disabled!");
    00318             KMessageBox::detailedSorry(0,errMsg,errMsgEx);
    00319             cfg.writeEntry("DownloadManager",QString::null);
    00320             cfg.sync ();
    00321         }
    00322         else
    00323         {
    00324             // ### suggestedFilename not taken into account. Fix this (and
    00325             // the duplicated code) with shiny new KDownload class for 3.2
    00326             // (pfeiffer)
    00327             // Until the shiny new class comes about, send the suggestedFilename
    00328             // along with the actual URL to download. (DA)
    00329             cmd += " " + KProcess::quote(url.url()) + " " + KProcess::quote(suggestedFilename);
    00330             kdDebug(1000) << "Calling command  " << cmd << endl;
    00331             // slave is already on hold (slotBrowserMimetype())
    00332             KIO::Scheduler::publishSlaveOnHold();
    00333             KRun::runCommand(cmd);
    00334             return;
    00335         }
    00336     }
    00337
    00338     // no download manager available, let's do it ourself
    00339     KFileDialog *dlg = new KFileDialog( QString::null, QString::null /*all files*/,
    00340                                         0L , "filedialog", true );
    00341     dlg->setOperationMode( KFileDialog::Saving );
    00342     dlg->setCaption(i18n("Save As"));
    00343
    00344     dlg->setSelection( suggestedFilename.isEmpty() ? url.fileName() : suggestedFilename );
    00345     if ( dlg->exec() )
    00346     {
    00347         KURL destURL( dlg->selectedURL() );
    00348         if ( !destURL.isMalformed() )
    00349         {
    00350             KIO::Job *job = KIO::copy( url, destURL );
    00351             job->setAutoErrorHandlingEnabled( true );
    00352         }
    00353     }
    00354     delete dlg;
    00355 }
    00356
    00357 void BrowserRun::slotStatResult( KIO::Job *job )
    00358 {
    00359     if ( job->error() ) {
    00360         kdDebug(1000) << "BrowserRun::slotStatResult : " << job->errorString() << endl;
    00361         handleError( job );
    00362     } else
    00363         KRun::slotStatResult( job );
    00364 }
    00365
    00366 void BrowserRun::handleError( KIO::Job * job )
    00367 {
    00368     if ( !job ) { // Shouldn't happen, see docu.
    00369         kdWarning(1000) << "BrowserRun::handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog << endl;
    00370         return;
    00371     }
    00372
    00373     // Reuse code in KRun, to benefit from d->m_showingError etc.
    00374     // KHTMLRun and KonqRun reimplement handleError anyway.
    00375     KRun::slotStatResult( job );
    00376 }
    00377
    00378 void BrowserRun::slotCopyToTempFileResult(KIO::Job *job)
    00379 {
    00380     if ( job->error() ) {
    00381         job->showErrorDialog( m_window );
    00382     } else {
    00383         // Same as KRun::foundMimeType but with a different URL
    00384         (void) (KRun::runURL( static_cast<KIO::FileCopyJob *>(job)->destURL(), m_sMimeType ));
    00385     }
    00386     m_bFault = true; // see above
    00387     m_bFinished = true;
    00388     m_timer.start( 0, true );
    00389 }
    00390
    00391 bool BrowserRun::isTextExecutable( const QString &serviceType )
    00392 {
    00393     return ( serviceType == "application/x-desktop" ||
    00394              serviceType == "application/x-shellscript" );
    00395 }
    00396
    00397 bool BrowserRun::isExecutable( const QString &serviceType )
    00398 {
    00399     return ( serviceType == "application/x-desktop" ||
    00400              serviceType == "application/x-executable" ||
    00401              serviceType == "application/x-msdos-program" ||
    00402              serviceType == "application/x-shellscript" );
    00403 }
    00404
    00405 bool BrowserRun::hideErrorDialog() const
    00406 {
    00407     return d->m_bHideErrorDialog;
    00408 }
    00409
    00410 #include "browserrun.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:26:50 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001