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