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