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 <qdir.h>
00038
#include <qfileinfo.h>
00039
#include <qtextcodec.h>
00040
#include <qtextstream.h>
00041
00042
#include "kconfigbackend.h"
00043
#include "kconfigbase.h"
00044
#include <kapplication.h>
00045
#include <kglobal.h>
00046
#include <kprocess.h>
00047
#include <klocale.h>
00048
#include <kstandarddirs.h>
00049
#include <ksavefile.h>
00050
#include <kurl.h>
00051
#include <kde_file.h>
00052
00053
extern bool checkAccess(
const QString& pathname,
int mode);
00054
00055
static QCString 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
QCString 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 QCString stringToPrintable(
const QCString& str){
00116
QCString result(str.length()*2);
00117
register char *r = result.data();
00118
register char *s = str.data();
00119
00120
if (!s)
return QCString(
"");
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 QCString decodeGroup(
const char*s,
int l)
00167 {
00168
QCString 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 QCString encodeGroup(
const QCString &str)
00198 {
00199
int l = str.length();
00200
QCString result(l*2+1);
00201
register char *r = result.data();
00202
register char *s = 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
class KConfigBackEnd::KConfigBackEndPrivate
00215 {
00216
public:
00217
QDateTime localLastModified;
00218 uint localLastSize;
00219 KLockFile::Ptr localLockFile;
00220 KLockFile::Ptr globalLockFile;
00221 };
00222
00223 void KConfigBackEnd::changeFileName(
const QString &_fileName,
00224
const char * _resType,
00225
bool _useKDEGlobals)
00226 {
00227 mfileName = _fileName;
00228 resType = _resType;
00229 useKDEGlobals = _useKDEGlobals;
00230
if (mfileName.isEmpty())
00231 mLocalFileName = QString::null;
00232
else if (!QDir::isRelativePath(mfileName))
00233 mLocalFileName = mfileName;
00234
else
00235 mLocalFileName =
KGlobal::dirs()->
saveLocation(resType) + mfileName;
00236
00237
if (useKDEGlobals)
00238 mGlobalFileName =
KGlobal::dirs()->
saveLocation(
"config") +
00239 QString::fromLatin1(
"kdeglobals");
00240
else
00241 mGlobalFileName = QString::null;
00242
00243 d->localLastModified =
QDateTime();
00244 d->localLastSize = 0;
00245 d->localLockFile = 0;
00246 d->globalLockFile = 0;
00247 }
00248
00249 KLockFile::Ptr KConfigBackEnd::lockFile(
bool bGlobal)
00250 {
00251
if (bGlobal)
00252 {
00253
if (d->globalLockFile)
00254
return d->globalLockFile;
00255
00256
if (!mGlobalFileName.isEmpty())
00257 {
00258 d->globalLockFile =
new KLockFile(mGlobalFileName+
".lock");
00259
return d->globalLockFile;
00260 }
00261 }
00262
else
00263 {
00264
if (d->localLockFile)
00265
return d->localLockFile;
00266
00267
if (!mLocalFileName.isEmpty())
00268 {
00269 d->localLockFile =
new KLockFile(mLocalFileName+
".lock");
00270
return d->localLockFile;
00271 }
00272 }
00273
return 0;
00274 }
00275
00276 KConfigBackEnd::KConfigBackEnd(
KConfigBase *_config,
00277
const QString &_fileName,
00278
const char * _resType,
00279
bool _useKDEGlobals)
00280 : pConfig(_config), bFileImmutable(false), mConfigState(
KConfigBase::NoAccess), mFileMode(-1)
00281 {
00282 d =
new KConfigBackEndPrivate;
00283
changeFileName(_fileName, _resType, _useKDEGlobals);
00284 }
00285
00286 KConfigBackEnd::~KConfigBackEnd()
00287 {
00288
delete d;
00289 }
00290
00291 void KConfigBackEnd::setFileWriteMode(
int mode)
00292 {
00293 mFileMode = mode;
00294 }
00295
00296 bool KConfigINIBackEnd::parseConfigFiles()
00297 {
00298
00299 mConfigState = KConfigBase::ReadOnly;
00300
if (!mLocalFileName.isEmpty() && !pConfig->
isReadOnly())
00301 {
00302
if (checkAccess(mLocalFileName, W_OK))
00303 {
00304 mConfigState = KConfigBase::ReadWrite;
00305 }
00306
else
00307 {
00308
00309
KURL path;
00310 path.
setPath(mLocalFileName);
00311
QString dir=path.
directory();
00312 KStandardDirs::makeDir(dir);
00313
00314
if (checkAccess(mLocalFileName, W_OK))
00315 {
00316 mConfigState = KConfigBase::ReadWrite;
00317 }
00318 }
00319
QFileInfo info(mLocalFileName);
00320 d->localLastModified = info.lastModified();
00321 d->localLastSize = info.size();
00322 }
00323
00324
00325 bFileImmutable =
false;
00326
00327
00328
if (useKDEGlobals) {
00329
QStringList kdercs =
KGlobal::dirs()->
00330 findAllResources(
"config", QString::fromLatin1(
"kdeglobals"));
00331
00332
#ifdef Q_WS_WIN
00333
QString etc_kderc = QFile::decodeName(
QCString(getenv(
"WINDIR")) +
"\\kderc" );
00334
#else
00335
QString etc_kderc = QString::fromLatin1(
"/etc/kderc");
00336
#endif
00337
00338
if (checkAccess(etc_kderc, R_OK))
00339 kdercs += etc_kderc;
00340
00341 kdercs +=
KGlobal::dirs()->
00342 findAllResources(
"config", QString::fromLatin1(
"system.kdeglobals"));
00343
00344 QStringList::ConstIterator it;
00345
00346
for (it = kdercs.fromLast(); it != kdercs.end(); --it) {
00347
00348
QFile aConfigFile( *it );
00349
if (!aConfigFile.open( IO_ReadOnly ))
00350
continue;
00351
parseSingleConfigFile( aConfigFile, 0L,
true, (*it != mGlobalFileName) );
00352 aConfigFile.close();
00353
if (bFileImmutable)
00354
break;
00355 }
00356 }
00357
00358
bool bReadFile = !mfileName.isEmpty();
00359
while(bReadFile) {
00360 bReadFile =
false;
00361
QString bootLanguage;
00362
if (useKDEGlobals && localeString.isEmpty() && !KGlobal::_locale) {
00363
00364 bootLanguage = KLocale::_initLanguage(pConfig);
00365 setLocaleString(bootLanguage.utf8());
00366 }
00367
00368 bFileImmutable =
false;
00369
QStringList list;
00370
if ( !QDir::isRelativePath(mfileName) )
00371 list << mfileName;
00372
else
00373 list =
KGlobal::dirs()->
findAllResources(resType, mfileName);
00374
00375 QStringList::ConstIterator it;
00376
00377
for (it = list.fromLast(); it != list.end(); --it) {
00378
00379
QFile aConfigFile( *it );
00380
00381
bool bIsLocal = (*it == mLocalFileName);
00382
if (aConfigFile.open( IO_ReadOnly )) {
00383
parseSingleConfigFile( aConfigFile, 0L,
false, !bIsLocal );
00384 aConfigFile.close();
00385
if (bFileImmutable)
00386
break;
00387 }
00388 }
00389
if (
KGlobal::dirs()->
isRestrictedResource(resType, mfileName))
00390 bFileImmutable =
true;
00391
QString currentLanguage;
00392
if (!bootLanguage.isEmpty())
00393 {
00394 currentLanguage = KLocale::_initLanguage(pConfig);
00395
00396
00397
if (bootLanguage != currentLanguage)
00398 {
00399 bReadFile =
true;
00400 setLocaleString(currentLanguage.utf8());
00401 }
00402 }
00403 }
00404
if (bFileImmutable)
00405 mConfigState = KConfigBase::ReadOnly;
00406
00407
return true;
00408 }
00409
00410
#ifdef HAVE_MMAP
00411
#ifdef SIGBUS
00412
static sigjmp_buf mmap_jmpbuf;
00413
struct sigaction mmap_old_sigact;
00414
00415
extern "C" {
00416
static void mmap_sigbus_handler(
int)
00417 {
00418 siglongjmp (mmap_jmpbuf, 1);
00419 }
00420 }
00421
#endif
00422
#endif
00423
00424
extern bool kde_kiosk_exception;
00425
00426 void KConfigINIBackEnd::parseSingleConfigFile(
QFile &rFile,
00427
KEntryMap *pWriteBackMap,
00428
bool bGlobal,
bool bDefault)
00429 {
00430
const char *s;
00431
const char *eof;
00432
QByteArray data;
00433
00434
if (!rFile.isOpen())
00435
return;
00436
00437
00438
00439
00440
00441
00442
QCString aCurrentGroup(
"<default>");
00443
00444
unsigned int ll = localeString.length();
00445
00446
#ifdef HAVE_MMAP
00447
static volatile const char *map;
00448 map = (
const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
00449 rFile.handle(), 0);
00450
00451
if ( map != MAP_FAILED )
00452 {
00453 s = (
const char*) map;
00454 eof = s + rFile.size();
00455
00456
#ifdef SIGBUS
00457
struct sigaction act;
00458 act.sa_handler = mmap_sigbus_handler;
00459 sigemptyset( &act.sa_mask );
00460
#ifdef SA_ONESHOT
00461
act.sa_flags = SA_ONESHOT;
00462
#else
00463
act.sa_flags = SA_RESETHAND;
00464
#endif
00465
sigaction( SIGBUS, &act, &mmap_old_sigact );
00466
00467
if (sigsetjmp (mmap_jmpbuf, 1))
00468 {
00469 qWarning(
"SIGBUS while reading %s", rFile.name().latin1());
00470 munmap((
char* )map, rFile.size());
00471 sigaction (SIGBUS, &mmap_old_sigact, 0);
00472
return;
00473 }
00474
#endif
00475
}
00476
else
00477
#endif
00478
{
00479 rFile.at(0);
00480 data = rFile.readAll();
00481 s = data.data();
00482 eof = s + data.size();
00483 }
00484
00485
bool fileOptionImmutable =
false;
00486
bool groupOptionImmutable =
false;
00487
bool groupSkip =
false;
00488
00489
int line = 0;
00490
for(; s < eof; s++)
00491 {
00492 line++;
00493
00494
while((s < eof) && isspace(*s) && (*s !=
'\n'))
00495 s++;
00496
00497
00498
if ((s < eof) && ((*s ==
'\n') || (*s ==
'#')))
00499 {
00500 sktoeol:
00501
while ((s < eof) && (*s !=
'\n'))
00502 s++;
00503
continue;
00504 }
00505
const char *startLine = s;
00506
00507
if (*s ==
'[')
00508 {
00509
00510
while ((s < eof) && (*s !=
'\n'))
00511 {
00512
if (*s ==
']')
00513 {
00514
if ((s+1 < eof) && (*(s+1) ==
']'))
00515 s++;
00516
else
00517
break;
00518 }
00519
00520 s++;
00521 }
00522
const char *e = s;
00523
while ((s < eof) && (*s !=
'\n')) s++;
00524
if ((e >= eof) || (*e !=
']'))
00525 {
00526 fprintf(stderr,
"Invalid group header at %s:%d\n", rFile.name().latin1(), line);
00527
continue;
00528 }
00529
00530
00531
if ((e-startLine == 3) &&
00532 (startLine[1] ==
'$') &&
00533 (startLine[2] ==
'i'))
00534 {
00535
if (!kde_kiosk_exception)
00536 fileOptionImmutable =
true;
00537
continue;
00538 }
00539
00540 aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
00541
00542
00543
00544
if (aCurrentGroup ==
"KDE Desktop Entry")
00545 aCurrentGroup =
"Desktop Entry";
00546
00547 groupOptionImmutable = fileOptionImmutable;
00548
00549 e++;
00550
if ((e+2 < eof) && (*e++ ==
'[') && (*e++ ==
'$'))
00551 {
00552
if ((*e ==
'i') && !kde_kiosk_exception)
00553 {
00554 groupOptionImmutable =
true;
00555 }
00556 }
00557
00558
KEntryKey groupKey(aCurrentGroup, 0);
00559
KEntry entry = pConfig->
lookupData(groupKey);
00560 groupSkip = entry.
bImmutable;
00561
00562
if (groupSkip && !bDefault)
00563
continue;
00564
00565 entry.
bImmutable |= groupOptionImmutable;
00566 pConfig->
putData(groupKey, entry,
false);
00567
00568
if (pWriteBackMap)
00569 {
00570
00571 (*pWriteBackMap)[groupKey] = entry;
00572 }
00573
00574
continue;
00575 }
00576
if (groupSkip && !bDefault)
00577
goto sktoeol;
00578
00579
bool optionImmutable = groupOptionImmutable;
00580
bool optionDeleted =
false;
00581
bool optionExpand =
false;
00582
const char *endOfKey = 0, *locale = 0, *elocale = 0;
00583
for (; (s < eof) && (*s !=
'\n'); s++)
00584 {
00585
if (*s ==
'=')
00586 {
00587
if (!endOfKey)
00588 endOfKey = s;
00589
goto haveeq;
00590 }
00591
if (*s ==
'[')
00592 {
00593
const char *option;
00594
const char *eoption;
00595 endOfKey = s;
00596 option = ++s;
00597
for (;; s++)
00598 {
00599
if ((s >= eof) || (*s ==
'\n') || (*s ==
'=')) {
00600 fprintf(stderr,
"Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
00601
goto sktoeol;
00602 }
00603
if (*s ==
']')
00604
break;
00605 }
00606 eoption = s;
00607
if (*option !=
'$')
00608 {
00609
00610
if (locale) {
00611 fprintf(stderr,
"Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
00612
goto sktoeol;
00613 }
00614 locale = option;
00615 elocale = eoption;
00616 }
00617
else
00618 {
00619
00620
while (option < eoption)
00621 {
00622 option++;
00623
if ((*option ==
'i') && !kde_kiosk_exception)
00624 optionImmutable =
true;
00625
else if (*option ==
'e')
00626 optionExpand =
true;
00627
else if (*option ==
'd')
00628 {
00629 optionDeleted =
true;
00630
goto haveeq;
00631 }
00632
else if (*option ==
']')
00633
break;
00634 }
00635 }
00636 }
00637 }
00638 fprintf(stderr,
"Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
00639
continue;
00640
00641 haveeq:
00642
for (endOfKey--; ; endOfKey--)
00643 {
00644
if (endOfKey < startLine)
00645 {
00646 fprintf(stderr,
"Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
00647
goto sktoeol;
00648 }
00649
if (!isspace(*endOfKey))
00650
break;
00651 }
00652
00653
const char *st = ++s;
00654
while ((s < eof) && (*s !=
'\n')) s++;
00655
00656
if (locale) {
00657
unsigned int cl = static_cast<unsigned int>(elocale - locale);
00658
if ((ll != cl) || memcmp(locale, localeString.data(), ll))
00659 {
00660
00661
if ( cl != 1 || ll != 5 || *locale !=
'C' || memcmp(localeString.data(),
"en_US", 5)) {
00662
00663
00664
if (!pWriteBackMap)
00665
continue;
00666
00667 endOfKey = elocale;
00668 locale = 0;
00669 }
00670 }
00671 }
00672
00673
00674
QCString key(startLine, endOfKey - startLine + 2);
00675
QCString val = printableToString(st, s - st);
00676
00677
00678
KEntryKey aEntryKey(aCurrentGroup, key);
00679 aEntryKey.
bLocal = (locale != 0);
00680 aEntryKey.
bDefault = bDefault;
00681
00682
KEntry aEntry;
00683 aEntry.
mValue = val;
00684 aEntry.
bGlobal = bGlobal;
00685 aEntry.
bImmutable = optionImmutable;
00686 aEntry.
bDeleted = optionDeleted;
00687 aEntry.
bExpand = optionExpand;
00688 aEntry.
bNLS = (locale != 0);
00689
00690
if (pWriteBackMap) {
00691
00692
00693 pWriteBackMap->insert(aEntryKey, aEntry);
00694 }
else {
00695
00696
00697
00698 pConfig->
putData(aEntryKey, aEntry,
false);
00699 }
00700 }
00701
if (fileOptionImmutable)
00702 bFileImmutable =
true;
00703
00704
#ifdef HAVE_MMAP
00705
if (map)
00706 {
00707 munmap((
char* )map, rFile.size());
00708
#ifdef SIGBUS
00709
sigaction (SIGBUS, &mmap_old_sigact, 0);
00710
#endif
00711
}
00712
#endif
00713
}
00714
00715
00716 void KConfigINIBackEnd::sync(
bool bMerge)
00717 {
00718
00719
if (!pConfig->
isDirty())
00720
return;
00721
00722
bool bEntriesLeft =
true;
00723
00724
00725
00726
00727
if (!mfileName.isEmpty()) {
00728
00729
if ((resType!=
"config") && !QDir::isRelativePath(mLocalFileName))
00730 {
00731
KURL path;
00732 path.
setPath(mLocalFileName);
00733
QString dir=path.
directory();
00734 KStandardDirs::makeDir(dir);
00735 }
00736
00737
00738
00739
00740
00741
if (checkAccess(mLocalFileName, W_OK)) {
00742
00743
KLockFile::Ptr lf;
00744
00745
bool mergeLocalFile = bMerge;
00746
00747
if (mergeLocalFile)
00748 {
00749 lf = lockFile(
false);
00750
if (lf && lf->isLocked())
00751 lf = 0;
00752
00753
if (lf)
00754 {
00755 lf->lock( KLockFile::LockForce );
00756
00757 }
00758
00759
QFileInfo info(mLocalFileName);
00760
if ((d->localLastSize == info.size()) &&
00761 (d->localLastModified == info.lastModified()))
00762 {
00763
00764 mergeLocalFile =
false;
00765 }
00766
else
00767 {
00768
00769 d->localLastModified =
QDateTime();
00770 d->localLastSize = 0;
00771 }
00772 }
00773
00774 bEntriesLeft =
writeConfigFile( mLocalFileName,
false, mergeLocalFile );
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
if (!mergeLocalFile)
00785 {
00786
QFileInfo info(mLocalFileName);
00787 d->localLastModified = info.lastModified();
00788 d->localLastSize = info.size();
00789 }
00790
if (lf) lf->unlock();
00791 }
00792 }
00793
00794
00795
00796
00797
if (bEntriesLeft && useKDEGlobals) {
00798
00799
00800
if (checkAccess ( mGlobalFileName, W_OK )) {
00801
KLockFile::Ptr lf = lockFile(
true);
00802
if (lf && lf->isLocked())
00803 lf = 0;
00804
00805
if (lf)
00806 {
00807 lf->lock( KLockFile::LockForce );
00808
00809 }
00810
writeConfigFile( mGlobalFileName,
true, bMerge );
00811
if (lf) lf->unlock();
00812 }
00813 }
00814
00815 }
00816
00817
static void writeEntries(FILE *pStream,
const KEntryMap& entryMap,
bool defaultGroup,
bool &firstEntry,
const QCString &localeString)
00818 {
00819
00820
QCString currentGroup;
00821
for (
KEntryMapConstIterator aIt = entryMap.begin();
00822 aIt != entryMap.end(); ++aIt)
00823 {
00824
const KEntryKey &key = aIt.key();
00825
00826
00827
if ((key.mGroup !=
"<default>") == defaultGroup)
00828
continue;
00829
00830
00831
if ((key.bDefault) || key.mKey.isEmpty())
00832
continue;
00833
00834
const KEntry ¤tEntry = *aIt;
00835
00836
KEntryMapConstIterator aTestIt = aIt;
00837 ++aTestIt;
00838
bool hasDefault = (aTestIt != entryMap.end());
00839
if (hasDefault)
00840 {
00841
const KEntryKey &defaultKey = aTestIt.key();
00842
if ((!defaultKey.bDefault) ||
00843 (defaultKey.mKey != key.mKey) ||
00844 (defaultKey.mGroup != key.mGroup) ||
00845 (defaultKey.bLocal != key.bLocal))
00846 hasDefault =
false;
00847 }
00848
00849
00850
if (hasDefault)
00851 {
00852
00853
if ((currentEntry.
mValue == (*aTestIt).mValue) &&
00854 (currentEntry.
bDeleted == (*aTestIt).bDeleted))
00855
continue;
00856 }
00857
else
00858 {
00859
00860
if (currentEntry.
bDeleted)
00861
continue;
00862 }
00863
00864
if (!defaultGroup && (currentGroup !=
key.mGroup)) {
00865
if (!firstEntry)
00866 fprintf(pStream,
"\n");
00867 currentGroup =
key.mGroup;
00868 fprintf(pStream,
"[%s]\n", encodeGroup(currentGroup).data());
00869 }
00870
00871 firstEntry =
false;
00872
00873 fputs(
key.mKey.data(), pStream);
00874
00875
if ( currentEntry.
bNLS )
00876 {
00877 fputc(
'[', pStream);
00878 fputs(localeString.data(), pStream);
00879 fputc(
']', pStream);
00880 }
00881
00882
if (currentEntry.
bDeleted)
00883 {
00884 fputs(
"[$d]\n", pStream);
00885 }
00886
else
00887 {
00888
if (currentEntry.
bImmutable || currentEntry.
bExpand)
00889 {
00890 fputc(
'[', pStream);
00891 fputc(
'$', pStream);
00892
if (currentEntry.
bImmutable)
00893 fputc(
'i', pStream);
00894
if (currentEntry.
bExpand)
00895 fputc(
'e', pStream);
00896
00897 fputc(
']', pStream);
00898 }
00899 fputc(
'=', pStream);
00900 fputs(stringToPrintable(currentEntry.
mValue).data(), pStream);
00901 fputc(
'\n', pStream);
00902 }
00903 }
00904 }
00905
00906 bool KConfigINIBackEnd::getEntryMap(
KEntryMap &aTempMap,
bool bGlobal,
00907
QFile *mergeFile)
00908 {
00909
bool bEntriesLeft =
false;
00910 bFileImmutable =
false;
00911
00912
00913
if (mergeFile && mergeFile->open(IO_ReadOnly))
00914 {
00915
00916
parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal,
false );
00917
00918
if (bFileImmutable)
00919
return bEntriesLeft;
00920 }
00921
00922
KEntryMap aMap = pConfig->
internalEntryMap();
00923
00924
00925
for (
KEntryMapIterator aIt = aMap.begin();
00926 aIt != aMap.end(); ++aIt)
00927 {
00928
const KEntry ¤tEntry = *aIt;
00929
if(aIt.key().bDefault)
00930 {
00931 aTempMap.replace(aIt.key(), currentEntry);
00932
continue;
00933 }
00934
00935
if (mergeFile && !currentEntry.
bDirty)
00936
continue;
00937
00938
00939
00940
if (currentEntry.
bGlobal != bGlobal)
00941 {
00942
00943 bEntriesLeft =
true;
00944
continue;
00945 }
00946
00947
00948
00949
KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
00950
if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
00951
continue;
00952
00953 aTempMap.insert(aIt.key(), currentEntry,
true);
00954 }
00955
00956
return bEntriesLeft;
00957 }
00958
00959
00960 bool KConfigINIBackEnd::writeConfigFile(
QString filename,
bool bGlobal,
00961
bool bMerge)
00962 {
00963
00964
if (pConfig->
isReadOnly())
00965
return true;
00966
00967
KEntryMap aTempMap;
00968
QFile *mergeFile = (bMerge ?
new QFile(filename) : 0);
00969
bool bEntriesLeft =
getEntryMap(aTempMap, bGlobal, mergeFile);
00970
delete mergeFile;
00971
if (bFileImmutable)
00972
return true;
00973
00974
00975
00976
00977
00978
int fileMode = -1;
00979
bool createNew =
true;
00980
00981 KDE_struct_stat buf;
00982
if (KDE_stat(QFile::encodeName(filename), &buf) == 0)
00983 {
00984
if (buf.st_uid == getuid())
00985 {
00986
00987 fileMode = buf.st_mode & 0777;
00988 }
00989
else
00990 {
00991
00992
00993 createNew =
false;
00994 }
00995 }
00996
00997
KSaveFile *pConfigFile = 0;
00998 FILE *pStream = 0;
00999
01000
if (createNew)
01001 {
01002 pConfigFile =
new KSaveFile( filename, 0600 );
01003
01004
if (pConfigFile->
status() != 0)
01005 {
01006
delete pConfigFile;
01007
return bEntriesLeft;
01008 }
01009
01010
if (!bGlobal && (fileMode == -1))
01011 fileMode = mFileMode;
01012
01013
if (fileMode != -1)
01014 {
01015 fchmod(pConfigFile->
handle(), fileMode);
01016 }
01017
01018 pStream = pConfigFile->
fstream();
01019 }
01020
else
01021 {
01022
01023
01024
int fd = KDE_open( QFile::encodeName(filename), O_WRONLY | O_TRUNC );
01025
if (fd < 0)
01026 {
01027
return bEntriesLeft;
01028 }
01029 pStream = KDE_fdopen( fd,
"w");
01030
if (!pStream)
01031 {
01032 close(fd);
01033
return bEntriesLeft;
01034 }
01035 }
01036
01037 writeEntries(pStream, aTempMap);
01038
01039
if (pConfigFile)
01040 {
01041
bool bEmptyFile = (ftell(pStream) == 0);
01042
if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
01043 {
01044
01045 ::unlink(QFile::encodeName(filename));
01046 pConfigFile->
abort();
01047 }
01048
else
01049 {
01050
01051 pConfigFile->
close();
01052 }
01053
delete pConfigFile;
01054 }
01055
else
01056 {
01057 fclose(pStream);
01058 }
01059
01060
return bEntriesLeft;
01061 }
01062
01063 void KConfigINIBackEnd::writeEntries(FILE *pStream,
const KEntryMap &aTempMap)
01064 {
01065
bool firstEntry =
true;
01066
01067
01068 ::writeEntries(pStream, aTempMap,
true, firstEntry, localeString);
01069
01070
01071 ::writeEntries(pStream, aTempMap,
false, firstEntry, localeString);
01072 }
01073
01074
void KConfigBackEnd::virtual_hook(
int,
void* )
01075 { }
01076
01077
void KConfigINIBackEnd::virtual_hook(
int id,
void* data )
01078 { KConfigBackEnd::virtual_hook(
id, data ); }
01079
01080 bool KConfigBackEnd::checkConfigFilesWritable(
bool warnUser)
01081 {
01082
01083
bool allWritable =
true;
01084
QString errorMsg( i18n(
"Will not save configuration.\n") );
01085
if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
01086 {
01087 allWritable =
false;
01088 errorMsg += i18n(
"Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
01089 }
01090
01091
01092
if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
01093 {
01094 errorMsg += i18n(
"Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
01095 allWritable =
false;
01096 }
01097
01098
if (warnUser && !allWritable)
01099 {
01100
01101 errorMsg += i18n(
"Please contact your system administrator.");
01102
QString cmdToExec = KStandardDirs::findExe(
QString(
"kdialog"));
01103
KApplication *app = kapp;
01104
if (!cmdToExec.isEmpty() && app)
01105 {
01106
KProcess lprocess;
01107 lprocess << cmdToExec <<
"--title" << app->
instanceName() <<
"--msgbox" << errorMsg.local8Bit();
01108 lprocess.
start( KProcess::Block );
01109 }
01110 }
01111
return allWritable;
01112 }