26 #ifdef HAVE_SYS_MMAN_H
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_STAT_H
38 #include <tqfileinfo.h>
39 #include <tqtextcodec.h>
40 #include <tqtextstream.h>
42 #include "tdeconfigbackend.h"
43 #include "tdeconfigbase.h"
44 #include <tdeapplication.h>
45 #include <tdeglobal.h>
46 #include <tdeprocess.h>
48 #include <tdestandarddirs.h>
49 #include <ksavefile.h>
53 extern bool checkAccess(
const TQString& pathname,
int mode);
55 static TQCString printableToString(
const char *str,
int l)
59 ((*str ==
' ') || (*str ==
'\t') || (*str ==
'\r')))
66 ((str[l-1] ==
' ') || (str[l-1] ==
'\t') || (str[l-1] ==
'\r')))
71 TQCString result(l + 1);
72 char *r = result.data();
74 for(
int i = 0; i < l;i++, str++)
111 result.truncate(r-result.data());
115 static TQCString stringToPrintable(
const TQCString& str){
116 TQCString result(str.length()*2);
117 char *r =
const_cast<TQCString&
>(result).data();
118 char *s =
const_cast<TQCString&
>(str).data();
120 if (!s)
return TQCString(
"");
125 *r++ =
'\\'; *r++ =
's';
135 *r++ =
'\\'; *r++ =
'n';
139 *r++ =
'\\'; *r++ =
't';
143 *r++ =
'\\'; *r++ =
'r';
147 *r++ =
'\\'; *r++ =
'\\';
158 *(r-1) =
'\\'; *r++ =
's';
162 result.truncate(r - result.data());
166 static TQCString decodeGroup(
const char*s,
int l)
169 char *r = result.data();
174 if ((*s ==
'[') && (l > 1))
182 if ((*s ==
']') && (l > 1))
193 result.truncate(r - result.data());
197 static TQCString encodeGroup(
const TQCString &str)
199 int l = str.length();
200 TQCString result(l*2+1);
201 char *r =
const_cast<TQCString&
>(result).data();
202 char *s =
const_cast<TQCString&
>(str).data();
205 if ((*s ==
'[') || (*s ==
']'))
210 result.truncate(r - result.data());
214 static TQCString encodeKey(
const char* key)
216 TQCString newKey(key);
218 newKey.replace(
'[',
"%5b");
219 newKey.replace(
']',
"%5d");
224 static TQCString decodeKey(
const char* key)
226 TQCString newKey(key);
228 newKey.replace(
"%5b",
"[");
229 newKey.replace(
"%5d",
"]");
234 class TDEConfigBackEnd::TDEConfigBackEndPrivate
237 TQDateTime localLastModified;
244 const char * _resType,
247 mfileName = _fileName;
249 useKDEGlobals = _useKDEGlobals;
250 if (mfileName.isEmpty()) {
251 mLocalFileName = TQString::null;
253 else if (!TQDir::isRelativePath(mfileName)) {
254 mLocalFileName = mfileName;
264 mGlobalFileName = TQString::null;
267 d->localLastModified = TQDateTime();
268 d->localLastSize = 0;
269 d->localLockFile = 0;
270 d->globalLockFile = 0;
277 if (d->globalLockFile)
278 return d->globalLockFile;
280 if (!mGlobalFileName.isEmpty())
282 d->globalLockFile =
new TDELockFile(mGlobalFileName+
".lock");
283 return d->globalLockFile;
288 if (d->localLockFile)
289 return d->localLockFile;
291 if (!mLocalFileName.isEmpty())
293 d->localLockFile =
new TDELockFile(mLocalFileName+
".lock");
294 return d->localLockFile;
301 const TQString &_fileName,
302 const char * _resType,
304 : pConfig(_config), bFileImmutable(false), mConfigState(
TDEConfigBase::NoAccess), mFileMode(-1)
306 d =
new TDEConfigBackEndPrivate;
323 mConfigState = TDEConfigBase::ReadOnly;
324 if (!mLocalFileName.isEmpty() && !pConfig->
isReadOnly())
326 if (checkAccess(mLocalFileName, W_OK))
328 mConfigState = TDEConfigBase::ReadWrite;
338 if (checkAccess(mLocalFileName, W_OK))
340 mConfigState = TDEConfigBase::ReadWrite;
343 TQFileInfo info(mLocalFileName);
344 d->localLastModified = info.lastModified();
345 d->localLastSize = info.size();
349 bFileImmutable =
false;
354 findAllResources(
"config", TQString::fromLatin1(
"kdeglobals"));
357 TQString etc_tderc = TQFile::decodeName( TQCString(getenv(
"WINDIR")) +
"\\tderc" );
359 TQString etc_tderc = TQString::fromLatin1(
"/etc/tderc");
362 if (checkAccess(etc_tderc, R_OK))
366 findAllResources(
"config", TQString::fromLatin1(
"system.kdeglobals"));
368 TQStringList::ConstIterator it;
370 for (it = tdercs.fromLast(); it != tdercs.end(); --it) {
372 TQFile aConfigFile( *it );
373 if (!aConfigFile.open( IO_ReadOnly ))
382 bool bReadFile = !mfileName.isEmpty();
385 TQString bootLanguage;
386 if (useKDEGlobals && localeString.isEmpty() && !TDEGlobal::_locale) {
388 bootLanguage = TDELocale::_initLanguage(pConfig);
392 bFileImmutable =
false;
394 if ( !TQDir::isRelativePath(mfileName) )
399 TQStringList::ConstIterator it;
401 for (it = list.fromLast(); it != list.end(); --it) {
403 TQFile aConfigFile( *it );
405 bool bIsLocal = (*it == mLocalFileName);
406 if (aConfigFile.open( IO_ReadOnly )) {
414 bFileImmutable =
true;
415 TQString currentLanguage;
416 if (!bootLanguage.isEmpty())
418 currentLanguage = TDELocale::_initLanguage(pConfig);
421 if (bootLanguage != currentLanguage)
429 mConfigState = TDEConfigBase::ReadOnly;
434 extern bool kde_kiosk_exception;
438 bool bGlobal,
bool bDefault)
443 TQCString aCurrentGroup(
"<default>");
445 unsigned int ll = localeString.length();
448 TQByteArray data = rFile.readAll();
449 const char *s = data.data();
450 const char *eof = s + data.size();
452 bool fileOptionImmutable =
false;
453 bool groupOptionImmutable =
false;
454 bool groupSkip =
false;
455 bool foundGettextDomain =
false;
456 TQCString gettextDomain;
463 while((s < eof) && isspace(*s) && (*s !=
'\n'))
467 if ((s < eof) && ((*s ==
'\n') || (*s ==
'#')))
470 while ((s < eof) && (*s !=
'\n'))
474 const char *startLine = s;
479 while ((s < eof) && (*s !=
'\n'))
483 if ((s+1 < eof) && (*(s+1) ==
']'))
492 while ((s < eof) && (*s !=
'\n')) s++;
493 if ((e >= eof) || (*e !=
']'))
495 fprintf(stderr,
"Invalid group header at %s:%d\n", rFile.name().latin1(), line);
500 if ((e-startLine == 3) &&
501 (startLine[1] ==
'$') &&
502 (startLine[2] ==
'i'))
504 if (!kde_kiosk_exception)
505 fileOptionImmutable =
true;
509 aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
513 if (aCurrentGroup ==
"KDE Desktop Entry")
514 aCurrentGroup =
"Desktop Entry";
516 groupOptionImmutable = fileOptionImmutable;
519 if ((e+2 < eof) && (*e++ ==
'[') && (*e++ ==
'$'))
521 if ((*e ==
'i') && !kde_kiosk_exception)
523 groupOptionImmutable =
true;
531 if (groupSkip && !bDefault)
535 pConfig->
putData(groupKey, entry,
false);
540 (*pWriteBackMap)[groupKey] = entry;
545 if (groupSkip && !bDefault)
549 bool optionImmutable = groupOptionImmutable;
550 bool optionDeleted =
false;
551 bool optionExpand =
false;
552 const char *endOfKey = 0, *locale = 0, *elocale = 0;
553 for (; (s < eof) && (*s !=
'\n'); s++)
569 if ((s >= eof) || (*s ==
'\n') || (*s ==
'=')) {
570 fprintf(stderr,
"Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
581 fprintf(stderr,
"Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
590 while (option < eoption)
593 if ((*option ==
'i') && !kde_kiosk_exception)
594 optionImmutable =
true;
595 else if (*option ==
'e')
597 else if (*option ==
'd')
599 optionDeleted =
true;
602 else if (*option ==
']')
608 fprintf(stderr,
"Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
612 for (endOfKey--; ; endOfKey--)
614 if (endOfKey < startLine)
616 fprintf(stderr,
"Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
619 if (!isspace(*endOfKey))
623 const char *st = ++s;
624 while ((s < eof) && (*s !=
'\n')) s++;
627 unsigned int cl =
static_cast<unsigned int>(elocale - locale);
628 if ((ll != cl) || memcmp(locale, localeString.data(), ll))
631 if ( cl != 1 || ll != 5 || *locale !=
'C' || memcmp(localeString.data(),
"en_US", 5)) {
644 TQCString key(startLine, endOfKey - startLine + 2);
645 TQCString val = printableToString(st, s - st);
648 if (TQString(key.data()) ==
"X-Ubuntu-Gettext-Domain") {
649 gettextDomain = val.data();
650 foundGettextDomain =
true;
653 KEntryKey aEntryKey(aCurrentGroup, decodeKey(key));
654 aEntryKey.
bLocal = (locale != 0);
663 aEntry.
bNLS = (locale != 0);
668 pWriteBackMap->insert(aEntryKey, aEntry);
673 pConfig->
putData(aEntryKey, aEntry,
false);
683 if (!pWriteBackMap) {
684 TQFile file(
"file.txt");
685 if (foundGettextDomain) {
689 TQString language = locale.
language();
690 translateKey(locale, aCurrentGroup, TQCString(
"Name"));
691 translateKey(locale, aCurrentGroup, TQCString(
"Comment"));
692 translateKey(locale, aCurrentGroup, TQCString(
"Language"));
693 translateKey(locale, aCurrentGroup, TQCString(
"Keywords"));
694 translateKey(locale, aCurrentGroup, TQCString(
"About"));
695 translateKey(locale, aCurrentGroup, TQCString(
"Description"));
696 translateKey(locale, aCurrentGroup, TQCString(
"GenericName"));
697 translateKey(locale, aCurrentGroup, TQCString(
"Query"));
698 translateKey(locale, aCurrentGroup, TQCString(
"ExtraNames"));
699 translateKey(locale, aCurrentGroup, TQCString(
"X-TDE-Submenu"));
703 if (fileOptionImmutable)
704 bFileImmutable =
true;
707 void TDEConfigINIBackEnd::translateKey(
TDELocale& locale, TQCString currentGroup, TQCString key) {
710 if (TQString(entry.mValue) !=
"") {
711 TQString orig = key +
"=" + entry.mValue;
712 TQString translate = locale.
translate(key +
"=" + entry.mValue);
713 if (TQString::compare(orig, translate) != 0) {
714 translate = translate.mid(key.length() + 1);
715 entry.mValue = translate.utf8();
718 pConfig->
putData(entryKey, entry,
false);
729 bool bEntriesLeft =
true;
734 if (!mfileName.isEmpty()) {
736 if ((resType!=
"config") && !TQDir::isRelativePath(mLocalFileName))
748 if (checkAccess(mLocalFileName, W_OK)) {
752 bool mergeLocalFile = bMerge;
766 TQFileInfo info(mLocalFileName);
767 if ((d->localLastSize == info.size()) &&
768 (d->localLastModified == info.lastModified()))
771 mergeLocalFile =
false;
776 d->localLastModified = TQDateTime();
777 d->localLastSize = 0;
781 bEntriesLeft =
writeConfigFile( mLocalFileName,
false, mergeLocalFile );
793 TQFileInfo info(mLocalFileName);
794 d->localLastModified = info.lastModified();
795 d->localLastSize = info.size();
804 if (bEntriesLeft && useKDEGlobals) {
807 if (checkAccess ( mGlobalFileName, W_OK )) {
824 static void writeEntries(FILE *pStream,
const KEntryMap& entryMap,
bool defaultGroup,
bool &firstEntry,
const TQCString &localeString)
827 TQCString currentGroup;
829 aIt != entryMap.end(); ++aIt)
834 if ((key.mGroup !=
"<default>") == defaultGroup)
838 if ((key.bDefault) || key.mKey.isEmpty())
841 const KEntry ¤tEntry = *aIt;
845 bool hasDefault = (aTestIt != entryMap.end());
848 const KEntryKey &defaultKey = aTestIt.key();
849 if ((!defaultKey.bDefault) ||
850 (defaultKey.mKey != key.mKey) ||
851 (defaultKey.mGroup != key.mGroup) ||
852 (defaultKey.bLocal != key.bLocal))
860 if ((currentEntry.mValue == (*aTestIt).mValue) &&
861 (currentEntry.
bDeleted == (*aTestIt).bDeleted))
871 if (!defaultGroup && (currentGroup !=
key.mGroup)) {
873 fprintf(pStream,
"\n");
874 currentGroup =
key.mGroup;
875 fprintf(pStream,
"[%s]\n", encodeGroup(currentGroup).data());
880 fputs(encodeKey(
key.mKey.data()), pStream);
882 if ( currentEntry.
bNLS )
885 fputs(localeString.data(), pStream);
891 fputs(
"[$d]\n", pStream);
907 fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
908 fputc(
'\n', pStream);
916 bool bEntriesLeft =
false;
917 bFileImmutable =
false;
920 if (mergeFile && mergeFile->open(IO_ReadOnly))
932 for (KEntryMapIterator aIt = aMap.begin();
933 aIt != aMap.end(); ++aIt)
935 const KEntry ¤tEntry = *aIt;
936 if(aIt.key().bDefault)
938 aTempMap.replace(aIt.key(), currentEntry);
942 if (mergeFile && !currentEntry.
bDirty)
947 if (currentEntry.
bGlobal != bGlobal)
956 KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
957 if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
960 aTempMap.insert(aIt.key(), currentEntry,
true);
975 TQFile *mergeFile = (bMerge ?
new TQFile(
filename) : 0);
976 bool bEntriesLeft =
getEntryMap(aTempMap, bGlobal, mergeFile);
986 bool createNew =
true;
989 if (KDE_stat(TQFile::encodeName(
filename), &buf) == 0)
991 if (buf.st_uid == getuid())
994 fileMode = buf.st_mode & 0777;
1011 if (pConfigFile->
status() != 0)
1014 return bEntriesLeft;
1017 if (!bGlobal && (fileMode == -1))
1018 fileMode = mFileMode;
1022 fchmod(pConfigFile->
handle(), fileMode);
1025 pStream = pConfigFile->
fstream();
1031 int fd = KDE_open( TQFile::encodeName(
filename), O_WRONLY | O_TRUNC );
1034 return bEntriesLeft;
1036 pStream = KDE_fdopen( fd,
"w");
1040 return bEntriesLeft;
1048 bool bEmptyFile = (ftell(pStream) == 0);
1049 if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
1052 ::unlink(TQFile::encodeName(
filename));
1053 pConfigFile->
abort();
1058 pConfigFile->
close();
1067 return bEntriesLeft;
1072 bool firstEntry =
true;
1075 ::writeEntries(pStream, aTempMap,
true, firstEntry, localeString);
1078 ::writeEntries(pStream, aTempMap,
false, firstEntry, localeString);
1081 void TDEConfigBackEnd::virtual_hook(
int,
void* )
1084 void TDEConfigINIBackEnd::virtual_hook(
int id,
void* data )
1085 { TDEConfigBackEnd::virtual_hook(
id, data ); }
1090 bool allWritable =
true;
1092 if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
1094 errorMsg = i18n(
"Will not save configuration.\n");
1095 allWritable =
false;
1096 errorMsg += i18n(
"Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
1100 if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
1102 if ( errorMsg.isEmpty() )
1103 errorMsg = i18n(
"Will not save configuration.\n");
1104 errorMsg += i18n(
"Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
1105 allWritable =
false;
1108 if (warnUser && !allWritable)
1111 errorMsg += i18n(
"Please contact your system administrator.");
1114 if (!cmdToExec.isEmpty() && app)
1117 lprocess << cmdToExec <<
"--title" << app->
instanceName() <<
"--msgbox" << TQCString(errorMsg.local8Bit());