00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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 );
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");
00106 entryMap.remove("Version");
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
00120
00121
00122
00123
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
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
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" ));
00189 entryMap.remove("Terminal");
00190 m_strTerminalOptions = config->readEntry( "TerminalOptions" );
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
00210 m_lstServiceTypes += config->readListEntry( "MimeType", ';' );
00211 entryMap.remove("MimeType");
00212
00213 if ( m_strType == "Application" && !m_lstServiceTypes.contains("Application") )
00214
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
00237
00238
00239
00240 QMap<QString,QString>::ConstIterator it = entryMap.begin();
00241 for( ; it != entryMap.end();++it)
00242 {
00243
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
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
00277
00278
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
00286
00287
00288
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;
00314 QString dummyStr1, dummyStr2;
00315 int dummyI1 = 0, dummyI2 = 0;
00316 Q_UINT32 dummyUI32 = 0;
00317
00318
00319
00320
00321
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;
00336
00337
00338
00339
00340
00341 QStringList::ConstIterator it = m_lstServiceTypes.begin();
00342 for( ; it != m_lstServiceTypes.end(); ++it )
00343 {
00344
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 { 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
00418
00419
00420
00421
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();
00428 }
00429
00430 QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( _name );
00431 if ( (it == m_mapProps.end()) || (!it.data().isValid()))
00432 {
00433
00434 return QVariant();
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
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
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
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