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()->readEntry("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 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 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
00557 KService::Ptr service = 0;
00558
00559
00560 if ( KDesktopFile::isDesktopFile( bin ) )
00561 {
00562 if (!KDesktopFile::isAuthorizedDesktopFile( bin))
00563 {
00564 KMessageBox::sorry(0, i18n("You are not authorized to execute this file."));
00565 return 0;
00566 }
00567 if( bin[0] == '/' )
00568 service = new KService( bin );
00569 else
00570 service = KService::serviceByDesktopName( bin );
00571 }
00572 bool startup_notify = false;
00573 QCString wmclass;
00574 KStartupInfoId id;
00575 if( service != NULL )
00576 {
00577 if( service->property( "X-KDE-StartupNotify" ).isValid())
00578 {
00579 startup_notify = service->property( "X-KDE-StartupNotify" ).toBool();
00580 wmclass = service->property( "X-KDE-WMClass" ).toString().latin1();
00581 }
00582 else
00583 {
00584 if( service->type() == "Application" )
00585 {
00586 startup_notify = true;
00587 wmclass = "0";
00588 }
00589 }
00590 }
00591 if( startup_notify )
00592 {
00593 id.initId();
00594 id.setupStartupEnv();
00595 if( execName.isEmpty())
00596 execName = service->name();
00597 if( iconName.isEmpty())
00598 iconName = service->icon();
00599 KStartupInfoData data;
00600 data.setHostname();
00601 data.setBin( KRun::binaryName( binName, true ));
00602 data.setName( execName );
00603 data.setIcon( iconName );
00604 if( !wmclass.isEmpty())
00605 data.setWMClass( wmclass );
00606 data.setDesktop( KWin::currentDesktop());
00607 KStartupInfo::sendStartup( id, data );
00608 }
00609 pid_t pid = KProcessRunner::run( proc, KRun::binaryName( binName, true ), id );
00610 if( startup_notify )
00611 {
00612 KStartupInfoData data;
00613 data.addPid( pid );
00614 KStartupInfo::sendChange( id, data );
00615 KStartupInfo::resetStartupEnv();
00616 }
00617 return pid;
00618 #else
00619 return KProcessRunner::run( proc, KRun::binaryName( binName, true ) );
00620 #endif
00621 }
00622
00623 static pid_t runTempService( const KService& _service, const KURL::List& _urls, bool tempFiles )
00624 {
00625 if (!_urls.isEmpty()) {
00626 kdDebug(7010) << "runTempService: first url " << _urls.first().url() << endl;
00627 }
00628
00629 QStringList args;
00630 if ((_urls.count() > 1) && !_service.allowMultipleFiles())
00631 {
00632
00633
00634
00635
00636
00637 KURL::List::ConstIterator it = _urls.begin();
00638 for(++it; it != _urls.end(); ++it)
00639 {
00640 KURL::List singleUrl;
00641 singleUrl.append(*it);
00642 runTempService( _service, singleUrl, tempFiles );
00643 }
00644 KURL::List singleUrl;
00645 singleUrl.append(_urls.first());
00646 args = KRun::processDesktopExec(_service, singleUrl, false, tempFiles);
00647 }
00648 else
00649 {
00650 args = KRun::processDesktopExec(_service, _urls, false, tempFiles);
00651 }
00652
00653 KProcess * proc = new KProcess;
00654 for(QStringList::Iterator it = args.begin();
00655 it != args.end(); ++it)
00656 {
00657 QString arg = *it;
00658 *proc << arg;
00659 }
00660 return runCommandInternal( proc, _service.exec(), _service.name(), _service.icon() );
00661 }
00662
00663
00664 pid_t KRun::run( const KService& _service, const KURL::List& _urls )
00665 {
00666 return run( _service, _urls, false );
00667 }
00668
00669 pid_t KRun::run( const KService& _service, const KURL::List& _urls, bool tempFiles )
00670 {
00671 if (!KDesktopFile::isAuthorizedDesktopFile( _service.desktopEntryPath()))
00672 {
00673 KMessageBox::sorry(0, i18n("You are not authorized to execute this service."));
00674 return 0;
00675 }
00676
00677 if ( !tempFiles )
00678 {
00679
00680 KURL::List::ConstIterator it = _urls.begin();
00681 for(; it != _urls.end(); ++it) {
00682
00683 KRecentDocument::add( *it, _service.desktopEntryName() );
00684 }
00685 }
00686
00687 if ( tempFiles || _service.desktopEntryPath().isEmpty())
00688 {
00689 return runTempService(_service, _urls, tempFiles);
00690 }
00691
00692 kdDebug(7010) << "KRun::run " << _service.desktopEntryPath() << endl;
00693
00694 if (!_urls.isEmpty()) {
00695 kdDebug(7010) << "First url " << _urls.first().url() << endl;
00696 }
00697
00698 QString error;
00699 int pid = 0;
00700
00701 int i = KApplication::startServiceByDesktopPath(
00702 _service.desktopEntryPath(), _urls.toStringList(), &error, 0L, &pid
00703 );
00704
00705 if (i != 0)
00706 {
00707 kdDebug(7010) << error << endl;
00708 KMessageBox::sorry( 0L, error );
00709 return 0;
00710 }
00711
00712 kdDebug(7010) << "startServiceByDesktopPath worked fine" << endl;
00713 return (pid_t) pid;
00714 }
00715
00716
00717 pid_t KRun::run( const QString& _exec, const KURL::List& _urls, const QString& _name,
00718 const QString& _icon, const QString&, const QString&)
00719 {
00720 KService::Ptr service = new KService(_name, _exec, _icon);
00721
00722 return run(*service, _urls);
00723 }
00724
00725 pid_t KRun::runCommand( QString cmd )
00726 {
00727 return KRun::runCommand( cmd, QString::null, QString::null );
00728 }
00729
00730 pid_t KRun::runCommand( const QString& cmd, const QString &execName, const QString & iconName )
00731 {
00732 kdDebug(7010) << "runCommand " << cmd << "," << execName << endl;
00733 KProcess * proc = new KProcess;
00734 proc->setUseShell(true);
00735 *proc << cmd;
00736 return runCommandInternal( proc, binaryName( cmd, false ), execName, iconName );
00737 }
00738
00739 KRun::KRun( const KURL& _url, mode_t _mode, bool _is_local_file, bool _showProgressInfo )
00740 : m_timer(0,"KRun::timer")
00741 {
00742 m_bFault = false;
00743 m_bAutoDelete = true;
00744 m_bProgressInfo = _showProgressInfo;
00745 m_bFinished = false;
00746 m_job = 0L;
00747 m_strURL = _url;
00748 m_bScanFile = false;
00749 m_bIsDirectory = false;
00750 m_bIsLocalFile = _is_local_file;
00751 m_mode = _mode;
00752 d = new KRunPrivate;
00753
00754
00755
00756
00757 m_bInit = true;
00758 connect( &m_timer, SIGNAL( timeout() ), this, SLOT( slotTimeout() ) );
00759 m_timer.start( 0, true );
00760 kdDebug(7010) << " new KRun " << this << " " << _url.prettyURL() << " timer=" << &m_timer << endl;
00761
00762 kapp->ref();
00763 }
00764
00765 void KRun::init()
00766 {
00767 kdDebug(7010) << "INIT called" << endl;
00768 if ( m_strURL.isMalformed() )
00769 {
00770 d->m_showingError = true;
00771 KMessageBoxWrapper::error( 0L, i18n( "Malformed URL\n%1" ).arg( m_strURL.url() ) );
00772 d->m_showingError = false;
00773 m_bFault = true;
00774 m_bFinished = true;
00775 m_timer.start( 0, true );
00776 return;
00777 }
00778
00779 if ( !m_bIsLocalFile && m_strURL.isLocalFile() )
00780
00781 m_bIsLocalFile = true;
00782
00783 if ( m_bIsLocalFile )
00784 {
00785 if ( m_mode == 0 )
00786 {
00787 struct stat buff;
00788 if ( stat( QFile::encodeName(m_strURL.path()), &buff ) == -1 )
00789 {
00790 d->m_showingError = true;
00791 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() ) );
00792 d->m_showingError = false;
00793 m_bFault = true;
00794 m_bFinished = true;
00795 m_timer.start( 0, true );
00796 return;
00797 }
00798 m_mode = buff.st_mode;
00799 }
00800
00801 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL, m_mode, m_bIsLocalFile );
00802 assert( mime != 0L );
00803 kdDebug(7010) << "MIME TYPE is " << mime->name() << endl;
00804 foundMimeType( mime->name() );
00805 return;
00806 }
00807 else if ( KProtocolInfo::isHelperProtocol( m_strURL ) ) {
00808 kdDebug(7010) << "Helper protocol" << endl;
00809
00810 KURL::List urls;
00811 urls.append( m_strURL );
00812 QString exec = KProtocolInfo::exec( m_strURL.protocol() );
00813 run( exec, urls );
00814
00815 m_bFinished = true;
00816
00817 m_timer.start( 0, true );
00818 return;
00819 }
00820
00821
00822 if ( S_ISDIR( m_mode ) )
00823 {
00824 foundMimeType( "inode/directory" );
00825 return;
00826 }
00827
00828
00829
00830 if ( !KProtocolInfo::supportsListing( m_strURL ) )
00831 {
00832
00833
00834 scanFile();
00835 return;
00836 }
00837
00838 kdDebug(7010) << "Testing directory (stating)" << endl;
00839
00840
00841 KIO::StatJob *job = KIO::stat( m_strURL, true, 0 , m_bProgressInfo );
00842 connect( job, SIGNAL( result( KIO::Job * ) ),
00843 this, SLOT( slotStatResult( KIO::Job * ) ) );
00844 m_job = job;
00845 kdDebug() << " Job " << job << " is about stating " << m_strURL.url() << endl;
00846 }
00847
00848 KRun::~KRun()
00849 {
00850 kdDebug(7010) << "KRun::~KRun() " << this << endl;
00851 m_timer.stop();
00852 killJob();
00853 kapp->deref();
00854 kdDebug(7010) << "KRun::~KRun() done " << this << endl;
00855 delete d;
00856 }
00857
00858 void KRun::scanFile()
00859 {
00860 kdDebug(7010) << "###### KRun::scanFile " << m_strURL.url() << endl;
00861
00862
00863 if ( m_strURL.query().isEmpty() )
00864 {
00865 KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
00866 assert( mime != 0L );
00867 if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
00868 {
00869 kdDebug(7010) << "Scanfile: MIME TYPE is " << mime->name() << endl;
00870 foundMimeType( mime->name() );
00871 return;
00872 }
00873 }
00874
00875
00876
00877
00878
00879 if ( !KProtocolInfo::supportsReading( m_strURL ) )
00880 {
00881 kdError(7010) << "#### NO SUPPORT FOR READING!" << endl;
00882 m_bFault = true;
00883 m_bFinished = true;
00884 m_timer.start( 0, true );
00885 return;
00886 }
00887 kdDebug(7010) << this << " Scanning file " << m_strURL.url() << endl;
00888
00889 KIO::TransferJob *job = KIO::get( m_strURL, false , m_bProgressInfo );
00890 connect(job, SIGNAL( result(KIO::Job *)),
00891 this, SLOT( slotScanFinished(KIO::Job *)));
00892 connect(job, SIGNAL( mimetype(KIO::Job *, const QString &)),
00893 this, SLOT( slotScanMimeType(KIO::Job *, const QString &)));
00894 m_job = job;
00895 kdDebug() << " Job " << job << " is about getting from " << m_strURL.url() << endl;
00896 }
00897
00898 void KRun::slotTimeout()
00899 {
00900 kdDebug(7010) << this << " slotTimeout called" << endl;
00901 if ( m_bInit )
00902 {
00903 m_bInit = false;
00904 init();
00905 return;
00906 }
00907
00908 if ( m_bFault ){
00909 emit error();
00910 }
00911 if ( m_bFinished ){
00912 emit finished();
00913 }
00914
00915 if ( m_bScanFile )
00916 {
00917 m_bScanFile = false;
00918 scanFile();
00919 return;
00920 }
00921 else if ( m_bIsDirectory )
00922 {
00923 m_bIsDirectory = false;
00924 foundMimeType( "inode/directory" );
00925 return;
00926 }
00927
00928 if ( m_bAutoDelete )
00929 {
00930 delete this;
00931 return;
00932 }
00933 }
00934
00935 void KRun::slotStatResult( KIO::Job * job )
00936 {
00937 m_job = 0L;
00938 if (job->error())
00939 {
00940 d->m_showingError = true;
00941 kdError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
00942 job->showErrorDialog();
00943
00944 d->m_showingError = false;
00945
00946 m_bFault = true;
00947 m_bFinished = true;
00948
00949
00950 m_timer.start( 0, true );
00951
00952 } else {
00953
00954 kdDebug(7010) << "Finished" << endl;
00955 if(!dynamic_cast<KIO::StatJob*>(job))
00956 kdFatal() << "job is a " << typeid(*job).name() << " should be a StatJob" << endl;
00957
00958 KIO::UDSEntry entry = ((KIO::StatJob*)job)->statResult();
00959 KIO::UDSEntry::ConstIterator it = entry.begin();
00960 for( ; it != entry.end(); it++ ) {
00961 if ( (*it).m_uds == KIO::UDS_FILE_TYPE )
00962 {
00963 if ( S_ISDIR( (mode_t)((*it).m_long) ) )
00964 m_bIsDirectory = true;
00965 else
00966 m_bScanFile = true;
00967 break;
00968 }
00969 }
00970
00971 assert ( m_bScanFile || m_bIsDirectory );
00972
00973
00974
00975
00976 m_timer.start( 0, true );
00977 }
00978 }
00979
00980 void KRun::slotScanMimeType( KIO::Job *, const QString &mimetype )
00981 {
00982 if ( mimetype.isEmpty() )
00983 kdWarning(7010) << "KRun::slotScanFinished : MimetypeJob didn't find a mimetype! Probably a kioslave bug." << endl;
00984 foundMimeType( mimetype );
00985 m_job = 0;
00986 }
00987
00988 void KRun::slotScanFinished( KIO::Job *job )
00989 {
00990 m_job = 0;
00991 if (job->error())
00992 {
00993 d->m_showingError = true;
00994 kdError(7010) << this << " ERROR (stat) : " << job->error() << " " << job->errorString() << endl;
00995 job->showErrorDialog();
00996
00997 d->m_showingError = false;
00998
00999 m_bFault = true;
01000 m_bFinished = true;
01001
01002
01003 m_timer.start( 0, true );
01004 }
01005 }
01006
01007 void KRun::foundMimeType( const QString& type )
01008 {
01009 kdDebug(7010) << "Resulting mime type is " << type << endl;
01010
01011
01012
01013
01014
01015
01016
01017
01018
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 if (m_job && m_job->inherits("KIO::TransferJob"))
01064 {
01065 KIO::TransferJob *job = static_cast<KIO::TransferJob *>(m_job);
01066 job->putOnHold();
01067 KIO::Scheduler::publishSlaveOnHold();
01068 m_job = 0;
01069 }
01070
01071 Q_ASSERT( !m_bFinished );
01072
01073
01074 if ( !d->m_preferredService.isEmpty() ) {
01075 kdDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService << endl;
01076 KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
01077 if ( serv && serv->hasServiceType( type ) )
01078 {
01079 KURL::List lst;
01080 lst.append( m_strURL );
01081 m_bFinished = KRun::run( *serv, lst );
01086 }
01087 }
01088
01089 if (!m_bFinished && KRun::runURL( m_strURL, type )){
01090 m_bFinished = true;
01091 }
01092 else{
01093 m_bFinished = true;
01094 m_bFault = true;
01095 }
01096
01097 m_timer.start( 0, true );
01098 }
01099
01100 void KRun::killJob()
01101 {
01102 if ( m_job )
01103 {
01104 kdDebug(7010) << "KRun::killJob run=" << this << " m_job=" << m_job << endl;
01105 m_job->kill();
01106 m_job = 0L;
01107 }
01108 }
01109
01110 void KRun::abort()
01111 {
01112 kdDebug() << "KRun::abort " << this << " m_showingError=" << d->m_showingError << endl;
01113 killJob();
01114
01115
01116 if ( d->m_showingError )
01117 return;
01118 m_bFault = true;
01119 m_bFinished = true;
01120
01121
01122 m_timer.start( 0, true );
01123 }
01124
01125 void KRun::setPreferredService( const QString& desktopEntryName )
01126 {
01127 d->m_preferredService = desktopEntryName;
01128 }
01129
01130
01131
01132 pid_t
01133 KProcessRunner::run(KProcess * p, const QString & binName)
01134 {
01135 return (new KProcessRunner(p, binName))->pid();
01136 }
01137
01138 #ifdef Q_WS_X11
01139 pid_t
01140 KProcessRunner::run(KProcess * p, const QString & binName, const KStartupInfoId& id )
01141 {
01142 return (new KProcessRunner(p, binName, id))->pid();
01143 }
01144 #endif
01145
01146 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName )
01147 : QObject(),
01148 process_(p),
01149 binName( _binName )
01150 {
01151 QObject::connect(
01152 process_, SIGNAL(processExited(KProcess *)),
01153 this, SLOT(slotProcessExited(KProcess *)));
01154
01155 process_->start();
01156 }
01157
01158 #ifdef Q_WS_X11
01159 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName, const KStartupInfoId& id )
01160 : QObject(),
01161 process_(p),
01162 binName( _binName ),
01163 id_( id )
01164 {
01165 QObject::connect(
01166 process_, SIGNAL(processExited(KProcess *)),
01167 this, SLOT(slotProcessExited(KProcess *)));
01168
01169 process_->start();
01170 }
01171 #endif
01172
01173 KProcessRunner::~KProcessRunner()
01174 {
01175 delete process_;
01176 }
01177
01178 pid_t
01179 KProcessRunner::pid() const
01180 {
01181 return process_->pid();
01182 }
01183
01184 void
01185 KProcessRunner::slotProcessExited(KProcess * p)
01186 {
01187 if (p != process_)
01188 return;
01189
01190 kdDebug(7010) << "slotProcessExited " << binName << endl;
01191 kdDebug(7010) << "normalExit " << process_->normalExit() << endl;
01192 kdDebug(7010) << "exitStatus " << process_->exitStatus() << endl;
01193 if ( !binName.isEmpty() && process_->normalExit()
01194 && ( process_->exitStatus() == 127 || process_->exitStatus() == 1 ) )
01195 {
01196
01197
01198
01199
01200 if ( !QFile( binName ).exists() && KStandardDirs::findExe( binName ).isEmpty() )
01201 {
01202 kapp->ref();
01203 KMessageBox::sorry( 0L, i18n("Couldn't find the program '%1'").arg( binName ) );
01204 kapp->deref();
01205 }
01206 }
01207 #ifdef Q_WS_X11
01208 if( !id_.none())
01209 {
01210 KStartupInfoData data;
01211 data.addPid( pid());
01212 data.setHostname();
01213 KStartupInfo::sendFinish( id_, data );
01214 }
01215 #endif
01216 delete this;
01217 }
01218
01219 void KRun::virtual_hook( int, void* )
01220 { }
01221
01222 #include "krun.moc"