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