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", "konsole");
00430 if (terminal == "konsole")
00431 terminal += " -caption=%c %i %m";
00432 terminal += " ";
00433 terminal += _service.terminalOptions();
00434 if( !mx1.expandMacrosShellQuote( terminal ) ) {
00435 kdWarning() << "KRun: syntax error in command `" << terminal << "', service `" << _service.name() << "'" << endl;
00436 return QStringList();
00437 }
00438 mx2.expandMacrosShellQuote( terminal );
00439 if (has_shell)
00440 result << terminal;
00441 else
00442 result = KShell::splitArgs( terminal );
00443 result << "-e";
00444 }
00445
00446 int err;
00447 if (_service.substituteUid()) {
00448 if (_service.terminal())
00449 result << "su";
00450 else
00451 result << "kdesu" << "-u";
00452 result << _service.username() << "-c";
00453 KShell::splitArgs(exec, KShell::AbortOnMeta, &err);
00454 if (err == KShell::FoundMeta) {
00455 shellQuote( exec );
00456 exec.prepend( "/bin/sh -c " );
00457 } else if (err != KShell::NoError)
00458 goto synerr;
00459 if (has_shell)
00460 shellQuote( exec );
00461 result << exec;
00462 } else {
00463 if (has_shell) {
00464 if (_service.terminal()) {
00465 KShell::splitArgs(exec, KShell::AbortOnMeta, &err);
00466 if (err == KShell::FoundMeta) {
00467 shellQuote( exec );
00468 exec.prepend( "/bin/sh -c " );
00469 } else if (err != KShell::NoError)
00470 goto synerr;
00471 }
00472 result << exec;
00473 } else {
00474 result += KShell::splitArgs(exec, KShell::AbortOnMeta, &err);
00475 if (err == KShell::FoundMeta)
00476 result << "/bin/sh" << "-c" << exec;
00477 else if (err != KShell::NoError)
00478 goto synerr;
00479 }
00480 }
00481
00482 return result;
00483
00484 synerr:
00485 kdWarning() << "KRun: syntax error in command `" << _service.exec() << "', service `" << _service.name() << "'" << endl;
00486 return QStringList();
00487 }
00488
00489
00490 QString KRun::binaryName( const QString & execLine, bool removePath )
00491 {
00492
00493 QStringList args = KShell::splitArgs( execLine );
00494 for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
00495 if (!(*it).contains('='))
00496
00497 return removePath ? (*it).mid((*it).findRev('/') + 1) : *it;
00498 return QString::null;
00499 }
00500
00501 static pid_t runCommandInternal( KProcess* proc, const KService* service, const QString& binName,
00502 const QString &execName, const QString & iconName )
00503 {
00504 if ( service && !KDesktopFile::isAuthorizedDesktopFile( service->desktopEntryPath() ))
00505 {
00506 KMessageBox::sorry(0, i18n("You are not authorized to execute this file."));
00507 return 0;
00508 }
00509 QString bin = KRun::binaryName( binName, true );
00510 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
00511 bool startup_notify = false;
00512 QCString wmclass;
00513 KStartupInfoId id;
00514 if( service && service->property( "StartupNotify" ).isValid())
00515 {
00516 startup_notify = service->property( "StartupNotify" ).toBool();
00517 wmclass = service->property( "StartupWMClass" ).toString().latin1();
00518 }
00519 else if( service && service->property( "X-KDE-StartupNotify" ).isValid())
00520 {
00521 startup_notify = service->property( "X-KDE-StartupNotify" ).toBool();
00522 wmclass = service->property( "X-KDE-WMClass" ).toString().latin1();
00523 }
00524 else
00525 {
00526 if( service && service->type() == "Application" )
00527 {
00528 startup_notify = true;
00529 wmclass = "0";
00530 }
00531 }
00532 if( startup_notify )
00533 {
00534 id.initId();
00535 id.setupStartupEnv();
00536 KStartupInfoData data;
00537 data.setHostname();
00538 data.setBin( bin );
00539 data.setName( execName.isEmpty() ? service->name() : execName );
00540 data.setDescription( i18n( "Launching %1" ).arg( data.name()));
00541 data.setIcon( iconName.isEmpty() ? service->icon() : iconName );
00542 if( !wmclass.isEmpty())
00543 data.setWMClass( wmclass );
00544 data.setDesktop( KWin::currentDesktop());
00545 KStartupInfo::sendStartup( id, data );
00546 }
00547 pid_t pid = KProcessRunner::run( proc, binName, id );
00548 if( startup_notify && pid )
00549 {
00550 KStartupInfoData data;
00551 data.addPid( pid );
00552 KStartupInfo::sendChange( id, data );
00553 KStartupInfo::resetStartupEnv();
00554 }
00555 return pid;
00556 #else
00557 Q_UNUSED( execName );
00558 Q_UNUSED( iconName );
00559 return KProcessRunner::run( proc, bin );
00560 #endif
00561 }
00562
00563 static pid_t runTempService( const KService& _service, const KURL::List& _urls, bool tempFiles )
00564 {
00565 if (!_urls.isEmpty()) {
00566 kdDebug(7010) << "runTempService: first url " << _urls.first().url() << endl;
00567 }
00568
00569 QStringList args;
00570 if ((_urls.count() > 1) && !_service.allowMultipleFiles())
00571 {
00572
00573
00574
00575
00576
00577 KURL::List::ConstIterator it = _urls.begin();
00578 while(++it != _urls.end())
00579 {
00580 KURL::List singleUrl;
00581 singleUrl.append(*it);
00582 runTempService( _service, singleUrl, tempFiles );
00583 }
00584 KURL::List singleUrl;
00585 singleUrl.append(_urls.first());
00586 args = KRun::processDesktopExec(_service, singleUrl, false, tempFiles);
00587 }
00588 else
00589 {
00590 args = KRun::processDesktopExec(_service, _urls, false, tempFiles);
00591 }
00592 kdDebug(7010) << "runTempService: KProcess args=" << args << endl;
00593
00594 KProcess * proc = new KProcess;
00595 *proc << args;
00596
00597 if (!_service.path().isEmpty())
00598 proc->setWorkingDirectory(_service.path());
00599
00600 return runCommandInternal( proc, &_service, KRun::binaryName( _service.exec(), false ),
00601 _service.name(), _service.icon() );
00602 }
00603
00604
00605 pid_t KRun::run( const KService& _service, const KURL::List& _urls )
00606 {
00607 return run( _service, _urls, false );
00608 }
00609
00610 pid_t KRun::run( const KService& _service, const KURL::List& _urls, bool tempFiles )
00611 {
00612 if (!_service.desktopEntryPath().isEmpty() &&
00613 !KDesktopFile::isAuthorizedDesktopFile( _service.desktopEntryPath()))
00614 {
00615 KMessageBox::sorry(0, i18n("You are not authorized to execute this service."));
00616 return 0;
00617 }
00618
00619 if ( !tempFiles )
00620 {
00621
00622 KURL::List::ConstIterator it = _urls.begin();
00623 for(; it != _urls.end(); ++it) {
00624
00625 KRecentDocument::add( *it, _service.desktopEntryName() );
00626 }
00627 }
00628
00629 if ( tempFiles || _service.desktopEntryPath().isEmpty())
00630 {
00631 return runTempService(_service, _urls, tempFiles);
00632 }
00633
00634 kdDebug(7010) << "KRun::run " << _service.desktopEntryPath() << endl;
00635
00636 if (!_urls.isEmpty()) {
00637 kdDebug(7010) << "First url " << _urls.first().url() << endl;
00638 }
00639
00640 QString error;
00641 int pid = 0;
00642
00643 int i = KApplication::startServiceByDesktopPath(
00644 _service.desktopEntryPath(), _urls.toStringList(), &error, 0L, &pid
00645 );
00646
00647 if (i != 0)
00648 {
00649 kdDebug(7010) << error << endl;
00650 KMessageBox::sorry( 0L, error );
00651 return 0;
00652 }
00653
00654 kdDebug(7010) << "startServiceByDesktopPath worked fine" << endl;
00655 return (pid_t) pid;
00656 }
00657
00658
00659 pid_t KRun::run( const QString& _exec, const KURL::List& _urls, const QString& _name,
00660 const QString& _icon, const QString&, const QString&)
00661 {
00662 KService::Ptr service = new KService(_name, _exec, _icon);
00663
00664 return run(*service, _urls);
00665 }
00666
00667 pid_t KRun::runCommand( QString cmd )
00668 {
00669 return KRun::runCommand( cmd, QString::null, QString::null );
00670 }
00671
00672 pid_t KRun::runCommand( const QString& cmd, const QString &execName, const QString & iconName )
00673 {
00674 kdDebug(7010) << "runCommand " << cmd << "," << execName << endl;
00675 KProcess * proc = new KProcess;
00676 proc->setUseShell(true);
00677 *proc << cmd;
00678 KService::Ptr service = KService::serviceByDesktopName( binaryName( cmd, true ));
00679 return runCommandInternal( proc, service.data(), binaryName( cmd, false ), execName, iconName );
00680 }
00681
00682 KRun::KRun( const KURL& url, mode_t mode, bool isLocalFile, bool showProgressInfo )
00683 :m_timer(0,"KRun::timer")
00684 {
00685 init (url, 0, mode, isLocalFile, showProgressInfo);
00686 }
00687
00688 KRun::KRun( const KURL& url, QWidget* window, mode_t mode, bool isLocalFile,
00689 bool showProgressInfo )
00690 :m_timer(0,"KRun::timer")
00691 {
00692 init (url, window, mode, isLocalFile, showProgressInfo);
00693 }
00694
00695 void KRun::init ( const KURL& url, QWidget* window, mode_t mode, bool isLocalFile,
00696 bool showProgressInfo )
00697 {
00698 m_bFault = false;
00699 m_bAutoDelete = true;
00700 m_bProgressInfo = showProgressInfo;
00701 m_bFinished = false;
00702 m_job = 0L;
00703 m_strURL = url;
00704 m_bScanFile = false;
00705 m_bIsDirectory = false;
00706 m_bIsLocalFile = isLocalFile;
00707 m_mode = mode;
00708 d = new KRunPrivate;
00709 d->m_runExecutables = true;
00710 d->m_window = window;
00711 setEnableExternalBrowser(true);
00712
00713
00714
00715
00716 m_bInit = true;
00717 connect( &m_timer, SIGNAL( timeout() ), this, SLOT( slotTimeout() ) );
00718 m_timer.start( 0, true );
00719 kdDebug(7010) << " new KRun " << this << " " << url.prettyURL() << " timer=" << &m_timer << endl;
00720
00721 kapp->ref();
00722 }
00723
00724 void KRun::init()
00725 {
00726 kdDebug(7010) << "INIT called" << endl;
00727 if ( !m_strURL.isValid() )
00728 {
00729 d->m_showingError = true;
00730 KMessageBoxWrapper::error( d->m_window, i18n( "Malformed URL\n%1" ).arg( m_strURL.url() ) );
00731 d->m_showingError = false;
00732 m_bFault = true;
00733 m_bFinished = true;
00734 m_timer.start( 0, true );
00735 return;
00736 }
00737 if ( !kapp->authorizeURLAction( "open", KURL(), m_strURL))
00738 {
00739 QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, m_strURL.prettyURL());
00740 d->m_showingError = true;
00741 KMessageBoxWrapper::error( d->m_window, msg );
00742 d->m_showingError = false;
00743 m_bFault = true;
00744 m_bFinished = true;
00745 m_timer.start( 0, true );
00746 return;
00747 }
00748
00749 if ( !m_bIsLocalFile && m_strURL.isLocalFile() )
00750 m_bIsLocalFile = true;
00751
00752 QString exec;
00753 if (m_strURL.protocol().startsWith("http"))
00754 {
00755 exec = d->m_externalBrowser;
00756 }
00757
00758 if ( m_bIsLocalFile )
00759 {
00760 if ( m_mode == 0 )
00761 {
00762 struct stat buff;
00763 if ( stat( QFile::encodeName(m_strURL.path()), &buff ) == -1 )
00764 {
00765 d->m_showingError = true;
00766 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() ) );
00767 d->m_showingError = false;
00768 m_bFault = true;
00769 m_bFinished = true;
00770 m_timer.start( 0, true );
00771 return;
00772 }
00773 m_mode = buff.st_mode;
00774 }
00775
00776 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL, m_mode, m_bIsLocalFile );
00777 assert( mime != 0L );
00778 kdDebug(7010) << "MIME TYPE is " << mime->name() << endl;
00779 foundMimeType( mime->name() );
00780 return;
00781 }
00782 else if ( !exec.isEmpty() || KProtocolInfo::isHelperProtocol( m_strURL ) ) {
00783 kdDebug(7010) << "Helper protocol" << endl;
00784
00785 bool ok;
00786 KURL::List urls;
00787 urls.append( m_strURL );
00788 if (exec.isEmpty())
00789 {
00790 exec = KProtocolInfo::exec( m_strURL.protocol() );
00791 run( exec, urls );
00792 ok = true;
00793 }
00794 else if (exec.startsWith("!"))
00795 {
00796 exec = exec.mid(1);
00797 exec += " %u";
00798 run( exec, urls );
00799 ok = true;
00800 }
00801 else
00802 {
00803 KService::Ptr service = KService::serviceByStorageId( exec );
00804 if (service)
00805 {
00806 run( *service, urls );
00807 ok = true;
00808 }
00809 }
00810
00811 if (ok)
00812 {
00813 m_bFinished = true;
00814
00815 m_timer.start( 0, true );
00816 return;
00817 }
00818 }
00819
00820
00821 if ( S_ISDIR( m_mode ) )
00822 {
00823 foundMimeType( "inode/directory" );
00824 return;
00825 }
00826
00827
00828
00829 if ( !KProtocolInfo::supportsListing( m_strURL ) )
00830 {
00831
00832
00833 scanFile();
00834 return;
00835 }
00836
00837 kdDebug(7010) << "Testing directory (stating)" << endl;
00838
00839
00840 KIO::StatJob *job = KIO::stat( m_strURL, true, 0 , m_bProgressInfo );
00841 job->setWindow (d->m_window);
00842 connect( job, SIGNAL( result( KIO::Job * ) ),
00843 this, SLOT( slotStatResult( KIO::Job * ) ) );
00844 m_job = job;
00845 kdDebug(7010) << " Job " << job << " is about stating " << m_strURL.url() << endl;
00846 }
00847
00848 KRun::~KRun()
00849 {
00850 kdDebug(7010) << "KRun::~KRun() " << this << endl;
00851 m_timer.stop();
00852 killJob();
00853 kapp->deref();
00854 kdDebug(7010) << "KRun::~KRun() done " << this << endl;
00855 delete d;
00856 }
00857
00858 void KRun::scanFile()
00859 {
00860 kdDebug(7010) << "###### KRun::scanFile " << m_strURL.url() << endl;
00861
00862
00863 if ( m_strURL.query().isEmpty() )
00864 {
00865 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
00866 assert( mime != 0L );
00867 if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
00868 {
00869 kdDebug(7010) << "Scanfile: MIME TYPE is " << mime->name() << endl;
00870 foundMimeType( mime->name() );
00871 return;
00872 }
00873 }
00874
00875
00876
00877
00878
00879 if ( !KProtocolInfo::supportsReading( m_strURL ) )
00880 {
00881 kdError(7010) << "#### NO SUPPORT FOR READING!" << endl;
00882 m_bFault = true;
00883 m_bFinished = true;
00884 m_timer.start( 0, true );
00885 return;
00886 }
00887 kdDebug(7010) << this << " Scanning file " << m_strURL.url() << endl;
00888
00889 KIO::TransferJob *job = KIO::get( m_strURL, false , m_bProgressInfo );
00890 job->setWindow (d->m_window);
00891 connect(job, SIGNAL( result(KIO::Job *)),
00892 this, SLOT( slotScanFinished(KIO::Job *)));
00893 connect(job, SIGNAL( mimetype(KIO::Job *, const QString &)),
00894 this, SLOT( slotScanMimeType(KIO::Job *, const QString &)));
00895 m_job = job;
00896 kdDebug(7010) << " Job " << job << " is about getting from " << m_strURL.url() << endl;
00897 }
00898
00899 void KRun::slotTimeout()
00900 {
00901 kdDebug(7010) << this << " slotTimeout called" << endl;
00902 if ( m_bInit )
00903 {
00904 m_bInit = false;
00905 init();
00906 return;
00907 }
00908
00909 if ( m_bFault ){
00910 emit error();
00911 }
00912 if ( m_bFinished ){
00913 emit finished();
00914 }
00915
00916 if ( m_bScanFile )
00917 {
00918 m_bScanFile = false;
00919 scanFile();
00920 return;
00921 }
00922 else if ( m_bIsDirectory )
00923 {
00924 m_bIsDirectory = false;
00925 foundMimeType( "inode/directory" );
00926 return;
00927 }
00928
00929 if ( m_bAutoDelete )
00930 {
00931 delete this;
00932 return;
00933 }
00934 }
00935
00936 void KRun::slotStatResult( KIO::Job * job )
00937 {
00938 m_job = 0L;
00939 if (job->error())
00940 {
00941 d->m_showingError = true;
00942 kdError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
00943 job->showErrorDialog();
00944
00945 d->m_showingError = false;
00946
00947 m_bFault = true;
00948 m_bFinished = true;
00949
00950
00951 m_timer.start( 0, true );
00952
00953 } else {
00954
00955 kdDebug(7010) << "Finished" << endl;
00956 if(!dynamic_cast<KIO::StatJob*>(job))
00957 kdFatal() << "job is a " << typeid(*job).name() << " should be a StatJob" << endl;
00958
00959 KIO::UDSEntry entry = ((KIO::StatJob*)job)->statResult();
00960 KIO::UDSEntry::ConstIterator it = entry.begin();
00961 for( ; it != entry.end(); it++ ) {
00962 if ( (*it).m_uds == KIO::UDS_FILE_TYPE )
00963 {
00964 if ( S_ISDIR( (mode_t)((*it).m_long) ) )
00965 m_bIsDirectory = true;
00966 else
00967 m_bScanFile = true;
00968 break;
00969 }
00970 }
00971
00972 assert ( m_bScanFile || m_bIsDirectory );
00973
00974
00975
00976
00977 m_timer.start( 0, true );
00978 }
00979 }
00980
00981 void KRun::slotScanMimeType( KIO::Job *, const QString &mimetype )
00982 {
00983 if ( mimetype.isEmpty() )
00984 kdWarning(7010) << "KRun::slotScanFinished : MimetypeJob didn't find a mimetype! Probably a kioslave bug." << endl;
00985 foundMimeType( mimetype );
00986 m_job = 0;
00987 }
00988
00989 void KRun::slotScanFinished( KIO::Job *job )
00990 {
00991 m_job = 0;
00992 if (job->error())
00993 {
00994 d->m_showingError = true;
00995 kdError(7010) << this << " ERROR (stat) : " << job->error() << " " << job->errorString() << endl;
00996 job->showErrorDialog();
00997
00998 d->m_showingError = false;
00999
01000 m_bFault = true;
01001 m_bFinished = true;
01002
01003
01004 m_timer.start( 0, true );
01005 }
01006 }
01007
01008 void KRun::foundMimeType( const QString& type )
01009 {
01010 kdDebug(7010) << "Resulting mime type is " << type << endl;
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
01064 if (m_job && m_job->inherits("KIO::TransferJob"))
01065 {
01066 KIO::TransferJob *job = static_cast<KIO::TransferJob *>(m_job);
01067 job->putOnHold();
01068 KIO::Scheduler::publishSlaveOnHold();
01069 m_job = 0;
01070 }
01071
01072 Q_ASSERT( !m_bFinished );
01073
01074
01075 if ( !d->m_preferredService.isEmpty() ) {
01076 kdDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService << endl;
01077 KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
01078 if ( serv && serv->hasServiceType( type ) )
01079 {
01080 KURL::List lst;
01081 lst.append( m_strURL );
01082 m_bFinished = KRun::run( *serv, lst );
01087 }
01088 }
01089
01090 if (!m_bFinished && KRun::runURL( m_strURL, type, false, d->m_runExecutables )){
01091 m_bFinished = true;
01092 }
01093 else{
01094 m_bFinished = true;
01095 m_bFault = true;
01096 }
01097
01098 m_timer.start( 0, true );
01099 }
01100
01101 void KRun::killJob()
01102 {
01103 if ( m_job )
01104 {
01105 kdDebug(7010) << "KRun::killJob run=" << this << " m_job=" << m_job << endl;
01106 m_job->kill();
01107 m_job = 0L;
01108 }
01109 }
01110
01111 void KRun::abort()
01112 {
01113 kdDebug(7010) << "KRun::abort " << this << " m_showingError=" << d->m_showingError << endl;
01114 killJob();
01115
01116
01117 if ( d->m_showingError )
01118 return;
01119 m_bFault = true;
01120 m_bFinished = true;
01121 m_bInit = false;
01122 m_bScanFile = false;
01123
01124
01125 m_timer.start( 0, true );
01126 }
01127
01128 void KRun::setEnableExternalBrowser(bool b)
01129 {
01130 if (b)
01131 d->m_externalBrowser = KConfigGroup(KGlobal::config(), "General").readEntry("BrowserApplication");
01132 else
01133 d->m_externalBrowser = QString::null;
01134 }
01135
01136 void KRun::setPreferredService( const QString& desktopEntryName )
01137 {
01138 d->m_preferredService = desktopEntryName;
01139 }
01140
01141 void KRun::setRunExecutables(bool b)
01142 {
01143 d->m_runExecutables = b;
01144 }
01145
01146 bool KRun::isExecutable( const QString& serviceType )
01147 {
01148 return ( serviceType == "application/x-desktop" ||
01149 serviceType == "application/x-executable" ||
01150 serviceType == "application/x-msdos-program" ||
01151 serviceType == "application/x-shellscript" );
01152 }
01153
01154
01155
01156 pid_t
01157 KProcessRunner::run(KProcess * p, const QString & binName)
01158 {
01159 return (new KProcessRunner(p, binName))->pid();
01160 }
01161
01162 #ifdef Q_WS_X11
01163 pid_t
01164 KProcessRunner::run(KProcess * p, const QString & binName, const KStartupInfoId& id )
01165 {
01166 return (new KProcessRunner(p, binName, id))->pid();
01167 }
01168 #endif
01169
01170 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName )
01171 : QObject(),
01172 process_(p),
01173 binName( _binName )
01174 {
01175 QObject::connect(
01176 process_, SIGNAL(processExited(KProcess *)),
01177 this, SLOT(slotProcessExited(KProcess *)));
01178
01179 process_->start();
01180 if ( !process_->pid() )
01181 slotProcessExited( process_ );
01182 }
01183
01184 #ifdef Q_WS_X11
01185 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName, const KStartupInfoId& id )
01186 : QObject(),
01187 process_(p),
01188 binName( _binName ),
01189 id_( id )
01190 {
01191 QObject::connect(
01192 process_, SIGNAL(processExited(KProcess *)),
01193 this, SLOT(slotProcessExited(KProcess *)));
01194
01195 process_->start();
01196 if ( !process_->pid() )
01197 slotProcessExited( process_ );
01198 }
01199 #endif
01200
01201 KProcessRunner::~KProcessRunner()
01202 {
01203 delete process_;
01204 }
01205
01206 pid_t
01207 KProcessRunner::pid() const
01208 {
01209 return process_->pid();
01210 }
01211
01212 void
01213 KProcessRunner::slotProcessExited(KProcess * p)
01214 {
01215 if (p != process_)
01216 return;
01217
01218 kdDebug(7010) << "slotProcessExited " << binName << endl;
01219 kdDebug(7010) << "normalExit " << process_->normalExit() << endl;
01220 kdDebug(7010) << "exitStatus " << process_->exitStatus() << endl;
01221 bool showErr = process_->normalExit()
01222 && ( process_->exitStatus() == 127 || process_->exitStatus() == 1 );
01223 if ( !binName.isEmpty() && ( showErr || process_->pid() == 0 ) )
01224 {
01225
01226
01227
01228
01229 if ( !QFile( binName ).exists() && KStandardDirs::findExe( binName ).isEmpty() )
01230 {
01231 kapp->ref();
01232 KMessageBox::sorry( 0L, i18n("Could not find the program '%1'").arg( binName ) );
01233 kapp->deref();
01234 }
01235 }
01236 #ifdef Q_WS_X11
01237 if( !id_.none())
01238 {
01239 KStartupInfoData data;
01240 data.addPid( pid());
01241 data.setHostname();
01242 KStartupInfo::sendFinish( id_, data );
01243 }
01244 #endif
01245 delete this;
01246 }
01247
01248 void KRun::virtual_hook( int, void* )
01249 { }
01250
01251 #include "krun.moc"