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", "konsole");
00500
00501 if (terminal == "konsole")
00502 terminal += " -caption=%c %i %m";
00503
00504 if (terminal_su)
00505 {
00506 QString cmd = result.join(" ");
00507 result = breakup(QString("%1 %2 -e su %3 -c").arg(terminal).arg(_service.terminalOptions()).arg(user));
00508 for(QStringList::Iterator it = result.begin();
00509 it != result.end(); ++it)
00510 {
00511 substitute(result, it, _service, _urls, has_shell);
00512 }
00513 result.append(cmd);
00514 }
00515 else if (terminal_sh)
00516 {
00517 QStringList cmd = result;
00518 result = breakup(QString("%1 %2 -e").arg(terminal).arg(_service.terminalOptions()));
00519 for(QStringList::Iterator it = result.begin();
00520 it != result.end(); ++it)
00521 {
00522 substitute(result, it, _service, _urls, has_shell);
00523 }
00524 result += cmd;
00525 }
00526 else if (kdesu)
00527 {
00528 result = breakup(QString("kdesu -u %1 --").arg(user))+result;
00529 }
00530
00531 return result;
00532 }
00533
00534
00535 QString KRun::binaryName( const QString & execLine, bool removePath )
00536 {
00537
00538 QStringList args = breakup( execLine );
00539 QString _bin_name;
00540 do {
00541 if ( args.isEmpty() )
00542 return QString::null;
00543 _bin_name = args.first();
00544 args.pop_front();
00545 } while (_bin_name.contains('='));
00546
00547 return removePath ? _bin_name.mid(_bin_name.findRev('/') + 1) : _bin_name;
00548 }
00549
00550 static pid_t runCommandInternal( KProcess* proc, const KService* service, const QString& binName,
00551 const QString &execName_P, const QString & iconName_P )
00552 {
00553 QString bin = KRun::binaryName( binName, false );
00554 QString execName = execName_P;
00555 QString iconName = iconName_P;
00556 if ( service && !KDesktopFile::isAuthorizedDesktopFile( service->desktopEntryPath() ))
00557 {
00558 KMessageBox::sorry(0, i18n("You are not authorized to execute this file."));
00559 return 0;
00560 }
00561 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
00562 bool startup_notify = false;
00563 QCString wmclass;
00564 KStartupInfoId id;
00565 if( service && service->property( "X-KDE-StartupNotify" ).isValid())
00566 {
00567 startup_notify = service->property( "X-KDE-StartupNotify" ).toBool();
00568 wmclass = service->property( "X-KDE-WMClass" ).toString().latin1();
00569 }
00570 else
00571 {
00572 if( service && service->type() == "Application" )
00573 {
00574 startup_notify = true;
00575 wmclass = "0";
00576 }
00577 }
00578 if( startup_notify )
00579 {
00580 id.initId();
00581 id.setupStartupEnv();
00582 if( execName.isEmpty())
00583 execName = service->name();
00584 if( iconName.isEmpty())
00585 iconName = service->icon();
00586 KStartupInfoData data;
00587 data.setHostname();
00588 data.setBin( KRun::binaryName( binName, true ));
00589 data.setName( execName );
00590 data.setIcon( iconName );
00591 if( !wmclass.isEmpty())
00592 data.setWMClass( wmclass );
00593 data.setDesktop( KWin::currentDesktop());
00594 KStartupInfo::sendStartup( id, data );
00595 }
00596 pid_t pid = KProcessRunner::run( proc, KRun::binaryName( binName, true ), id );
00597 if( startup_notify )
00598 {
00599 KStartupInfoData data;
00600 if ( pid )
00601 {
00602 data.addPid( pid );
00603 KStartupInfo::sendChange( id, data );
00604 } else
00605 {
00606 data.setHostname();
00607 KStartupInfo::sendFinish( id, data );
00608 }
00609 KStartupInfo::resetStartupEnv();
00610 }
00611 return pid;
00612 #else
00613 return KProcessRunner::run( proc, KRun::binaryName( binName, true ) );
00614 #endif
00615 }
00616
00617 static pid_t runTempService( const KService& _service, const KURL::List& _urls, bool tempFiles )
00618 {
00619 if (!_urls.isEmpty()) {
00620 kdDebug(7010) << "runTempService: first url " << _urls.first().url() << endl;
00621 }
00622
00623 QStringList args;
00624 if ((_urls.count() > 1) && !_service.allowMultipleFiles())
00625 {
00626
00627
00628
00629
00630
00631 KURL::List::ConstIterator it = _urls.begin();
00632 for(++it; it != _urls.end(); ++it)
00633 {
00634 KURL::List singleUrl;
00635 singleUrl.append(*it);
00636 runTempService( _service, singleUrl, tempFiles );
00637 }
00638 KURL::List singleUrl;
00639 singleUrl.append(_urls.first());
00640 args = KRun::processDesktopExec(_service, singleUrl, false, tempFiles);
00641 }
00642 else
00643 {
00644 args = KRun::processDesktopExec(_service, _urls, false, tempFiles);
00645 }
00646
00647
00648 KProcess * proc = new KProcess;
00649 for(QStringList::Iterator it = args.begin();
00650 it != args.end(); ++it)
00651 {
00652 QString arg = *it;
00653 *proc << arg;
00654 }
00655 return runCommandInternal( proc, &_service, _service.exec(), _service.name(), _service.icon() );
00656 }
00657
00658
00659 pid_t KRun::run( const KService& _service, const KURL::List& _urls )
00660 {
00661 return run( _service, _urls, false );
00662 }
00663
00664 pid_t KRun::run( const KService& _service, const KURL::List& _urls, bool tempFiles )
00665 {
00666 if (!_service.desktopEntryPath().isEmpty() &&
00667 !KDesktopFile::isAuthorizedDesktopFile( _service.desktopEntryPath()))
00668 {
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 QString bin = binaryName( cmd, false );
00733 KService::Ptr service = KService::serviceByDesktopName( bin );
00734 return runCommandInternal( proc, service.data(), bin, execName, iconName );
00735 }
00736
00737 KRun::KRun( const KURL& _url, mode_t _mode, bool _is_local_file, bool _showProgressInfo )
00738 : m_timer(0,"KRun::timer")
00739 {
00740 m_bFault = false;
00741 m_bAutoDelete = true;
00742 m_bProgressInfo = _showProgressInfo;
00743 m_bFinished = false;
00744 m_job = 0L;
00745 m_strURL = _url;
00746 m_bScanFile = false;
00747 m_bIsDirectory = false;
00748 m_bIsLocalFile = _is_local_file;
00749 m_mode = _mode;
00750 d = new KRunPrivate;
00751
00752
00753
00754
00755 m_bInit = true;
00756 connect( &m_timer, SIGNAL( timeout() ), this, SLOT( slotTimeout() ) );
00757 m_timer.start( 0, true );
00758 kdDebug(7010) << " new KRun " << this << " " << _url.prettyURL() << " timer=" << &m_timer << endl;
00759
00760 kapp->ref();
00761 }
00762
00763 void KRun::init()
00764 {
00765 kdDebug(7010) << "INIT called" << endl;
00766 if ( m_strURL.isMalformed() )
00767 {
00768 d->m_showingError = true;
00769 KMessageBoxWrapper::error( 0L, i18n( "Malformed URL\n%1" ).arg( m_strURL.url() ) );
00770 d->m_showingError = false;
00771 m_bFault = true;
00772 m_bFinished = true;
00773 m_timer.start( 0, true );
00774 return;
00775 }
00776 if ( !kapp->authorizeURLAction( "open", KURL(), m_strURL))
00777 {
00778 QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, m_strURL.prettyURL());
00779 d->m_showingError = true;
00780 KMessageBoxWrapper::error( 0L, msg );
00781 d->m_showingError = false;
00782 m_bFault = true;
00783 m_bFinished = true;
00784 m_timer.start( 0, true );
00785 return;
00786 }
00787
00788 if ( !m_bIsLocalFile && m_strURL.isLocalFile() )
00789
00790 m_bIsLocalFile = true;
00791
00792 if ( m_bIsLocalFile )
00793 {
00794 if ( m_mode == 0 )
00795 {
00796 struct stat buff;
00797 if ( stat( QFile::encodeName(m_strURL.path()), &buff ) == -1 )
00798 {
00799 d->m_showingError = true;
00800 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() ) );
00801 d->m_showingError = false;
00802 m_bFault = true;
00803 m_bFinished = true;
00804 m_timer.start( 0, true );
00805 return;
00806 }
00807 m_mode = buff.st_mode;
00808 }
00809
00810 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL, m_mode, m_bIsLocalFile );
00811 assert( mime != 0L );
00812 kdDebug(7010) << "MIME TYPE is " << mime->name() << endl;
00813 foundMimeType( mime->name() );
00814 return;
00815 }
00816 else if ( KProtocolInfo::isHelperProtocol( m_strURL ) ) {
00817 kdDebug(7010) << "Helper protocol" << endl;
00818
00819 KURL::List urls;
00820 urls.append( m_strURL );
00821 QString exec = KProtocolInfo::exec( m_strURL.protocol() );
00822 run( exec, urls );
00823
00824 m_bFinished = true;
00825
00826 m_timer.start( 0, true );
00827 return;
00828 }
00829
00830
00831 if ( S_ISDIR( m_mode ) )
00832 {
00833 foundMimeType( "inode/directory" );
00834 return;
00835 }
00836
00837
00838
00839 if ( !KProtocolInfo::supportsListing( m_strURL ) )
00840 {
00841
00842
00843 scanFile();
00844 return;
00845 }
00846
00847 kdDebug(7010) << "Testing directory (stating)" << endl;
00848
00849
00850 KIO::StatJob *job = KIO::stat( m_strURL, true, 0 , m_bProgressInfo );
00851 connect( job, SIGNAL( result( KIO::Job * ) ),
00852 this, SLOT( slotStatResult( KIO::Job * ) ) );
00853 m_job = job;
00854 kdDebug() << " Job " << job << " is about stating " << m_strURL.url() << endl;
00855 }
00856
00857 KRun::~KRun()
00858 {
00859 kdDebug(7010) << "KRun::~KRun() " << this << endl;
00860 m_timer.stop();
00861 killJob();
00862 kapp->deref();
00863 kdDebug(7010) << "KRun::~KRun() done " << this << endl;
00864 delete d;
00865 }
00866
00867 void KRun::scanFile()
00868 {
00869 kdDebug(7010) << "###### KRun::scanFile " << m_strURL.url() << endl;
00870
00871
00872 if ( m_strURL.query().isEmpty() )
00873 {
00874 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
00875 assert( mime != 0L );
00876 if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
00877 {
00878 kdDebug(7010) << "Scanfile: MIME TYPE is " << mime->name() << endl;
00879 foundMimeType( mime->name() );
00880 return;
00881 }
00882 }
00883
00884
00885
00886
00887
00888 if ( !KProtocolInfo::supportsReading( m_strURL ) )
00889 {
00890 kdError(7010) << "#### NO SUPPORT FOR READING!" << endl;
00891 m_bFault = true;
00892 m_bFinished = true;
00893 m_timer.start( 0, true );
00894 return;
00895 }
00896 kdDebug(7010) << this << " Scanning file " << m_strURL.url() << endl;
00897
00898 KIO::TransferJob *job = KIO::get( m_strURL, false , m_bProgressInfo );
00899 connect(job, SIGNAL( result(KIO::Job *)),
00900 this, SLOT( slotScanFinished(KIO::Job *)));
00901 connect(job, SIGNAL( mimetype(KIO::Job *, const QString &)),
00902 this, SLOT( slotScanMimeType(KIO::Job *, const QString &)));
00903 m_job = job;
00904 kdDebug() << " Job " << job << " is about getting from " << m_strURL.url() << endl;
00905 }
00906
00907 void KRun::slotTimeout()
00908 {
00909 kdDebug(7010) << this << " slotTimeout called" << endl;
00910 if ( m_bInit )
00911 {
00912 m_bInit = false;
00913 init();
00914 return;
00915 }
00916
00917 if ( m_bFault ){
00918 emit error();
00919 }
00920 if ( m_bFinished ){
00921 emit finished();
00922 }
00923
00924 if ( m_bScanFile )
00925 {
00926 m_bScanFile = false;
00927 scanFile();
00928 return;
00929 }
00930 else if ( m_bIsDirectory )
00931 {
00932 m_bIsDirectory = false;
00933 foundMimeType( "inode/directory" );
00934 return;
00935 }
00936
00937 if ( m_bAutoDelete )
00938 {
00939 delete this;
00940 return;
00941 }
00942 }
00943
00944 void KRun::slotStatResult( KIO::Job * job )
00945 {
00946 m_job = 0L;
00947 if (job->error())
00948 {
00949 d->m_showingError = true;
00950 kdError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
00951 job->showErrorDialog();
00952
00953 d->m_showingError = false;
00954
00955 m_bFault = true;
00956 m_bFinished = true;
00957
00958
00959 m_timer.start( 0, true );
00960
00961 } else {
00962
00963 kdDebug(7010) << "Finished" << endl;
00964 if(!dynamic_cast<KIO::StatJob*>(job))
00965 kdFatal() << "job is a " << typeid(*job).name() << " should be a StatJob" << endl;
00966
00967 KIO::UDSEntry entry = ((KIO::StatJob*)job)->statResult();
00968 KIO::UDSEntry::ConstIterator it = entry.begin();
00969 for( ; it != entry.end(); it++ ) {
00970 if ( (*it).m_uds == KIO::UDS_FILE_TYPE )
00971 {
00972 if ( S_ISDIR( (mode_t)((*it).m_long) ) )
00973 m_bIsDirectory = true;
00974 else
00975 m_bScanFile = true;
00976 break;
00977 }
00978 }
00979
00980 assert ( m_bScanFile || m_bIsDirectory );
00981
00982
00983
00984
00985 m_timer.start( 0, true );
00986 }
00987 }
00988
00989 void KRun::slotScanMimeType( KIO::Job *, const QString &mimetype )
00990 {
00991 if ( mimetype.isEmpty() )
00992 kdWarning(7010) << "KRun::slotScanFinished : MimetypeJob didn't find a mimetype! Probably a kioslave bug." << endl;
00993 foundMimeType( mimetype );
00994 m_job = 0;
00995 }
00996
00997 void KRun::slotScanFinished( KIO::Job *job )
00998 {
00999 m_job = 0;
01000 if (job->error())
01001 {
01002 d->m_showingError = true;
01003 kdError(7010) << this << " ERROR (stat) : " << 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 }
01015
01016 void KRun::foundMimeType( const QString& type )
01017 {
01018 kdDebug(7010) << "Resulting mime type is " << type << endl;
01019
01020
01021
01022
01023
01024
01025
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 if (m_job && m_job->inherits("KIO::TransferJob"))
01073 {
01074 KIO::TransferJob *job = static_cast<KIO::TransferJob *>(m_job);
01075 job->putOnHold();
01076 KIO::Scheduler::publishSlaveOnHold();
01077 m_job = 0;
01078 }
01079
01080 Q_ASSERT( !m_bFinished );
01081
01082
01083 if ( !d->m_preferredService.isEmpty() ) {
01084 kdDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService << endl;
01085 KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
01086 if ( serv && serv->hasServiceType( type ) )
01087 {
01088 KURL::List lst;
01089 lst.append( m_strURL );
01090 m_bFinished = KRun::run( *serv, lst );
01095 }
01096 }
01097
01098 if (!m_bFinished && KRun::runURL( m_strURL, type )){
01099 m_bFinished = true;
01100 }
01101 else{
01102 m_bFinished = true;
01103 m_bFault = true;
01104 }
01105
01106 m_timer.start( 0, true );
01107 }
01108
01109 void KRun::killJob()
01110 {
01111 if ( m_job )
01112 {
01113 kdDebug(7010) << "KRun::killJob run=" << this << " m_job=" << m_job << endl;
01114 m_job->kill();
01115 m_job = 0L;
01116 }
01117 }
01118
01119 void KRun::abort()
01120 {
01121 kdDebug() << "KRun::abort " << this << " m_showingError=" << d->m_showingError << endl;
01122 killJob();
01123
01124
01125 if ( d->m_showingError )
01126 return;
01127 m_bFault = true;
01128 m_bFinished = true;
01129
01130
01131 m_timer.start( 0, true );
01132 }
01133
01134 void KRun::setPreferredService( const QString& desktopEntryName )
01135 {
01136 d->m_preferredService = desktopEntryName;
01137 }
01138
01139
01140
01141 pid_t
01142 KProcessRunner::run(KProcess * p, const QString & binName)
01143 {
01144 return (new KProcessRunner(p, binName))->pid();
01145 }
01146
01147 #ifdef Q_WS_X11
01148 pid_t
01149 KProcessRunner::run(KProcess * p, const QString & binName, const KStartupInfoId& id )
01150 {
01151 return (new KProcessRunner(p, binName, id))->pid();
01152 }
01153 #endif
01154
01155 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName )
01156 : QObject(),
01157 process_(p),
01158 binName( _binName )
01159 {
01160 QObject::connect(
01161 process_, SIGNAL(processExited(KProcess *)),
01162 this, SLOT(slotProcessExited(KProcess *)));
01163
01164 process_->start();
01165 }
01166
01167 #ifdef Q_WS_X11
01168 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName, const KStartupInfoId& id )
01169 : QObject(),
01170 process_(p),
01171 binName( _binName ),
01172 id_( id )
01173 {
01174 QObject::connect(
01175 process_, SIGNAL(processExited(KProcess *)),
01176 this, SLOT(slotProcessExited(KProcess *)));
01177
01178 process_->start();
01179 }
01180 #endif
01181
01182 KProcessRunner::~KProcessRunner()
01183 {
01184 delete process_;
01185 }
01186
01187 pid_t
01188 KProcessRunner::pid() const
01189 {
01190 return process_->pid();
01191 }
01192
01193 void
01194 KProcessRunner::slotProcessExited(KProcess * p)
01195 {
01196 if (p != process_)
01197 return;
01198
01199 kdDebug(7010) << "slotProcessExited " << binName << endl;
01200 kdDebug(7010) << "normalExit " << process_->normalExit() << endl;
01201 kdDebug(7010) << "exitStatus " << process_->exitStatus() << endl;
01202 if ( !binName.isEmpty() && process_->normalExit()
01203 && ( process_->exitStatus() == 127 || process_->exitStatus() == 1 ) )
01204 {
01205
01206
01207
01208
01209 if ( !QFile( binName ).exists() && KStandardDirs::findExe( binName ).isEmpty() )
01210 {
01211 kapp->ref();
01212 KMessageBox::sorry( 0L, i18n("Couldn't find the program '%1'").arg( binName ) );
01213 kapp->deref();
01214 }
01215 }
01216 #ifdef Q_WS_X11
01217 if( !id_.none())
01218 {
01219 KStartupInfoData data;
01220 data.addPid( pid());
01221 data.setHostname();
01222 KStartupInfo::sendFinish( id_, data );
01223 }
01224 #endif
01225 delete this;
01226 }
01227
01228 void KRun::virtual_hook( int, void* )
01229 { }
01230
01231 #include "krun.moc"