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