00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <unistd.h>
00025 #include <ctype.h>
00026 #ifdef HAVE_SYS_MMAN_H
00027 #include <sys/mman.h>
00028 #endif
00029 #include <sys/types.h>
00030 #ifdef HAVE_SYS_STAT_H
00031 #include <sys/stat.h>
00032 #endif
00033 #include <fcntl.h>
00034 #include <signal.h>
00035 #include <setjmp.h>
00036
00037 #include <tqdir.h>
00038 #include <tqfileinfo.h>
00039 #include <tqtextcodec.h>
00040 #include <tqtextstream.h>
00041
00042 #include "tdeconfigbackend.h"
00043 #include "tdeconfigbase.h"
00044 #include <tdeapplication.h>
00045 #include <tdeglobal.h>
00046 #include <kprocess.h>
00047 #include <tdelocale.h>
00048 #include <kstandarddirs.h>
00049 #include <ksavefile.h>
00050 #include <kurl.h>
00051 #include <kde_file.h>
00052
00053 extern bool checkAccess(const TQString& pathname, int mode);
00054
00055 static TQCString printableToString(const char *str, int l)
00056 {
00057
00058 while((l>0) &&
00059 ((*str == ' ') || (*str == '\t') || (*str == '\r')))
00060 {
00061 str++; l--;
00062 }
00063
00064
00065 while((l>0) &&
00066 ((str[l-1] == ' ') || (str[l-1] == '\t') || (str[l-1] == '\r')))
00067 {
00068 l--;
00069 }
00070
00071 TQCString result(l + 1);
00072 char *r = result.data();
00073
00074 for(int i = 0; i < l;i++, str++)
00075 {
00076 if (*str == '\\')
00077 {
00078 i++, str++;
00079 if (i >= l)
00080 {
00081 *r++ = '\\';
00082 break;
00083 }
00084 switch(*str)
00085 {
00086 case 's':
00087 *r++ = ' ';
00088 break;
00089 case 't':
00090 *r++ = '\t';
00091 break;
00092 case 'n':
00093 *r++ = '\n';
00094 break;
00095 case 'r':
00096 *r++ = '\r';
00097 break;
00098 case '\\':
00099 *r++ = '\\';
00100 break;
00101 default:
00102 *r++ = '\\';
00103 *r++ = *str;
00104 }
00105 }
00106 else
00107 {
00108 *r++ = *str;
00109 }
00110 }
00111 result.truncate(r-result.data());
00112 return result;
00113 }
00114
00115 static TQCString stringToPrintable(const TQCString& str){
00116 TQCString result(str.length()*2);
00117 register char *r = const_cast<TQCString&>(result).data();
00118 register char *s = const_cast<TQCString&>(str).data();
00119
00120 if (!s) return TQCString("");
00121
00122
00123 if (*s == ' ')
00124 {
00125 *r++ = '\\'; *r++ = 's';
00126 s++;
00127 }
00128
00129 if (*s)
00130 {
00131 while(*s)
00132 {
00133 if (*s == '\n')
00134 {
00135 *r++ = '\\'; *r++ = 'n';
00136 }
00137 else if (*s == '\t')
00138 {
00139 *r++ = '\\'; *r++ = 't';
00140 }
00141 else if (*s == '\r')
00142 {
00143 *r++ = '\\'; *r++ = 'r';
00144 }
00145 else if (*s == '\\')
00146 {
00147 *r++ = '\\'; *r++ = '\\';
00148 }
00149 else
00150 {
00151 *r++ = *s;
00152 }
00153 s++;
00154 }
00155
00156 if (*(r-1) == ' ')
00157 {
00158 *(r-1) = '\\'; *r++ = 's';
00159 }
00160 }
00161
00162 result.truncate(r - result.data());
00163 return result;
00164 }
00165
00166 static TQCString decodeGroup(const char*s, int l)
00167 {
00168 TQCString result(l);
00169 register char *r = result.data();
00170
00171 l--;
00172 while(l)
00173 {
00174 if ((*s == '[') && (l > 1))
00175 {
00176 if ((*(s+1) == '['))
00177 {
00178 l--;
00179 s++;
00180 }
00181 }
00182 if ((*s == ']') && (l > 1))
00183 {
00184 if ((*(s+1) == ']'))
00185 {
00186 l--;
00187 s++;
00188 }
00189 }
00190 *r++ = *s++;
00191 l--;
00192 }
00193 result.truncate(r - result.data());
00194 return result;
00195 }
00196
00197 static TQCString encodeGroup(const TQCString &str)
00198 {
00199 int l = str.length();
00200 TQCString result(l*2+1);
00201 register char *r = const_cast<TQCString&>(result).data();
00202 register char *s = const_cast<TQCString&>(str).data();
00203 while(l)
00204 {
00205 if ((*s == '[') || (*s == ']'))
00206 *r++ = *s;
00207 *r++ = *s++;
00208 l--;
00209 }
00210 result.truncate(r - result.data());
00211 return result;
00212 }
00213
00214 static TQCString encodeKey(const char* key)
00215 {
00216 TQCString newKey(key);
00217
00218 newKey.replace('[', "%5b");
00219 newKey.replace(']', "%5d");
00220
00221 return newKey;
00222 }
00223
00224 static TQCString decodeKey(const char* key)
00225 {
00226 TQCString newKey(key);
00227
00228 newKey.replace("%5b", "[");
00229 newKey.replace("%5d", "]");
00230
00231 return newKey;
00232 }
00233
00234 class TDEConfigBackEnd::TDEConfigBackEndPrivate
00235 {
00236 public:
00237 TQDateTime localLastModified;
00238 uint localLastSize;
00239 TDELockFile::Ptr localLockFile;
00240 TDELockFile::Ptr globalLockFile;
00241 };
00242
00243 void TDEConfigBackEnd::changeFileName(const TQString &_fileName,
00244 const char * _resType,
00245 bool _useKDEGlobals)
00246 {
00247 mfileName = _fileName;
00248 resType = _resType;
00249 useKDEGlobals = _useKDEGlobals;
00250 if (mfileName.isEmpty()) {
00251 mLocalFileName = TQString::null;
00252 }
00253 else if (!TQDir::isRelativePath(mfileName)) {
00254 mLocalFileName = mfileName;
00255 }
00256 else {
00257 mLocalFileName = TDEGlobal::dirs()->saveLocation(resType, TQString(), false) + mfileName;
00258 }
00259
00260 if (useKDEGlobals) {
00261 mGlobalFileName = TDEGlobal::dirs()->saveLocation("config", TQString(), false) + TQString::fromLatin1("kdeglobals");
00262 }
00263 else {
00264 mGlobalFileName = TQString::null;
00265 }
00266
00267 d->localLastModified = TQDateTime();
00268 d->localLastSize = 0;
00269 d->localLockFile = 0;
00270 d->globalLockFile = 0;
00271 }
00272
00273 TDELockFile::Ptr TDEConfigBackEnd::lockFile(bool bGlobal)
00274 {
00275 if (bGlobal)
00276 {
00277 if (d->globalLockFile)
00278 return d->globalLockFile;
00279
00280 if (!mGlobalFileName.isEmpty())
00281 {
00282 d->globalLockFile = new TDELockFile(mGlobalFileName+".lock");
00283 return d->globalLockFile;
00284 }
00285 }
00286 else
00287 {
00288 if (d->localLockFile)
00289 return d->localLockFile;
00290
00291 if (!mLocalFileName.isEmpty())
00292 {
00293 d->localLockFile = new TDELockFile(mLocalFileName+".lock");
00294 return d->localLockFile;
00295 }
00296 }
00297 return 0;
00298 }
00299
00300 TDEConfigBackEnd::TDEConfigBackEnd(TDEConfigBase *_config,
00301 const TQString &_fileName,
00302 const char * _resType,
00303 bool _useKDEGlobals)
00304 : pConfig(_config), bFileImmutable(false), mConfigState(TDEConfigBase::NoAccess), mFileMode(-1)
00305 {
00306 d = new TDEConfigBackEndPrivate;
00307 changeFileName(_fileName, _resType, _useKDEGlobals);
00308 }
00309
00310 TDEConfigBackEnd::~TDEConfigBackEnd()
00311 {
00312 delete d;
00313 }
00314
00315 void TDEConfigBackEnd::setFileWriteMode(int mode)
00316 {
00317 mFileMode = mode;
00318 }
00319
00320 bool TDEConfigINIBackEnd::parseConfigFiles()
00321 {
00322
00323 mConfigState = TDEConfigBase::ReadOnly;
00324 if (!mLocalFileName.isEmpty() && !pConfig->isReadOnly())
00325 {
00326 if (checkAccess(mLocalFileName, W_OK))
00327 {
00328 mConfigState = TDEConfigBase::ReadWrite;
00329 }
00330 else
00331 {
00332
00333 KURL path;
00334 path.setPath(mLocalFileName);
00335 TQString dir=path.directory();
00336 TDEStandardDirs::makeDir(dir);
00337
00338 if (checkAccess(mLocalFileName, W_OK))
00339 {
00340 mConfigState = TDEConfigBase::ReadWrite;
00341 }
00342 }
00343 TQFileInfo info(mLocalFileName);
00344 d->localLastModified = info.lastModified();
00345 d->localLastSize = info.size();
00346 }
00347
00348
00349 bFileImmutable = false;
00350
00351
00352 if (useKDEGlobals) {
00353 TQStringList tdercs = TDEGlobal::dirs()->
00354 findAllResources("config", TQString::fromLatin1("kdeglobals"));
00355
00356 #ifdef Q_WS_WIN
00357 TQString etc_tderc = TQFile::decodeName( TQCString(getenv("WINDIR")) + "\\tderc" );
00358 #else
00359 TQString etc_tderc = TQString::fromLatin1("/etc/tderc");
00360 #endif
00361
00362 if (checkAccess(etc_tderc, R_OK))
00363 tdercs += etc_tderc;
00364
00365 tdercs += TDEGlobal::dirs()->
00366 findAllResources("config", TQString::fromLatin1("system.kdeglobals"));
00367
00368 TQStringList::ConstIterator it;
00369
00370 for (it = tdercs.fromLast(); it != tdercs.end(); --it) {
00371
00372 TQFile aConfigFile( *it );
00373 if (!aConfigFile.open( IO_ReadOnly ))
00374 continue;
00375 parseSingleConfigFile( aConfigFile, 0L, true, (*it != mGlobalFileName) );
00376 aConfigFile.close();
00377 if (bFileImmutable)
00378 break;
00379 }
00380 }
00381
00382 bool bReadFile = !mfileName.isEmpty();
00383 while(bReadFile) {
00384 bReadFile = false;
00385 TQString bootLanguage;
00386 if (useKDEGlobals && localeString.isEmpty() && !TDEGlobal::_locale) {
00387
00388 bootLanguage = TDELocale::_initLanguage(pConfig);
00389 setLocaleString(bootLanguage.utf8());
00390 }
00391
00392 bFileImmutable = false;
00393 TQStringList list;
00394 if ( !TQDir::isRelativePath(mfileName) )
00395 list << mfileName;
00396 else
00397 list = TDEGlobal::dirs()->findAllResources(resType, mfileName);
00398
00399 TQStringList::ConstIterator it;
00400
00401 for (it = list.fromLast(); it != list.end(); --it) {
00402
00403 TQFile aConfigFile( *it );
00404
00405 bool bIsLocal = (*it == mLocalFileName);
00406 if (aConfigFile.open( IO_ReadOnly )) {
00407 parseSingleConfigFile( aConfigFile, 0L, false, !bIsLocal );
00408 aConfigFile.close();
00409 if (bFileImmutable)
00410 break;
00411 }
00412 }
00413 if (TDEGlobal::dirs()->isRestrictedResource(resType, mfileName))
00414 bFileImmutable = true;
00415 TQString currentLanguage;
00416 if (!bootLanguage.isEmpty())
00417 {
00418 currentLanguage = TDELocale::_initLanguage(pConfig);
00419
00420
00421 if (bootLanguage != currentLanguage)
00422 {
00423 bReadFile = true;
00424 setLocaleString(currentLanguage.utf8());
00425 }
00426 }
00427 }
00428 if (bFileImmutable)
00429 mConfigState = TDEConfigBase::ReadOnly;
00430
00431 return true;
00432 }
00433
00434 #ifdef HAVE_MMAP
00435 #ifdef SIGBUS
00436 static sigjmp_buf mmap_jmpbuf;
00437 struct sigaction mmap_old_sigact;
00438
00439 extern "C" {
00440 static void mmap_sigbus_handler(int)
00441 {
00442 siglongjmp (mmap_jmpbuf, 1);
00443 }
00444 }
00445 #endif
00446 #endif
00447
00448 extern bool kde_kiosk_exception;
00449
00450 void TDEConfigINIBackEnd::parseSingleConfigFile(TQFile &rFile,
00451 KEntryMap *pWriteBackMap,
00452 bool bGlobal, bool bDefault)
00453 {
00454 const char *s;
00455 const char *eof;
00456 TQByteArray data;
00457
00458 if (!rFile.isOpen())
00459 return;
00460
00461
00462
00463
00464
00465
00466 TQCString aCurrentGroup("<default>");
00467
00468 unsigned int ll = localeString.length();
00469
00470 #ifdef HAVE_MMAP
00471 static volatile const char *map;
00472 map = ( const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
00473 rFile.handle(), 0);
00474
00475 if ( map != MAP_FAILED )
00476 {
00477 s = (const char*) map;
00478 eof = s + rFile.size();
00479
00480 #ifdef SIGBUS
00481 struct sigaction act;
00482 act.sa_handler = mmap_sigbus_handler;
00483 sigemptyset( &act.sa_mask );
00484 #ifdef SA_ONESHOT
00485 act.sa_flags = SA_ONESHOT;
00486 #else
00487 act.sa_flags = SA_RESETHAND;
00488 #endif
00489 sigaction( SIGBUS, &act, &mmap_old_sigact );
00490
00491 if (sigsetjmp (mmap_jmpbuf, 1))
00492 {
00493 tqWarning("SIGBUS while reading %s", rFile.name().latin1());
00494 munmap(( char* )map, rFile.size());
00495 sigaction (SIGBUS, &mmap_old_sigact, 0);
00496 return;
00497 }
00498 #endif
00499 }
00500 else
00501 #endif
00502 {
00503 rFile.at(0);
00504 data = rFile.readAll();
00505 s = data.data();
00506 eof = s + data.size();
00507 }
00508
00509 bool fileOptionImmutable = false;
00510 bool groupOptionImmutable = false;
00511 bool groupSkip = false;
00512 bool foundGettextDomain = false;
00513 TQCString gettextDomain;
00514
00515 int line = 0;
00516 for(; s < eof; s++)
00517 {
00518 line++;
00519
00520 while((s < eof) && isspace(*s) && (*s != '\n'))
00521 s++;
00522
00523
00524 if ((s < eof) && ((*s == '\n') || (*s == '#')))
00525 {
00526 sktoeol:
00527 while ((s < eof) && (*s != '\n'))
00528 s++;
00529 continue;
00530 }
00531 const char *startLine = s;
00532
00533 if (*s == '[')
00534 {
00535
00536 while ((s < eof) && (*s != '\n'))
00537 {
00538 if (*s == ']')
00539 {
00540 if ((s+1 < eof) && (*(s+1) == ']'))
00541 s++;
00542 else
00543 break;
00544 }
00545
00546 s++;
00547 }
00548 const char *e = s;
00549 while ((s < eof) && (*s != '\n')) s++;
00550 if ((e >= eof) || (*e != ']'))
00551 {
00552 fprintf(stderr, "Invalid group header at %s:%d\n", rFile.name().latin1(), line);
00553 continue;
00554 }
00555
00556
00557 if ((e-startLine == 3) &&
00558 (startLine[1] == '$') &&
00559 (startLine[2] == 'i'))
00560 {
00561 if (!kde_kiosk_exception)
00562 fileOptionImmutable = true;
00563 continue;
00564 }
00565
00566 aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
00567
00568
00569
00570 if (aCurrentGroup == "KDE Desktop Entry")
00571 aCurrentGroup = "Desktop Entry";
00572
00573 groupOptionImmutable = fileOptionImmutable;
00574
00575 e++;
00576 if ((e+2 < eof) && (*e++ == '[') && (*e++ == '$'))
00577 {
00578 if ((*e == 'i') && !kde_kiosk_exception)
00579 {
00580 groupOptionImmutable = true;
00581 }
00582 }
00583
00584 KEntryKey groupKey(aCurrentGroup, 0);
00585 KEntry entry = pConfig->lookupData(groupKey);
00586 groupSkip = entry.bImmutable;
00587
00588 if (groupSkip && !bDefault)
00589 continue;
00590
00591 entry.bImmutable |= groupOptionImmutable;
00592 pConfig->putData(groupKey, entry, false);
00593
00594 if (pWriteBackMap)
00595 {
00596
00597 (*pWriteBackMap)[groupKey] = entry;
00598 }
00599
00600 continue;
00601 }
00602 if (groupSkip && !bDefault)
00603 goto sktoeol;
00604
00605
00606 bool optionImmutable = groupOptionImmutable;
00607 bool optionDeleted = false;
00608 bool optionExpand = false;
00609 const char *endOfKey = 0, *locale = 0, *elocale = 0;
00610 for (; (s < eof) && (*s != '\n'); s++)
00611 {
00612 if (*s == '=')
00613 {
00614 if (!endOfKey)
00615 endOfKey = s;
00616 goto haveeq;
00617 }
00618 if (*s == '[')
00619 {
00620 const char *option;
00621 const char *eoption;
00622 endOfKey = s;
00623 option = ++s;
00624 for (;; s++)
00625 {
00626 if ((s >= eof) || (*s == '\n') || (*s == '=')) {
00627 fprintf(stderr, "Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
00628 goto sktoeol;
00629 }
00630 if (*s == ']')
00631 break;
00632 }
00633 eoption = s;
00634 if (*option != '$')
00635 {
00636
00637 if (locale) {
00638 fprintf(stderr, "Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
00639 goto sktoeol;
00640 }
00641 locale = option;
00642 elocale = eoption;
00643 }
00644 else
00645 {
00646
00647 while (option < eoption)
00648 {
00649 option++;
00650 if ((*option == 'i') && !kde_kiosk_exception)
00651 optionImmutable = true;
00652 else if (*option == 'e')
00653 optionExpand = true;
00654 else if (*option == 'd')
00655 {
00656 optionDeleted = true;
00657 goto haveeq;
00658 }
00659 else if (*option == ']')
00660 break;
00661 }
00662 }
00663 }
00664 }
00665 fprintf(stderr, "Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
00666 continue;
00667
00668 haveeq:
00669 for (endOfKey--; ; endOfKey--)
00670 {
00671 if (endOfKey < startLine)
00672 {
00673 fprintf(stderr, "Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
00674 goto sktoeol;
00675 }
00676 if (!isspace(*endOfKey))
00677 break;
00678 }
00679
00680 const char *st = ++s;
00681 while ((s < eof) && (*s != '\n')) s++;
00682
00683 if (locale) {
00684 unsigned int cl = static_cast<unsigned int>(elocale - locale);
00685 if ((ll != cl) || memcmp(locale, localeString.data(), ll))
00686 {
00687
00688 if ( cl != 1 || ll != 5 || *locale != 'C' || memcmp(localeString.data(), "en_US", 5)) {
00689
00690
00691 if (!pWriteBackMap)
00692 continue;
00693
00694 endOfKey = elocale;
00695 locale = 0;
00696 }
00697 }
00698 }
00699
00700
00701 TQCString key(startLine, endOfKey - startLine + 2);
00702 TQCString val = printableToString(st, s - st);
00703
00704
00705 if (TQString(key.data()) == "X-Ubuntu-Gettext-Domain") {
00706 gettextDomain = val.data();
00707 foundGettextDomain = true;
00708 }
00709
00710 KEntryKey aEntryKey(aCurrentGroup, decodeKey(key));
00711 aEntryKey.bLocal = (locale != 0);
00712 aEntryKey.bDefault = bDefault;
00713
00714 KEntry aEntry;
00715 aEntry.mValue = val;
00716 aEntry.bGlobal = bGlobal;
00717 aEntry.bImmutable = optionImmutable;
00718 aEntry.bDeleted = optionDeleted;
00719 aEntry.bExpand = optionExpand;
00720 aEntry.bNLS = (locale != 0);
00721
00722 if (pWriteBackMap) {
00723
00724
00725 pWriteBackMap->insert(aEntryKey, aEntry);
00726 } else {
00727
00728
00729
00730 pConfig->putData(aEntryKey, aEntry, false);
00731 }
00732 }
00733
00734
00735
00736
00737
00738
00739
00740 if (!pWriteBackMap) {
00741 TQFile file("file.txt");
00742 if (foundGettextDomain) {
00743
00744 TDELocale locale(gettextDomain);
00745
00746 TQString language = locale.language();
00747 translateKey(locale, aCurrentGroup, TQCString("Name"));
00748 translateKey(locale, aCurrentGroup, TQCString("Comment"));
00749 translateKey(locale, aCurrentGroup, TQCString("Language"));
00750 translateKey(locale, aCurrentGroup, TQCString("Keywords"));
00751 translateKey(locale, aCurrentGroup, TQCString("About"));
00752 translateKey(locale, aCurrentGroup, TQCString("Description"));
00753 translateKey(locale, aCurrentGroup, TQCString("GenericName"));
00754 translateKey(locale, aCurrentGroup, TQCString("Query"));
00755 translateKey(locale, aCurrentGroup, TQCString("ExtraNames"));
00756 translateKey(locale, aCurrentGroup, TQCString("X-TDE-Submenu"));
00757 }
00758 }
00759
00760
00761 if (fileOptionImmutable)
00762 bFileImmutable = true;
00763
00764 #ifdef HAVE_MMAP
00765 if (map)
00766 {
00767 munmap(( char* )map, rFile.size());
00768 #ifdef SIGBUS
00769 sigaction (SIGBUS, &mmap_old_sigact, 0);
00770 #endif
00771 }
00772 #endif
00773 }
00774
00775 void TDEConfigINIBackEnd::translateKey(TDELocale& locale, TQCString currentGroup, TQCString key) {
00776 KEntryKey entryKey = KEntryKey(currentGroup, key);
00777 KEntry entry = pConfig->lookupData(entryKey);
00778 if (TQString(entry.mValue) != "") {
00779 TQString orig = key + "=" + entry.mValue;
00780 TQString translate = locale.translate(key + "=" + entry.mValue);
00781 if (TQString::compare(orig, translate) != 0) {
00782 translate = translate.mid(key.length() + 1);
00783 entry.mValue = translate.utf8();
00784 entryKey.bLocal = true;
00785 entry.bNLS = true;
00786 pConfig->putData(entryKey, entry, false);
00787 }
00788 }
00789 }
00790
00791 void TDEConfigINIBackEnd::sync(bool bMerge)
00792 {
00793
00794 if (!pConfig->isDirty())
00795 return;
00796
00797 bool bEntriesLeft = true;
00798
00799
00800
00801
00802 if (!mfileName.isEmpty()) {
00803
00804 if ((resType!="config") && !TQDir::isRelativePath(mLocalFileName))
00805 {
00806 KURL path;
00807 path.setPath(mLocalFileName);
00808 TQString dir=path.directory();
00809 TDEStandardDirs::makeDir(dir);
00810 }
00811
00812
00813
00814
00815
00816 if (checkAccess(mLocalFileName, W_OK)) {
00817
00818 TDELockFile::Ptr lf;
00819
00820 bool mergeLocalFile = bMerge;
00821
00822 if (mergeLocalFile)
00823 {
00824 lf = lockFile(false);
00825 if (lf && lf->isLocked())
00826 lf = 0;
00827
00828 if (lf)
00829 {
00830 lf->lock( TDELockFile::LockForce );
00831
00832 }
00833
00834 TQFileInfo info(mLocalFileName);
00835 if ((d->localLastSize == info.size()) &&
00836 (d->localLastModified == info.lastModified()))
00837 {
00838
00839 mergeLocalFile = false;
00840 }
00841 else
00842 {
00843
00844 d->localLastModified = TQDateTime();
00845 d->localLastSize = 0;
00846 }
00847 }
00848
00849 bEntriesLeft = writeConfigFile( mLocalFileName, false, mergeLocalFile );
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859 if (!mergeLocalFile)
00860 {
00861 TQFileInfo info(mLocalFileName);
00862 d->localLastModified = info.lastModified();
00863 d->localLastSize = info.size();
00864 }
00865 if (lf) lf->unlock();
00866 }
00867 }
00868
00869
00870
00871
00872 if (bEntriesLeft && useKDEGlobals) {
00873
00874
00875 if (checkAccess ( mGlobalFileName, W_OK )) {
00876 TDELockFile::Ptr lf = lockFile(true);
00877 if (lf && lf->isLocked())
00878 lf = 0;
00879
00880 if (lf)
00881 {
00882 lf->lock( TDELockFile::LockForce );
00883
00884 }
00885 writeConfigFile( mGlobalFileName, true, bMerge );
00886 if (lf) lf->unlock();
00887 }
00888 }
00889
00890 }
00891
00892 static void writeEntries(FILE *pStream, const KEntryMap& entryMap, bool defaultGroup, bool &firstEntry, const TQCString &localeString)
00893 {
00894
00895 TQCString currentGroup;
00896 for (KEntryMapConstIterator aIt = entryMap.begin();
00897 aIt != entryMap.end(); ++aIt)
00898 {
00899 const KEntryKey &key = aIt.key();
00900
00901
00902 if ((key.mGroup != "<default>") == defaultGroup)
00903 continue;
00904
00905
00906 if ((key.bDefault) || key.mKey.isEmpty())
00907 continue;
00908
00909 const KEntry ¤tEntry = *aIt;
00910
00911 KEntryMapConstIterator aTestIt = aIt;
00912 ++aTestIt;
00913 bool hasDefault = (aTestIt != entryMap.end());
00914 if (hasDefault)
00915 {
00916 const KEntryKey &defaultKey = aTestIt.key();
00917 if ((!defaultKey.bDefault) ||
00918 (defaultKey.mKey != key.mKey) ||
00919 (defaultKey.mGroup != key.mGroup) ||
00920 (defaultKey.bLocal != key.bLocal))
00921 hasDefault = false;
00922 }
00923
00924
00925 if (hasDefault)
00926 {
00927
00928 if ((currentEntry.mValue == (*aTestIt).mValue) &&
00929 (currentEntry.bDeleted == (*aTestIt).bDeleted))
00930 continue;
00931 }
00932 else
00933 {
00934
00935 if (currentEntry.bDeleted)
00936 continue;
00937 }
00938
00939 if (!defaultGroup && (currentGroup != key.mGroup)) {
00940 if (!firstEntry)
00941 fprintf(pStream, "\n");
00942 currentGroup = key.mGroup;
00943 fprintf(pStream, "[%s]\n", encodeGroup(currentGroup).data());
00944 }
00945
00946 firstEntry = false;
00947
00948 fputs(encodeKey(key.mKey.data()), pStream);
00949
00950 if ( currentEntry.bNLS )
00951 {
00952 fputc('[', pStream);
00953 fputs(localeString.data(), pStream);
00954 fputc(']', pStream);
00955 }
00956
00957 if (currentEntry.bDeleted)
00958 {
00959 fputs("[$d]\n", pStream);
00960 }
00961 else
00962 {
00963 if (currentEntry.bImmutable || currentEntry.bExpand)
00964 {
00965 fputc('[', pStream);
00966 fputc('$', pStream);
00967 if (currentEntry.bImmutable)
00968 fputc('i', pStream);
00969 if (currentEntry.bExpand)
00970 fputc('e', pStream);
00971
00972 fputc(']', pStream);
00973 }
00974 fputc('=', pStream);
00975 fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
00976 fputc('\n', pStream);
00977 }
00978 }
00979 }
00980
00981 bool TDEConfigINIBackEnd::getEntryMap(KEntryMap &aTempMap, bool bGlobal,
00982 TQFile *mergeFile)
00983 {
00984 bool bEntriesLeft = false;
00985 bFileImmutable = false;
00986
00987
00988 if (mergeFile && mergeFile->open(IO_ReadOnly))
00989 {
00990
00991 parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal, false );
00992
00993 if (bFileImmutable)
00994 return bEntriesLeft;
00995 }
00996
00997 KEntryMap aMap = pConfig->internalEntryMap();
00998
00999
01000 for (KEntryMapIterator aIt = aMap.begin();
01001 aIt != aMap.end(); ++aIt)
01002 {
01003 const KEntry ¤tEntry = *aIt;
01004 if(aIt.key().bDefault)
01005 {
01006 aTempMap.replace(aIt.key(), currentEntry);
01007 continue;
01008 }
01009
01010 if (mergeFile && !currentEntry.bDirty)
01011 continue;
01012
01013
01014
01015 if (currentEntry.bGlobal != bGlobal)
01016 {
01017
01018 bEntriesLeft = true;
01019 continue;
01020 }
01021
01022
01023
01024 KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
01025 if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
01026 continue;
01027
01028 aTempMap.insert(aIt.key(), currentEntry, true);
01029 }
01030
01031 return bEntriesLeft;
01032 }
01033
01034
01035 bool TDEConfigINIBackEnd::writeConfigFile(TQString filename, bool bGlobal,
01036 bool bMerge)
01037 {
01038
01039 if (pConfig->isReadOnly())
01040 return true;
01041
01042 KEntryMap aTempMap;
01043 TQFile *mergeFile = (bMerge ? new TQFile(filename) : 0);
01044 bool bEntriesLeft = getEntryMap(aTempMap, bGlobal, mergeFile);
01045 delete mergeFile;
01046 if (bFileImmutable)
01047 return true;
01048
01049
01050
01051
01052
01053 int fileMode = -1;
01054 bool createNew = true;
01055
01056 KDE_struct_stat buf;
01057 if (KDE_stat(TQFile::encodeName(filename), &buf) == 0)
01058 {
01059 if (buf.st_uid == getuid())
01060 {
01061
01062 fileMode = buf.st_mode & 0777;
01063 }
01064 else
01065 {
01066
01067
01068 createNew = false;
01069 }
01070 }
01071
01072 KSaveFile *pConfigFile = 0;
01073 FILE *pStream = 0;
01074
01075 if (createNew)
01076 {
01077 pConfigFile = new KSaveFile( filename, 0600 );
01078
01079 if (pConfigFile->status() != 0)
01080 {
01081 delete pConfigFile;
01082 return bEntriesLeft;
01083 }
01084
01085 if (!bGlobal && (fileMode == -1))
01086 fileMode = mFileMode;
01087
01088 if (fileMode != -1)
01089 {
01090 fchmod(pConfigFile->handle(), fileMode);
01091 }
01092
01093 pStream = pConfigFile->fstream();
01094 }
01095 else
01096 {
01097
01098
01099 int fd = KDE_open( TQFile::encodeName(filename), O_WRONLY | O_TRUNC );
01100 if (fd < 0)
01101 {
01102 return bEntriesLeft;
01103 }
01104 pStream = KDE_fdopen( fd, "w");
01105 if (!pStream)
01106 {
01107 close(fd);
01108 return bEntriesLeft;
01109 }
01110 }
01111
01112 writeEntries(pStream, aTempMap);
01113
01114 if (pConfigFile)
01115 {
01116 bool bEmptyFile = (ftell(pStream) == 0);
01117 if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
01118 {
01119
01120 ::unlink(TQFile::encodeName(filename));
01121 pConfigFile->abort();
01122 }
01123 else
01124 {
01125
01126 pConfigFile->close();
01127 }
01128 delete pConfigFile;
01129 }
01130 else
01131 {
01132 fclose(pStream);
01133 }
01134
01135 return bEntriesLeft;
01136 }
01137
01138 void TDEConfigINIBackEnd::writeEntries(FILE *pStream, const KEntryMap &aTempMap)
01139 {
01140 bool firstEntry = true;
01141
01142
01143 ::writeEntries(pStream, aTempMap, true, firstEntry, localeString);
01144
01145
01146 ::writeEntries(pStream, aTempMap, false, firstEntry, localeString);
01147 }
01148
01149 void TDEConfigBackEnd::virtual_hook( int, void* )
01150 { }
01151
01152 void TDEConfigINIBackEnd::virtual_hook( int id, void* data )
01153 { TDEConfigBackEnd::virtual_hook( id, data ); }
01154
01155 bool TDEConfigBackEnd::checkConfigFilesWritable(bool warnUser)
01156 {
01157
01158 bool allWritable = true;
01159 TQString errorMsg;
01160 if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
01161 {
01162 errorMsg = i18n("Will not save configuration.\n");
01163 allWritable = false;
01164 errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
01165 }
01166
01167
01168 if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
01169 {
01170 if ( errorMsg.isEmpty() )
01171 errorMsg = i18n("Will not save configuration.\n");
01172 errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
01173 allWritable = false;
01174 }
01175
01176 if (warnUser && !allWritable)
01177 {
01178
01179 errorMsg += i18n("Please contact your system administrator.");
01180 TQString cmdToExec = TDEStandardDirs::findExe(TQString("kdialog"));
01181 TDEApplication *app = kapp;
01182 if (!cmdToExec.isEmpty() && app)
01183 {
01184 TDEProcess lprocess;
01185 lprocess << cmdToExec << "--title" << app->instanceName() << "--msgbox" << TQCString(errorMsg.local8Bit());
01186 lprocess.start( TDEProcess::Block );
01187 }
01188 }
01189 return allWritable;
01190 }