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