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
00620
00621 wmclass = "0";
00622 silent = true;
00623 }
00624 }
00625 if( silent_arg != NULL )
00626 *silent_arg = silent;
00627 if( wmclass_arg != NULL )
00628 *wmclass_arg = wmclass;
00629 return true;
00630 }
00631
00632 static pid_t runTempService( const KService& _service, const KURL::List& _urls, bool tempFiles, const QString& suggestedFileName )
00633 {
00634 if (!_urls.isEmpty()) {
00635 kdDebug(7010) << "runTempService: first url " << _urls.first().url() << endl;
00636 }
00637
00638 QStringList args;
00639 if ((_urls.count() > 1) && !_service.allowMultipleFiles())
00640 {
00641
00642
00643
00644
00645
00646 KURL::List::ConstIterator it = _urls.begin();
00647 while(++it != _urls.end())
00648 {
00649 KURL::List singleUrl;
00650 singleUrl.append(*it);
00651 runTempService( _service, singleUrl, tempFiles, suggestedFileName );
00652 }
00653 KURL::List singleUrl;
00654 singleUrl.append(_urls.first());
00655 args = KRun::processDesktopExec(_service, singleUrl, false, tempFiles, suggestedFileName);
00656 }
00657 else
00658 {
00659 args = KRun::processDesktopExec(_service, _urls, false, tempFiles, suggestedFileName);
00660 }
00661 kdDebug(7010) << "runTempService: KProcess args=" << args << endl;
00662
00663 KProcess * proc = new KProcess;
00664 *proc << args;
00665
00666 if (!_service.path().isEmpty())
00667 proc->setWorkingDirectory(_service.path());
00668
00669 return runCommandInternal( proc, &_service, KRun::binaryName( _service.exec(), false ),
00670 _service.name(), _service.icon() );
00671 }
00672
00673
00674 static KURL::List resolveURLs( const KURL::List& _urls, const KService& _service )
00675 {
00676
00677
00678 QStringList supportedProtocols = _service.property("X-KDE-Protocols").toStringList();
00679 KRunMX1 mx1( _service );
00680 QString exec = _service.exec();
00681 if ( mx1.expandMacrosShellQuote( exec ) && !mx1.hasUrls ) {
00682 Q_ASSERT( supportedProtocols.isEmpty() );
00683 } else {
00684 if ( supportedProtocols.isEmpty() )
00685 {
00686
00687 QStringList categories = _service.property("Categories").toStringList();
00688 if ( categories.find("KDE") != categories.end() )
00689 supportedProtocols.append( "KIO" );
00690 else {
00691 supportedProtocols.append( "http");
00692 supportedProtocols.append( "ftp");
00693 }
00694 }
00695 }
00696 kdDebug(7010) << "supportedProtocols:" << supportedProtocols << endl;
00697
00698 KURL::List urls( _urls );
00699 if ( supportedProtocols.find( "KIO" ) == supportedProtocols.end() ) {
00700 for( KURL::List::Iterator it = urls.begin(); it != urls.end(); ++it ) {
00701 const KURL url = *it;
00702 bool supported = url.isLocalFile() || supportedProtocols.find( url.protocol().lower() ) != supportedProtocols.end();
00703 kdDebug(7010) << "Looking at url=" << url << " supported=" << supported << endl;
00704 if ( !supported && KProtocolInfo::protocolClass(url.protocol()) == ":local" )
00705 {
00706
00707 KURL localURL = KIO::NetAccess::mostLocalURL( url, 0 );
00708 if ( localURL != url ) {
00709 *it = localURL;
00710 kdDebug(7010) << "Changed to " << localURL << endl;
00711 }
00712 }
00713 }
00714 }
00715 return urls;
00716 }
00717
00718
00719 pid_t KRun::run( const KService& _service, const KURL::List& _urls )
00720 {
00721 return run( _service, _urls, 0, false, QString::null );
00722 }
00723
00724 pid_t KRun::run( const KService& _service, const KURL::List& _urls, bool tempFiles )
00725 {
00726 return run( _service, _urls, 0, tempFiles, QString::null );
00727 }
00728
00729 pid_t KRun::run( const KService& _service, const KURL::List& _urls, QWidget* window, bool tempFiles )
00730 {
00731 return run( _service, _urls, window, tempFiles, QString::null );
00732 }
00733
00734 pid_t KRun::run( const KService& _service, const KURL::List& _urls, QWidget* window, bool tempFiles, const QString& suggestedFileName )
00735 {
00736 if (!_service.desktopEntryPath().isEmpty() &&
00737 !KDesktopFile::isAuthorizedDesktopFile( _service.desktopEntryPath()))
00738 {
00739 kdWarning() << "No authorization to execute " << _service.desktopEntryPath() << endl;
00740 KMessageBox::sorry(window, i18n("You are not authorized to execute this service."));
00741 return 0;
00742 }
00743
00744 if ( !tempFiles )
00745 {
00746
00747 KURL::List::ConstIterator it = _urls.begin();
00748 for(; it != _urls.end(); ++it) {
00749
00750 KRecentDocument::add( *it, _service.desktopEntryName() );
00751 }
00752 }
00753
00754 if ( tempFiles || _service.desktopEntryPath().isEmpty() || !suggestedFileName.isEmpty() )
00755 {
00756 return runTempService(_service, _urls, tempFiles, suggestedFileName);
00757 }
00758
00759 kdDebug(7010) << "KRun::run " << _service.desktopEntryPath() << endl;
00760
00761 if (!_urls.isEmpty()) {
00762 kdDebug(7010) << "First url " << _urls.first().url() << endl;
00763 }
00764
00765
00766 const KURL::List urls = resolveURLs( _urls, _service );
00767
00768 QString error;
00769 int pid = 0;
00770
00771 int i = KApplication::startServiceByDesktopPath(
00772 _service.desktopEntryPath(), urls.toStringList(), &error, 0L, &pid
00773 );
00774
00775 if (i != 0)
00776 {
00777 kdDebug(7010) << error << endl;
00778 KMessageBox::sorry( window, error );
00779 return 0;
00780 }
00781
00782 kdDebug(7010) << "startServiceByDesktopPath worked fine" << endl;
00783 return (pid_t) pid;
00784 }
00785
00786
00787 pid_t KRun::run( const QString& _exec, const KURL::List& _urls, const QString& _name,
00788 const QString& _icon, const QString&, const QString&)
00789 {
00790 KService::Ptr service = new KService(_name, _exec, _icon);
00791
00792 return run(*service, _urls);
00793 }
00794
00795 pid_t KRun::runCommand( QString cmd )
00796 {
00797 return KRun::runCommand( cmd, QString::null, QString::null );
00798 }
00799
00800 pid_t KRun::runCommand( const QString& cmd, const QString &execName, const QString & iconName )
00801 {
00802 kdDebug(7010) << "runCommand " << cmd << "," << execName << endl;
00803 KProcess * proc = new KProcess;
00804 proc->setUseShell(true);
00805 *proc << cmd;
00806 KService::Ptr service = KService::serviceByDesktopName( binaryName( execName, true ) );
00807 return runCommandInternal( proc, service.data(), binaryName( execName, false ), execName, iconName );
00808 }
00809
00810 KRun::KRun( const KURL& url, mode_t mode, bool isLocalFile, bool showProgressInfo )
00811 :m_timer(0,"KRun::timer")
00812 {
00813 init (url, 0, mode, isLocalFile, showProgressInfo);
00814 }
00815
00816 KRun::KRun( const KURL& url, QWidget* window, mode_t mode, bool isLocalFile,
00817 bool showProgressInfo )
00818 :m_timer(0,"KRun::timer")
00819 {
00820 init (url, window, mode, isLocalFile, showProgressInfo);
00821 }
00822
00823 void KRun::init ( const KURL& url, QWidget* window, mode_t mode, bool isLocalFile,
00824 bool showProgressInfo )
00825 {
00826 m_bFault = false;
00827 m_bAutoDelete = true;
00828 m_bProgressInfo = showProgressInfo;
00829 m_bFinished = false;
00830 m_job = 0L;
00831 m_strURL = url;
00832 m_bScanFile = false;
00833 m_bIsDirectory = false;
00834 m_bIsLocalFile = isLocalFile;
00835 m_mode = mode;
00836 d = new KRunPrivate;
00837 d->m_runExecutables = true;
00838 d->m_window = window;
00839 setEnableExternalBrowser(true);
00840
00841
00842
00843
00844 m_bInit = true;
00845 connect( &m_timer, SIGNAL( timeout() ), this, SLOT( slotTimeout() ) );
00846 m_timer.start( 0, true );
00847 kdDebug(7010) << " new KRun " << this << " " << url.prettyURL() << " timer=" << &m_timer << endl;
00848
00849 kapp->ref();
00850 }
00851
00852 void KRun::init()
00853 {
00854 kdDebug(7010) << "INIT called" << endl;
00855 if ( !m_strURL.isValid() )
00856 {
00857 d->m_showingError = true;
00858 KMessageBoxWrapper::error( d->m_window, i18n( "Malformed URL\n%1" ).arg( m_strURL.url() ) );
00859 d->m_showingError = false;
00860 m_bFault = true;
00861 m_bFinished = true;
00862 m_timer.start( 0, true );
00863 return;
00864 }
00865 if ( !kapp->authorizeURLAction( "open", KURL(), m_strURL))
00866 {
00867 QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, m_strURL.prettyURL());
00868 d->m_showingError = true;
00869 KMessageBoxWrapper::error( d->m_window, msg );
00870 d->m_showingError = false;
00871 m_bFault = true;
00872 m_bFinished = true;
00873 m_timer.start( 0, true );
00874 return;
00875 }
00876
00877 if ( !m_bIsLocalFile && m_strURL.isLocalFile() )
00878 m_bIsLocalFile = true;
00879
00880 QString exec;
00881 if (m_strURL.protocol().startsWith("http"))
00882 {
00883 exec = d->m_externalBrowser;
00884 }
00885
00886 if ( m_bIsLocalFile )
00887 {
00888 if ( m_mode == 0 )
00889 {
00890 KDE_struct_stat buff;
00891 if ( KDE_stat( QFile::encodeName(m_strURL.path()), &buff ) == -1 )
00892 {
00893 d->m_showingError = true;
00894 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() ) );
00895 d->m_showingError = false;
00896 m_bFault = true;
00897 m_bFinished = true;
00898 m_timer.start( 0, true );
00899 return;
00900 }
00901 m_mode = buff.st_mode;
00902 }
00903
00904 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL, m_mode, m_bIsLocalFile );
00905 assert( mime != 0L );
00906 kdDebug(7010) << "MIME TYPE is " << mime->name() << endl;
00907 foundMimeType( mime->name() );
00908 return;
00909 }
00910 else if ( !exec.isEmpty() || KProtocolInfo::isHelperProtocol( m_strURL ) ) {
00911 kdDebug(7010) << "Helper protocol" << endl;
00912
00913 bool ok = false;
00914 KURL::List urls;
00915 urls.append( m_strURL );
00916 if (exec.isEmpty())
00917 {
00918 exec = KProtocolInfo::exec( m_strURL.protocol() );
00919 if (exec.isEmpty())
00920 {
00921 foundMimeType(KProtocolInfo::defaultMimetype(m_strURL));
00922 return;
00923 }
00924 run( exec, urls );
00925 ok = true;
00926 }
00927 else if (exec.startsWith("!"))
00928 {
00929 exec = exec.mid(1);
00930 exec += " %u";
00931 run( exec, urls );
00932 ok = true;
00933 }
00934 else
00935 {
00936 KService::Ptr service = KService::serviceByStorageId( exec );
00937 if (service)
00938 {
00939 run( *service, urls );
00940 ok = true;
00941 }
00942 }
00943
00944 if (ok)
00945 {
00946 m_bFinished = true;
00947
00948 m_timer.start( 0, true );
00949 return;
00950 }
00951 }
00952
00953
00954 if ( S_ISDIR( m_mode ) )
00955 {
00956 foundMimeType( "inode/directory" );
00957 return;
00958 }
00959
00960
00961
00962 if ( !KProtocolInfo::supportsListing( m_strURL ) )
00963 {
00964
00965
00966 scanFile();
00967 return;
00968 }
00969
00970 kdDebug(7010) << "Testing directory (stating)" << endl;
00971
00972
00973 KIO::StatJob *job = KIO::stat( m_strURL, true, 0 , m_bProgressInfo );
00974 job->setWindow (d->m_window);
00975 connect( job, SIGNAL( result( KIO::Job * ) ),
00976 this, SLOT( slotStatResult( KIO::Job * ) ) );
00977 m_job = job;
00978 kdDebug(7010) << " Job " << job << " is about stating " << m_strURL.url() << endl;
00979 }
00980
00981 KRun::~KRun()
00982 {
00983 kdDebug(7010) << "KRun::~KRun() " << this << endl;
00984 m_timer.stop();
00985 killJob();
00986 kapp->deref();
00987 kdDebug(7010) << "KRun::~KRun() done " << this << endl;
00988 delete d;
00989 }
00990
00991 void KRun::scanFile()
00992 {
00993 kdDebug(7010) << "###### KRun::scanFile " << m_strURL.url() << endl;
00994
00995
00996 if ( m_strURL.query().isEmpty() )
00997 {
00998 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
00999 assert( mime != 0L );
01000 if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
01001 {
01002 kdDebug(7010) << "Scanfile: MIME TYPE is " << mime->name() << endl;
01003 foundMimeType( mime->name() );
01004 return;
01005 }
01006 }
01007
01008
01009
01010
01011
01012 if ( !KProtocolInfo::supportsReading( m_strURL ) )
01013 {
01014 kdError(7010) << "#### NO SUPPORT FOR READING!" << endl;
01015 m_bFault = true;
01016 m_bFinished = true;
01017 m_timer.start( 0, true );
01018 return;
01019 }
01020 kdDebug(7010) << this << " Scanning file " << m_strURL.url() << endl;
01021
01022 KIO::TransferJob *job = KIO::get( m_strURL, false , m_bProgressInfo );
01023 job->setWindow (d->m_window);
01024 connect(job, SIGNAL( result(KIO::Job *)),
01025 this, SLOT( slotScanFinished(KIO::Job *)));
01026 connect(job, SIGNAL( mimetype(KIO::Job *, const QString &)),
01027 this, SLOT( slotScanMimeType(KIO::Job *, const QString &)));
01028 m_job = job;
01029 kdDebug(7010) << " Job " << job << " is about getting from " << m_strURL.url() << endl;
01030 }
01031
01032 void KRun::slotTimeout()
01033 {
01034 kdDebug(7010) << this << " slotTimeout called" << endl;
01035 if ( m_bInit )
01036 {
01037 m_bInit = false;
01038 init();
01039 return;
01040 }
01041
01042 if ( m_bFault ) {
01043 emit error();
01044 }
01045 if ( m_bFinished ) {
01046 emit finished();
01047 }
01048 else
01049 {
01050 if ( m_bScanFile )
01051 {
01052 m_bScanFile = false;
01053 scanFile();
01054 return;
01055 }
01056 else if ( m_bIsDirectory )
01057 {
01058 m_bIsDirectory = false;
01059 foundMimeType( "inode/directory" );
01060 return;
01061 }
01062 }
01063
01064 if ( m_bAutoDelete )
01065 {
01066 delete this;
01067 return;
01068 }
01069 }
01070
01071 void KRun::slotStatResult( KIO::Job * job )
01072 {
01073 m_job = 0L;
01074 if (job->error())
01075 {
01076 d->m_showingError = true;
01077 kdError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
01078 job->showErrorDialog();
01079
01080 d->m_showingError = false;
01081
01082 m_bFault = true;
01083 m_bFinished = true;
01084
01085
01086 m_timer.