# kio Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kservice.cpp

    00001 /*  This file is part of the KDE libraries
    00002  *  Copyright (C) 1999 - 2001 Waldo Bastian <bastian@kde.org>
    00003  *  Copyright (C) 1999        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 version 2 as published by the Free Software Foundation;
    00008  *
    00009  *  This library is distributed in the hope that it will be useful,
    00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012  *  Library General Public License for more details.
    00013  *
    00014  *  You should have received a copy of the GNU Library General Public License
    00015  *  along with this library; see the file COPYING.LIB.  If not, write to
    00016  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00017  *  Boston, MA 02111-1307, USA.
    00018  **/
    00019
    00020 // $Id: kservice.cpp,v 1.125.2.2 2003/07/09 16:11:28 waba Exp $
    00021
    00022 #include <config.h>
    00023
    00024 #include "kservice.h"
    00025 #include <sys/types.h>
    00026 #include <sys/stat.h>
    00027
    00028 #include <stddef.h>
    00029 #include <unistd.h>
    00030 #include <stdlib.h>
    00031
    00032 #include <qstring.h>
    00033 #include <qfile.h>
    00034 #include <qtl.h>
    00035
    00036 #include <ksimpleconfig.h>
    00037 #include <kapplication.h>
    00038 #include <kdebug.h>
    00039 #include <kdesktopfile.h>
    00040 #include <kglobal.h>
    00041 #include <kiconloader.h>
    00042 #include <klocale.h>
    00043 #include <kconfigbase.h>
    00044 #include <dcopclient.h>
    00045
    00046 #include "kservicefactory.h"
    00047 #include "kservicetypefactory.h"
    00048 #include "kservicetype.h"
    00049 #include "kuserprofile.h"
    00050 #include "ksycoca.h"
    00051
    00052 class KService::KServicePrivate
    00053 {
    00054 public:
    00055   QStringList categories;
    00056 };
    00057
    00058 KService::KService( const QString & _name, const QString &_exec, const QString &_icon)
    00059  : KSycocaEntry( QString::null)
    00060 {
    00061   d = new KServicePrivate;
    00062   m_bValid = true;
    00063   m_bDeleted = false;
    00064   m_strType = "Application";
    00065   m_strName = _name;
    00066   m_strExec = _exec;
    00067   m_strIcon = _icon;
    00068   m_bTerminal = false;
    00069   m_bAllowAsDefault = true;
    00070   m_initialPreference = 10;
    00071 }
    00072
    00073
    00074 KService::KService( const QString & _fullpath )
    00075  : KSycocaEntry( _fullpath)
    00076 {
    00077   KDesktopFile config( _fullpath );
    00078
    00079   init(&config);
    00080 }
    00081
    00082 KService::KService( KDesktopFile *config )
    00083  : KSycocaEntry( config->filename())
    00084 {
    00085   init(config);
    00086 }
    00087
    00088 void
    00089 KService::init( KDesktopFile *config )
    00090 {
    00091   d = new KServicePrivate;
    00092   m_bValid = true;
    00093
    00094   bool absPath = (entryPath()[0] == '/');
    00095
    00096   config->setDesktopGroup();
    00097   config->setDollarExpansion( true ); // mainly for Exec and Path
    00098   if(absPath && access(QFile::encodeName(entryPath()), R_OK))
    00099   {
    00100     m_bValid = false;
    00101     return;
    00102   }
    00103   QMap<QString, QString> entryMap = config->entryMap(config->group());
    00104
    00105   entryMap.remove("Encoding"); // reserved as part of Desktop Entry Standard
    00106   entryMap.remove("Version");  // reserved as part of Desktop Entry Standard
    00107
    00108   m_bDeleted = config->readBoolEntry( "Hidden", false );
    00109   entryMap.remove("Hidden");
    00110   if (m_bDeleted)
    00111   {
    00112     m_bValid = false;
    00113     return;
    00114   }
    00115   m_strType = config->readEntry( "Type" );
    00116   entryMap.remove("Type");
    00117   if ( m_strType.isEmpty() )
    00118   {
    00119     /*kdWarning(7012) << "The desktop entry file " << entryPath()
    00120                     << " has no Type=... entry."
    00121                     << " It should be \"Application\" or \"Service\"" << endl;
    00122     m_bValid = false;
    00123     return;*/
    00124     m_strType = "Application";
    00125   } else if ( m_strType != "Application" && m_strType != "Service" )
    00126   {
    00127     kdWarning(7012) << "The desktop entry file " << entryPath()
    00128                     << " has Type=" << m_strType
    00129                     << " instead of \"Application\" or \"Service\"" << endl;
    00130     m_bValid = false;
    00131     return;
    00132   }
    00133
    00134   // In case Try Exec is set, check if the application is available
    00135   if (!config->tryExec()) {
    00136       m_bDeleted = true;
    00137       m_bValid = false;
    00138       return;
    00139   }
    00140
    00141   QString resource = config->resource();
    00142
    00143   if ( (m_strType == "Application") &&
    00144        (!resource.isEmpty()) &&
    00145        (resource != "apps") &&
    00146        !absPath)
    00147   {
    00148     kdWarning(7012) << "The desktop entry file " << entryPath()
    00149            << " has Type=" << m_strType << " but is located under \"" << resource
    00150            << "\" instead of \"apps\"" << endl;
    00151     m_bValid = false;
    00152     return;
    00153   }
    00154
    00155   if ( (m_strType == "Service") &&
    00156        (!resource.isEmpty()) &&
    00157        (resource != "services") &&
    00158        !absPath)
    00159   {
    00160     kdWarning(7012) << "The desktop entry file " << entryPath()
    00161            << " has Type=" << m_strType << " but is located under \"" << resource
    00162            << "\" instead of \"services\"" << endl;
    00163     m_bValid = false;
    00164     return;
    00165   }
    00166
    00167   QString name = entryPath();
    00168   int pos = name.findRev('/');
    00169   if (pos != -1)
    00170      name = name.mid(pos+1);
    00171   pos = name.find('.');
    00172   if (pos != -1)
    00173      name = name.left(pos);
    00174
    00175   m_strExec = config->readPathEntry( "Exec" );
    00176   entryMap.remove("Exec");
    00177   m_strName = config->readEntry( "Name" );
    00178   //kdDebug() << "parsing " << entryPath() << " Name=" << m_strName << endl;
    00179   entryMap.remove("Name");
    00180   if ( m_strName.isEmpty() )
    00181   {
    00182     m_bValid = false;
    00183     return;
    00184   }
    00185
    00186   m_strIcon = config->readEntry( "Icon", "unknown" );
    00187   entryMap.remove("Icon");
    00188   m_bTerminal = (config->readBoolEntry( "Terminal" )); // should be a property IMHO
    00189   entryMap.remove("Terminal");
    00190   m_strTerminalOptions = config->readEntry( "TerminalOptions" ); // should be a property IMHO
    00191   entryMap.remove("TerminalOptions");
    00192   m_strPath = config->readPathEntry( "Path" );
    00193   entryMap.remove("Path");
    00194   m_strComment = config->readEntry( "Comment" );
    00195   entryMap.remove("Comment");
    00196   m_strGenName = config->readEntry( "GenericName" );
    00197   entryMap.remove("GenericName");
    00198   m_lstKeywords = config->readListEntry("Keywords");
    00199   entryMap.remove("Keywords");
    00200   d->categories = config->readListEntry("Categories", ';');
    00201   entryMap.remove("Categories");
    00202   m_strLibrary = config->readEntry( "X-KDE-Library" );
    00203   entryMap.remove("X-KDE-Library");
    00204   m_strInit = config->readEntry("X-KDE-Init" );
    00205   entryMap.remove("X-KDE-Init");
    00206
    00207   m_lstServiceTypes = config->readListEntry( "ServiceTypes" );
    00208   entryMap.remove("ServiceTypes");
    00209   // For compatibility with KDE 1.x
    00210   m_lstServiceTypes += config->readListEntry( "MimeType", ';' );
    00211   entryMap.remove("MimeType");
    00212
    00213   if ( m_strType == "Application" && !m_lstServiceTypes.contains("Application") )
    00214     // Applications implement the service type "Application" ;-)
    00215     m_lstServiceTypes += "Application";
    00216
    00217   QString dcopServiceType = config->readEntry("X-DCOP-ServiceType").lower();
    00218   entryMap.remove("X-DCOP-ServiceType");
    00219   if (dcopServiceType == "unique")
    00220      m_DCOPServiceType = DCOP_Unique;
    00221   else if (dcopServiceType == "multi")
    00222      m_DCOPServiceType = DCOP_Multi;
    00223   else if (dcopServiceType == "wait")
    00224      m_DCOPServiceType = DCOP_Wait;
    00225   else
    00226      m_DCOPServiceType = DCOP_None;
    00227
    00228   m_strDesktopEntryName = name.lower();
    00229
    00230   m_bAllowAsDefault = config->readBoolEntry( "AllowDefault", true );
    00231   entryMap.remove("AllowDefault");
    00232
    00233   m_initialPreference = config->readNumEntry( "InitialPreference", 1 );
    00234   entryMap.remove("InitialPreference");
    00235
    00236   // Store all additional entries in the property map.
    00237   // A QMap<QString,QString> would be easier for this but we can't
    00238   // brake BC, so we have to store it in m_mapProps.
    00239 //  qWarning("Path = %s", entryPath().latin1());
    00240   QMap<QString,QString>::ConstIterator it = entryMap.begin();
    00241   for( ; it != entryMap.end();++it)
    00242   {
    00243 //     qWarning("   Key = %s Data = %s", it.key().latin1(), it.data().latin1());
    00244      m_mapProps.insert( it.key(), QVariant( it.data()));
    00245   }
    00246 }
    00247
    00248 KService::KService( QDataStream& _str, int offset ) : KSycocaEntry( _str, offset )
    00249 {
    00250   d = new KServicePrivate;
    00251   load( _str );
    00252 }
    00253
    00254 KService::~KService()
    00255 {
    00256   //debug("KService::~KService()");
    00257   delete d;
    00258 }
    00259
    00260 QPixmap KService::pixmap( KIcon::Group _group, int _force_size, int _state, QString * _path ) const
    00261 {
    00262   KIconLoader *iconLoader=KGlobal::iconLoader();
    00263   if (!iconLoader->extraDesktopThemesAdded())
    00264   {
    00265       QPixmap pixmap=iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path, true );
    00266       if (!pixmap.isNull() ) return pixmap;
    00267
    00268       iconLoader->addExtraDesktopThemes();
    00269   }
    00270
    00271   return iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path );
    00272 }
    00273
    00274 void KService::load( QDataStream& s )
    00275 {
    00276   // dummies are here because of fields that were removed, to keep bin compat.
    00277   // Feel free to re-use, but fields for Applications only (not generic services)
    00278   // should rather be added to application.desktop
    00279   Q_INT8 def, term, dummy1, dummy2;
    00280   Q_INT8 dst, initpref;
    00281   QString dummyStr1, dummyStr2;
    00282   int dummyI1, dummyI2;
    00283   Q_UINT32 dummyUI32;
    00284
    00285   // WARNING: IN KDE 3.x THIS NEEDS TO REMAIN COMPATIBLE WITH KDE 2.x!
    00286   // !! This data structure should remain binary compatible at all times !!
    00287   // You may add new fields at the end. Make sure to update the version
    00288   // number in ksycoca.h
    00289   s >> m_strType >> m_strName >> m_strExec >> m_strIcon
    00290     >> term >> m_strTerminalOptions
    00291     >> m_strPath >> m_strComment >> m_lstServiceTypes >> def >> m_mapProps
    00292     >> m_strLibrary >> dummyI1 >> dummyI2
    00293     >> dst
    00294     >> m_strDesktopEntryName
    00295     >> dummy1 >> dummyStr1 >> initpref >> dummyStr2 >> dummy2
    00296     >> m_lstKeywords >> m_strInit >> dummyUI32 >> m_strGenName
    00297     >> d->categories;
    00298
    00299   m_bAllowAsDefault = def;
    00300   m_bTerminal = term;
    00301   m_DCOPServiceType = (DCOPServiceType_t) dst;
    00302   m_initialPreference = initpref;
    00303
    00304   m_bValid = true;
    00305 }
    00306
    00307 void KService::save( QDataStream& s )
    00308 {
    00309   KSycocaEntry::save( s );
    00310   Q_INT8 def = m_bAllowAsDefault, initpref = m_initialPreference;
    00311   Q_INT8 term = m_bTerminal;
    00312   Q_INT8 dst = (Q_INT8) m_DCOPServiceType;
    00313   Q_INT8 dummy1 = 0, dummy2 = 0; // see ::load
    00314   QString dummyStr1, dummyStr2;
    00315   int dummyI1 = 0, dummyI2 = 0;
    00316   Q_UINT32 dummyUI32 = 0;
    00317
    00318   // WARNING: IN KDE 3.x THIS NEEDS TO REMAIN COMPATIBLE WITH KDE 2.x!
    00319   // !! This data structure should remain binary compatible at all times !!
    00320   // You may add new fields at the end. Make sure to update the version
    00321   // number in ksycoca.h
    00322   s << m_strType << m_strName << m_strExec << m_strIcon
    00323     << term << m_strTerminalOptions
    00324     << m_strPath << m_strComment << m_lstServiceTypes << def << m_mapProps
    00325     << m_strLibrary << dummyI1 << dummyI2
    00326     << dst
    00327     << m_strDesktopEntryName
    00328     << dummy1 << dummyStr1 << initpref << dummyStr2 << dummy2
    00329     << m_lstKeywords << m_strInit << dummyUI32 << m_strGenName
    00330     << d->categories;
    00331 }
    00332
    00333 bool KService::hasServiceType( const QString& _servicetype ) const
    00334 {
    00335   if (!m_bValid) return false; // safety test
    00336
    00337   //kdDebug(7012) << "Testing " << m_strDesktopEntryName << " for " << _servicetype << endl;
    00338
    00339   // For each service type we are associated with, if it doesn't
    00340   // match then we try its parent service types.
    00341   QStringList::ConstIterator it = m_lstServiceTypes.begin();
    00342   for( ; it != m_lstServiceTypes.end(); ++it )
    00343   {
    00344       //kdDebug(7012) << "    has " << (*it) << endl;
    00345       KServiceType::Ptr ptr = KServiceType::serviceType( *it );
    00346       if ( ptr && ptr->inherits( _servicetype ) )
    00347           return true;
    00348   }
    00349   return false;
    00350 }
    00351
    00352 class KServiceReadProperty : public KConfigBase
    00353 {
    00354 public:
    00355    KServiceReadProperty(const QString &_key, const QCString &_value)
    00356         : key(_key), value(_value) { }
    00357
    00358    bool internalHasGroup(const QCString &) const { /*qDebug("hasGroup(const QCString &)");*/ return false; }
    00359
    00360    QStringList groupList() const { return QStringList(); }
    00361
    00362    QMap<QString,QString> entryMap(const QString &) const
    00363       { return QMap<QString,QString>(); }
    00364
    00365    void reparseConfiguration() { }
    00366
    00367    KEntryMap internalEntryMap( const QString &) const { return KEntryMap(); }
    00368
    00369    KEntryMap internalEntryMap() const { return KEntryMap(); }
    00370
    00371    void putData(const KEntryKey &, const KEntry&, bool) { }
    00372
    00373    KEntry lookupData(const KEntryKey &) const
    00374    { KEntry entry; entry.mValue = value; return entry; }
    00375 protected:
    00376    QString key;
    00377    QCString value;
    00378 };
    00379
    00380 QVariant KService::property( const QString& _name ) const
    00381 {
    00382   if ( _name == "Type" )
    00383     return QVariant( m_strType );
    00384   else if ( _name == "Name" )
    00385     return QVariant( m_strName );
    00386   else if ( _name == "Exec" )
    00387     return QVariant( m_strExec );
    00388   else if ( _name == "Icon" )
    00389     return QVariant( m_strIcon );
    00390   else if ( _name == "Terminal" )
    00391     return QVariant( static_cast<int>(m_bTerminal) );
    00392   else if ( _name == "TerminalOptions" )
    00393     return QVariant( m_strTerminalOptions );
    00394   else if ( _name == "Path" )
    00395     return QVariant( m_strPath );
    00396   else if ( _name == "Comment" )
    00397     return QVariant( m_strComment );
    00398   else if ( _name == "GenericName" )
    00399     return QVariant( m_strGenName );
    00400   else if ( _name == "ServiceTypes" )
    00401     return QVariant( m_lstServiceTypes );
    00402   else if ( _name == "AllowAsDefault" )
    00403     return QVariant( static_cast<int>(m_bAllowAsDefault) );
    00404   else if ( _name == "InitialPreference" )
    00405     return QVariant( m_initialPreference );
    00406   else if ( _name == "Library" )
    00407     return QVariant( m_strLibrary );
    00408   else if ( _name == "DesktopEntryPath" )
    00409     return QVariant( entryPath() );
    00410   else if ( _name == "DesktopEntryName")
    00411     return QVariant( m_strDesktopEntryName );
    00412   else if ( _name == "Categories")
    00413     return QVariant( d->categories );
    00414   else if ( _name == "Keywords")
    00415     return QVariant( m_lstKeywords );
    00416
    00417   // Ok we need to convert the property from a QString to its real type.
    00418   // First we need to ask KServiceTypeFactory what the type of this property
    00419   // is supposed to be.
    00420   // Then we use a homebuild class based on KBaseConfig to convert the QString.
    00421   // For some often used property types we do the conversion ourselves.
    00422
    00423   QVariant::Type t = KServiceTypeFactory::self()->findPropertyTypeByName(_name);
    00424   if (t == QVariant::Invalid)
    00425   {
    00426     kdDebug(7012) << "Request for unknown property '" << _name << "'\n";
    00427     return QVariant(); // Unknown property: Invalid variant.
    00428   }
    00429
    00430   QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( _name );
    00431   if ( (it == m_mapProps.end()) || (!it.data().isValid()))
    00432   {
    00433      //kdDebug(7012) << "Property not found " << _name << endl;
    00434      return QVariant(); // No property set.
    00435   }
    00436
    00437   switch(t)
    00438   {
    00439     case QVariant::String:
    00440         return it.data();
    00441     case QVariant::Bool:
    00442     case QVariant::Int:
    00443         {
    00444            QString aValue = it.data().toString();
    00445            int val = 0;
    00446            if (aValue == "true" || aValue == "on" || aValue == "yes")
    00447               val = 1;
    00448            else
    00449            {
    00450               bool bOK;
    00451               val = aValue.toInt( &bOK );
    00452               if( !bOK )
    00453                  val = 0;
    00454            }
    00455            if (t == QVariant::Bool)
    00456            {
    00457               if (val)
    00458                  return QVariant(true);
    00459               else
    00460                  return QVariant(false);
    00461            }
    00462            return QVariant(val);
    00463         }
    00464     default:
    00465         // All others
    00466         KServiceReadProperty ksrp(_name, it.data().toString().utf8());
    00467         return ksrp.readPropertyEntry(_name, t);
    00468   }
    00469 }
    00470
    00471 QStringList KService::propertyNames() const
    00472 {
    00473   QStringList res;
    00474
    00475   QMap<QString,QVariant>::ConstIterator it = m_mapProps.begin();
    00476   for( ; it != m_mapProps.end(); ++it )
    00477     res.append( it.key() );
    00478
    00479   res.append( "Type" );
    00480   res.append( "Name" );
    00481   res.append( "Comment" );
    00482   res.append( "GenericName" );
    00483   res.append( "Icon" );
    00484   res.append( "Exec" );
    00485   res.append( "Terminal" );
    00486   res.append( "TerminalOptions" );
    00487   res.append( "Path" );
    00488   res.append( "ServiceTypes" );
    00489   res.append( "AllowAsDefault" );
    00490   res.append( "InitialPreference" );
    00491   res.append( "Library" );
    00492   res.append( "DesktopEntryPath" );
    00493   res.append( "DesktopEntryName" );
    00494   res.append( "Keywords" );
    00495   res.append( "Categories" );
    00496
    00497   return res;
    00498 }
    00499
    00500 KService::List KService::allServices()
    00501 {
    00502   return KServiceFactory::self()->allServices();
    00503 }
    00504
    00505 KService::Ptr KService::serviceByName( const QString& _name )
    00506 {
    00507   KService * s = KServiceFactory::self()->findServiceByName( _name );
    00508   return KService::Ptr( s );
    00509 }
    00510
    00511 KService::Ptr KService::serviceByDesktopPath( const QString& _name )
    00512 {
    00513   KService * s = KServiceFactory::self()->findServiceByDesktopPath( _name );
    00514   return KService::Ptr( s );
    00515 }
    00516
    00517 KService::Ptr KService::serviceByDesktopName( const QString& _name )
    00518 {
    00519   KService * s = KServiceFactory::self()->findServiceByDesktopName( _name );
    00520   return KService::Ptr( s );
    00521 }
    00522
    00523 KService::List KService::allInitServices()
    00524 {
    00525   return KServiceFactory::self()->allInitServices();
    00526 }
    00527
    00528 bool KService::substituteUid() const {
    00529   QVariant v = property("X-KDE-SubstituteUID");
    00530   return v.isValid() && v.toBool();
    00531 }
    00532
    00533 QString KService::username() const {
    00534   // See also KDesktopFile::tryExec()
    00535   QString user;
    00536   QVariant v = property("X-KDE-Username");
    00537   user = v.isValid() ? v.toString() : QString::null;
    00538   if (user.isEmpty())
    00539      user = ::getenv("ADMIN_ACCOUNT");
    00540   if (user.isEmpty())
    00541      user = "root";
    00542   return user;
    00543 }
    00544
    00545 bool KService::noDisplay() const {
    00546   QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( "NoDisplay" );
    00547   if ( (it == m_mapProps.end()) || (!it.data().isValid()))
    00548   {
    00549      return false;
    00550   }
    00551
    00552   QString aValue = it.data().toString();
    00553   if (aValue == "true" || aValue == "on" || aValue == "yes")
    00554      return true;
    00555   else
    00556      return false;
    00557 }
    00558
    00559 QString KService::parentApp() const {
    00560   QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( "X-KDE-ParentApp" );
    00561   if ( (it == m_mapProps.end()) || (!it.data().isValid()))
    00562   {
    00563      return QString::null;
    00564   }
    00565
    00566   return it.data().toString();
    00567 }
    00568
    00569 bool KService::allowMultipleFiles() const {
    00570   // Can we pass multiple files on the command line or do we have to start the application for every single file ?
    00571   if ( m_strExec.find( "%F" ) != -1 || m_strExec.find( "%U" ) != -1 ||
    00572        m_strExec.find( "%N" ) != -1 || m_strExec.find( "%D" ) != -1 )
    00573     return true;
    00574   else
    00575     return false;
    00576 }
    00577
    00578 QStringList KService::categories() const
    00579 {
    00580   return d->categories;
    00581 }
    00582
    00583
    00584 void KService::virtual_hook( int id, void* data )
    00585 { KSycocaEntry::virtual_hook( id, data ); }
    00586

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:17 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001