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, 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 ? i18n("Open '%1' using '%2'?").
00280                    arg( surl ).arg(offer->name())
00281                    : i18n("Open '%1'?").arg( surl );
00282     } else {
00283         question = offer ? i18n("Open '%1' (%2) using '%3'?").
00284                    arg( surl ).arg(suggestedFilename).arg(offer->name())
00285                    : i18n("Open '%1' (%2)?").arg( surl ).arg(suggestedFilename);
00286     }
00287     int choice = KMessageBox::questionYesNoCancel(
00288         0L, question, QString::null,
00289         KStdGuiItem::saveAs(), i18n("&Open"),
00290         QString::fromLatin1("askSave")+ mimeType ); // dontAskAgainName
00291     return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel );
00292 }
00293 // Default implementation, overriden in KHTMLRun
00294 void BrowserRun::save( const KURL & url, const QString & suggestedFilename )
00295 {
00296     simpleSave( url, suggestedFilename );
00297 }
00298 
00299 // static
00300 void BrowserRun::simpleSave( const KURL & url, const QString & suggestedFilename )
00301 {
00302     // DownloadManager <-> konqueror integration
00303     // find if the integration is enabled
00304     // the empty key  means no integration
00305     KConfig cfg("konquerorrc", false, false);
00306     cfg.setGroup("HTML Settings");
00307     QString downloadManger = cfg.readEntry("DownloadManager");
00308     if (!downloadManger.isEmpty())
00309     {
00310         // then find the download manager location
00311         kdDebug(1000) << "Using: "<<downloadManger <<" as Download Manager" <<endl;
00312         QString cmd=KStandardDirs::findExe(downloadManger);
00313         if (cmd.isEmpty())
00314         {
00315             QString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ").arg(downloadManger);
00316             QString errMsgEx= i18n("Try to reinstall it  \n\nThe integration with Konqueror will be disabled!");
00317             KMessageBox::detailedSorry(0,errMsg,errMsgEx);
00318             cfg.writeEntry("DownloadManager",QString::null);
00319             cfg.sync ();
00320         }
00321         else
00322         {
00323             // ### suggestedFilename not taken into account. Fix this (and
00324             // the duplicated code) with shiny new KDownload class for 3.2
00325             // (pfeiffer)
00326             cmd += " " + KProcess::quote(url.url());
00327             kdDebug(1000) << "Calling command  "<<cmd<<endl;
00328             // slave is already on hold (slotBrowserMimetype())
00329             KIO::Scheduler::publishSlaveOnHold();
00330             KRun::runCommand(cmd);
00331             return;
00332         }
00333     }
00334 
00335     // no download manager available, let's do it ourself
00336     KFileDialog *dlg = new KFileDialog( QString::null, QString::null /*all files*/,
00337                                         0L , "filedialog", true );
00338     dlg->setOperationMode( KFileDialog::Saving );
00339     dlg->setCaption(i18n("Save As"));
00340 
00341     dlg->setSelection( suggestedFilename.isEmpty() ? url.fileName() : suggestedFilename );
00342     if ( dlg->exec() )
00343     {
00344         KURL destURL( dlg->selectedURL() );
00345         if ( !destURL.isMalformed() )
00346         {
00347             KIO::Job *job = KIO::copy( url, destURL );
00348         job->setAutoErrorHandlingEnabled( true );
00349         }
00350     }
00351     delete dlg;
00352 }
00353 
00354 void BrowserRun::slotStatResult( KIO::Job *job )
00355 {
00356     if ( job->error() ) {
00357         kdDebug(1000) << "BrowserRun::slotStatResult : " << job->errorString() << endl;
00358         handleError( job );
00359     } else
00360         KRun::slotStatResult( job );
00361 }
00362 
00363 void BrowserRun::handleError( KIO::Job * job )
00364 {
00365     if ( !job ) { // Shouldn't happen, see docu.
00366         kdWarning(1000) << "BrowserRun::handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog << endl;
00367         return;
00368     }
00369 
00370     // Reuse code in KRun, to benefit from d->m_showingError etc.
00371     // KHTMLRun and KonqRun reimplement handleError anyway.
00372     KRun::slotStatResult( job );
00373 }
00374 
00375 void BrowserRun::slotCopyToTempFileResult(KIO::Job *job)
00376 {
00377     if ( job->error() ) {
00378         job->showErrorDialog( m_window );
00379     } else {
00380         // Same as KRun::foundMimeType but with a different URL
00381         (void) (KRun::runURL( static_cast<KIO::FileCopyJob *>(job)->destURL(), m_sMimeType ));
00382     }
00383     m_bFault = true; // see above
00384     m_bFinished = true;
00385     m_timer.start( 0, true );
00386 }
00387 
00388 bool BrowserRun::isTextExecutable( const QString &serviceType )
00389 {
00390     return ( serviceType == "application/x-desktop" ||
00391              serviceType == "application/x-shellscript" );
00392 }
00393 
00394 bool BrowserRun::isExecutable( const QString &serviceType )
00395 {
00396     return ( serviceType == "application/x-desktop" ||
00397              serviceType == "application/x-executable" ||
00398              serviceType == "application/x-msdos-program" ||
00399              serviceType == "application/x-shellscript" );
00400 }
00401 
00402 bool BrowserRun::hideErrorDialog() const
00403 {
00404     return d->m_bHideErrorDialog;
00405 }
00406 
00407 #include "browserrun.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:45 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001