• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kio/kio
 

kio/kio

krun.cpp
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 2000 Torben Weis <weis@kde.org>
00003     Copyright (C) 2006 David Faure <faure@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "krun.h"
00022 
00023 #include <assert.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 #include <typeinfo>
00028 
00029 #include <tqwidget.h>
00030 #include <tqguardedptr.h>
00031 
00032 #include "kuserprofile.h"
00033 #include "kmimetype.h"
00034 #include "kmimemagic.h"
00035 #include "kio/job.h"
00036 #include "kio/global.h"
00037 #include "kio/scheduler.h"
00038 #include "kio/netaccess.h"
00039 #include "kfile/kopenwith.h"
00040 #include "kfile/krecentdocument.h"
00041 
00042 #include <kdatastream.h>
00043 #include <kmessageboxwrapper.h>
00044 #include <kurl.h>
00045 #include <kapplication.h>
00046 #include <kdebug.h>
00047 #include <klocale.h>
00048 #include <kprotocolinfo.h>
00049 #include <kstandarddirs.h>
00050 #include <kprocess.h>
00051 #include <dcopclient.h>
00052 #include <tqfile.h>
00053 #include <tqfileinfo.h>
00054 #include <tqtextstream.h>
00055 #include <tqdatetime.h>
00056 #include <tqregexp.h>
00057 #include <kdesktopfile.h>
00058 #include <kstartupinfo.h>
00059 #include <kmacroexpander.h>
00060 #include <kshell.h>
00061 #include <kde_file.h>
00062 #include <kstringhandler.h>
00063 
00064 #ifdef Q_WS_X11
00065 #include <kwin.h>
00066 #endif
00067 
00068 class KRun::KRunPrivate
00069 {
00070 public:
00071     KRunPrivate() { m_showingError = false; }
00072 
00073     bool m_showingError;
00074     bool m_runExecutables;
00075 
00076     TQString m_preferredService;
00077     TQString m_externalBrowser;
00078     TQString m_localPath;
00079     TQString m_suggestedFileName;
00080     TQGuardedPtr <TQWidget> m_window;
00081     TQCString m_asn;
00082 };
00083 
00084 pid_t KRun::runURL( const KURL& u, const TQString& _mimetype )
00085 {
00086     return runURL( u, _mimetype, false, true, TQString::null );
00087 }
00088 
00089 pid_t KRun::runURL( const KURL& u, const TQString& _mimetype, bool tempFile )
00090 {
00091     return runURL( u, _mimetype, tempFile, true, TQString::null );
00092 }
00093 
00094 pid_t KRun::runURL( const KURL& u, const TQString& _mimetype, bool tempFile, bool runExecutables )
00095 {
00096     return runURL( u, _mimetype, tempFile, runExecutables, TQString::null );
00097 }
00098 
00099 bool KRun::isExecutableFile( const KURL& url, const TQString &mimetype )
00100 {
00101   if ( !url.isLocalFile() )
00102      return false;
00103   TQFileInfo file( url.path() );
00104   if ( file.isExecutable() )  // Got a prospective file to run
00105   {
00106     KMimeType::Ptr mimeType = KMimeType::mimeType( mimetype );
00107 
00108     if ( mimeType->is("application/x-executable") || mimeType->is("application/x-executable-script") )
00109       return true;
00110   }
00111   return false;
00112 }
00113 
00114 pid_t KRun::runURL( const KURL& u, const TQString& _mimetype, bool tempFile, bool runExecutables, const TQString& suggestedFileName )
00115 {
00116     return runURL( u, _mimetype, NULL, "", tempFile, runExecutables, suggestedFileName );
00117 }
00118 
00119 // This is called by foundMimeType, since it knows the mimetype of the URL
00120 pid_t KRun::runURL( const KURL& u, const TQString& _mimetype, TQWidget* window, const TQCString& asn,
00121     bool tempFile, bool runExecutables, const TQString& suggestedFileName )
00122 {
00123   bool noRun = false;
00124   bool noAuth = false;
00125   if ( _mimetype == "inode/directory-locked" )
00126   {
00127     KMessageBoxWrapper::error( window,
00128             i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>").arg(u.htmlURL()) );
00129     return 0;
00130   }
00131   else if ( (_mimetype == "application/x-desktop") ||
00132             (_mimetype == "media/builtin-mydocuments") ||
00133             (_mimetype == "media/builtin-mycomputer") ||
00134             (_mimetype == "media/builtin-mynetworkplaces") ||
00135             (_mimetype == "media/builtin-printers") ||
00136             (_mimetype == "media/builtin-trash") ||
00137             (_mimetype == "media/builtin-webbrowser") )
00138   {
00139     if ( u.isLocalFile() && runExecutables )
00140       return KDEDesktopMimeType::run( u, true );
00141   }
00142   else if ( isExecutableFile(u, _mimetype) )
00143   {
00144     if ( u.isLocalFile() && runExecutables)
00145     {
00146       if (kapp->authorize("shell_access"))
00147       {
00148         TQString path = u.path();
00149         shellQuote( path );
00150         return (KRun::runCommand(path, TQString::null, TQString::null, window, asn)); // just execute the url as a command
00151         // ## TODO implement deleting the file if tempFile==true
00152       }
00153       else
00154       {
00155         noAuth = true;
00156       }
00157     }
00158     else if (_mimetype == "application/x-executable" || _mimetype == "application/x-pie-executable")
00159     {
00160       noRun = true;
00161     }
00162   }
00163   else if ( isExecutable(_mimetype) )
00164   {
00165     if (!runExecutables)
00166       noRun = true;
00167 
00168     if (!kapp->authorize("shell_access"))
00169       noAuth = true;
00170   }
00171 
00172   if ( noRun )
00173   {
00174     KMessageBox::sorry( window,
00175         i18n("<qt>The file <b>%1</b> is an executable program. "
00176              "For safety it will not be started.</qt>").arg(u.htmlURL()));
00177     return 0;
00178   }
00179   if ( noAuth )
00180   {
00181     KMessageBoxWrapper::error( window,
00182         i18n("<qt>You do not have permission to run <b>%1</b>.</qt>").arg(u.htmlURL()) );
00183     return 0;
00184   }
00185 
00186   KURL::List lst;
00187   lst.append( u );
00188 
00189   static const TQString& app_str = KGlobal::staticQString("Application");
00190 
00191   KService::Ptr offer = KServiceTypeProfile::preferredService( _mimetype, app_str );
00192 
00193   if ( !offer )
00194   {
00195     // Open-with dialog
00196     // TODO : pass the mimetype as a parameter, to show it (comment field) in the dialog !
00197     // Hmm, in fact KOpenWithDlg::setServiceType already guesses the mimetype from the first URL of the list...
00198     return displayOpenWithDialog( lst, tempFile, suggestedFileName );
00199   }
00200 
00201   return KRun::run( *offer, lst, window, asn, tempFile, suggestedFileName );
00202 }
00203 
00204 bool KRun::displayOpenWithDialog( const KURL::List& lst )
00205 {
00206     return displayOpenWithDialog( lst, false, TQString::null );
00207 }
00208 
00209 bool KRun::displayOpenWithDialog( const KURL::List& lst, bool tempFiles )
00210 {
00211     return displayOpenWithDialog( lst, tempFiles, TQString::null );
00212 }
00213 
00214 bool KRun::displayOpenWithDialog( const KURL::List& lst, bool tempFiles, const TQString& suggestedFileName )
00215 {
00216     if (kapp && !kapp->authorizeKAction("openwith"))
00217     {
00218        // TODO: Better message, i18n freeze :-(
00219        KMessageBox::sorry(0L, i18n("You are not authorized to open this file."));
00220        return false;
00221     }
00222 
00223     KOpenWithDlg l( lst, i18n("Open with:"), TQString::null, 0L );
00224     if ( l.exec() )
00225     {
00226       KService::Ptr service = l.service();
00227       if ( !!service )
00228         return KRun::run( *service, lst, 0 /*window*/, tempFiles, suggestedFileName );
00229 
00230       kdDebug(7010) << "No service set, running " << l.text() << endl;
00231       return KRun::run( l.text(), lst, suggestedFileName ); // TODO handle tempFiles
00232     }
00233     return false;
00234 }
00235 
00236 void KRun::shellQuote( TQString &_str )
00237 {
00238     // Credits to Walter, says Bernd G. :)
00239     if (_str.isEmpty()) // Don't create an explicit empty parameter
00240         return;
00241     TQChar q('\'');
00242     _str.replace(q, "'\\''").prepend(q).append(q);
00243 }
00244 
00245 
00246 class KRunMX1 : public KMacroExpanderBase {
00247 public:
00248     KRunMX1( const KService &_service ) :
00249         KMacroExpanderBase( '%' ), hasUrls( false ), hasSpec( false ), service( _service ) {}
00250     bool hasUrls:1, hasSpec:1;
00251 
00252 protected:
00253     virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
00254 
00255 private:
00256     const KService &service;
00257 };
00258 
00259 int
00260 KRunMX1::expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret )
00261 {
00262    uint option = str[pos + 1];
00263    switch( option ) {
00264    case 'c':
00265       ret << service.name().replace( '%', "%%" );
00266       break;
00267    case 'k':
00268       ret << service.desktopEntryPath().replace( '%', "%%" );
00269       break;
00270    case 'i':
00271       ret << "-icon" << service.icon().replace( '%', "%%" );
00272       break;
00273    case 'm':
00274       ret << "-miniicon" << service.icon().replace( '%', "%%" );
00275       break;
00276    case 'u':
00277    case 'U':
00278       hasUrls = true;
00279       /* fallthrough */
00280    case 'f':
00281    case 'F':
00282    case 'n':
00283    case 'N':
00284    case 'd':
00285    case 'D':
00286    case 'v':
00287       hasSpec = true;
00288       /* fallthrough */
00289    default:
00290       return -2; // subst with same and skip
00291    }
00292    return 2;
00293 }
00294 
00295 class KRunMX2 : public KMacroExpanderBase {
00296 public:
00297     KRunMX2( const KURL::List &_urls ) :
00298         KMacroExpanderBase( '%' ), ignFile( false ), urls( _urls ) {}
00299     bool ignFile:1;
00300 
00301 protected:
00302     virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
00303 
00304 private:
00305     void subst( int option, const KURL &url, TQStringList &ret );
00306 
00307     const KURL::List &urls;
00308 };
00309 
00310 void
00311 KRunMX2::subst( int option, const KURL &url, TQStringList &ret )
00312 {
00313    switch( option ) {
00314    case 'u':
00315       ret << url.pathOrURL();
00316       break;
00317    case 'd':
00318       ret << url.directory();
00319       break;
00320    case 'f':
00321       ret << url.path();
00322       break;
00323    case 'n':
00324       ret << url.fileName();
00325       break;
00326    case 'v':
00327       if (url.isLocalFile() && TQFile::exists( url.path() ) )
00328           ret << KDesktopFile( url.path(), true ).readEntry( "Dev" );
00329       break;
00330    }
00331    return;
00332 }
00333 
00334 int
00335 KRunMX2::expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret )
00336 {
00337    uint option = str[pos + 1];
00338    switch( option ) {
00339    case 'f':
00340    case 'u':
00341    case 'n':
00342    case 'd':
00343    case 'v':
00344       if( urls.isEmpty() ) {
00345          if (!ignFile)
00346             kdDebug() << "KRun::processDesktopExec: No URLs supplied to single-URL service " << str << endl;
00347       } else if( urls.count() > 1 )
00348           kdWarning() << "KRun::processDesktopExec: " << urls.count() << " URLs supplied to single-URL service " << str << endl;
00349       else
00350          subst( option, urls.first(), ret );
00351       break;
00352    case 'F':
00353    case 'U':
00354    case 'N':
00355    case 'D':
00356       option += 'a' - 'A';
00357       for( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it )
00358          subst( option, *it, ret );
00359       break;
00360    case '%':
00361       ret = "%";
00362       break;
00363    default:
00364       return -2; // subst with same and skip
00365    }
00366    return 2;
00367 }
00368 
00369 // BIC: merge methods below
00370 TQStringList KRun::processDesktopExec(const KService &_service, const KURL::List& _urls, bool has_shell) {
00371     return processDesktopExec( _service, _urls, has_shell, false, TQString::null );
00372 }
00373 
00374 TQStringList KRun::processDesktopExec(const KService &_service, const KURL::List& _urls, bool has_shell /* KDE4: remove */, bool tempFiles)
00375 {
00376     return processDesktopExec( _service, _urls, has_shell, tempFiles, TQString::null );
00377 }
00378 
00379 TQStringList KRun::processDesktopExec(const KService &_service, const KURL::List& _urls, bool has_shell /* KDE4: remove */, bool tempFiles, const TQString& suggestedFileName)
00380 {
00381   TQString exec = _service.exec();
00382   TQStringList result;
00383   bool appHasTempFileOption;
00384 
00385   KRunMX1 mx1( _service );
00386   KRunMX2 mx2( _urls );
00387 
00389   TQRegExp re("^\\s*(?:/bin/)?sh\\s+-c\\s+(.*)$");
00390   if (!re.search( exec )) {
00391     exec = TQString(re.cap( 1 )).stripWhiteSpace();
00392     for (uint pos = 0; pos < exec.length(); ) {
00393       TQChar c = exec.unicode()[pos];
00394       if (c != '\'' && c != '"')
00395         goto synerr; // what else can we do? after normal parsing the substs would be insecure
00396       int pos2 = exec.find( c, pos + 1 ) - 1;
00397       if (pos2 < 0)
00398         goto synerr; // quoting error
00399       memcpy( (void *)(exec.unicode() + pos), exec.unicode() + pos + 1, (pos2 - pos) * sizeof(TQChar));
00400       pos = pos2;
00401       exec.remove( pos, 2 );
00402     }
00403   }
00404 
00405   if( !mx1.expandMacrosShellQuote( exec ) )
00406     goto synerr; // error in shell syntax
00407 
00408   // FIXME: the current way of invoking kioexec disables term and su use
00409 
00410   // Check if we need "tempexec" (kioexec in fact)
00411   appHasTempFileOption = tempFiles && _service.property("X-KDE-HasTempFileOption").toBool();
00412   if( tempFiles && !appHasTempFileOption && _urls.size() ) {
00413     result << "kioexec" << "--tempfiles" << exec;
00414     result += _urls.toStringList();
00415     if (has_shell)
00416       result = KShell::joinArgs( result );
00417     return result;
00418   }
00419 
00420   // Check if we need kioexec
00421   if( !mx1.hasUrls ) {
00422     for( KURL::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it )
00423       if ( !(*it).isLocalFile() && !KProtocolInfo::isHelperProtocol(*it) ) {
00424         // We need to run the app through kioexec
00425         result << "kioexec";
00426         if ( tempFiles )
00427             result << "--tempfiles";
00428         if ( !suggestedFileName.isEmpty() ) {
00429             result << "--suggestedfilename";
00430             result << suggestedFileName;
00431         }
00432         result << exec;
00433         result += _urls.toStringList();
00434         if (has_shell)
00435           result = KShell::joinArgs( result );
00436         return result;
00437       }
00438   }
00439 
00440   if ( appHasTempFileOption )
00441       exec += " --tempfile";
00442 
00443   // Did the user forget to append something like '%f'?
00444   // If so, then assume that '%f' is the right choice => the application
00445   // accepts only local files.
00446   if( !mx1.hasSpec ) {
00447     exec += " %f";
00448     mx2.ignFile = true;
00449   }
00450 
00451   mx2.expandMacrosShellQuote( exec ); // syntax was already checked, so don't check return value
00452 
00453 /*
00454  1 = need_shell, 2 = terminal, 4 = su, 8 = has_shell
00455 
00456  0                                                           << split(cmd)
00457  1                                                           << "sh" << "-c" << cmd
00458  2 << split(term) << "-e"                                    << split(cmd)
00459  3 << split(term) << "-e"                                    << "sh" << "-c" << cmd
00460 
00461  4                        << "kdesu" << "-u" << user << "-c" << cmd
00462  5                        << "kdesu" << "-u" << user << "-c" << ("sh -c " + quote(cmd))
00463  6 << split(term) << "-e" << "su"            << user << "-c" << cmd
00464  7 << split(term) << "-e" << "su"            << user << "-c" << ("sh -c " + quote(cmd))
00465 
00466  8                                                           << cmd
00467  9                                                           << cmd
00468  a << term        << "-e"                                    << cmd
00469  b << term        << "-e"                                    << ("sh -c " + quote(cmd))
00470 
00471  c                        << "kdesu" << "-u" << user << "-c" << quote(cmd)
00472  d                        << "kdesu" << "-u" << user << "-c" << quote("sh -c " + quote(cmd))
00473  e << term        << "-e" << "su"            << user << "-c" << quote(cmd)
00474  f << term        << "-e" << "su"            << user << "-c" << quote("sh -c " + quote(cmd))
00475 
00476  "sh -c" is needed in the "su" case, too, as su uses the user's login shell, not sh.
00477  this could be optimized with the -s switch of some su versions (e.g., debian linux).
00478 */
00479 
00480   if (_service.terminal()) {
00481     KConfigGroupSaver gs(KGlobal::config(), "General");
00482     TQString terminal = KGlobal::config()->readPathEntry("TerminalApplication", "konsole");
00483     if (terminal == "konsole")
00484       terminal += " -caption=%c %i %m";
00485     terminal += " ";
00486     terminal += _service.terminalOptions();
00487     if( !mx1.expandMacrosShellQuote( terminal ) ) {
00488       kdWarning() << "KRun: syntax error in command `" << terminal << "', service `" << _service.name() << "'" << endl;
00489       return TQStringList();
00490     }
00491     mx2.expandMacrosShellQuote( terminal );
00492     if (has_shell)
00493       result << terminal;
00494     else
00495       result = KShell::splitArgs( terminal ); // assuming that the term spec never needs a shell!
00496     result << "-e";
00497   }
00498 
00499   int err;
00500   if (_service.substituteUid()) {
00501     if (_service.terminal())
00502       result << "su";
00503     else
00504       result << "kdesu" << "-u";
00505     result << _service.username() << "-c";
00506     KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
00507     if (err == KShell::FoundMeta) {
00508       shellQuote( exec );
00509       exec.prepend( "/bin/sh -c " );
00510     } else if (err != KShell::NoError)
00511       goto synerr;
00512     if (has_shell)
00513       shellQuote( exec );
00514     result << exec;
00515   } else {
00516     if (has_shell) {
00517       if (_service.terminal()) {
00518         KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
00519         if (err == KShell::FoundMeta) {
00520           shellQuote( exec );
00521           exec.prepend( "/bin/sh -c " );
00522         } else if (err != KShell::NoError)
00523           goto synerr;
00524       }
00525       result << exec;
00526     } else {
00527       result += KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
00528       if (err == KShell::FoundMeta)
00529         result << "/bin/sh" << "-c" << exec;
00530       else if (err != KShell::NoError)
00531         goto synerr;
00532     }
00533   }
00534 
00535   return result;
00536 
00537  synerr:
00538   kdWarning() << "KRun: syntax error in command `" << _service.exec() << "', service `" << _service.name() << "'" << endl;
00539   return TQStringList();
00540 }
00541 
00542 //static
00543 TQString KRun::binaryName( const TQString & execLine, bool removePath )
00544 {
00545   // Remove parameters and/or trailing spaces.
00546   TQStringList args = KShell::splitArgs( execLine );
00547   for (TQStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
00548     if (!(*it).contains('='))
00549       // Remove path if wanted
00550   return removePath ? (*it).mid(TQString(*it).findRev('/') + 1) : *it; 
00551   return TQString();
00552 }
00553 
00554 static pid_t runCommandInternal( KProcess* proc, const KService* service, const TQString& binName,
00555     const TQString &execName, const TQString & iconName, TQWidget* window, TQCString asn )
00556 {
00557   if (service && !service->desktopEntryPath().isEmpty()
00558       && !KDesktopFile::isAuthorizedDesktopFile( service->desktopEntryPath() ))
00559   {
00560      kdWarning() << "No authorization to execute " << service->desktopEntryPath() << endl;
00561      KMessageBox::sorry(window, i18n("You are not authorized to execute this file."));
00562      return 0;
00563   }
00564   TQString bin = KRun::binaryName( binName, true );
00565 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
00566   bool silent;
00567   TQCString wmclass;
00568   KStartupInfoId id;
00569   bool startup_notify = ( asn != "0" && KRun::checkStartupNotify( binName, service, &silent, &wmclass ));
00570   if( startup_notify )
00571   {
00572       id.initId( asn );
00573       id.setupStartupEnv();
00574       KStartupInfoData data;
00575       data.setHostname();
00576       data.setBin( bin );
00577       if( !execName.isEmpty())
00578           data.setName( execName );
00579       else if( service && !service->name().isEmpty())
00580           data.setName( service->name());
00581       data.setDescription( i18n( "Launching %1" ).arg( data.name()));
00582       if( !iconName.isEmpty())
00583           data.setIcon( iconName );
00584       else if( service && !service->icon().isEmpty())
00585           data.setIcon( service->icon());
00586       if( !wmclass.isEmpty())
00587           data.setWMClass( wmclass );
00588       if( silent )
00589           data.setSilent( KStartupInfoData::Yes );
00590       data.setDesktop( KWin::currentDesktop());
00591       if( window )
00592           data.setLaunchedBy( window->winId());
00593       KStartupInfo::sendStartup( id, data );
00594   }
00595   pid_t pid = KProcessRunner::run( proc, binName, id );
00596   if( startup_notify && pid )
00597   {
00598       KStartupInfoData data;
00599       data.addPid( pid );
00600       KStartupInfo::sendChange( id, data );
00601       KStartupInfo::resetStartupEnv();
00602   }
00603   return pid;
00604 #else
00605   Q_UNUSED( execName );
00606   Q_UNUSED( iconName );
00607   return KProcessRunner::run( proc, bin );
00608 #endif
00609 }
00610 
00611 // This code is also used in klauncher.
00612 bool KRun::checkStartupNotify( const TQString& /*binName*/, const KService* service, bool* silent_arg, TQCString* wmclass_arg )
00613 {
00614   bool silent = false;
00615   TQCString wmclass;
00616   if( service && service->property( "StartupNotify" ).isValid())
00617   {
00618       silent = !service->property( "StartupNotify" ).toBool();
00619       wmclass = service->property( "StartupWMClass" ).toString().latin1();
00620   }
00621   else if( service && service->property( "X-KDE-StartupNotify" ).isValid())
00622   {
00623       silent = !service->property( "X-KDE-StartupNotify" ).toBool();
00624       wmclass = service->property( "X-KDE-WMClass" ).toString().latin1();
00625   }
00626   else // non-compliant app
00627   {
00628       if( service )
00629       {
00630           if( service->type() == "Application" )
00631               wmclass = "0"; // doesn't have .desktop entries needed, start as non-compliant
00632           else
00633               return false; // no startup notification at all
00634       }
00635       else
00636       {
00637 #if 0
00638         // Create startup notification even for apps for which there shouldn't be any,
00639         // just without any visual feedback. This will ensure they'll be positioned on the proper
00640         // virtual desktop, and will get user timestamp from the ASN ID.
00641           wmclass = "0";
00642           silent = true;
00643 #else   // That unfortunately doesn't work, when the launched non-compliant application
00644         // launches another one that is compliant and there is any delay inbetween (bnc:#343359)
00645           return false;
00646 #endif
00647       }
00648   }
00649   if( silent_arg != NULL )
00650       *silent_arg = silent;
00651   if( wmclass_arg != NULL )
00652       *wmclass_arg = wmclass;
00653   return true;
00654 }
00655 
00656 static pid_t runTempService( const KService& _service, const KURL::List& _urls, TQWidget* window,
00657     const TQCString& asn, bool tempFiles, const TQString& suggestedFileName )
00658 {
00659   if (!_urls.isEmpty()) {
00660     kdDebug(7010) << "runTempService: first url " << _urls.first().url() << endl;
00661   }
00662 
00663   TQStringList args;
00664   if ((_urls.count() > 1) && !_service.allowMultipleFiles())
00665   {
00666       // We need to launch the application N times. That sucks.
00667       // We ignore the result for application 2 to N.
00668       // For the first file we launch the application in the
00669       // usual way. The reported result is based on this
00670       // application.
00671       KURL::List::ConstIterator it = _urls.begin();
00672       while(++it != _urls.end())
00673       {
00674          KURL::List singleUrl;
00675          singleUrl.append(*it);
00676          runTempService( _service, singleUrl, window, "", tempFiles, suggestedFileName );
00677       }
00678       KURL::List singleUrl;
00679       singleUrl.append(_urls.first());
00680       args = KRun::processDesktopExec(_service, singleUrl, false, tempFiles, suggestedFileName);
00681   }
00682   else
00683   {
00684       args = KRun::processDesktopExec(_service, _urls, false, tempFiles, suggestedFileName);
00685   }
00686   kdDebug(7010) << "runTempService: KProcess args=" << args << endl;
00687 
00688   KProcess * proc = new KProcess;
00689   *proc << args;
00690 
00691   if (!_service.path().isEmpty())
00692      proc->setWorkingDirectory(_service.path());
00693 
00694   return runCommandInternal( proc, &_service, KRun::binaryName( _service.exec(), false ),
00695                              _service.name(), _service.icon(), window, asn );
00696 }
00697 
00698 // WARNING: don't call this from processDesktopExec, since klauncher uses that too...
00699 static KURL::List resolveURLs( const KURL::List& _urls, const KService& _service )
00700 {
00701   // Check which protocols the application supports.
00702   // This can be a list of actual protocol names, or just KIO for KDE apps.
00703   TQStringList supportedProtocols = _service.property("X-KDE-Protocols").toStringList();
00704   KRunMX1 mx1( _service );
00705   TQString exec = _service.exec();
00706   if ( mx1.expandMacrosShellQuote( exec ) && !mx1.hasUrls ) {
00707     Q_ASSERT( supportedProtocols.isEmpty() ); // huh? If you support protocols you need %u or %U...
00708   } else {
00709     if ( supportedProtocols.isEmpty() )
00710     {
00711       // compat mode: assume KIO if not set and it's a KDE app
00712       TQStringList categories = _service.property("Categories").toStringList();
00713       if (( categories.find("TDE") != categories.end() ) && ( categories.find("KDE") != categories.end() ))
00714          supportedProtocols.append( "KIO" );
00715       else { // if no KDE app, be a bit over-generic
00716          supportedProtocols.append( "http");
00717          supportedProtocols.append( "ftp");
00718       }
00719     }
00720   }
00721   kdDebug(7010) << "supportedProtocols:" << supportedProtocols << endl;
00722 
00723   KURL::List urls( _urls );
00724   if ( supportedProtocols.find( "KIO" ) == supportedProtocols.end() ) {
00725     for( KURL::List::Iterator it = urls.begin(); it != urls.end(); ++it ) {
00726       const KURL url = *it;
00727       bool supported = url.isLocalFile() || supportedProtocols.find( url.protocol().lower() ) != supportedProtocols.end();
00728       kdDebug(7010) << "Looking at url=" << url << " supported=" << supported << endl;
00729       if ( !supported && KProtocolInfo::protocolClass(url.protocol()) == ":local" &&
00730            !url.url().startsWith("media:/") && !url.url().startsWith("system:/media"))
00731       {
00732         // Maybe we can resolve to a local URL?
00733         KURL localURL = KIO::NetAccess::mostLocalURL( url, 0 );
00734         if ( localURL != url ) {
00735           *it = localURL;
00736           kdDebug(7010) << "Changed to " << localURL << endl;
00737         }
00738       }
00739     }
00740   }
00741   return urls;
00742 }
00743 
00744 // BIC merge methods below
00745 pid_t KRun::run( const KService& _service, const KURL::List& _urls )
00746 {
00747     return run( _service, _urls, 0, false, TQString::null );
00748 }
00749 
00750 pid_t KRun::run( const KService& _service, const KURL::List& _urls, bool tempFiles )
00751 {
00752     return run( _service, _urls, 0, tempFiles, TQString::null );
00753 }
00754 
00755 pid_t KRun::run( const KService& _service, const KURL::List& _urls, TQWidget* window, bool tempFiles )
00756 {
00757     return run( _service, _urls, window, "", tempFiles, TQString::null );
00758 }
00759 
00760 pid_t KRun::run( const KService& _service, const KURL::List& _urls, TQWidget* window, const TQCString& asn, bool tempFiles )
00761 {
00762     return run( _service, _urls, window, asn, tempFiles, TQString::null );
00763 }
00764 
00765 pid_t KRun::run( const KService& _service, const KURL::List& _urls, TQWidget* window, bool tempFiles, const TQString& suggestedFileName )
00766 {
00767     return run( _service, _urls, window, "", tempFiles, suggestedFileName );
00768 }
00769 
00770 pid_t KRun::run( const KService& _service, const KURL::List& _urls, TQWidget* window, const TQCString& asn,
00771     bool tempFiles, const TQString& suggestedFileName )
00772 {
00773   if (!_service.desktopEntryPath().isEmpty() &&
00774       !KDesktopFile::isAuthorizedDesktopFile( _service.desktopEntryPath()))
00775   {
00776      kdWarning() << "No authorization to execute " << _service.desktopEntryPath() << endl;
00777      KMessageBox::sorry(window, i18n("You are not authorized to execute this service."));
00778      return 0;
00779   }
00780 
00781   if ( !tempFiles )
00782   {
00783       // Remember we opened those urls, for the "recent documents" menu in kicker
00784       KURL::List::ConstIterator it = _urls.begin();
00785       for(; it != _urls.end(); ++it) {
00786           //kdDebug(7010) << "KRecentDocument::adding " << (*it).url() << endl;
00787           KRecentDocument::add( *it, _service.desktopEntryName() );
00788       }
00789   }
00790 
00791   if ( tempFiles || _service.desktopEntryPath().isEmpty() || !suggestedFileName.isEmpty() )
00792   {
00793      return runTempService(_service, _urls, window, asn, tempFiles, suggestedFileName);
00794   }
00795 
00796   kdDebug(7010) << "KRun::run " << _service.desktopEntryPath() << endl;
00797 
00798   if (!_urls.isEmpty()) {
00799     kdDebug(7010) << "First url " << _urls.first().url() << endl;
00800   }
00801 
00802   // Resolve urls if needed, depending on what the app supports
00803   const KURL::List urls = resolveURLs( _urls, _service );
00804 
00805   TQString error;
00806   int pid = 0;
00807 
00808   TQCString myasn = asn;
00809   // startServiceByDesktopPath() doesn't take TQWidget*, add it to the startup info now
00810   if( window != NULL )
00811   {
00812     if( myasn.isEmpty())
00813         myasn = KStartupInfo::createNewStartupId();
00814     if( myasn != "0" )
00815     {
00816         KStartupInfoId id;
00817         id.initId( myasn );
00818         KStartupInfoData data;
00819         data.setLaunchedBy( window->winId());
00820         KStartupInfo::sendChange( id, data );
00821     }
00822   }
00823 
00824   int i = KApplication::startServiceByDesktopPath(
00825         _service.desktopEntryPath(), urls.toStringList(), &error, 0L, &pid, myasn
00826         );
00827 
00828   if (i != 0)
00829   {
00830      kdDebug(7010) << error << endl;
00831      KMessageBox::sorry( window, error );
00832      return 0;
00833   }
00834 
00835   kdDebug(7010) << "startServiceByDesktopPath worked fine" << endl;
00836   return (pid_t) pid;
00837 }
00838 
00839 
00840 pid_t KRun::run( const TQString& _exec, const KURL::List& _urls, const TQString& _name,
00841                 const TQString& _icon, const TQString&, const TQString&)
00842 {
00843   KService::Ptr service = new KService(_name, _exec, _icon);
00844 
00845   return run(*service, _urls);
00846 }
00847 
00848 pid_t KRun::runCommand( TQString cmd )
00849 {
00850   return KRun::runCommand( cmd, TQString::null, TQString::null, NULL, "" );
00851 }
00852 
00853 pid_t KRun::runCommand( const TQString& cmd, const TQString &execName, const TQString & iconName )
00854 {
00855   return KRun::runCommand( cmd, execName, iconName, NULL, "" );
00856 }
00857 
00858 pid_t KRun::runCommand( const TQString& cmd, const TQString &execName, const TQString & iconName,
00859     TQWidget* window, const TQCString& asn )
00860 {
00861   kdDebug(7010) << "runCommand " << cmd << "," << execName << endl;
00862   KProcess * proc = new KProcess;
00863   proc->setUseShell(true);
00864   *proc << cmd;
00865   KService::Ptr service = KService::serviceByDesktopName( binaryName( execName, true ) );
00866   TQString bin = binaryName( cmd, false );
00867   int pos = bin.findRev( '/' );
00868   if (pos != -1) {
00869     proc->setWorkingDirectory( bin.mid(0, pos) );
00870   }
00871   return runCommandInternal( proc, service.data(), binaryName( execName, false ), execName, iconName, window, asn );
00872 }
00873 
00874 KRun::KRun( const KURL& url, mode_t mode, bool isLocalFile, bool showProgressInfo )
00875      :m_timer(0,"KRun::timer")
00876 {
00877   init (url, 0, "", mode, isLocalFile, showProgressInfo);
00878 }
00879 
00880 KRun::KRun( const KURL& url, TQWidget* window, mode_t mode, bool isLocalFile,
00881             bool showProgressInfo )
00882      :m_timer(0,"KRun::timer")
00883 {
00884   init (url, window, "", mode, isLocalFile, showProgressInfo);
00885 }
00886 
00887 KRun::KRun( const KURL& url, TQWidget* window, const TQCString& asn, mode_t mode, bool isLocalFile,
00888             bool showProgressInfo )
00889      :m_timer(0,"KRun::timer")
00890 {
00891   init (url, window, asn, mode, isLocalFile, showProgressInfo);
00892 }
00893 
00894 void KRun::init ( const KURL& url, TQWidget* window, const TQCString& asn, mode_t mode, bool isLocalFile,
00895                   bool showProgressInfo )
00896 {
00897   m_bFault = false;
00898   m_bAutoDelete = true;
00899   m_bProgressInfo = showProgressInfo;
00900   m_bFinished = false;
00901   m_job = 0L;
00902   m_strURL = url;
00903   m_bScanFile = false;
00904   m_bIsDirectory = false;
00905   m_bIsLocalFile = isLocalFile;
00906   m_mode = mode;
00907   d = new KRunPrivate;
00908   d->m_runExecutables = true;
00909   d->m_window = window;
00910   d->m_asn = asn;
00911   setEnableExternalBrowser(true);
00912 
00913   // Start the timer. This means we will return to the event
00914   // loop and do initialization afterwards.
00915   // Reason: We must complete the constructor before we do anything else.
00916   m_bInit = true;
00917   connect( &m_timer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotTimeout() ) );
00918   m_timer.start( 0, true );
00919   kdDebug(7010) << " new KRun " << this << " " << url.prettyURL() << " timer=" << &m_timer << endl;
00920 
00921   kapp->ref();
00922 }
00923 
00924 void KRun::init()
00925 {
00926   kdDebug(7010) << "INIT called" << endl;
00927 
00928   bool bypassErrorMessage = false;
00929 
00930   if (m_strURL.url().startsWith("$(")) {
00931       // check for environment variables and make necessary translations
00932       TQString aValue = m_strURL.url();
00933       int nDollarPos = aValue.find( '$' );
00934 
00935       while( nDollarPos != -1 && nDollarPos+1 < static_cast<int>(aValue.length())) {
00936         // there is at least one $
00937         if( (aValue)[nDollarPos+1] != '$' ) {
00938           uint nEndPos = nDollarPos+1;
00939           // the next character is no $
00940           TQString aVarName;
00941           if (aValue[nEndPos]=='{')
00942           {
00943             while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!='}') )
00944                 nEndPos++;
00945             nEndPos++;
00946             aVarName = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
00947           }
00948           else
00949           {
00950             while ( nEndPos <= aValue.length() && (aValue[nEndPos].isNumber()
00951                     || aValue[nEndPos].isLetter() || aValue[nEndPos]=='_' )  )
00952                 nEndPos++;
00953             aVarName = aValue.mid( nDollarPos+1, nEndPos-nDollarPos-1 );
00954           }
00955           const char* pEnv = 0;
00956           if (!aVarName.isEmpty())
00957                pEnv = getenv( aVarName.ascii() );
00958           if( pEnv ) {
00959             // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
00960             // A environment variables may contain values in 8bit
00961             // locale cpecified encoding or in UTF8 encoding.
00962             aValue.replace( nDollarPos, nEndPos-nDollarPos, KStringHandler::from8Bit( pEnv ) );
00963           } else
00964             aValue.remove( nDollarPos, nEndPos-nDollarPos );
00965         } else {
00966           // remove one of the dollar signs
00967           aValue.remove( nDollarPos, 1 );
00968           nDollarPos++;
00969         }
00970         nDollarPos = aValue.find( '$', nDollarPos );
00971       }
00972       m_strURL = KURL(aValue);
00973       bypassErrorMessage = true;
00974   }
00975 
00976   if ( !m_strURL.isValid() )
00977   {
00978     if (bypassErrorMessage == false) {
00979       d->m_showingError = true;
00980       KMessageBoxWrapper::error( d->m_window, i18n( "Malformed URL\n%1" ).arg( m_strURL.url() ) );
00981       d->m_showingError = false;
00982     }
00983     m_bFault = true;
00984     m_bFinished = true;
00985     m_timer.start( 0, true );
00986     return;
00987   }
00988   if ( !kapp->authorizeURLAction( "open", KURL(), m_strURL))
00989   {
00990     TQString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, m_strURL.prettyURL());
00991     d->m_showingError = true;
00992     KMessageBoxWrapper::error( d->m_window, msg );
00993     d->m_showingError = false;
00994     m_bFault = true;
00995     m_bFinished = true;
00996     m_timer.start( 0, true );
00997     return;
00998   }
00999 
01000   if ( !m_bIsLocalFile && m_strURL.isLocalFile() )
01001     m_bIsLocalFile = true;
01002 
01003   TQString exec;
01004   if (m_strURL.protocol().startsWith("http"))
01005   {
01006     exec = d->m_externalBrowser;
01007   }
01008 
01009   if ( m_bIsLocalFile )
01010   {
01011     if ( m_mode == 0 )
01012     {
01013       KDE_struct_stat buff;
01014       if ( KDE_stat( TQFile::encodeName(m_strURL.path()), &buff ) == -1 )
01015       {
01016         d->m_showingError = true;
01017         KMessageBoxWrapper::error( d->m_window, i18n( "<qt>Unable to run the command specified. The file or folder <b>%1</b> does not exist.</qt>" ).arg( m_strURL.htmlURL() ) );
01018         d->m_showingError = false;
01019         m_bFault = true;
01020         m_bFinished = true;
01021         m_timer.start( 0, true );
01022         return;
01023       }
01024       m_mode = buff.st_mode;
01025     }
01026 
01027     KMimeType::Ptr mime = KMimeType::findByURL( m_strURL, m_mode, m_bIsLocalFile );
01028     assert( mime != 0L );
01029     kdDebug(7010) << "MIME TYPE is " << mime->name() << endl;
01030     foundMimeType( mime->name() );
01031     return;
01032   }
01033   else if ( !exec.isEmpty() || KProtocolInfo::isHelperProtocol( m_strURL ) ) {
01034     kdDebug(7010) << "Helper protocol" << endl;
01035 
01036     bool ok = false;
01037     KURL::List urls;
01038     if (!((m_strURL.protocol().startsWith("http")) && (m_strURL.url() == "http://default.browser")))
01039         urls.append( m_strURL );
01040     if (exec.isEmpty())
01041     {
01042        exec = KProtocolInfo::exec( m_strURL.protocol() );
01043        if (exec.isEmpty())
01044        {
01045           foundMimeType(KProtocolInfo::defaultMimetype(m_strURL));
01046           return;
01047        }
01048        run( exec, urls );
01049        ok = true;
01050     }
01051     else if (exec.startsWith("!"))
01052     {
01053        exec = exec.mid(1); // Literal command
01054        exec += " %u";
01055        run( exec, urls );
01056        ok = true;
01057     }
01058     else
01059     {
01060        KService::Ptr service = KService::serviceByStorageId( exec );
01061        if (service)
01062        {
01063           run( *service, urls, d->m_window, d->m_asn );
01064           ok = true;
01065        }
01066     }
01067 
01068     if (ok)
01069     {
01070        m_bFinished = true;
01071        // will emit the error and autodelete this
01072        m_timer.start( 0, true );
01073        return;
01074     }
01075   }
01076 
01077   if ((m_strURL.protocol().startsWith("http")) && (m_strURL.url() == "http://default.browser")) {
01078     KURL::List urls;
01079     run( "kfmclient openProfile webbrowsing", urls );
01080     m_bFinished = true;
01081     // will emit the error and autodelete this
01082     m_timer.start( 0, true );
01083     return;
01084   }
01085 
01086   // Did we already get the information that it is a directory ?
01087   if ( S_ISDIR( m_mode ) )
01088   {
01089     foundMimeType( "inode/directory" );
01090     return;
01091   }
01092 
01093   // Let's see whether it is a directory
01094 
01095   if ( !KProtocolInfo::supportsListing( m_strURL ) )
01096   {
01097     //kdDebug(7010) << "Protocol has no support for listing" << endl;
01098     // No support for listing => it can't be a directory (example: http)
01099     scanFile();
01100     return;
01101   }
01102 
01103   kdDebug(7010) << "Testing directory (stating)" << endl;
01104 
01105   // It may be a directory or a file, let's stat
01106   KIO::StatJob *job = KIO::stat( m_strURL, true, 0 /* no details */, m_bProgressInfo );
01107   job->setWindow (d->m_window);
01108   connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
01109            this, TQT_SLOT( slotStatResult( KIO::Job * ) ) );
01110   m_job = job;
01111   kdDebug(7010) << " Job " << job << " is about stating " << m_strURL.url() << endl;
01112 }
01113 
01114 KRun::~KRun()
01115 {
01116   kdDebug(7010) << "KRun::~KRun() " << this << endl;
01117   m_timer.stop();
01118   killJob();
01119   kapp->deref();
01120   kdDebug(7010) << "KRun::~KRun() done " << this << endl;
01121   delete d;
01122 }
01123 
01124 void KRun::scanFile()
01125 {
01126   kdDebug(7010) << "###### KRun::scanFile " << m_strURL.url() << endl;
01127   // First, let's check for well-known extensions
01128   // Not when there is a query in the URL, in any case.
01129   if ( m_strURL.query().isEmpty() )
01130   {
01131     KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
01132     assert( mime != 0L );
01133     if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
01134     {
01135       kdDebug(7010) << "Scanfile: MIME TYPE is " << mime->name() << endl;
01136       foundMimeType( mime->name() );
01137       return;
01138     }
01139   }
01140 
01141   // No mimetype found, and the URL is not local  (or fast mode not allowed).
01142   // We need to apply the 'KIO' method, i.e. either asking the server or
01143   // getting some data out of the file, to know what mimetype it is.
01144 
01145   if ( !KProtocolInfo::supportsReading( m_strURL ) )
01146   {
01147     kdError(7010) << "#### NO SUPPORT FOR READING!" << endl;
01148     m_bFault = true;
01149     m_bFinished = true;
01150     m_timer.start( 0, true );
01151     return;
01152   }
01153   kdDebug(7010) << this << " Scanning file " << m_strURL.url() << endl;
01154 
01155   KIO::TransferJob *job = KIO::get( m_strURL, false /*reload*/, m_bProgressInfo );
01156   job->setWindow (d->m_window);
01157   connect(job, TQT_SIGNAL( result(KIO::Job *)),
01158           this, TQT_SLOT( slotScanFinished(KIO::Job *)));
01159   connect(job, TQT_SIGNAL( mimetype(KIO::Job *, const TQString &)),
01160           this, TQT_SLOT( slotScanMimeType(KIO::Job *, const TQString &)));
01161   m_job = job;
01162   kdDebug(7010) << " Job " << job << " is about getting from " << m_strURL.url() << endl;
01163 }
01164 
01165 void KRun::slotTimeout()
01166 {
01167   kdDebug(7010) << this << " slotTimeout called" << endl;
01168   if ( m_bInit )
01169   {
01170     m_bInit = false;
01171     init();
01172     return;
01173   }
01174 
01175   if ( m_bFault ) {
01176       emit error();
01177   }
01178   if ( m_bFinished ) {
01179       emit finished();
01180   }
01181   else
01182   {
01183     if ( m_bScanFile )
01184     {
01185       m_bScanFile = false;
01186       scanFile();
01187       return;
01188     }
01189     else if ( m_bIsDirectory )
01190     {
01191       m_bIsDirectory = false;
01192       foundMimeType( "inode/directory" );
01193       return;
01194     }
01195   }
01196 
01197   if ( m_bAutoDelete )
01198   {
01199     delete this;
01200     return;
01201   }
01202 }
01203 
01204 void KRun::slotStatResult( KIO::Job * job )
01205 {
01206   m_job = 0L;
01207   if (job->error())
01208   {
01209     d->m_showingError = true;
01210     kdError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
01211     job->showErrorDialog();
01212     //kdDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us" << endl;
01213     d->m_showingError = false;
01214 
01215     m_bFault = true;
01216     m_bFinished = true;
01217 
01218     // will emit the error and autodelete this
01219     m_timer.start( 0, true );
01220 
01221   } else {
01222 
01223     kdDebug(7010) << "Finished" << endl;
01224     if(!dynamic_cast<KIO::StatJob*>(job))
01225         kdFatal() << "job is a " << typeid(*job).name() << " should be a StatJob" << endl;
01226 
01227     TQString knownMimeType;
01228     KIO::UDSEntry entry = ((KIO::StatJob*)job)->statResult();
01229     KIO::UDSEntry::ConstIterator it = entry.begin();
01230     for( ; it != entry.end(); it++ ) {
01231         switch( (*it).m_uds ) {
01232         case KIO::UDS_FILE_TYPE:
01233             if ( S_ISDIR( (mode_t)((*it).m_long) ) )
01234                 m_bIsDirectory = true; // it's a dir
01235             else
01236                 m_bScanFile = true; // it's a file
01237             break;
01238         case KIO::UDS_MIME_TYPE: // mimetype already known? (e.g. print:/manager)
01239             knownMimeType = (*it).m_str;
01240             break;
01241         case KIO::UDS_LOCAL_PATH:
01242             d->m_localPath = (*it).m_str;
01243             break;
01244         default:
01245             break;
01246         }
01247     }
01248     if ( !knownMimeType.isEmpty() )
01249     {
01250         foundMimeType( knownMimeType );
01251         m_bFinished = true;
01252     }
01253 
01254     // We should have found something
01255     assert ( m_bScanFile || m_bIsDirectory );
01256 
01257     // Start the timer. Once we get the timer event this
01258     // protocol server is back in the pool and we can reuse it.
01259     // This gives better performance than starting a new slave
01260     m_timer.start( 0, true );
01261   }
01262 }
01263 
01264 void KRun::slotScanMimeType( KIO::Job *, const TQString &mimetype )
01265 {
01266   if ( mimetype.isEmpty() )
01267     kdWarning(7010) << "KRun::slotScanFinished : MimetypeJob didn't find a mimetype! Probably a kioslave bug." << endl;
01268   foundMimeType( mimetype );
01269   m_job = 0;
01270 }
01271 
01272 void KRun::slotScanFinished( KIO::Job *job )
01273 {
01274   m_job = 0;
01275   if (job->error())
01276   {
01277     d->m_showingError = true;
01278     kdError(7010) << this << " ERROR (stat) : " << job->error() << " " << job->errorString() << endl;
01279     job->showErrorDialog();
01280     //kdDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us" << endl;
01281     d->m_showingError = false;
01282 
01283     m_bFault = true;
01284     m_bFinished = true;
01285 
01286     // will emit the error and autodelete this
01287     m_timer.start( 0, true );
01288   }
01289 }
01290 
01291 void KRun::foundMimeType( const TQString& type )
01292 {
01293   kdDebug(7010) << "Resulting mime type is " << type << endl;
01294 
01295 /*
01296   // Automatically unzip stuff
01297 
01298   // Disabled since the new KIO doesn't have filters yet.
01299 
01300   if ( type == "application/x-gzip"  ||
01301        type == "application/x-bzip"  ||
01302        type == "application/x-bzip2"  )
01303   {
01304     KURL::List lst = KURL::split( m_strURL );
01305     if ( lst.isEmpty() )
01306     {
01307       TQString tmp = i18n( "Malformed URL" );
01308       tmp += "\n";
01309       tmp += m_strURL.url();
01310       KMessageBoxWrapper::error( 0L, tmp );
01311       return;
01312     }
01313 
01314     if ( type == "application/x-gzip" )
01315       lst.prepend( KURL( "gzip:/decompress" ) );
01316     else if ( type == "application/x-bzip" )
01317       lst.prepend( KURL( "bzip:/decompress" ) );
01318     else if ( type == "application/x-bzip2" )
01319       lst.prepend( KURL( "bzip2:/decompress" ) );
01320     else if ( type == "application/x-tar" )
01321       lst.prepend( KURL( "tar:/" ) );
01322 
01323     // Move the HTML style reference to the leftmost URL
01324     KURL::List::Iterator it = lst.begin();
01325     ++it;
01326     (*lst.begin()).setRef( (*it).ref() );
01327     (*it).setRef( TQString::null );
01328 
01329     // Create the new URL
01330     m_strURL = KURL::join( lst );
01331 
01332     kdDebug(7010) << "Now trying with " << debugString(m_strURL.url()) << endl;
01333 
01334     killJob();
01335 
01336     // We don't know if this is a file or a directory. Let's test this first.
01337     // (For instance a tar.gz is a directory contained inside a file)
01338     // It may be a directory or a file, let's stat
01339     KIO::StatJob *job = KIO::stat( m_strURL, m_bProgressInfo );
01340     connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
01341              this, TQT_SLOT( slotStatResult( KIO::Job * ) ) );
01342     m_job = job;
01343 
01344     return;
01345   }
01346 */
01347   KIO::TransferJob *job = ::tqqt_cast<KIO::TransferJob *>( m_job );
01348   if ( job )
01349   {
01350      job->putOnHold();
01351      KIO::Scheduler::publishSlaveOnHold();
01352      m_job = 0;
01353   }
01354 
01355   Q_ASSERT( !m_bFinished );
01356 
01357   // Suport for preferred service setting, see setPreferredService
01358   if ( !d->m_preferredService.isEmpty() ) {
01359       kdDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService << endl;
01360       KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
01361       if ( serv && serv->hasServiceType( type ) )
01362       {
01363           KURL::List lst;
01364           lst.append( m_strURL );
01365           m_bFinished = KRun::run( *serv, lst, d->m_window, d->m_asn );
01370       }
01371   }
01372 
01373   // Resolve .desktop files from media:/, remote:/, applications:/ etc.
01374   if ( ((type == "application/x-desktop") ||
01375       (type == "media/builtin-mydocuments") ||
01376       (type == "media/builtin-mycomputer") ||
01377       (type == "media/builtin-mynetworkplaces") ||
01378       (type == "media/builtin-printers") ||
01379       (type == "media/builtin-trash") ||
01380       (type == "media/builtin-webbrowser")) /* or inheriting? */ && (!d->m_localPath.isEmpty()) )
01381   {
01382     m_strURL = KURL();
01383     m_strURL.setPath( d->m_localPath );
01384   }
01385 
01386   if (!m_bFinished && KRun::runURL( m_strURL, type, d->m_window, d->m_asn, false, d->m_runExecutables, d->m_suggestedFileName )){
01387     m_bFinished = true;
01388   }
01389   else{
01390     m_bFinished = true;
01391      m_bFault = true;
01392   }
01393 
01394   m_timer.start( 0, true );
01395 }
01396 
01397 void KRun::killJob()
01398 {
01399   if ( m_job )
01400   {
01401     kdDebug(7010) << "KRun::killJob run=" << this << " m_job=" << m_job << endl;
01402     m_job->kill();
01403     m_job = 0L;
01404   }
01405 }
01406 
01407 void KRun::abort()
01408 {
01409   kdDebug(7010) << "KRun::abort " << this << " m_showingError=" << d->m_showingError << endl;
01410   killJob();
01411   // If we're showing an error message box, the rest will be done
01412   // after closing the msgbox -> don't autodelete nor emit signals now.
01413   if ( d->m_showingError )
01414     return;
01415   m_bFault = true;
01416   m_bFinished = true;
01417   m_bInit = false;
01418   m_bScanFile = false;
01419 
01420   // will emit the error and autodelete this
01421   m_timer.start( 0, true );
01422 }
01423 
01424 void KRun::setEnableExternalBrowser(bool b)
01425 {
01426    if (b)
01427       d->m_externalBrowser = KConfigGroup(KGlobal::config(), "General").readEntry("BrowserApplication");
01428    else
01429       d->m_externalBrowser = TQString::null;
01430 }
01431 
01432 void KRun::setPreferredService( const TQString& desktopEntryName )
01433 {
01434     d->m_preferredService = desktopEntryName;
01435 }
01436 
01437 void KRun::setRunExecutables(bool b)
01438 {
01439     d->m_runExecutables = b;
01440 }
01441 
01442 void KRun::setSuggestedFileName( const TQString& fileName )
01443 {
01444     d->m_suggestedFileName = fileName;
01445 }
01446 
01447 bool KRun::isExecutable( const TQString& serviceType )
01448 {
01449     return ( serviceType == "application/x-desktop" ||
01450              serviceType == "media/builtin-mydocuments" ||
01451              serviceType == "media/builtin-mycomputer" ||
01452              serviceType == "media/builtin-mynetworkplaces" ||
01453              serviceType == "media/builtin-printers" ||
01454              serviceType == "media/builtin-trash" ||
01455              serviceType == "media/builtin-webbrowser" ||
01456              serviceType == "application/x-executable" ||
01457              serviceType == "application/x-pie-executable" ||
01458              serviceType == "application/x-msdos-program" ||
01459              serviceType == "application/x-shellscript" );
01460 }
01461 
01462 /****************/
01463 
01464 pid_t
01465 KProcessRunner::run(KProcess * p, const TQString & binName)
01466 {
01467   return (new KProcessRunner(p, binName))->pid();
01468 }
01469 
01470 #ifdef Q_WS_X11
01471 pid_t
01472 KProcessRunner::run(KProcess * p, const TQString & binName, const KStartupInfoId& id )
01473 {
01474   return (new KProcessRunner(p, binName, id))->pid();
01475 }
01476 #endif
01477 
01478 KProcessRunner::KProcessRunner(KProcess * p, const TQString & _binName )
01479   : TQObject(),
01480     process_(p),
01481     binName( _binName )
01482 {
01483   TQObject::connect(
01484       process_, TQT_SIGNAL(processExited(KProcess *)),
01485       this,     TQT_SLOT(slotProcessExited(KProcess *)));
01486 
01487   process_->start();
01488   if ( !process_->pid() )
01489       slotProcessExited( process_ );
01490 }
01491 
01492 #ifdef Q_WS_X11
01493 KProcessRunner::KProcessRunner(KProcess * p, const TQString & _binName, const KStartupInfoId& id )
01494   : TQObject(),
01495     process_(p),
01496     binName( _binName ),
01497     id_( id )
01498 {
01499   TQObject::connect(
01500       process_, TQT_SIGNAL(processExited(KProcess *)),
01501       this,     TQT_SLOT(slotProcessExited(KProcess *)));
01502 
01503   process_->start();
01504   if ( !process_->pid() )
01505       slotProcessExited( process_ );
01506 }
01507 #endif
01508 
01509 KProcessRunner::~KProcessRunner()
01510 {
01511   delete process_;
01512 }
01513 
01514   pid_t
01515 KProcessRunner::pid() const
01516 {
01517   return process_->pid();
01518 }
01519 
01520   void
01521 KProcessRunner::slotProcessExited(KProcess * p)
01522 {
01523   if (p != process_)
01524     return; // Eh ?
01525 
01526   kdDebug(7010) << "slotProcessExited " << binName << endl;
01527   kdDebug(7010) << "normalExit " << process_->normalExit() << endl;
01528   kdDebug(7010) << "exitStatus " << process_->exitStatus() << endl;
01529   bool showErr = process_->normalExit()
01530                  && ( process_->exitStatus() == 127 || process_->exitStatus() == 1 );
01531   if ( !binName.isEmpty() && ( showErr || process_->pid() == 0 ) )
01532   {
01533     // Often we get 1 (zsh, csh) or 127 (ksh, bash) because the binary doesn't exist.
01534     // We can't just rely on that, but it's a good hint.
01535     // Before assuming its really so, we'll try to find the binName
01536     // relatively to current directory,  and then in the PATH.
01537     if ( !TQFile( binName ).exists() && KStandardDirs::findExe( binName ).isEmpty() )
01538     {
01539       kapp->ref();
01540       KMessageBox::sorry( 0L, i18n("Could not find the program '%1'").arg( binName ) );
01541       kapp->deref();
01542     }
01543   }
01544 #ifdef Q_WS_X11
01545   if( !id_.none())
01546   {
01547       KStartupInfoData data;
01548       data.addPid( pid()); // announce this pid for the startup notification has finished
01549       data.setHostname();
01550       KStartupInfo::sendFinish( id_, data );
01551   }
01552 #endif
01553   deleteLater();
01554 }
01555 
01556 void KRun::virtual_hook( int, void* )
01557 { /*BASE::virtual_hook( id, data );*/ }
01558 
01559 #include "krun.moc"

kio/kio

Skip menu "kio/kio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kio/kio

Skip menu "kio/kio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kio/kio by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |