kdecore Library API Documentation

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