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