• 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           while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!=')') )
00938               nEndPos++;
00939           nEndPos++;
00940           TQString cmd = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
00941 
00942           TQString result;
00943           FILE *fs = popen(TQFile::encodeName(cmd).data(), "r");
00944           if (fs)
00945           {
00946              {
00947              TQTextStream ts(fs, IO_ReadOnly);
00948              result = ts.read().stripWhiteSpace();
00949              }
00950              pclose(fs);
00951           }
00952           aValue.replace( nDollarPos, nEndPos-nDollarPos, result );
00953         } else if( (aValue)[nDollarPos+1] != '$' ) {
00954           uint nEndPos = nDollarPos+1;
00955           // the next character is no $
00956           TQString aVarName;
00957           if (aValue[nEndPos]=='{')
00958           {
00959             while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!='}') )
00960                 nEndPos++;
00961             nEndPos++;
00962             aVarName = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
00963           }
00964           else
00965           {
00966             while ( nEndPos <= aValue.length() && (aValue[nEndPos].isNumber()
00967                     || aValue[nEndPos].isLetter() || aValue[nEndPos]=='_' )  )
00968                 nEndPos++;
00969             aVarName = aValue.mid( nDollarPos+1, nEndPos-nDollarPos-1 );
00970           }
00971           const char* pEnv = 0;
00972           if (!aVarName.isEmpty())
00973                pEnv = getenv( aVarName.ascii() );
00974           if( pEnv ) {
00975             // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
00976             // A environment variables may contain values in 8bit
00977             // locale cpecified encoding or in UTF8 encoding.
00978             aValue.replace( nDollarPos, nEndPos-nDollarPos, KStringHandler::from8Bit( pEnv ) );
00979           } else
00980             aValue.remove( nDollarPos, nEndPos-nDollarPos );
00981         } else {
00982           // remove one of the dollar signs
00983           aValue.remove( nDollarPos, 1 );
00984           nDollarPos++;
00985         }
00986         nDollarPos = aValue.find( '$', nDollarPos );
00987       }
00988       m_strURL = KURL(aValue);
00989       bypassErrorMessage = true;
00990   }
00991 
00992   if ( !m_strURL.isValid() )
00993   {
00994     if (bypassErrorMessage == false) {
00995       d->m_showingError = true;
00996       KMessageBoxWrapper::error( d->m_window, i18n( "Malformed URL\n%1" ).arg( m_strURL.url() ) );
00997       d->m_showingError = false;
00998     }
00999     m_bFault = true;
01000     m_bFinished = true;
01001     m_timer.start( 0, true );
01002     return;
01003   }
01004   if ( !kapp->authorizeURLAction( "open", KURL(), m_strURL))
01005   {
01006     TQString msg = TDEIO::buildErrorString(TDEIO::ERR_ACCESS_DENIED, m_strURL.prettyURL());
01007     d->m_showingError = true;
01008     KMessageBoxWrapper::error( d->m_window, msg );
01009     d->m_showingError = false;
01010     m_bFault = true;
01011     m_bFinished = true;
01012     m_timer.start( 0, true );
01013     return;
01014   }
01015 
01016   if ( !m_bIsLocalFile && m_strURL.isLocalFile() )
01017     m_bIsLocalFile = true;
01018 
01019   TQString exec;
01020   if (m_strURL.protocol().startsWith("http"))
01021   {
01022     exec = d->m_externalBrowser;
01023   }
01024 
01025   if ( m_bIsLocalFile )
01026   {
01027     if ( m_mode == 0 )
01028     {
01029       KDE_struct_stat buff;
01030       if ( KDE_stat( TQFile::encodeName(m_strURL.path()), &buff ) == -1 )
01031       {
01032         d->m_showingError = true;
01033         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() ) );
01034         d->m_showingError = false;
01035         m_bFault = true;
01036         m_bFinished = true;
01037         m_timer.start( 0, true );
01038         return;
01039       }
01040       m_mode = buff.st_mode;
01041     }
01042 
01043     KMimeType::Ptr mime = KMimeType::findByURL( m_strURL, m_mode, m_bIsLocalFile );
01044     assert( mime != 0L );
01045     kdDebug(7010) << "MIME TYPE is " << mime->name() << endl;
01046     foundMimeType( mime->name() );
01047     return;
01048   }
01049   else if ( !exec.isEmpty() || KProtocolInfo::isHelperProtocol( m_strURL ) ) {
01050     kdDebug(7010) << "Helper protocol" << endl;
01051 
01052     bool ok = false;
01053     KURL::List urls;
01054     if (!((m_strURL.protocol().startsWith("http")) && (m_strURL.url() == "http://default.browser")))
01055         urls.append( m_strURL );
01056     if (exec.isEmpty())
01057     {
01058        exec = KProtocolInfo::exec( m_strURL.protocol() );
01059        if (exec.isEmpty())
01060        {
01061           foundMimeType(KProtocolInfo::defaultMimetype(m_strURL));
01062           return;
01063        }
01064        run( exec, urls );
01065        ok = true;
01066     }
01067     else if (exec.startsWith("!"))
01068     {
01069        exec = exec.mid(1); // Literal command
01070        exec += " %u";
01071        run( exec, urls );
01072        ok = true;
01073     }
01074     else
01075     {
01076        KService::Ptr service = KService::serviceByStorageId( exec );
01077        if (service)
01078        {
01079           run( *service, urls, d->m_window, d->m_asn );
01080           ok = true;
01081        }
01082     }
01083 
01084     if (ok)
01085     {
01086        m_bFinished = true;
01087        // will emit the error and autodelete this
01088        m_timer.start( 0, true );
01089        return;
01090     }
01091   }
01092 
01093   if ((m_strURL.protocol().startsWith("http")) && (m_strURL.url() == "http://default.browser")) {
01094     KURL::List urls;
01095     run( "kfmclient openProfile webbrowsing", urls );
01096     m_bFinished = true;
01097     // will emit the error and autodelete this
01098     m_timer.start( 0, true );
01099     return;
01100   }
01101 
01102   // Did we already get the information that it is a directory ?
01103   if ( S_ISDIR( m_mode ) )
01104   {
01105     foundMimeType( "inode/directory" );
01106     return;
01107   }
01108 
01109   // Let's see whether it is a directory
01110 
01111   if ( !KProtocolInfo::supportsListing( m_strURL ) )
01112   {
01113     //kdDebug(7010) << "Protocol has no support for listing" << endl;
01114     // No support for listing => it can't be a directory (example: http)
01115     scanFile();
01116     return;
01117   }
01118 
01119   kdDebug(7010) << "Testing directory (stating)" << endl;
01120 
01121   // It may be a directory or a file, let's stat
01122   TDEIO::StatJob *job = TDEIO::stat( m_strURL, true, 0 /* no details */, m_bProgressInfo );
01123   job->setWindow (d->m_window);
01124   connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
01125            this, TQT_SLOT( slotStatResult( TDEIO::Job * ) ) );
01126   m_job = job;
01127   kdDebug(7010) << " Job " << job << " is about stating " << m_strURL.url() << endl;
01128 }
01129 
01130 KRun::~KRun()
01131 {
01132   kdDebug(7010) << "KRun::~KRun() " << this << endl;
01133   m_timer.stop();
01134   killJob();
01135   kapp->deref();
01136   kdDebug(7010) << "KRun::~KRun() done " << this << endl;
01137   delete d;
01138 }
01139 
01140 void KRun::scanFile()
01141 {
01142   kdDebug(7010) << "###### KRun::scanFile " << m_strURL.url() << endl;
01143   // First, let's check for well-known extensions
01144   // Not when there is a query in the URL, in any case.
01145   if ( m_strURL.query().isEmpty() )
01146   {
01147     KMimeType::Ptr mime = KMimeType::findByURL( m_strURL );
01148     assert( mime != 0L );
01149     if ( mime->name() != "application/octet-stream" || m_bIsLocalFile )
01150     {
01151       kdDebug(7010) << "Scanfile: MIME TYPE is " << mime->name() << endl;
01152       foundMimeType( mime->name() );
01153       return;
01154     }
01155   }
01156 
01157   // No mimetype found, and the URL is not local  (or fast mode not allowed).
01158   // We need to apply the 'TDEIO' method, i.e. either asking the server or
01159   // getting some data out of the file, to know what mimetype it is.
01160 
01161   if ( !KProtocolInfo::supportsReading( m_strURL ) )
01162   {
01163     kdError(7010) << "#### NO SUPPORT FOR READING!" << endl;
01164     m_bFault = true;
01165     m_bFinished = true;
01166     m_timer.start( 0, true );
01167     return;
01168   }
01169   kdDebug(7010) << this << " Scanning file " << m_strURL.url() << endl;
01170 
01171   TDEIO::TransferJob *job = TDEIO::get( m_strURL, false /*reload*/, m_bProgressInfo );
01172   job->setWindow (d->m_window);
01173   connect(job, TQT_SIGNAL( result(TDEIO::Job *)),
01174           this, TQT_SLOT( slotScanFinished(TDEIO::Job *)));
01175   connect(job, TQT_SIGNAL( mimetype(TDEIO::Job *, const TQString &)),
01176           this, TQT_SLOT( slotScanMimeType(TDEIO::Job *, const TQString &)));
01177   m_job = job;
01178   kdDebug(7010) << " Job " << job << " is about getting from " << m_strURL.url() << endl;
01179 }
01180 
01181 void KRun::slotTimeout()
01182 {
01183   kdDebug(7010) << this << " slotTimeout called" << endl;
01184   if ( m_bInit )
01185   {
01186     m_bInit = false;
01187     init();
01188     return;
01189   }
01190 
01191   if ( m_bFault ) {
01192       emit error();
01193   }
01194   if ( m_bFinished ) {
01195       emit finished();
01196   }
01197   else
01198   {
01199     if ( m_bScanFile )
01200     {
01201       m_bScanFile = false;
01202       scanFile();
01203       return;
01204     }
01205     else if ( m_bIsDirectory )
01206     {
01207       m_bIsDirectory = false;
01208       foundMimeType( "inode/directory" );
01209       return;
01210     }
01211   }
01212 
01213   if ( m_bAutoDelete )
01214   {
01215     delete this;
01216     return;
01217   }
01218 }
01219 
01220 void KRun::slotStatResult( TDEIO::Job * job )
01221 {
01222   m_job = 0L;
01223   if (job->error())
01224   {
01225     d->m_showingError = true;
01226     kdError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
01227     job->showErrorDialog();
01228     //kdDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us" << endl;
01229     d->m_showingError = false;
01230 
01231     m_bFault = true;
01232     m_bFinished = true;
01233 
01234     // will emit the error and autodelete this
01235     m_timer.start( 0, true );
01236 
01237   } else {
01238 
01239     kdDebug(7010) << "Finished" << endl;
01240     if(!dynamic_cast<TDEIO::StatJob*>(job))
01241         kdFatal() << "job is a " << typeid(*job).name() << " should be a StatJob" << endl;
01242 
01243     TQString knownMimeType;
01244     TDEIO::UDSEntry entry = ((TDEIO::StatJob*)job)->statResult();
01245     TDEIO::UDSEntry::ConstIterator it = entry.begin();
01246     for( ; it != entry.end(); it++ ) {
01247         switch( (*it).m_uds ) {
01248         case TDEIO::UDS_FILE_TYPE:
01249             if ( S_ISDIR( (mode_t)((*it).m_long) ) )
01250                 m_bIsDirectory = true; // it's a dir
01251             else
01252                 m_bScanFile = true; // it's a file
01253             break;
01254         case TDEIO::UDS_MIME_TYPE: // mimetype already known? (e.g. print:/manager)
01255             knownMimeType = (*it).m_str;
01256             break;
01257         case TDEIO::UDS_LOCAL_PATH:
01258             d->m_localPath = (*it).m_str;
01259             break;
01260         default:
01261             break;
01262         }
01263     }
01264     if ( !knownMimeType.isEmpty() )
01265     {
01266         foundMimeType( knownMimeType );
01267         m_bFinished = true;
01268     }
01269 
01270     // We should have found something
01271     assert ( m_bScanFile || m_bIsDirectory );
01272 
01273     // Start the timer. Once we get the timer event this
01274     // protocol server is back in the pool and we can reuse it.
01275     // This gives better performance than starting a new slave
01276     m_timer.start( 0, true );
01277   }
01278 }
01279 
01280 void KRun::slotScanMimeType( TDEIO::Job *, const TQString &mimetype )
01281 {
01282   if ( mimetype.isEmpty() )
01283     kdWarning(7010) << "KRun::slotScanFinished : MimetypeJob didn't find a mimetype! Probably a tdeioslave bug." << endl;
01284   foundMimeType( mimetype );
01285   m_job = 0;
01286 }
01287 
01288 void KRun::slotScanFinished( TDEIO::Job *job )
01289 {
01290   m_job = 0;
01291   if (job->error())
01292   {
01293     d->m_showingError = true;
01294     kdError(7010) << this << " ERROR (stat) : " << job->error() << " " << job->errorString() << endl;
01295     job->showErrorDialog();
01296     //kdDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us" << endl;
01297     d->m_showingError = false;
01298 
01299     m_bFault = true;
01300     m_bFinished = true;
01301 
01302     // will emit the error and autodelete this
01303     m_timer.start( 0, true );
01304   }
01305 }
01306 
01307 void KRun::foundMimeType( const TQString& type )
01308 {
01309   kdDebug(7010) << "Resulting mime type is " << type << endl;
01310 
01311 /*
01312   // Automatically unzip stuff
01313 
01314   // Disabled since the new TDEIO doesn't have filters yet.
01315 
01316   if ( type == "application/x-gzip"  ||
01317        type == "application/x-bzip"  ||
01318        type == "application/x-bzip2"  )
01319   {
01320     KURL::List lst = KURL::split( m_strURL );
01321     if ( lst.isEmpty() )
01322     {
01323       TQString tmp = i18n( "Malformed URL" );
01324       tmp += "\n";
01325       tmp += m_strURL.url();
01326       KMessageBoxWrapper::error( 0L, tmp );
01327       return;
01328     }
01329 
01330     if ( type == "application/x-gzip" )
01331       lst.prepend( KURL( "gzip:/decompress" ) );
01332     else if ( type == "application/x-bzip" )
01333       lst.prepend( KURL( "bzip:/decompress" ) );
01334     else if ( type == "application/x-bzip2" )
01335       lst.prepend( KURL( "bzip2:/decompress" ) );
01336     else if ( type == "application/x-tar" )
01337       lst.prepend( KURL( "tar:/" ) );
01338 
01339     // Move the HTML style reference to the leftmost URL
01340     KURL::List::Iterator it = lst.begin();
01341     ++it;
01342     (*lst.begin()).setRef( (*it).ref() );
01343     (*it).setRef( TQString::null );
01344 
01345     // Create the new URL
01346     m_strURL = KURL::join( lst );
01347 
01348     kdDebug(7010) << "Now trying with " << debugString(m_strURL.url()) << endl;
01349 
01350     killJob();
01351 
01352     // We don't know if this is a file or a directory. Let's test this first.
01353     // (For instance a tar.gz is a directory contained inside a file)
01354     // It may be a directory or a file, let's stat
01355     TDEIO::StatJob *job = TDEIO::stat( m_strURL, m_bProgressInfo );
01356     connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ),
01357              this, TQT_SLOT( slotStatResult( TDEIO::Job * ) ) );
01358     m_job = job;
01359 
01360     return;
01361   }
01362 */
01363   TDEIO::TransferJob *job = ::tqqt_cast<TDEIO::TransferJob *>( m_job );
01364   if ( job )
01365   {
01366      job->putOnHold();
01367      TDEIO::Scheduler::publishSlaveOnHold();
01368      m_job = 0;
01369   }
01370 
01371   Q_ASSERT( !m_bFinished );
01372 
01373   // Suport for preferred service setting, see setPreferredService
01374   if ( !d->m_preferredService.isEmpty() ) {
01375       kdDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService << endl;
01376       KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
01377       if ( serv && serv->hasServiceType( type ) )
01378       {
01379           KURL::List lst;
01380           lst.append( m_strURL );
01381           m_bFinished = KRun::run( *serv, lst, d->m_window, d->m_asn );
01386       }
01387   }
01388 
01389   // Resolve .desktop files from media:/, remote:/, applications:/ etc.
01390   if ( ((type == "application/x-desktop") ||
01391       (type == "media/builtin-mydocuments") ||
01392       (type == "media/builtin-mycomputer") ||
01393       (type == "media/builtin-mynetworkplaces") ||
01394       (type == "media/builtin-printers") ||
01395       (type == "media/builtin-trash") ||
01396       (type == "media/builtin-webbrowser")) /* or inheriting? */ && (!d->m_localPath.isEmpty()) )
01397   {
01398     m_strURL = KURL();
01399     m_strURL.setPath( d->m_localPath );
01400   }
01401 
01402   if (!m_bFinished && KRun::runURL( m_strURL, type, d->m_window, d->m_asn, false, d->m_runExecutables, d->m_suggestedFileName )){
01403     m_bFinished = true;
01404   }
01405   else{
01406     m_bFinished = true;
01407      m_bFault = true;
01408   }
01409 
01410   m_timer.start( 0, true );
01411 }
01412 
01413 void KRun::killJob()
01414 {
01415   if ( m_job )
01416   {
01417     kdDebug(7010) << "KRun::killJob run=" << this << " m_job=" << m_job << endl;
01418     m_job->kill();
01419     m_job = 0L;
01420   }
01421 }
01422 
01423 void KRun::abort()
01424 {
01425   kdDebug(7010) << "KRun::abort " << this << " m_showingError=" << d->m_showingError << endl;
01426   killJob();
01427   // If we're showing an error message box, the rest will be done
01428   // after closing the msgbox -> don't autodelete nor emit signals now.
01429   if ( d->m_showingError )
01430     return;
01431   m_bFault = true;
01432   m_bFinished = true;
01433   m_bInit = false;
01434   m_bScanFile = false;
01435 
01436   // will emit the error and autodelete this
01437   m_timer.start( 0, true );
01438 }
01439 
01440 void KRun::setEnableExternalBrowser(bool b)
01441 {
01442    if (b)
01443       d->m_externalBrowser = TDEConfigGroup(TDEGlobal::config(), "General").readEntry("BrowserApplication");
01444    else
01445       d->m_externalBrowser = TQString::null;
01446 }
01447 
01448 void KRun::setPreferredService( const TQString& desktopEntryName )
01449 {
01450     d->m_preferredService = desktopEntryName;
01451 }
01452 
01453 void KRun::setRunExecutables(bool b)
01454 {
01455     d->m_runExecutables = b;
01456 }
01457 
01458 void KRun::setSuggestedFileName( const TQString& fileName )
01459 {
01460     d->m_suggestedFileName = fileName;
01461 }
01462 
01463 bool KRun::isExecutable( const TQString& serviceType )
01464 {
01465     return ( serviceType == "application/x-desktop" ||
01466              serviceType == "media/builtin-mydocuments" ||
01467              serviceType == "media/builtin-mycomputer" ||
01468              serviceType == "media/builtin-mynetworkplaces" ||
01469              serviceType == "media/builtin-printers" ||
01470              serviceType == "media/builtin-trash" ||
01471              serviceType == "media/builtin-webbrowser" ||
01472              serviceType == "application/x-executable" ||
01473              serviceType == "application/x-msdos-program" ||
01474              serviceType == "application/x-shellscript" );
01475 }
01476 
01477 /****************/
01478 
01479 pid_t
01480 TDEProcessRunner::run(TDEProcess * p, const TQString & binName)
01481 {
01482   return (new TDEProcessRunner(p, binName))->pid();
01483 }
01484 
01485 #ifdef Q_WS_X11
01486 pid_t
01487 TDEProcessRunner::run(TDEProcess * p, const TQString & binName, const TDEStartupInfoId& id )
01488 {
01489   return (new TDEProcessRunner(p, binName, id))->pid();
01490 }
01491 #endif
01492 
01493 TDEProcessRunner::TDEProcessRunner(TDEProcess * p, const TQString & _binName )
01494   : TQObject(),
01495     process_(p),
01496     binName( _binName )
01497 {
01498   TQObject::connect(
01499       process_, TQT_SIGNAL(processExited(TDEProcess *)),
01500       this,     TQT_SLOT(slotProcessExited(TDEProcess *)));
01501 
01502   process_->start();
01503   if ( !process_->pid() )
01504       slotProcessExited( process_ );
01505 }
01506 
01507 #ifdef Q_WS_X11
01508 TDEProcessRunner::TDEProcessRunner(TDEProcess * p, const TQString & _binName, const TDEStartupInfoId& id )
01509   : TQObject(),
01510     process_(p),
01511     binName( _binName ),
01512     id_( id )
01513 {
01514   TQObject::connect(
01515       process_, TQT_SIGNAL(processExited(TDEProcess *)),
01516       this,     TQT_SLOT(slotProcessExited(TDEProcess *)));
01517 
01518   process_->start();
01519   if ( !process_->pid() )
01520       slotProcessExited( process_ );
01521 }
01522 #endif
01523 
01524 TDEProcessRunner::~TDEProcessRunner()
01525 {
01526   delete process_;
01527 }
01528 
01529   pid_t
01530 TDEProcessRunner::pid() const
01531 {
01532   return process_->pid();
01533 }
01534 
01535   void
01536 TDEProcessRunner::slotProcessExited(TDEProcess * p)
01537 {
01538   if (p != process_)
01539     return; // Eh ?
01540 
01541   kdDebug(7010) << "slotProcessExited " << binName << endl;
01542   kdDebug(7010) << "normalExit " << process_->normalExit() << endl;
01543   kdDebug(7010) << "exitStatus " << process_->exitStatus() << endl;
01544   bool showErr = process_->normalExit()
01545                  && ( process_->exitStatus() == 127 || process_->exitStatus() == 1 );
01546   if ( !binName.isEmpty() && ( showErr || process_->pid() == 0 ) )
01547   {
01548     // Often we get 1 (zsh, csh) or 127 (ksh, bash) because the binary doesn't exist.
01549     // We can't just rely on that, but it's a good hint.
01550     // Before assuming its really so, we'll try to find the binName
01551     // relatively to current directory,  and then in the PATH.
01552     if ( !TQFile( binName ).exists() && TDEStandardDirs::findExe( binName ).isEmpty() )
01553     {
01554       kapp->ref();
01555       KMessageBox::sorry( 0L, i18n("Could not find the program '%1'").arg( binName ) );
01556       kapp->deref();
01557     }
01558   }
01559 #ifdef Q_WS_X11
01560   if( !id_.none())
01561   {
01562       TDEStartupInfoData data;
01563       data.addPid( pid()); // announce this pid for the startup notification has finished
01564       data.setHostname();
01565       TDEStartupInfo::sendFinish( id_, data );
01566   }
01567 #endif
01568   deleteLater();
01569 }
01570 
01571 void KRun::virtual_hook( int, void* )
01572 { /*BASE::virtual_hook( id, data );*/ }
01573 
01574 #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.6.3
This website is maintained by Timothy Pearson.