00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 #include <assert.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024 
00025 #include "krun.h"
00026 #include "kuserprofile.h"
00027 #include "kmimetype.h"
00028 #include "kmimemagic.h"
00029 #include "kio/job.h"
00030 #include "kio/global.h"
00031 #include "kio/scheduler.h"
00032 #include "kfile/kopenwith.h"
00033 #include "kfile/krecentdocument.h"
00034 
00035 #include <kdatastream.h>
00036 #include <kmessageboxwrapper.h>
00037 #include <kurl.h>
00038 #include <kapplication.h>
00039 #include <kdebug.h>
00040 #include <klocale.h>
00041 #include <kprotocolinfo.h>
00042 #include <kstandarddirs.h>
00043 #include <kprocess.h>
00044 #include <dcopclient.h>
00045 #include <qfile.h>
00046 #include <qtextstream.h>
00047 #include <qdatetime.h>
00048 #include <qregexp.h>
00049 #include <kwin.h>
00050 #include <kdesktopfile.h>
00051 #include <kstartupinfo.h>
00052 #include <kmacroexpander.h>
00053 #include <kshell.h>
00054 #include <typeinfo>
00055 #include <qwidget.h>
00056 #include <qguardedptr.h>
00057 
00058 #ifdef Q_WS_X11
00059 #include <X11/Xlib.h>
00060 #include <fixx11h.h>
00061 extern Time qt_x_user_time;
00062 #endif
00063 
00064 class KRun::KRunPrivate
00065 {
00066 public:
00067     KRunPrivate() { m_showingError = false; }
00068 
00069     bool m_showingError;
00070     bool m_runExecutables;
00071 
00072     QString m_preferredService;
00073     QGuardedPtr <QWidget> m_window;
00074 };
00075 
00076 pid_t KRun::runURL( const KURL& u, const QString& _mimetype )
00077 {
00078     return runURL( u, _mimetype, false, true );
00079 }
00080 
00081 pid_t KRun::runURL( const KURL& u, const QString& _mimetype, bool tempFile )
00082 {
00083     return runURL( u, _mimetype, tempFile, true );
00084 }
00085 
00086 
00087 pid_t KRun::runURL( const KURL& u, const QString& _mimetype, bool tempFile, bool runExecutables )
00088 {
00089   bool noRun = false;
00090   bool noAuth = false;
00091   if ( _mimetype == "inode/directory-locked" )
00092   {
00093     KMessageBoxWrapper::error( 0L,
00094             i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>").arg(u.htmlURL()) );
00095     return 0;
00096   }
00097   else if ( _mimetype == "application/x-desktop" )
00098   {
00099     if ( u.isLocalFile() && runExecutables)
00100       return KDEDesktopMimeType::run( u, true );
00101   }
00102   else if ( _mimetype == "application/x-executable"  ||
00103             _mimetype == "application/x-shellscript")
00104   {
00105     if ( u.isLocalFile() && runExecutables)
00106     {
00107       if (kapp->authorize("shell_access"))
00108       {
00109         QString path = u.path();
00110         shellQuote( path );
00111         return (KRun::runCommand(path)); 
00112         
00113       }
00114       else
00115       {
00116         noAuth = true;
00117       }
00118     }
00119     else if (_mimetype == "application/x-executable")
00120       noRun = true;
00121   }
00122   else if ( isExecutable(_mimetype) )
00123   {
00124     if (!runExecutables)
00125       noRun = true;
00126 
00127     if (!kapp->authorize("shell_access"))
00128       noAuth = true;
00129   }
00130 
00131   if ( noRun )
00132   {
00133     KMessageBox::sorry( 0L,
00134         i18n("<qt>The file <b>%1</b> is an executable program. "
00135              "For safety it will not be started.</qt>").arg(u.htmlURL()));
00136     return 0;
00137   }
00138   if ( noAuth )
00139   {
00140     KMessageBoxWrapper::error( 0L,
00141         i18n("<qt>You do not have permission to run <b>%1</b>.</qt>").arg(u.htmlURL()) );
00142     return 0;
00143   }
00144 
00145   KURL::List lst;
00146   lst.append( u );
00147 
00148   static const QString& app_str = KGlobal::staticQString("Application");
00149 
00150   KService::Ptr offer = KServiceTypeProfile::preferredService( _mimetype, app_str );
00151 
00152   if ( !offer )
00153   {
00154     
00155     
00156     
00157     return displayOpenWithDialog( lst, tempFile );
00158   }
00159 
00160   return KRun::run( *offer, lst, tempFile );
00161 }
00162 
00163 bool KRun::displayOpenWithDialog( const KURL::List& lst )
00164 {
00165     return displayOpenWithDialog( lst, false );
00166 }
00167 
00168 bool KRun::displayOpenWithDialog( const KURL::List& lst, bool tempFiles )
00169 {
00170     if (kapp && !kapp->authorizeKAction("openwith"))
00171     {
00172        
00173        KMessageBox::sorry(0L, i18n("You are not authorized to execute this file."));
00174        return false;
00175     }
00176 
00177     KOpenWithDlg l( lst, i18n("Open with:"), QString::null, 0L );
00178     if ( l.exec() )
00179     {
00180       KService::Ptr service = l.service();
00181       if ( !!service )
00182         return KRun::run( *service, lst, tempFiles );
00183 
00184       kdDebug(250) << "No service set, running " << l.text() << endl;
00185       return KRun::run( l.text(), lst ); 
00186     }
00187     return false;
00188 }
00189 
00190 void KRun::shellQuote( QString &_str )
00191 {
00192     
00193     if (_str.isEmpty()) 
00194         return;
00195     QChar q('\'');
00196     _str.replace(q, "'\\''").prepend(q).append(q);
00197 }
00198 
00199 
00200 class KRunMX1 : public KMacroExpanderBase {
00201 public:
00202     KRunMX1( const KService &_service ) :
00203         KMacroExpanderBase( '%' ), hasUrls( false ), hasSpec( false ), service( _service ) {}
00204     bool hasUrls:1, hasSpec:1;
00205 
00206 protected:
00207     virtual int expandEscapedMacro( const QString &str, uint pos, QStringList &ret );
00208 
00209 private:
00210     const KService &service;
00211 };
00212 
00213 int
00214 KRunMX1::expandEscapedMacro( const QString &str, uint pos, QStringList &ret )
00215 {
00216    uint option = str[pos + 1];
00217    switch( option ) {
00218    case 'c':
00219       ret << service.name().replace( '%', "%%" );
00220       break;
00221    case 'k':
00222       ret << service.desktopEntryPath().replace( '%', "%%" );
00223       break;
00224    case 'i':
00225       ret << "-icon" << service.icon().replace( '%', "%%" );
00226       break;
00227    case 'm':
00228       ret << "-miniicon" << service.icon().replace( '%', "%%" );
00229       break;
00230    case 'u':
00231    case 'U':
00232       hasUrls = true;
00233       
00234    case 'f':
00235    case 'F':
00236    case 'n':
00237    case 'N':
00238    case 'd':
00239    case 'D':
00240    case 'v':
00241       hasSpec = true;
00242       
00243    default:
00244       return -2; 
00245    }
00246    return 2;
00247 }
00248 
00249 class KRunMX2 : public KMacroExpanderBase {
00250 public:
00251     KRunMX2( const KURL::List &_urls ) :
00252         KMacroExpanderBase( '%' ), ignFile( false ), urls( _urls ) {}
00253     bool ignFile:1;
00254 
00255 protected:
00256     virtual int expandEscapedMacro( const QString &str, uint pos, QStringList &ret );
00257 
00258 private:
00259     void subst( int option, const KURL &url, QStringList &ret );
00260 
00261     const KURL::List &urls;
00262 };
00263 
00264 void
00265 KRunMX2::subst( int option, const KURL &url, QStringList &ret )
00266 {
00267    switch( option ) {
00268    case 'u':
00269       ret << (url.isLocalFile() ? url.path() : url.url());
00270       break;
00271    case 'd':
00272       ret << url.directory();
00273       break;
00274    case 'f':
00275       ret << url.path();
00276       break;
00277    case 'n':
00278       ret << url.fileName();
00279       break;
00280    case 'v':
00281       if (url.isLocalFile() && QFile::exists( url.path() ) )
00282           ret << KDesktopFile( url.path(), true ).readEntry( "Dev" );
00283       break;
00284    }
00285    return;
00286 }
00287 
00288 int
00289 KRunMX2::expandEscapedMacro( const QString &str, uint pos, QStringList &ret )
00290 {
00291    uint option = str[pos + 1];
00292    switch( option ) {
00293    case 'f':
00294    case 'u':
00295    case 'n':
00296    case 'd':
00297    case 'v':
00298       if( urls.isEmpty() ) {
00299          if (!ignFile)
00300             kdWarning() << "KRun::processDesktopExec: No URLs supplied to single-URL service " << str << endl;
00301       } else if( urls.count() > 1 )
00302           kdWarning() << "KRun::processDesktopExec: " << urls.count() << " URLs supplied to single-URL service " << str << endl;
00303       else
00304          subst( option, urls.first(), ret );
00305       break;
00306    case 'F':
00307    case 'U':
00308    case 'N':
00309    case 'D':
00310       option += 'a' - 'A';
00311       for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it )
00312          subst( option, *it, ret );
00313       break;
00314    case '%':
00315       ret = "%";
00316       break;
00317    default:
00318       return -2; 
00319    }
00320    return 2;
00321 }
00322 
00323 
00324 QStringList KRun::processDesktopExec(const KService &_service, const KURL::List& _urls, bool has_shell) {
00325     return processDesktopExec( _service, _urls, has_shell, false );
00326 }
00327 
00328 QStringList KRun::processDesktopExec(const KService &_service, const KURL::List& _urls, bool has_shell , bool tempFiles)
00329 {
00330   QString exec = _service.exec();
00331   QStringList result;
00332 
00333   KRunMX1 mx1( _service );
00334   KRunMX2 mx2( _urls );
00335 
00337   QRegExp re("^\\s*(?:/bin/)?sh\\s+-c\\s+(.*)$");
00338   if (!re.search( exec )) {
00339     exec = re.cap( 1 ).stripWhiteSpace();
00340     for (uint pos = 0; pos < exec.length(); ) {
00341       QChar c = exec.unicode()[pos];
00342       if (c != '\'' && c != '"')
00343         goto synerr; 
00344       int pos2 = exec.find( c, pos + 1 ) - 1;
00345       if (pos2 < 0)
00346         goto synerr; 
00347       memcpy( (void *)(exec.unicode() + pos), exec.unicode() + pos + 1, (pos2 - pos) * sizeof(QChar));
00348       pos = pos2;
00349       exec.remove( pos, 2 );
00350     }
00351   }
00352 
00353   if( !mx1.expandMacrosShellQuote( exec ) )
00354     goto synerr; 
00355 
00356   
00357 
00358   
00359   if( tempFiles ) {
00360     result << "kioexec" << "--tempfiles" << exec;
00361     result += _urls.toStringList();
00362     if (has_shell)
00363       result = KShell::joinArgs( result );
00364     return result;
00365   }
00366 
00367   
00368   if( !mx1.hasUrls ) {
00369     for( KURL::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it )
00370       if ( !(*it).isLocalFile() ) {
00371         
00372         result << "kioexec" << exec;
00373         result += _urls.toStringList();
00374         if (has_shell)
00375           result = KShell::joinArgs( result );
00376         return result;
00377       }
00378   }
00379 
00380   
00381   
00382   
00383   if( !mx1.hasSpec ) {
00384     exec += " %f";
00385     mx2.ignFile = true;
00386   }
00387 
00388   mx2.expandMacrosShellQuote( exec ); 
00389 
00390 
00391 
00392 
00393 
00394 
00395 
00396 
00397 
00398 
00399 
00400 
00401 
00402 
00403 
00404 
00405 
00406 
00407 
00408 
00409 
00410 
00411 
00412 
00413 
00414 
00415 
00416 
00417   if (_service.terminal()) {
00418     KConfigGroupSaver gs(KGlobal::config(), "General");
00419     QString terminal = KGlobal::config()->readPathEntry("TerminalApplication", "konsole");
00420     if (terminal == "konsole")
00421       terminal += " -caption=%c %i %m";
00422     terminal += " ";
00423     terminal += _service.terminalOptions();
00424     if( !mx1.expandMacrosShellQuote( terminal ) ) {
00425       kdWarning() << "KRun: syntax error in command `" << terminal << "', service `" << _service.name() << "'" << endl;
00426       return QStringList();
00427     }
00428     mx2.expandMacrosShellQuote( terminal );
00429     if (has_shell)
00430       result << terminal;
00431     else
00432       result = KShell::splitArgs( terminal ); 
00433     result << "-e";
00434   }
00435 
00436   int err;
00437   if (_service.substituteUid()) {
00438     if (_service.terminal())
00439       result << "su";
00440     else
00441       result << "kdesu" << "-u";
00442     result << _service.username() << "-c";
00443     KShell::splitArgs(exec, KShell::AbortOnMeta, &err);
00444     if (err == KShell::FoundMeta) {
00445       shellQuote( exec );
00446       exec.prepend( "/bin/sh -c " );
00447     } else if (err != KShell::NoError)
00448       goto synerr;
00449     if (has_shell)
00450       shellQuote( exec );
00451     result << exec;
00452   } else {
00453     if (has_shell) {
00454       if (_service.terminal()) {
00455         KShell::splitArgs(exec, KShell::AbortOnMeta, &err);
00456         if (err == KShell::FoundMeta) {
00457           shellQuote( exec );
00458           exec.prepend( "/bin/sh -c " );
00459         } else if (err != KShell::NoError)
00460           goto synerr;
00461       }
00462       result << exec;
00463     } else {
00464       result += KShell::splitArgs(exec, KShell::AbortOnMeta, &err);
00465       if (err == KShell::FoundMeta)
00466         result << "/bin/sh" << "-c" << exec;
00467       else if (err != KShell::NoError)
00468         goto synerr;
00469     }
00470   }
00471 
00472   return result;
00473 
00474  synerr:
00475   kdWarning() << "KRun: syntax error in command `" << _service.exec() << "', service `" << _service.name() << "'" << endl;
00476   return QStringList();
00477 }
00478 
00479 
00480 QString KRun::binaryName( const QString & execLine, bool removePath )
00481 {
00482   
00483   QStringList args = KShell::splitArgs( execLine );
00484   for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
00485     if (!(*it).contains('='))
00486       
00487       return removePath ? (*it).mid((*it).findRev('/') + 1) : *it;
00488   return QString::null;
00489 }
00490 
00491 static pid_t runCommandInternal( KProcess* proc, const KService* service, const QString& binName,
00492     const QString &execName, const QString & iconName )
00493 {
00494   if ( service && !KDesktopFile::isAuthorizedDesktopFile( service->desktopEntryPath() ))
00495   {
00496      KMessageBox::sorry(0, i18n("You are not authorized to execute this file."));
00497      return 0;
00498   }
00499   QString bin = KRun::binaryName( binName, true );
00500 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
00501   bool startup_notify = false;
00502   QCString wmclass;
00503   KStartupInfoId id;
00504   if( service && service->property( "StartupNotify" ).isValid())
00505   {
00506       startup_notify = service->property( "StartupNotify" ).toBool();
00507       wmclass = service->property( "StartupWMClass" ).toString().latin1();
00508   }
00509   else if( service && service->property( "X-KDE-StartupNotify" ).isValid())
00510   {
00511       startup_notify = service->property( "X-KDE-StartupNotify" ).toBool();
00512       wmclass = service->property( "X-KDE-WMClass" ).toString().latin1();
00513   }
00514   else 
00515   {
00516       if( service && service->type() == "Application" )
00517       {
00518           startup_notify = true; 
00519           wmclass = "0";         
00520       }
00521   }
00522   if( startup_notify )
00523   {
00524       id.initId();
00525       id.setupStartupEnv();
00526       KStartupInfoData data;
00527       data.setHostname();
00528       data.setBin( bin );
00529       data.setName( execName.isEmpty() ? service->name() : execName );
00530       data.setDescription( i18n( "Launching %1" ).arg( data.name()));
00531       data.setIcon( iconName.isEmpty() ? service->icon() : iconName );
00532 #ifdef Q_WS_X11
00533       data.setTimestamp( qt_x_user_time );
00534 #endif
00535       if( !wmclass.isEmpty())
00536           data.setWMClass( wmclass );
00537       data.setDesktop( KWin::currentDesktop());
00538       KStartupInfo::sendStartup( id, data );
00539   }
00540   pid_t pid = KProcessRunner::run( proc, binName, id );
00541   if( startup_notify && pid )
00542   {
00543       KStartupInfoData data;
00544       data.addPid( pid );
00545       KStartupInfo::sendChange( id, data );
00546       KStartupInfo::resetStartupEnv();
00547   }
00548   return pid;
00549 #else
00550   Q_UNUSED( execName );
00551   Q_UNUSED( iconName );
00552   return KProcessRunner::run( proc, bin );
00553 #endif
00554 }
00555 
00556 static pid_t runTempService( const KService& _service, const KURL::List& _urls, bool tempFiles )
00557 {
00558   if (!_urls.isEmpty()) {
00559     kdDebug(7010) << "runTempService: first url " << _urls.first().url() << endl;
00560   }
00561 
00562   QStringList args;
00563   if ((_urls.count() > 1) && !_service.allowMultipleFiles())
00564   {
00565       
00566       
00567       
00568       
00569       
00570       KURL::List::ConstIterator it = _urls.begin();
00571       while(++it != _urls.end())
00572       {
00573          KURL::List singleUrl;
00574          singleUrl.append(*it);
00575          runTempService( _service, singleUrl, tempFiles );
00576       }
00577       KURL::List singleUrl;
00578       singleUrl.append(_urls.first());
00579       args = KRun::processDesktopExec(_service, singleUrl, false, tempFiles);
00580   }
00581   else
00582   {
00583       args = KRun::processDesktopExec(_service, _urls, false, tempFiles);
00584   }
00585   kdDebug(7010) << "runTempService: KProcess args=" << args << endl;
00586 
00587   KProcess * proc = new KProcess;
00588   *proc << args;
00589 
00590   if (!_service.path().isEmpty())
00591      proc->setWorkingDirectory(_service.path());
00592 
00593   return runCommandInternal( proc, &_service, _service.exec(), _service.name(), _service.icon() );
00594 }
00595 
00596 
00597 pid_t KRun::run( const KService& _service, const KURL::List& _urls )
00598 {
00599     return run( _service, _urls, false );
00600 }
00601 
00602 pid_t KRun::run( const KService& _service, const KURL::List& _urls, bool tempFiles )
00603 {
00604   if (!_service.desktopEntryPath().isEmpty() &&
00605       !KDesktopFile::isAuthorizedDesktopFile( _service.desktopEntryPath()))
00606   {
00607      KMessageBox::sorry(0, i18n("You are not authorized to execute this service."));
00608      return 0;
00609   }
00610 
00611   if ( !tempFiles )
00612   {
00613       
00614       KURL::List::ConstIterator it = _urls.begin();
00615       for(; it != _urls.end(); ++it) {
00616           
00617           KRecentDocument::add( *it, _service.desktopEntryName() );
00618       }
00619   }
00620 
00621   if ( tempFiles || _service.desktopEntryPath().isEmpty())
00622   {
00623      return runTempService(_service, _urls, tempFiles);
00624   }
00625 
00626   kdDebug(7010) << "KRun::run " << _service.desktopEntryPath() << endl;
00627 
00628   if (!_urls.isEmpty()) {
00629     kdDebug(7010) << "First url " << _urls.first().url() << endl;
00630   }
00631 
00632   QString error;
00633   int pid = 0;
00634 
00635   int i = KApplication::startServiceByDesktopPath(
00636         _service.desktopEntryPath(), _urls.toStringList(), &error, 0L, &pid
00637         );
00638 
00639   if (i != 0)
00640   {
00641      kdDebug(7010) << error << endl;
00642      KMessageBox::sorry( 0L, error );
00643      return 0;
00644   }
00645 
00646   kdDebug(7010) << "startServiceByDesktopPath worked fine" << endl;
00647   return (pid_t) pid;
00648 }
00649 
00650 
00651 pid_t KRun::run( const QString& _exec, const KURL::List& _urls, const QString& _name,
00652                 const QString& _icon, const QString&, const QString&)
00653 {
00654   KService::Ptr service = new KService(_name, _exec, _icon);
00655 
00656   return run(*service, _urls);
00657 }
00658 
00659 pid_t KRun::runCommand( QString cmd )
00660 {
00661   return KRun::runCommand( cmd, QString::null, QString::null );
00662 }
00663 
00664 pid_t KRun::runCommand( const QString& cmd, const QString &execName, const QString & iconName )
00665 {
00666   kdDebug(7010) << "runCommand " << cmd << "," << execName << endl;
00667   KProcess * proc = new KProcess;
00668   proc->setUseShell(true);
00669   *proc << cmd;
00670   KService::Ptr service = KService::serviceByDesktopName( binaryName( cmd, true ));
00671   return runCommandInternal( proc, service.data(), binaryName( cmd, false ), execName, iconName );
00672 }
00673 
00674 KRun::KRun( const KURL& url, mode_t mode, bool isLocalFile, bool showProgressInfo )
00675      :m_timer(0,"KRun::timer")
00676 {
00677   init (url, 0, mode, isLocalFile, showProgressInfo);
00678 }
00679 
00680 KRun::KRun( const KURL& url, QWidget* window, mode_t mode, bool isLocalFile,
00681             bool showProgressInfo )
00682      :m_timer(0,"KRun::timer")
00683 {
00684   init (url, window, mode, isLocalFile, showProgressInfo);
00685 }
00686 
00687 void KRun::init ( const KURL& url, QWidget* window, mode_t mode, bool isLocalFile,
00688                   bool showProgressInfo )
00689 {
00690   m_bFault = false;
00691   m_bAutoDelete = true;
00692   m_bProgressInfo = showProgressInfo;
00693   m_bFinished = false;
00694   m_job = 0L;
00695   m_strURL = url;
00696   m_bScanFile = false;
00697   m_bIsDirectory = false;
00698   m_bIsLocalFile = isLocalFile;
00699   m_mode = mode;
00700   d = new KRunPrivate;
00701   d->m_runExecutables = true;
00702   d->m_window = window;
00703 
00704   
00705   
00706   
00707   m_bInit = true;
00708   connect( &m_timer, SIGNAL( timeout() ), this, SLOT( slotTimeout() ) );
00709   m_timer.start( 0, true );
00710   kdDebug(7010) << " new KRun " << this << " " << url.prettyURL() << " timer=" << &m_timer << endl;
00711 
00712   kapp->ref();
00713 }
00714 
00715 void KRun::init()
00716 {
00717   kdDebug(7010) << "INIT called" << endl;
00718   if ( !m_strURL.isValid() )
00719   {
00720     d->m_showingError = true;
00721     KMessageBoxWrapper::error( d->m_window, i18n( "Malformed URL\n%1" ).arg( m_strURL.url() ) );
00722     d->m_showingError = false;
00723     m_bFault = true;
00724     m_bFinished = true;
00725     m_timer.start( 0, true );
00726     return;
00727   }
00728   if ( !kapp->authorizeURLAction( "open", KURL(), m_strURL))
00729   {
00730     QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, m_strURL.prettyURL());
00731     d->m_showingError = true;
00732     KMessageBoxWrapper::error( d->m_window, msg );
00733     d->m_showingError = false;
00734     m_bFault = true;
00735     m_bFinished = true;
00736     m_timer.start( 0, true );
00737     return;
00738   }
00739 
00740   if ( !m_bIsLocalFile && m_strURL.isLocalFile() )
00741 
00742     m_bIsLocalFile = true;
00743 
00744   if ( m_bIsLocalFile )
00745   {
00746     if ( m_mode == 0 )
00747     {
00748       struct stat buff;
00749       if ( stat( QFile::encodeName(m_strURL.path()), &buff ) == -1 )
00750       {
00751         d->m_showingError = true;
00752         KMessageBoxWrapper::error( d->m_window, i18n( "<qt>Unable to run the command specified. The file or folder <b>%1</b> does not exist.</qt>" ).arg( m_strURL.htmlURL() ) );
00753         d->m_showingError = false;
00754         m_bFault = true;
00755         m_bFinished = true;
00756         m_timer.start( 0, true );
00757         return;
00758       }
00759       m_mode = buff.st_mode;
00760     }
00761 
00762     KMimeType::Ptr mime = KMimeType::findByURL( m_strURL, m_mode, m_bIsLocalFile );
00763     assert( mime != 0L );
00764     kdDebug(7010) << "MIME TYPE is " << mime->name() << endl;
00765     foundMimeType( mime->name() );
00766     return;
00767   }
00768   else if ( KProtocolInfo::isHelperProtocol( m_strURL ) ) {
00769     kdDebug(7010) << "Helper protocol" << endl;
00770 
00771     KURL::List urls;
00772     urls.append( m_strURL );
00773     QString exec = KProtocolInfo::exec( m_strURL.protocol() );
00774     run( exec, urls );
00775 
00776     m_bFinished = true;
00777     
00778     m_timer.start( 0, true );
00779     return;
00780   }
00781 
00782   
00783   if ( S_ISDIR( m_mode ) )
00784   {
00785     foundMimeType( "inode/directory" );
00786     return;
00787   }
00788 
00789   
00790 
00791   if ( !KProtocolInfo::supportsListing( m_strURL ) )
00792   {
00793     
00794     
00795     scanFile();
00796     return;
00797   }
00798 
00799   kdDebug(7010) << "Testing directory (stating)" << endl;
00800 
00801   
00802   KIO::StatJob *job = KIO::stat( m_strURL, true, 0 , m_bProgressInfo );
00803   job->setWindow (d->m_window);
00804   connect( job, SIGNAL( result( KIO::Job * ) ),
00805            this, SLOT( slotStatResult( KIO::Job * ) ) );
00806   m_job = job;
00807   kdDebug(7010) << " Job " << job << " is about stating " << m_strURL.url() << endl;
00808 }
00809 
00810 KRun::~KRun()
00811 {
00812   kdDebug(7010) << "KRun::~KRun() " << this << endl;
00813   m_timer.stop();
00814   killJob();
00815   kapp->deref();
00816   kdDebug(7010) << "KRun::~KRun() done " << this << endl;
00817   delete d;
00818 }
00819 
00820 void KRun::scanFile()
00821 {
00822   kdDebug(7010) << "###### KRun::scanFile " << m_strURL.url() << endl;
00823   
00824   
00825   if ( m_strURL.query().isEmpty() )
00826   {
00827     KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
00828     assert( mime != 0L );
00829     if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
00830     {
00831       kdDebug(7010) << "Scanfile: MIME TYPE is " << mime->name() << endl;
00832       foundMimeType( mime->name() );
00833       return;
00834     }
00835   }
00836 
00837   
00838   
00839   
00840 
00841   if ( !KProtocolInfo::supportsReading( m_strURL ) )
00842   {
00843     kdError(7010) << "#### NO SUPPORT FOR READING!" << endl;
00844     m_bFault = true;
00845     m_bFinished = true;
00846     m_timer.start( 0, true );
00847     return;
00848   }
00849   kdDebug(7010) << this << " Scanning file " << m_strURL.url() << endl;
00850 
00851   KIO::TransferJob *job = KIO::get( m_strURL, false , m_bProgressInfo );
00852   job->setWindow (d->m_window);
00853   connect(job, SIGNAL( result(KIO::Job *)),
00854           this, SLOT( slotScanFinished(KIO::Job *)));
00855   connect(job, SIGNAL( mimetype(KIO::Job *, const QString &)),
00856           this, SLOT( slotScanMimeType(KIO::Job *, const QString &)));
00857   m_job = job;
00858   kdDebug(7010) << " Job " << job << " is about getting from " << m_strURL.url() << endl;
00859 }
00860 
00861 void KRun::slotTimeout()
00862 {
00863   kdDebug(7010) << this << " slotTimeout called" << endl;
00864   if ( m_bInit )
00865   {
00866     m_bInit = false;
00867     init();
00868     return;
00869   }
00870 
00871   if ( m_bFault ){
00872       emit error();
00873   }
00874   if ( m_bFinished ){
00875       emit finished();
00876   }
00877 
00878   if ( m_bScanFile )
00879   {
00880     m_bScanFile = false;
00881     scanFile();
00882     return;
00883   }
00884   else if ( m_bIsDirectory )
00885   {
00886     m_bIsDirectory = false;
00887     foundMimeType( "inode/directory" );
00888     return;
00889   }
00890 
00891   if ( m_bAutoDelete )
00892   {
00893     delete this;
00894     return;
00895   }
00896 }
00897 
00898 void KRun::slotStatResult( KIO::Job * job )
00899 {
00900   m_job = 0L;
00901   if (job->error())
00902   {
00903     d->m_showingError = true;
00904     kdError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
00905     job->showErrorDialog();
00906     
00907     d->m_showingError = false;
00908 
00909     m_bFault = true;
00910     m_bFinished = true;
00911 
00912     
00913     m_timer.start( 0, true );
00914 
00915   } else {
00916 
00917     kdDebug(7010) << "Finished" << endl;
00918     if(!dynamic_cast<KIO::StatJob*>(job))
00919         kdFatal() << "job is a " << typeid(*job).name() << " should be a StatJob" << endl;
00920 
00921     KIO::UDSEntry entry = ((KIO::StatJob*)job)->statResult();
00922     KIO::UDSEntry::ConstIterator it = entry.begin();
00923     for( ; it != entry.end(); it++ ) {
00924         if ( (*it).m_uds == KIO::UDS_FILE_TYPE )
00925         {
00926             if ( S_ISDIR( (mode_t)((*it).m_long) ) )
00927                 m_bIsDirectory = true; 
00928             else
00929                 m_bScanFile = true; 
00930             break;
00931         }
00932     }
00933     
00934     assert ( m_bScanFile || m_bIsDirectory );
00935 
00936     
00937     
00938     
00939     m_timer.start( 0, true );
00940   }
00941 }
00942 
00943 void KRun::slotScanMimeType( KIO::Job *, const QString &mimetype )
00944 {
00945   if ( mimetype.isEmpty() )
00946     kdWarning(7010) << "KRun::slotScanFinished : MimetypeJob didn't find a mimetype! Probably a kioslave bug." << endl;
00947   foundMimeType( mimetype );
00948   m_job = 0;
00949 }
00950 
00951 void KRun::slotScanFinished( KIO::Job *job )
00952 {
00953   m_job = 0;
00954   if (job->error())
00955   {
00956     d->m_showingError = true;
00957     kdError(7010) << this << " ERROR (stat) : " << job->error() << " " << job->errorString() << endl;
00958     job->showErrorDialog();
00959     
00960     d->m_showingError = false;
00961 
00962     m_bFault = true;
00963     m_bFinished = true;
00964 
00965     
00966     m_timer.start( 0, true );
00967   }
00968 }
00969 
00970 void KRun::foundMimeType( const QString& type )
00971 {
00972   kdDebug(7010) << "Resulting mime type is " << type << endl;
00973 
00974 
00975 
00976 
00977 
00978 
00979 
00980 
00981 
00982 
00983 
00984 
00985 
00986 
00987 
00988 
00989 
00990 
00991 
00992 
00993 
00994 
00995 
00996 
00997 
00998 
00999 
01000 
01001 
01002 
01003 
01004 
01005 
01006 
01007 
01008 
01009 
01010 
01011 
01012 
01013 
01014 
01015 
01016 
01017 
01018 
01019 
01020 
01021 
01022 
01023 
01024 
01025 
01026   if (m_job && m_job->inherits("KIO::TransferJob"))
01027   {
01028      KIO::TransferJob *job = static_cast<KIO::TransferJob *>(m_job);
01029      job->putOnHold();
01030      KIO::Scheduler::publishSlaveOnHold();
01031      m_job = 0;
01032   }
01033 
01034   Q_ASSERT( !m_bFinished );
01035 
01036   
01037   if ( !d->m_preferredService.isEmpty() ) {
01038       kdDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService << endl;
01039       KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
01040       if ( serv && serv->hasServiceType( type ) )
01041       {
01042           KURL::List lst;
01043           lst.append( m_strURL );
01044           m_bFinished = KRun::run( *serv, lst );
01049       }
01050   }
01051 
01052   if (!m_bFinished && KRun::runURL( m_strURL, type, false, d->m_runExecutables )){
01053     m_bFinished = true;
01054   }
01055   else{
01056     m_bFinished = true;
01057      m_bFault = true;
01058   }
01059 
01060   m_timer.start( 0, true );
01061 }
01062 
01063 void KRun::killJob()
01064 {
01065   if ( m_job )
01066   {
01067     kdDebug(7010) << "KRun::killJob run=" << this << " m_job=" << m_job << endl;
01068     m_job->kill();
01069     m_job = 0L;
01070   }
01071 }
01072 
01073 void KRun::abort()
01074 {
01075   kdDebug(7010) << "KRun::abort " << this << " m_showingError=" << d->m_showingError << endl;
01076   killJob();
01077   
01078   
01079   if ( d->m_showingError )
01080     return;
01081   m_bFault = true;
01082   m_bFinished = true;
01083   m_bInit = false;
01084   m_bScanFile = false;
01085 
01086   
01087   m_timer.start( 0, true );
01088 }
01089 
01090 void KRun::setPreferredService( const QString& desktopEntryName )
01091 {
01092     d->m_preferredService = desktopEntryName;
01093 }
01094 
01095 void KRun::setRunExecutables(bool b)
01096 {
01097     d->m_runExecutables = b;
01098 }
01099 
01100 bool KRun::isExecutable( const QString& serviceType )
01101 {
01102     return ( serviceType == "application/x-desktop" ||
01103              serviceType == "application/x-executable" ||
01104              serviceType == "application/x-msdos-program" ||
01105              serviceType == "application/x-shellscript" );
01106 }
01107 
01108 
01109 
01110 pid_t
01111 KProcessRunner::run(KProcess * p, const QString & binName)
01112 {
01113   return (new KProcessRunner(p, binName))->pid();
01114 }
01115 
01116 #ifdef Q_WS_X11
01117 pid_t
01118 KProcessRunner::run(KProcess * p, const QString & binName, const KStartupInfoId& id )
01119 {
01120   return (new KProcessRunner(p, binName, id))->pid();
01121 }
01122 #endif
01123 
01124 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName )
01125   : QObject(),
01126     process_(p),
01127     binName( _binName )
01128 {
01129   QObject::connect(
01130       process_, SIGNAL(processExited(KProcess *)),
01131       this,     SLOT(slotProcessExited(KProcess *)));
01132 
01133   process_->start();
01134   if ( !process_->pid() )
01135       slotProcessExited( process_ );
01136 }
01137 
01138 #ifdef Q_WS_X11
01139 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName, const KStartupInfoId& id )
01140   : QObject(),
01141     process_(p),
01142     binName( _binName ),
01143     id_( id )
01144 {
01145   QObject::connect(
01146       process_, SIGNAL(processExited(KProcess *)),
01147       this,     SLOT(slotProcessExited(KProcess *)));
01148 
01149   process_->start();
01150   if ( !process_->pid() )
01151       slotProcessExited( process_ );
01152 }
01153 #endif
01154 
01155 KProcessRunner::~KProcessRunner()
01156 {
01157   delete process_;
01158 }
01159 
01160   pid_t
01161 KProcessRunner::pid() const
01162 {
01163   return process_->pid();
01164 }
01165 
01166   void
01167 KProcessRunner::slotProcessExited(KProcess * p)
01168 {
01169   if (p != process_)
01170     return; 
01171 
01172   kdDebug(7010) << "slotProcessExited " << binName << endl;
01173   kdDebug(7010) << "normalExit " << process_->normalExit() << endl;
01174   kdDebug(7010) << "exitStatus " << process_->exitStatus() << endl;
01175   bool showErr = process_->normalExit()
01176                  && ( process_->exitStatus() == 127 || process_->exitStatus() == 1 );
01177   if ( !binName.isEmpty() && ( showErr || process_->pid() == 0 ) )
01178   {
01179     
01180     
01181     
01182     
01183     if ( !QFile( binName ).exists() && KStandardDirs::findExe( binName ).isEmpty() )
01184     {
01185       kapp->ref();
01186       KMessageBox::sorry( 0L, i18n("Couldn't find the program '%1'").arg( binName ) );
01187       kapp->deref();
01188     }
01189   }
01190 #ifdef Q_WS_X11
01191   if( !id_.none())
01192   {
01193       KStartupInfoData data;
01194       data.addPid( pid()); 
01195       data.setHostname();
01196       KStartupInfo::sendFinish( id_, data );
01197   }
01198 #endif
01199   delete this;
01200 }
01201 
01202 void KRun::virtual_hook( int, void* )
01203 {  }
01204 
01205 #include "krun.moc"