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

tdeio/tdeio

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

tdeio/tdeio

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

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.