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