kstandarddirs.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
00003    Copyright (C) 1999 Stephan Kulow <coolo@kde.org>
00004    Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License version 2 as published by the Free Software Foundation.
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 /*
00022  * Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
00023  * Version: $Id: kstandarddirs.cpp 601485 2006-11-03 12:50:30Z lunakl $
00024  * Generated:   Thu Mar  5 16:05:28 EST 1998
00025  */
00026 
00027 #include "config.h"
00028 
00029 #include <stdlib.h>
00030 #include <assert.h>
00031 #include <errno.h>
00032 #ifdef HAVE_SYS_STAT_H
00033 #include <sys/stat.h>
00034 #endif
00035 #include <sys/param.h>
00036 #include <sys/types.h>
00037 #include <dirent.h>
00038 #include <pwd.h>
00039 #include <grp.h>
00040 
00041 #include <qregexp.h>
00042 #include <qasciidict.h>
00043 #include <qdict.h>
00044 #include <qdir.h>
00045 #include <qfileinfo.h>
00046 #include <qstring.h>
00047 #include <qstringlist.h>
00048 
00049 #include "kstandarddirs.h"
00050 #include "kconfig.h"
00051 #include "kdebug.h"
00052 #include "kinstance.h"
00053 #include "kshell.h"
00054 #include "ksimpleconfig.h"
00055 #include "kuser.h"
00056 #include "kstaticdeleter.h"
00057 #include <kde_file.h>
00058 
00059 template class QDict<QStringList>;
00060 
00061 class KStandardDirs::KStandardDirsPrivate
00062 {
00063 public:
00064    KStandardDirsPrivate()
00065     : restrictionsActive(false),
00066       dataRestrictionActive(false),
00067       checkRestrictions(true)
00068    { }
00069 
00070    bool restrictionsActive;
00071    bool dataRestrictionActive;
00072    bool checkRestrictions;
00073    QAsciiDict<bool> restrictions;
00074    QStringList xdgdata_prefixes;
00075    QStringList xdgconf_prefixes;
00076 };
00077 
00078 // Singleton, with data shared by all kstandarddirs instances.
00079 // Used in static methods like findExe()
00080 class KStandardDirsSingleton
00081 {
00082 public:
00083    QString defaultprefix;
00084    QString defaultbindir;
00085    static KStandardDirsSingleton* self();
00086 private:
00087    static KStandardDirsSingleton* s_self;
00088 };
00089 static KStaticDeleter<KStandardDirsSingleton> kstds_sd;
00090 KStandardDirsSingleton* KStandardDirsSingleton::s_self = 0;
00091 KStandardDirsSingleton* KStandardDirsSingleton::self() {
00092     if ( !s_self )
00093         kstds_sd.setObject( s_self, new KStandardDirsSingleton );
00094     return s_self;
00095 }
00096 
00097 static const char* const types[] = {"html", "icon", "apps", "sound",
00098                   "data", "locale", "services", "mime",
00099                   "servicetypes", "config", "exe",
00100                   "wallpaper", "lib", "pixmap", "templates",
00101                   "module", "qtplugins",
00102                   "xdgdata-apps", "xdgdata-dirs", "xdgconf-menu",
00103                   "xdgdata-icon", "xdgdata-pixmap",
00104                   "kcfg", "emoticons", 0 };
00105 
00106 static int tokenize( QStringList& token, const QString& str,
00107         const QString& delim );
00108 
00109 KStandardDirs::KStandardDirs( ) : addedCustoms(false)
00110 {
00111     d = new KStandardDirsPrivate;
00112     dircache.setAutoDelete(true);
00113     relatives.setAutoDelete(true);
00114     absolutes.setAutoDelete(true);
00115     savelocations.setAutoDelete(true);
00116     addKDEDefaults();
00117 }
00118 
00119 KStandardDirs::~KStandardDirs()
00120 {
00121     delete d;
00122 }
00123 
00124 bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const
00125 {
00126    if (!d || !d->restrictionsActive)
00127       return false;
00128 
00129    if (d->restrictions[type])
00130       return true;
00131 
00132    if (strcmp(type, "data")==0)
00133    {
00134       applyDataRestrictions(relPath);
00135       if (d->dataRestrictionActive)
00136       {
00137          d->dataRestrictionActive = false;
00138          return true;
00139       }
00140    }
00141    return false;
00142 }
00143 
00144 void KStandardDirs::applyDataRestrictions(const QString &relPath) const
00145 {
00146    QString key;
00147    int i = relPath.find('/');
00148    if (i != -1)
00149       key = "data_"+relPath.left(i);
00150    else
00151       key = "data_"+relPath;
00152 
00153    if (d && d->restrictions[key.latin1()])
00154       d->dataRestrictionActive = true;
00155 }
00156 
00157 
00158 QStringList KStandardDirs::allTypes() const
00159 {
00160     QStringList list;
00161     for (int i = 0; types[i] != 0; ++i)
00162         list.append(QString::fromLatin1(types[i]));
00163     return list;
00164 }
00165 
00166 static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority)
00167 {
00168     if (priority && !prefixes.isEmpty())
00169     {
00170         // Add in front but behind $KDEHOME
00171         QStringList::iterator it = prefixes.begin();
00172         it++;
00173         prefixes.insert(it, 1, dir);
00174     }
00175     else
00176     {
00177         prefixes.append(dir);
00178     }
00179 }
00180 
00181 void KStandardDirs::addPrefix( const QString& _dir )
00182 {
00183     addPrefix(_dir, false);
00184 }
00185 
00186 void KStandardDirs::addPrefix( const QString& _dir, bool priority )
00187 {
00188     if (_dir.isEmpty())
00189     return;
00190 
00191     QString dir = _dir;
00192     if (dir.at(dir.length() - 1) != '/')
00193     dir += '/';
00194 
00195     if (!prefixes.contains(dir)) {
00196         priorityAdd(prefixes, dir, priority);
00197     dircache.clear();
00198     }
00199 }
00200 
00201 void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
00202 {
00203     addXdgConfigPrefix(_dir, false);
00204 }
00205 
00206 void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority )
00207 {
00208     if (_dir.isEmpty())
00209     return;
00210 
00211     QString dir = _dir;
00212     if (dir.at(dir.length() - 1) != '/')
00213     dir += '/';
00214 
00215     if (!d->xdgconf_prefixes.contains(dir)) {
00216         priorityAdd(d->xdgconf_prefixes, dir, priority);
00217     dircache.clear();
00218     }
00219 }
00220 
00221 void KStandardDirs::addXdgDataPrefix( const QString& _dir )
00222 {
00223     addXdgDataPrefix(_dir, false);
00224 }
00225 
00226 void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority )
00227 {
00228     if (_dir.isEmpty())
00229     return;
00230 
00231     QString dir = _dir;
00232     if (dir.at(dir.length() - 1) != '/')
00233     dir += '/';
00234 
00235     if (!d->xdgdata_prefixes.contains(dir)) {
00236     priorityAdd(d->xdgdata_prefixes, dir, priority);
00237     dircache.clear();
00238     }
00239 }
00240 
00241 QString KStandardDirs::kfsstnd_prefixes()
00242 {
00243    return prefixes.join(QChar(KPATH_SEPARATOR));
00244 }
00245 
00246 QString KStandardDirs::kfsstnd_xdg_conf_prefixes()
00247 {
00248    return d->xdgconf_prefixes.join(QChar(KPATH_SEPARATOR));
00249 }
00250 
00251 QString KStandardDirs::kfsstnd_xdg_data_prefixes()
00252 {
00253    return d->xdgdata_prefixes.join(QChar(KPATH_SEPARATOR));
00254 }
00255 
00256 bool KStandardDirs::addResourceType( const char *type,
00257                      const QString& relativename )
00258 {
00259     return addResourceType(type, relativename, true);
00260 }
00261 bool KStandardDirs::addResourceType( const char *type,
00262                      const QString& relativename,
00263                      bool priority )
00264 {
00265     if (relativename.isEmpty())
00266        return false;
00267 
00268     QStringList *rels = relatives.find(type);
00269     if (!rels) {
00270     rels = new QStringList();
00271     relatives.insert(type, rels);
00272     }
00273     QString copy = relativename;
00274     if (copy.at(copy.length() - 1) != '/')
00275     copy += '/';
00276     if (!rels->contains(copy)) {
00277         if (priority)
00278         rels->prepend(copy);
00279     else
00280         rels->append(copy);
00281     dircache.remove(type); // clean the cache
00282     return true;
00283     }
00284     return false;
00285 }
00286 
00287 bool KStandardDirs::addResourceDir( const char *type,
00288                     const QString& absdir)
00289 {
00290     // KDE4: change priority to bring in line with addResourceType
00291     return addResourceDir(type, absdir, false);
00292 }
00293 
00294 bool KStandardDirs::addResourceDir( const char *type,
00295                     const QString& absdir,
00296                     bool priority)
00297 {
00298     QStringList *paths = absolutes.find(type);
00299     if (!paths) {
00300     paths = new QStringList();
00301     absolutes.insert(type, paths);
00302     }
00303     QString copy = absdir;
00304     if (copy.at(copy.length() - 1) != '/')
00305       copy += '/';
00306 
00307     if (!paths->contains(copy)) {
00308         if (priority)
00309             paths->prepend(copy);
00310         else
00311         paths->append(copy);
00312     dircache.remove(type); // clean the cache
00313     return true;
00314     }
00315     return false;
00316 }
00317 
00318 QString KStandardDirs::findResource( const char *type,
00319                      const QString& filename ) const
00320 {
00321     if (!QDir::isRelativePath(filename))
00322     return filename; // absolute dirs are absolute dirs, right? :-/
00323 
00324     QString newFilename(filename);
00325     if ( strcmp(type, "lib") == 0 || strcmp(type, "module") == 0 )
00326     {
00327     if (newFilename.right(3) == ".la")
00328            newFilename = newFilename.replace( newFilename.length() - 3, 3, ".so" );
00329     }
00330 
00331 #if 0
00332 kdDebug() << "Find resource: " << type << endl;
00333 for (QStringList::ConstIterator pit = prefixes.begin();
00334      pit != prefixes.end();
00335      pit++)
00336 {
00337   kdDebug() << "Prefix: " << *pit << endl;
00338 }
00339 #endif
00340 
00341     QString dir = findResourceDir(type, newFilename);
00342     if (dir.isEmpty())
00343     return dir;
00344     else return dir + newFilename;
00345 }
00346 
00347 static Q_UINT32 updateHash(const QString &file, Q_UINT32 hash)
00348 {
00349     QCString cFile = QFile::encodeName(file);
00350     KDE_struct_stat buff;
00351     if ((access(cFile, R_OK) == 0) &&
00352         (KDE_stat( cFile, &buff ) == 0) &&
00353         (S_ISREG( buff.st_mode )))
00354     {
00355        hash = hash + (Q_UINT32) buff.st_ctime;
00356     }
00357     return hash;
00358 }
00359 
00360 Q_UINT32 KStandardDirs::calcResourceHash( const char *type,
00361                   const QString& filename, bool deep) const
00362 {
00363     Q_UINT32 hash = 0;
00364 
00365     if (!QDir::isRelativePath(filename))
00366     {
00367         // absolute dirs are absolute dirs, right? :-/
00368     return updateHash(filename, hash);
00369     }
00370     if (d && d->restrictionsActive && (strcmp(type, "data")==0))
00371        applyDataRestrictions(filename);
00372     QStringList candidates = resourceDirs(type);
00373     QString fullPath;
00374 
00375     for (QStringList::ConstIterator it = candidates.begin();
00376      it != candidates.end(); ++it)
00377     {
00378         hash = updateHash(*it + filename, hash);
00379         if (!deep && hash)
00380            return hash;
00381     }
00382     return hash;
00383 }
00384 
00385 
00386 QStringList KStandardDirs::findDirs( const char *type,
00387                                      const QString& reldir ) const
00388 {
00389     QDir testdir;
00390     QStringList list;
00391     if (!QDir::isRelativePath(reldir))
00392     {
00393         testdir.setPath(reldir);
00394         if (testdir.exists())
00395         {
00396             if (reldir.endsWith("/"))
00397                list.append(reldir);
00398             else
00399                list.append(reldir+'/');
00400         }
00401         return list;
00402     }
00403 
00404     checkConfig();
00405 
00406     if (d && d->restrictionsActive && (strcmp(type, "data")==0))
00407        applyDataRestrictions(reldir);
00408     QStringList candidates = resourceDirs(type);
00409 
00410     for (QStringList::ConstIterator it = candidates.begin();
00411          it != candidates.end(); ++it) {
00412         testdir.setPath(*it + reldir);
00413         if (testdir.exists())
00414             list.append(testdir.absPath() + '/');
00415     }
00416 
00417     return list;
00418 }
00419 
00420 QString KStandardDirs::findResourceDir( const char *type,
00421                     const QString& filename) const
00422 {
00423 #ifndef NDEBUG
00424     if (filename.isEmpty()) {
00425       kdWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!" << endl;
00426       return QString::null;
00427     }
00428 #endif
00429 
00430     if (d && d->restrictionsActive && (strcmp(type, "data")==0))
00431        applyDataRestrictions(filename);
00432     QStringList candidates = resourceDirs(type);
00433     QString fullPath;
00434 
00435     for (QStringList::ConstIterator it = candidates.begin();
00436       it != candidates.end(); ++it) {
00437       if( exists_ext(*it + filename, (qstrcmp("exe",type)==0)? X_OK: R_OK) ) {
00438 #ifdef Q_WS_WIN //this ensures we're using installed .la files
00439           if ((*it).isEmpty() && filename.right(3)==".la") {
00440 #ifndef NDEBUG
00441               kdDebug() << "KStandardDirs::findResourceDir() found .la in cwd: skipping. (fname=" << filename  << ")" << endl;
00442 #endif
00443               continue;
00444           }
00445 #endif //Q_WS_WIN
00446           return *it;
00447       }
00448     }
00449 
00450 #ifndef NDEBUG
00451     if(false && strcmp(type, "locale"))
00452       kdDebug() << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\"." << endl;
00453 #endif
00454 
00455     return QString::null;
00456 }
00457 
00458 bool KStandardDirs::exists(const QString &fullPath)
00459 {
00460     return exists_ext( fullPath, R_OK );
00461 }
00462 
00463 bool KStandardDirs::exists_ext(const QString &fullPath, int mode)
00464 {
00465     KDE_struct_stat buff;
00466     if (access(QFile::encodeName(fullPath), mode) == 0 && KDE_stat( QFile::encodeName(fullPath), &buff ) == 0)
00467     if (fullPath.at(fullPath.length() - 1) != '/') {
00468         if (S_ISREG( buff.st_mode ))
00469         return true;
00470     } else
00471         if (S_ISDIR( buff.st_mode ))
00472         return true;
00473     return false;
00474 }
00475 
00476 bool KStandardDirs::exists_exe(const QString &fullPath)
00477 {
00478     return exists_ext( fullPath, X_OK );
00479 }
00480 
00481 static void lookupDirectory(const QString& path, const QString &relPart,
00482                 const QRegExp &regexp,
00483                 QStringList& list,
00484                 QStringList& relList,
00485                 bool recursive, bool unique)
00486 {
00487   QString pattern = regexp.pattern();
00488   if (recursive || pattern.contains('?') || pattern.contains('*'))
00489   {
00490     if (path.isEmpty()) //for sanity
00491       return;
00492     // We look for a set of files.
00493     DIR *dp = opendir( QFile::encodeName(path));
00494     if (!dp)
00495       return;
00496 
00497 #ifdef Q_WS_WIN
00498     assert(path.at(path.length() - 1) == '/' || path.at(path.length() - 1) == '\\');
00499 #else
00500     assert(path.at(path.length() - 1) == '/');
00501 #endif
00502 
00503     struct dirent *ep;
00504     KDE_struct_stat buff;
00505 
00506     QString _dot(".");
00507     QString _dotdot("..");
00508 
00509     while( ( ep = readdir( dp ) ) != 0L )
00510     {
00511       QString fn( QFile::decodeName(ep->d_name));
00512       if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1).latin1() == '~')
00513     continue;
00514 
00515       if (!recursive && !regexp.exactMatch(fn))
00516     continue; // No match
00517 
00518       QString pathfn = path + fn;
00519       if ( KDE_stat( QFile::encodeName(pathfn), &buff ) != 0 ) {
00520     kdDebug() << "Error stat'ing " << pathfn << " : " << perror << endl;
00521     continue; // Couldn't stat (e.g. no read permissions)
00522       }
00523       if ( recursive ) {
00524     if ( S_ISDIR( buff.st_mode )) {
00525       lookupDirectory(pathfn + '/', relPart + fn + '/', regexp, list, relList, recursive, unique);
00526     }
00527         if (!regexp.exactMatch(fn))
00528       continue; // No match
00529       }
00530       if ( S_ISREG( buff.st_mode))
00531       {
00532         if (!unique || !relList.contains(relPart + fn))
00533         {
00534         list.append( pathfn );
00535         relList.append( relPart + fn );
00536         }
00537       }
00538     }
00539     closedir( dp );
00540   }
00541   else
00542   {
00543      // We look for a single file.
00544      QString fn = pattern;
00545      QString pathfn = path + fn;
00546      KDE_struct_stat buff;
00547      if ( KDE_stat( QFile::encodeName(pathfn), &buff ) != 0 )
00548         return; // File not found
00549      if ( S_ISREG( buff.st_mode))
00550      {
00551        if (!unique || !relList.contains(relPart + fn))
00552        {
00553          list.append( pathfn );
00554          relList.append( relPart + fn );
00555        }
00556      }
00557   }
00558 }
00559 
00560 static void lookupPrefix(const QString& prefix, const QString& relpath,
00561                          const QString& relPart,
00562              const QRegExp &regexp,
00563              QStringList& list,
00564              QStringList& relList,
00565              bool recursive, bool unique)
00566 {
00567     if (relpath.isEmpty()) {
00568        lookupDirectory(prefix, relPart, regexp, list,
00569                relList, recursive, unique);
00570        return;
00571     }
00572     QString path;
00573     QString rest;
00574 
00575     if (relpath.length())
00576     {
00577        int slash = relpath.find('/');
00578        if (slash < 0)
00579        rest = relpath.left(relpath.length() - 1);
00580        else {
00581        path = relpath.left(slash);
00582        rest = relpath.mid(slash + 1);
00583        }
00584     }
00585 
00586     if (prefix.isEmpty()) //for sanity
00587       return;
00588 #ifdef Q_WS_WIN
00589     assert(prefix.at(prefix.length() - 1) == '/' || prefix.at(prefix.length() - 1) == '\\');
00590 #else
00591     assert(prefix.at(prefix.length() - 1) == '/');
00592 #endif
00593     KDE_struct_stat buff;
00594 
00595     if (path.contains('*') || path.contains('?')) {
00596 
00597     QRegExp pathExp(path, true, true);
00598     DIR *dp = opendir( QFile::encodeName(prefix) );
00599     if (!dp) {
00600         return;
00601     }
00602 
00603     struct dirent *ep;
00604 
00605         QString _dot(".");
00606         QString _dotdot("..");
00607 
00608     while( ( ep = readdir( dp ) ) != 0L )
00609         {
00610         QString fn( QFile::decodeName(ep->d_name));
00611         if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1) == '~')
00612             continue;
00613 
00614         if ( !pathExp.exactMatch(fn) )
00615             continue; // No match
00616         QString rfn = relPart+fn;
00617         fn = prefix + fn;
00618         if ( KDE_stat( QFile::encodeName(fn), &buff ) != 0 ) {
00619             kdDebug() << "Error statting " << fn << " : " << perror << endl;
00620             continue; // Couldn't stat (e.g. no permissions)
00621         }
00622         if ( S_ISDIR( buff.st_mode ))
00623             lookupPrefix(fn + '/', rest, rfn + '/', regexp, list, relList, recursive, unique);
00624         }
00625 
00626     closedir( dp );
00627     } else {
00628         // Don't stat, if the dir doesn't exist we will find out
00629         // when we try to open it.
00630         lookupPrefix(prefix + path + '/', rest,
00631                      relPart + path + '/', regexp, list,
00632                      relList, recursive, unique);
00633     }
00634 }
00635 
00636 QStringList
00637 KStandardDirs::findAllResources( const char *type,
00638                      const QString& filter,
00639                  bool recursive,
00640                      bool unique,
00641                                  QStringList &relList) const
00642 {
00643     QStringList list;
00644     QString filterPath;
00645     QString filterFile;
00646 
00647     if (filter.length())
00648     {
00649        int slash = filter.findRev('/');
00650        if (slash < 0)
00651        filterFile = filter;
00652        else {
00653        filterPath = filter.left(slash + 1);
00654        filterFile = filter.mid(slash + 1);
00655        }
00656     }
00657 
00658     checkConfig();
00659 
00660     QStringList candidates;
00661     if (!QDir::isRelativePath(filter)) // absolute path
00662     {
00663 #ifdef Q_OS_WIN
00664         candidates << filterPath.left(3); //e.g. "C:\"
00665         filterPath = filterPath.mid(3);
00666 #else
00667         candidates << "/";
00668         filterPath = filterPath.mid(1);
00669 #endif
00670     }
00671     else
00672     {
00673         if (d && d->restrictionsActive && (strcmp(type, "data")==0))
00674             applyDataRestrictions(filter);
00675         candidates = resourceDirs(type);
00676     }
00677     if (filterFile.isEmpty())
00678     filterFile = "*";
00679 
00680     QRegExp regExp(filterFile, true, true);
00681 
00682     for (QStringList::ConstIterator it = candidates.begin();
00683          it != candidates.end(); ++it)
00684     {
00685         lookupPrefix(*it, filterPath, "", regExp, list,
00686                      relList, recursive, unique);
00687     }
00688 
00689     return list;
00690 }
00691 
00692 QStringList
00693 KStandardDirs::findAllResources( const char *type,
00694                      const QString& filter,
00695                  bool recursive,
00696                      bool unique) const
00697 {
00698     QStringList relList;
00699     return findAllResources(type, filter, recursive, unique, relList);
00700 }
00701 
00702 QString
00703 KStandardDirs::realPath(const QString &dirname)
00704 {
00705     char realpath_buffer[MAXPATHLEN + 1];
00706     memset(realpath_buffer, 0, MAXPATHLEN + 1);
00707 
00708     /* If the path contains symlinks, get the real name */
00709     if (realpath( QFile::encodeName(dirname).data(), realpath_buffer) != 0) {
00710         // success, use result from realpath
00711         int len = strlen(realpath_buffer);
00712         realpath_buffer[len] = '/';
00713         realpath_buffer[len+1] = 0;
00714         return QFile::decodeName(realpath_buffer);
00715     }
00716 
00717     return dirname;
00718 }
00719 
00720 QString
00721 KStandardDirs::realFilePath(const QString &filename)
00722 {
00723     char realpath_buffer[MAXPATHLEN + 1];
00724     memset(realpath_buffer, 0, MAXPATHLEN + 1);
00725 
00726     /* If the path contains symlinks, get the real name */
00727     if (realpath( QFile::encodeName(filename).data(), realpath_buffer) != 0) {
00728         // success, use result from realpath
00729         return QFile::decodeName(realpath_buffer);
00730     }
00731 
00732     return filename;
00733 }
00734 
00735 void KStandardDirs::createSpecialResource(const char *type)
00736 {
00737    char hostname[256];
00738    hostname[0] = 0;
00739    gethostname(hostname, 255);
00740    QString dir = QString("%1%2-%3").arg(localkdedir()).arg(type).arg(hostname);
00741    char link[1024];
00742    link[1023] = 0;
00743    int result = readlink(QFile::encodeName(dir).data(), link, 1023);
00744    bool relink = (result == -1) && (errno == ENOENT);
00745    if (result > 0)
00746    {
00747       link[result] = 0;
00748       if (!QDir::isRelativePath(link))
00749       {
00750          KDE_struct_stat stat_buf;
00751          int res = KDE_lstat(link, &stat_buf);
00752          if ((res == -1) && (errno == ENOENT))
00753          {
00754             relink = true;
00755          }
00756          else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
00757          {
00758             fprintf(stderr, "Error: \"%s\" is not a directory.\n", link);
00759             relink = true;
00760          }
00761          else if (stat_buf.st_uid != getuid())
00762          {
00763             fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
00764             relink = true;
00765          }
00766       }
00767    }
00768 #ifdef Q_WS_WIN
00769    if (relink)
00770    {
00771       if (!makeDir(dir, 0700))
00772          fprintf(stderr, "failed to create \"%s\"", dir.latin1());
00773       else
00774          result = readlink(QFile::encodeName(dir).data(), link, 1023);
00775    }
00776 #else //UNIX
00777    if (relink)
00778    {
00779       QString srv = findExe(QString::fromLatin1("lnusertemp"), kfsstnd_defaultbindir());
00780       if (srv.isEmpty())
00781          srv = findExe(QString::fromLatin1("lnusertemp"));
00782       if (!srv.isEmpty())
00783       {
00784          system(QFile::encodeName(srv)+" "+type);
00785          result = readlink(QFile::encodeName(dir).data(), link, 1023);
00786       }
00787    }
00788    if (result > 0)
00789    {
00790       link[result] = 0;
00791       if (link[0] == '/')
00792          dir = QFile::decodeName(link);
00793       else
00794          dir = QDir::cleanDirPath(dir+QFile::decodeName(link));
00795    }
00796 #endif
00797    addResourceDir(type, dir+'/');
00798 }
00799 
00800 QStringList KStandardDirs::resourceDirs(const char *type) const
00801 {
00802     QStringList *candidates = dircache.find(type);
00803 
00804     if (!candidates) { // filling cache
00805         if (strcmp(type, "socket") == 0)
00806            const_cast<KStandardDirs *>(this)->createSpecialResource(type);
00807         else if (strcmp(type, "tmp") == 0)
00808            const_cast<KStandardDirs *>(this)->createSpecialResource(type);
00809         else if (strcmp(type, "cache") == 0)
00810            const_cast<KStandardDirs *>(this)->createSpecialResource(type);
00811 
00812         QDir testdir;
00813 
00814         candidates = new QStringList();
00815         QStringList *dirs;
00816 
00817         bool restrictionActive = false;
00818         if (d && d->restrictionsActive)
00819         {
00820            if (d->dataRestrictionActive)
00821               restrictionActive = true;
00822            else if (d->restrictions["all"])
00823               restrictionActive = true;
00824            else if (d->restrictions[type])
00825               restrictionActive = true;
00826            d->dataRestrictionActive = false; // Reset
00827         }
00828 
00829         dirs = relatives.find(type);
00830         if (dirs)
00831         {
00832             bool local = true;
00833             const QStringList *prefixList = 0;
00834             if (strncmp(type, "xdgdata-", 8) == 0)
00835                 prefixList = &(d->xdgdata_prefixes);
00836             else if (strncmp(type, "xdgconf-", 8) == 0)
00837                 prefixList = &(d->xdgconf_prefixes);
00838             else
00839                 prefixList = &prefixes;
00840 
00841             for (QStringList::ConstIterator pit = prefixList->begin();
00842                  pit != prefixList->end();
00843                  ++pit)
00844             {
00845                 for (QStringList::ConstIterator it = dirs->begin();
00846                      it != dirs->end(); ++it) {
00847                     QString path = realPath(*pit + *it);
00848                     testdir.setPath(path);
00849                     if (local && restrictionActive)
00850                        continue;
00851                     if ((local || testdir.exists()) && !candidates->contains(path))
00852                         candidates->append(path);
00853                 }
00854                 local = false;
00855             }
00856         }
00857         dirs = absolutes.find(type);
00858         if (dirs)
00859             for (QStringList::ConstIterator it = dirs->begin();
00860                  it != dirs->end(); ++it)
00861             {
00862                 testdir.setPath(*it);
00863                 if (testdir.exists())
00864                 {
00865                     QString filename = realPath(*it);
00866                     if (!candidates->contains(filename))
00867                         candidates->append(filename);
00868                 }
00869             }
00870         dircache.insert(type, candidates);
00871     }
00872 
00873 #if 0
00874     kdDebug() << "found dirs for resource " << type << ":" << endl;
00875     for (QStringList::ConstIterator pit = candidates->begin();
00876      pit != candidates->end();
00877      pit++)
00878     {
00879     fprintf(stderr, "%s\n", (*pit).latin1());
00880     }
00881 #endif
00882 
00883 
00884   return *candidates;
00885 }
00886 
00887 QStringList KStandardDirs::systemPaths( const QString& pstr )
00888 {
00889     QStringList tokens;
00890     QString p = pstr;
00891 
00892     if( p.isNull() )
00893     {
00894     p = getenv( "PATH" );
00895     }
00896 
00897     QString delimiters(QChar(KPATH_SEPARATOR));
00898     delimiters += "\b";
00899     tokenize( tokens, p, delimiters );
00900 
00901     QStringList exePaths;
00902 
00903     // split path using : or \b as delimiters
00904     for( unsigned i = 0; i < tokens.count(); i++ )
00905     {
00906     p = tokens[ i ];
00907 
00908         if ( p[ 0 ] == '~' )
00909         {
00910             int len = p.find( '/' );
00911             if ( len == -1 )
00912                 len = p.length();
00913             if ( len == 1 )
00914             {
00915                 p.replace( 0, 1, QDir::homeDirPath() );
00916             }
00917             else
00918             {
00919                 QString user = p.mid( 1, len - 1 );
00920                 struct passwd *dir = getpwnam( user.local8Bit().data() );
00921                 if ( dir && strlen( dir->pw_dir ) )
00922                     p.replace( 0, len, QString::fromLocal8Bit( dir->pw_dir ) );
00923             }
00924         }
00925 
00926     exePaths << p;
00927     }
00928 
00929     return exePaths;
00930 }
00931 
00932 
00933 QString KStandardDirs::findExe( const QString& appname,
00934                 const QString& pstr, bool ignore)
00935 {
00936 #ifdef Q_WS_WIN
00937     QString real_appname = appname + ".exe";
00938 #else
00939     QString real_appname = appname;
00940 #endif
00941     QFileInfo info;
00942 
00943     // absolute path ?
00944     if (!QDir::isRelativePath(real_appname))
00945     {
00946         info.setFile( real_appname );
00947         if( info.exists() && ( ignore || info.isExecutable() )
00948             && info.isFile() ) {
00949             return real_appname;
00950         }
00951         return QString::null;
00952     }
00953 
00954     QString p = QString("%1/%2").arg(kfsstnd_defaultbindir()).arg(real_appname);
00955     info.setFile( p );
00956     if( info.exists() && ( ignore || info.isExecutable() )
00957          && ( info.isFile() || info.isSymLink() )  ) {
00958          return p;
00959     }
00960 
00961     QStringList exePaths = systemPaths( pstr );
00962     for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
00963     {
00964     p = (*it) + "/";
00965     p += real_appname;
00966 
00967     // Check for executable in this tokenized path
00968     info.setFile( p );
00969 
00970     if( info.exists() && ( ignore || info.isExecutable() )
00971            && ( info.isFile() || info.isSymLink() )  ) {
00972         return p;
00973     }
00974     }
00975 
00976     // If we reach here, the executable wasn't found.
00977     // So return empty string.
00978 
00979     return QString::null;
00980 }
00981 
00982 int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
00983             const QString& pstr, bool ignore )
00984 {
00985 #ifdef Q_WS_WIN
00986     QString real_appname = appname + ".exe";
00987 #else
00988     QString real_appname = appname;
00989 #endif
00990     QFileInfo info;
00991     QString p;
00992     list.clear();
00993 
00994     QStringList exePaths = systemPaths( pstr );
00995     for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
00996     {
00997     p = (*it) + "/";
00998     p += real_appname;
00999 
01000     info.setFile( p );
01001 
01002     if( info.exists() && (ignore || info.isExecutable())
01003         && info.isFile() ) {
01004         list.append( p );
01005     }
01006     }
01007 
01008     return list.count();
01009 }
01010 
01011 static int tokenize( QStringList& tokens, const QString& str,
01012              const QString& delim )
01013 {
01014     int len = str.length();
01015     QString token = "";
01016 
01017     for( int index = 0; index < len; index++)
01018     {
01019     if ( delim.find( str[ index ] ) >= 0 )
01020     {
01021         tokens.append( token );
01022         token = "";
01023     }
01024     else
01025     {
01026         token += str[ index ];
01027     }
01028     }
01029     if ( token.length() > 0 )
01030     {
01031     tokens.append( token );
01032     }
01033 
01034     return tokens.count();
01035 }
01036 
01037 QString KStandardDirs::kde_default(const char *type) {
01038     if (!strcmp(type, "data"))
01039     return "share/apps/";
01040     if (!strcmp(type, "html"))
01041     return "share/doc/HTML/";
01042     if (!strcmp(type, "icon"))
01043     return "share/icons/";
01044     if (!strcmp(type, "config"))
01045     return "share/config/";
01046     if (!strcmp(type, "pixmap"))
01047     return "share/pixmaps/";
01048     if (!strcmp(type, "apps"))
01049     return "share/applnk/";
01050     if (!strcmp(type, "sound"))
01051     return "share/sounds/";
01052     if (!strcmp(type, "locale"))
01053     return "share/kde/locale/";
01054     if (!strcmp(type, "services"))
01055     return "share/services/";
01056     if (!strcmp(type, "servicetypes"))
01057     return "share/servicetypes/";
01058     if (!strcmp(type, "mime"))
01059     return "share/mimelnk/";
01060     if (!strcmp(type, "cgi"))
01061     return "cgi-bin/";
01062     if (!strcmp(type, "wallpaper"))
01063     return "share/wallpapers/";
01064     if (!strcmp(type, "templates"))
01065     return "share/templates/";
01066     if (!strcmp(type, "exe"))
01067     return "bin/";
01068     if (!strcmp(type, "lib"))
01069     return "lib" KDELIBSUFF "/";
01070     if (!strcmp(type, "module"))
01071     return "lib" KDELIBSUFF "/kde3/";
01072     if (!strcmp(type, "qtplugins"))
01073         return "lib" KDELIBSUFF "/kde3/plugins";
01074     if (!strcmp(type, "xdgdata-apps"))
01075         return "applications/";
01076     if (!strcmp(type, "xdgdata-icon"))
01077         return "icons/";
01078     if (!strcmp(type, "xdgdata-pixmap"))
01079         return "pixmaps/";
01080     if (!strcmp(type, "xdgdata-dirs"))
01081         return "desktop-directories/";
01082     if (!strcmp(type, "xdgconf-menu"))
01083         return "menus/";
01084     if (!strcmp(type, "kcfg"))
01085     return "share/config.kcfg";
01086     if (!strcmp(type, "emoticons"))
01087             return "share/emoticons";
01088 
01089 
01090     qFatal("unknown resource type %s", type);
01091     return QString::null;
01092 }
01093 
01094 QString KStandardDirs::saveLocation(const char *type,
01095                     const QString& suffix,
01096                     bool create) const
01097 {
01098     checkConfig();
01099 
01100     QString *pPath = savelocations.find(type);
01101     if (!pPath)
01102     {
01103        QStringList *dirs = relatives.find(type);
01104        if (!dirs && (
01105                      (strcmp(type, "socket") == 0) ||
01106                      (strcmp(type, "tmp") == 0) ||
01107                      (strcmp(type, "cache") == 0) ))
01108        {
01109           (void) resourceDirs(type); // Generate socket|tmp|cache resource.
01110           dirs = relatives.find(type); // Search again.
01111        }
01112        if (dirs)
01113        {
01114           // Check for existence of typed directory + suffix
01115           if (strncmp(type, "xdgdata-", 8) == 0)
01116              pPath = new QString(realPath(localxdgdatadir() + dirs->last()));
01117           else if (strncmp(type, "xdgconf-", 8) == 0)
01118              pPath = new QString(realPath(localxdgconfdir() + dirs->last()));
01119           else
01120              pPath = new QString(realPath(localkdedir() + dirs->last()));
01121        }
01122        else {
01123           dirs = absolutes.find(type);
01124           if (!dirs)
01125              qFatal("KStandardDirs: The resource type %s is not registered", type);
01126           pPath = new QString(realPath(dirs->last()));
01127        }
01128 
01129        savelocations.insert(type, pPath);
01130     }
01131     QString fullPath = *pPath + (pPath->endsWith("/") ? "" : "/") + suffix;
01132 
01133     KDE_struct_stat st;
01134     if (KDE_stat(QFile::encodeName(fullPath), &st) != 0 || !(S_ISDIR(st.st_mode))) {
01135     if(!create) {
01136 #ifndef NDEBUG
01137         kdDebug() << QString("save location %1 doesn't exist").arg(fullPath) << endl;
01138 #endif
01139         return fullPath;
01140     }
01141     if(!makeDir(fullPath, 0700)) {
01142         return fullPath;
01143     }
01144         dircache.remove(type);
01145     }
01146     if (!fullPath.endsWith("/"))
01147         fullPath += "/";
01148     return fullPath;
01149 }
01150 
01151 QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
01152 {
01153     QString fullPath = absPath;
01154     int i = absPath.findRev('/');
01155     if (i != -1)
01156     {
01157        fullPath = realPath(absPath.left(i+1))+absPath.mid(i+1); // Normalize
01158     }
01159 
01160     QStringList candidates = resourceDirs(type);
01161 
01162     for (QStringList::ConstIterator it = candidates.begin();
01163      it != candidates.end(); ++it)
01164       if (fullPath.startsWith(*it))
01165       {
01166     return fullPath.mid((*it).length());
01167       }
01168 
01169     return absPath;
01170 }
01171 
01172 
01173 bool KStandardDirs::makeDir(const QString& dir, int mode)
01174 {
01175     // we want an absolute path
01176     if (QDir::isRelativePath(dir))
01177         return false;
01178 
01179     QString target = dir;
01180     uint len = target.length();
01181 
01182     // append trailing slash if missing
01183     if (dir.at(len - 1) != '/')
01184         target += '/';
01185 
01186     QString base("");
01187     uint i = 1;
01188 
01189     while( i < len )
01190     {
01191         KDE_struct_stat st;
01192         int pos = target.find('/', i);
01193         base += target.mid(i - 1, pos - i + 1);
01194         QCString baseEncoded = QFile::encodeName(base);
01195         // bail out if we encountered a problem
01196         if (KDE_stat(baseEncoded, &st) != 0)
01197         {
01198           // Directory does not exist....
01199           // Or maybe a dangling symlink ?
01200           if (KDE_lstat(baseEncoded, &st) == 0)
01201               (void)unlink(baseEncoded); // try removing
01202 
01203       if ( KDE_mkdir(baseEncoded, (mode_t) mode) != 0) {
01204             baseEncoded.prepend( "trying to create local folder " );
01205         perror(baseEncoded.data());
01206         return false; // Couldn't create it :-(
01207       }
01208         }
01209         i = pos + 1;
01210     }
01211     return true;
01212 }
01213 
01214 static QString readEnvPath(const char *env)
01215 {
01216    QCString c_path = getenv(env);
01217    if (c_path.isEmpty())
01218       return QString::null;
01219 #ifdef Q_OS_WIN
01220    //win32 paths are case-insensitive: avoid duplicates on various dir lists
01221    return QFile::decodeName(c_path).lower();
01222 #else
01223    return QFile::decodeName(c_path);
01224 #endif
01225 }
01226 
01227 #ifdef __linux__
01228 static QString executablePrefix()
01229 {
01230    char path_buffer[MAXPATHLEN + 1];
01231    path_buffer[MAXPATHLEN] = 0;
01232    int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN);
01233    if (length == -1)
01234       return QString::null;
01235 
01236    path_buffer[length] = '\0';
01237 
01238    QString path = QFile::decodeName(path_buffer);
01239 
01240    if(path.isEmpty())
01241       return QString::null;
01242 
01243    int pos = path.findRev('/'); // Skip filename
01244    if(pos <= 0)
01245       return QString::null;
01246    pos = path.findRev('/', pos - 1); // Skip last directory
01247    if(pos <= 0)
01248       return QString::null;
01249 
01250    return path.left(pos);
01251 }
01252 #endif
01253 
01254 QString KStandardDirs::kfsstnd_defaultprefix()
01255 {
01256    KStandardDirsSingleton* s = KStandardDirsSingleton::self();
01257    if (!s->defaultprefix.isEmpty())
01258       return s->defaultprefix;
01259 #ifdef Q_WS_WIN
01260    s->defaultprefix = readEnvPath("KDEDIR");
01261    if (s->defaultprefix.isEmpty()) {
01262       s->defaultprefix = QFile::decodeName("c:\\kde");
01263       //TODO: find other location (the Registry?)
01264    }
01265 #else //UNIX
01266    s->defaultprefix = KDEDIR;
01267 #endif
01268    if (s->defaultprefix.isEmpty())
01269       kdWarning() << "KStandardDirs::kfsstnd_defaultprefix(): default KDE prefix not found!" << endl;
01270    return s->defaultprefix;
01271 }
01272 
01273 QString KStandardDirs::kfsstnd_defaultbindir()
01274 {
01275    KStandardDirsSingleton* s = KStandardDirsSingleton::self();
01276    if (!s->defaultbindir.isEmpty())
01277       return s->defaultbindir;
01278 #ifdef Q_WS_WIN
01279    s->defaultbindir = kfsstnd_defaultprefix() + QString::fromLatin1("/bin");
01280 #else //UNIX
01281    s->defaultbindir = __KDE_BINDIR;
01282    if (s->defaultbindir.isEmpty())
01283       s->defaultbindir = kfsstnd_defaultprefix() + QString::fromLatin1("/bin");
01284 #endif
01285    if (s->defaultbindir.isEmpty())
01286       kdWarning() << "KStandardDirs::kfsstnd_defaultbindir(): default binary KDE dir not found!" << endl;
01287   return s->defaultbindir;
01288 }
01289 
01290 void KStandardDirs::addKDEDefaults()
01291 {
01292     QStringList kdedirList;
01293 
01294     // begin KDEDIRS
01295     QString kdedirs = readEnvPath("KDEDIRS");
01296     if (!kdedirs.isEmpty())
01297     {
01298         tokenize(kdedirList, kdedirs, QChar(KPATH_SEPARATOR));
01299     }
01300     else
01301     {
01302         QString kdedir = readEnvPath("KDEDIR");
01303         if (!kdedir.isEmpty())
01304         {
01305            kdedir = KShell::tildeExpand(kdedir);
01306            kdedirList.append(kdedir);
01307         }
01308     }
01309     kdedirList.append("/etc/kde/distribution");
01310     kdedirList.append("/etc/kde");
01311 
01312 #ifndef Q_OS_WIN //no default KDEDIR on win32 defined
01313     kdedirList.append(KDEDIR);
01314 #endif
01315 
01316 #ifdef __KDE_EXECPREFIX
01317     QString execPrefix(__KDE_EXECPREFIX);
01318     if (execPrefix!="NONE")
01319        kdedirList.append(execPrefix);
01320 #endif
01321 #ifdef __linux__
01322     const QString linuxExecPrefix = executablePrefix();
01323     if ( !linuxExecPrefix.isEmpty() )
01324        kdedirList.append( linuxExecPrefix );
01325 #endif
01326 
01327     // We treat root differently to prevent a "su" shell messing up the
01328     // file permissions in the user's home directory.
01329     QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
01330     if (!localKdeDir.isEmpty())
01331     {
01332        if (localKdeDir[localKdeDir.length()-1] != '/')
01333           localKdeDir += '/';
01334     }
01335     else
01336     {
01337        localKdeDir =  QDir::homeDirPath() + "/.kde/";
01338     }
01339 
01340     if (localKdeDir != "-/")
01341     {
01342         localKdeDir = KShell::tildeExpand(localKdeDir);
01343         addPrefix(localKdeDir);
01344     }
01345 
01346     QStringList::ConstIterator end(kdedirList.end());
01347     for (QStringList::ConstIterator it = kdedirList.begin();
01348      it != end; ++it)
01349     {
01350         QString dir = KShell::tildeExpand(*it);
01351     addPrefix(dir);
01352     }
01353     // end KDEDIRS
01354 
01355     // begin XDG_CONFIG_XXX
01356     QStringList xdgdirList;
01357     QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
01358     if (!xdgdirs.isEmpty())
01359     {
01360     tokenize(xdgdirList, xdgdirs, QChar(KPATH_SEPARATOR));
01361     }
01362     else
01363     {
01364     xdgdirList.clear();
01365         xdgdirList.append("/etc/xdg");
01366 #ifdef Q_WS_WIN
01367         xdgdirList.append(kfsstnd_defaultprefix() + "/etc/xdg");
01368 #else
01369         xdgdirList.append(KDESYSCONFDIR "/xdg");
01370 #endif
01371         xdgdirList.append("/etc/kde/xdg");
01372     }
01373 
01374     QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
01375     if (!localXdgDir.isEmpty())
01376     {
01377        if (localXdgDir[localXdgDir.length()-1] != '/')
01378           localXdgDir += '/';
01379     }
01380     else
01381     {
01382        localXdgDir =  QDir::homeDirPath() + "/.config/";
01383     }
01384 
01385     localXdgDir = KShell::tildeExpand(localXdgDir);
01386     addXdgConfigPrefix(localXdgDir);
01387 
01388     for (QStringList::ConstIterator it = xdgdirList.begin();
01389      it != xdgdirList.end(); ++it)
01390     {
01391         QString dir = KShell::tildeExpand(*it);
01392     addXdgConfigPrefix(dir);
01393     }
01394     // end XDG_CONFIG_XXX
01395 
01396     // begin XDG_DATA_XXX
01397     xdgdirs = readEnvPath("XDG_DATA_DIRS");
01398     if (!xdgdirs.isEmpty())
01399     {
01400     tokenize(xdgdirList, xdgdirs, QChar(KPATH_SEPARATOR));
01401     }
01402     else
01403     {
01404     xdgdirList.clear();
01405         for (QStringList::ConstIterator it = kdedirList.begin();
01406            it != kdedirList.end(); ++it)
01407         {
01408            QString dir = *it;
01409            if (dir[dir.length()-1] != '/')
01410              dir += '/';
01411            xdgdirList.append(dir+"share/");
01412         }
01413 
01414         xdgdirList.append("/usr/local/share/");
01415         xdgdirList.append("/var/cache");
01416         xdgdirList.append("/usr/share/");
01417     }
01418 
01419     localXdgDir = readEnvPath("XDG_DATA_HOME");
01420     if (!localXdgDir.isEmpty())
01421     {
01422        if (localXdgDir[localXdgDir.length()-1] != '/')
01423           localXdgDir += '/';
01424     }
01425     else
01426     {
01427        localXdgDir = QDir::homeDirPath() + "/.local/share/";
01428     }
01429 
01430     localXdgDir = KShell::tildeExpand(localXdgDir);
01431     addXdgDataPrefix(localXdgDir);
01432 
01433     for (QStringList::ConstIterator it = xdgdirList.begin();
01434      it != xdgdirList.end(); ++it)
01435     {
01436         QString dir = KShell::tildeExpand(*it);
01437     addXdgDataPrefix(dir);
01438     }
01439     // end XDG_DATA_XXX
01440 
01441 
01442     uint index = 0;
01443     while (types[index] != 0) {
01444     addResourceType(types[index], kde_default(types[index]));
01445     index++;
01446     }
01447 
01448     addResourceDir("home", QDir::homeDirPath());
01449 }
01450 
01451 void KStandardDirs::checkConfig() const
01452 {
01453     if (!addedCustoms && KGlobal::_instance && KGlobal::_instance->_config)
01454         const_cast<KStandardDirs*>(this)->addCustomized(KGlobal::_instance->_config);
01455 }
01456 
01457 static QStringList lookupProfiles(const QString &mapFile)
01458 {
01459     QStringList profiles;
01460 
01461     if (mapFile.isEmpty() || !QFile::exists(mapFile))
01462     {
01463        profiles << "default";
01464        return profiles;
01465     }
01466 
01467     struct passwd *pw = getpwuid(geteuid());
01468     if (!pw)
01469     {
01470         profiles << "default";
01471         return profiles; // Not good
01472     }
01473 
01474     QCString user = pw->pw_name;
01475 
01476     gid_t sup_gids[512];
01477     int sup_gids_nr = getgroups(512, sup_gids);
01478 
01479     KSimpleConfig mapCfg(mapFile, true);
01480     mapCfg.setGroup("Users");
01481     if (mapCfg.hasKey(user.data()))
01482     {
01483         profiles = mapCfg.readListEntry(user.data());
01484         return profiles;
01485     }
01486 
01487     mapCfg.setGroup("General");
01488     QStringList groups = mapCfg.readListEntry("groups");
01489 
01490     mapCfg.setGroup("Groups");
01491 
01492     for( QStringList::ConstIterator it = groups.begin();
01493          it != groups.end(); ++it )
01494     {
01495         QCString grp = (*it).utf8();
01496         // Check if user is in this group
01497         struct group *grp_ent = getgrnam(grp);
01498         if (!grp_ent) continue;
01499         gid_t gid = grp_ent->gr_gid;
01500         if (pw->pw_gid == gid)
01501         {
01502             // User is in this group --> add profiles
01503             profiles += mapCfg.readListEntry(*it);
01504         }
01505         else
01506         {
01507             for(int i = 0; i < sup_gids_nr; i++)
01508             {
01509                 if (sup_gids[i] == gid)
01510                 {
01511                     // User is in this group --> add profiles
01512                     profiles += mapCfg.readListEntry(*it);
01513                     break;
01514                 }
01515             }
01516         }
01517     }
01518 
01519     if (profiles.isEmpty())
01520         profiles << "default";
01521     return profiles;
01522 }
01523 
01524 extern bool kde_kiosk_admin;
01525 
01526 bool KStandardDirs::addCustomized(KConfig *config)
01527 {
01528     if (addedCustoms && !d->checkRestrictions) // there are already customized entries
01529         return false; // we just quit and hope they are the right ones
01530 
01531     // save the numbers of config directories. If this changes,
01532     // we will return true to give KConfig a chance to reparse
01533     uint configdirs = resourceDirs("config").count();
01534 
01535     // Remember original group
01536     QString oldGroup = config->group();
01537 
01538     if (!addedCustoms)
01539     {
01540         // We only add custom entries once
01541         addedCustoms = true;
01542 
01543         // reading the prefixes in
01544         QString group = QString::fromLatin1("Directories");
01545         config->setGroup(group);
01546 
01547         QString kioskAdmin = config->readEntry("kioskAdmin");
01548         if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
01549         {
01550             int i = kioskAdmin.find(':');
01551             QString user = kioskAdmin.left(i);
01552             QString host = kioskAdmin.mid(i+1);
01553 
01554             KUser thisUser;
01555             char hostname[ 256 ];
01556             hostname[ 0 ] = '\0';
01557             if (!gethostname( hostname, 255 ))
01558                 hostname[sizeof(hostname)-1] = '\0';
01559 
01560             if ((user == thisUser.loginName()) &&
01561                 (host.isEmpty() || (host == hostname)))
01562             {
01563                 kde_kiosk_admin = true;
01564             }
01565         }
01566 
01567         bool readProfiles = true;
01568 
01569         if (kde_kiosk_admin && !QCString(getenv("KDE_KIOSK_NO_PROFILES")).isEmpty())
01570             readProfiles = false;
01571 
01572         QString userMapFile = config->readEntry("userProfileMapFile");
01573         QString profileDirsPrefix = config->readEntry("profileDirsPrefix");
01574         if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith("/"))
01575             profileDirsPrefix.append('/');
01576 
01577         QStringList profiles;
01578         if (readProfiles)
01579             profiles = lookupProfiles(userMapFile);
01580         QString profile;
01581 
01582         bool priority = false;
01583         while(true)
01584         {
01585             config->setGroup(group);
01586             QStringList list = config->readListEntry("prefixes");
01587             for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
01588             {
01589                 addPrefix(*it, priority);
01590                 addXdgConfigPrefix(*it+"/etc/xdg", priority);
01591                 addXdgDataPrefix(*it+"/share", priority);
01592             }
01593             // If there are no prefixes defined, check if there is a directory
01594             // for this profile under <profileDirsPrefix>
01595             if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
01596             {
01597                 QString dir = profileDirsPrefix + profile;
01598                 addPrefix(dir, priority);
01599                 addXdgConfigPrefix(dir+"/etc/xdg", priority);
01600                 addXdgDataPrefix(dir+"/share", priority);
01601             }
01602 
01603             // iterating over all entries in the group Directories
01604             // to find entries that start with dir_$type
01605             QMap<QString, QString> entries = config->entryMap(group);
01606             for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
01607                  it2 != entries.end(); it2++)
01608             {
01609                 QString key = it2.key();
01610                 if (key.startsWith("dir_")) {
01611                     // generate directory list, there may be more than 1.
01612                     QStringList dirs = QStringList::split(',', *it2);
01613                     QStringList::Iterator sIt(dirs.begin());
01614                     QString resType = key.mid(4, key.length());
01615                     for (; sIt != dirs.end(); ++sIt)
01616                     {
01617                         addResourceDir(resType.latin1(), *sIt, priority);
01618                     }
01619                 }
01620             }
01621             if (profiles.isEmpty())
01622                 break;
01623             profile = profiles.back();
01624             group = QString::fromLatin1("Directories-%1").arg(profile);
01625             profiles.pop_back();
01626             priority = true;
01627         }
01628     }
01629 
01630     // Process KIOSK restrictions.
01631     if (!kde_kiosk_admin || QCString(getenv("KDE_KIOSK_NO_RESTRICTIONS")).isEmpty())
01632     {
01633         config->setGroup("KDE Resource Restrictions");
01634         QMap<QString, QString> entries = config->entryMap("KDE Resource Restrictions");
01635         for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
01636             it2 != entries.end(); it2++)
01637         {
01638             QString key = it2.key();
01639             if (!config->readBoolEntry(key, true))
01640             {
01641                 d->restrictionsActive = true;
01642                 d->restrictions.insert(key.latin1(), &d->restrictionsActive); // Anything will do
01643                 dircache.remove(key.latin1());
01644             }
01645         }
01646     }
01647 
01648     config->setGroup(oldGroup);
01649 
01650     // check if the number of config dirs changed
01651     bool configDirsChanged = (resourceDirs("config").count() != configdirs);
01652     // If the config dirs changed, we check kiosk restrictions again.
01653     d->checkRestrictions = configDirsChanged;
01654     // return true if the number of config dirs changed: reparse config file
01655     return configDirsChanged;
01656 }
01657 
01658 QString KStandardDirs::localkdedir() const
01659 {
01660     // Return the prefix to use for saving
01661     return prefixes.first();
01662 }
01663 
01664 QString KStandardDirs::localxdgdatadir() const
01665 {
01666     // Return the prefix to use for saving
01667     return d->xdgdata_prefixes.first();
01668 }
01669 
01670 QString KStandardDirs::localxdgconfdir() const
01671 {
01672     // Return the prefix to use for saving
01673     return d->xdgconf_prefixes.first();
01674 }
01675 
01676 
01677 // just to make code more readable without macros
01678 QString locate( const char *type,
01679         const QString& filename, const KInstance* inst )
01680 {
01681     return inst->dirs()->findResource(type, filename);
01682 }
01683 
01684 QString locateLocal( const char *type,
01685                  const QString& filename, const KInstance* inst )
01686 {
01687     return locateLocal(type, filename, true, inst);
01688 }
01689 
01690 QString locateLocal( const char *type,
01691                  const QString& filename, bool createDir, const KInstance* inst )
01692 {
01693     // try to find slashes. If there are some, we have to
01694     // create the subdir first
01695     int slash = filename.findRev('/')+1;
01696     if (!slash) // only one filename
01697     return inst->dirs()->saveLocation(type, QString::null, createDir) + filename;
01698 
01699     // split path from filename
01700     QString dir = filename.left(slash);
01701     QString file = filename.mid(slash);
01702     return inst->dirs()->saveLocation(type, dir, createDir) + file;
01703 }
KDE Home | KDE Accessibility Home | Description of Access Keys