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