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