kio Library API Documentation

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