38#include <tqfileinfo.h>
39#include <tqtextcodec.h>
40#include <tqtextstream.h>
42#include "tdeconfigbackend.h"
43#include "tdeconfigbase.h"
44#include <tdeapplication.h>
46#include <tdeprocess.h>
48#include <tdestandarddirs.h>
53extern bool checkAccess(
const TQString& pathname,
int mode);
55static 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());
115static 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());
166static 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());
197static 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());
214static TQCString encodeKey(
const char* key)
216 TQCString newKey(key);
218 newKey.replace(
'[',
"%5b");
219 newKey.replace(
']',
"%5d");
224static TQCString decodeKey(
const char* key)
226 TQCString newKey(key);
228 newKey.replace(
"%5b",
"[");
229 newKey.replace(
"%5d",
"]");
234class 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;
434extern 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;
707void 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 )) {
824static 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);
1081void TDEConfigBackEnd::virtual_hook(
int,
void* )
1084void 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());
The KSaveFile class has been made to write out changes to an existing file atomically.
int status() const
Returns the status of the file based on errno.
FILE * fstream()
A FILE* stream open for writing to the file.
bool close()
Closes the file and makes the changes definitive.
void abort()
Aborts the write operation and removes any intermediate files This implies a close.
int handle() const
An integer file descriptor open for writing to the file.
Represents and parses a URL.
TQString directory(bool _strip_trailing_slash_from_result=true, bool _ignore_trailing_slash_in_path=true) const
Returns the directory of the path.
void setPath(const TQString &path)
Sets the decoded path of the URL.
Controls and provides information to all KDE applications.
TDELockFile::Ptr lockFile(bool bGlobal=false)
Returns a lock file object for the configuration file.
void setLocaleString(const TQCString &_localeString)
Set the locale string that defines the current language.
TDEConfigBackEnd(TDEConfigBase *_config, const TQString &_fileName, const char *_resType, bool _useKDEGlobals)
Constructs a configuration back end.
bool checkConfigFilesWritable(bool warnUser)
Check whether the config files are writable.
virtual ~TDEConfigBackEnd()
Destructs the configuration backend.
TDE_DEPRECATED TQString filename() const
void setFileWriteMode(int mode)
Set the file mode for newly created files.
void changeFileName(const TQString &_fileName, const char *_resType, bool _useKDEGlobals)
Changes the filenames associated with this back end.
KDE Configuration Management abstract base class.
virtual KEntry lookupData(const KEntryKey &_key) const =0
Looks up an entry in the config object's internal structure.
bool isReadOnly() const
Returns the read-only status of the config object.
virtual void putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup=true)=0
Inserts a (key/value) pair into the internal storage mechanism of the configuration object.
bool isDirty() const
Checks whether the config file has any dirty (modified) entries.
virtual KEntryMap internalEntryMap(const TQString &pGroup) const =0
Returns a map (tree) of the entries in the specified group.
void writeEntries(FILE *pStream, const KEntryMap &aTempMap)
Write the entries in aTempMap to the file stream.
virtual void sync(bool bMerge=true)
Writes configuration data to file(s).
bool parseConfigFiles()
Parses all INI-style configuration files for a config object.
bool getEntryMap(KEntryMap &map, bool bGlobal, TQFile *mergeFile)
Get the entry map.
void parseSingleConfigFile(TQFile &rFile, KEntryMap *pWriteBackMap=0L, bool bGlobal=false, bool bDefault=false)
Parses one configuration file.
bool writeConfigFile(TQString filename, bool bGlobal=false, bool bMerge=true)
Writes configuration file back.
static TDEStandardDirs * dirs()
Returns the application standard dirs object.
bool checkAccess(const TQString &pathname, int mode)
Check, if a file may be accessed in a given mode.
TQCString instanceName() const
Returns the name of the instance.
TDELocale provides support for country specific stuff like the national language.
TQString language() const
Returns the language used by this object.
TQString translate(const char *index) const
Translates the string into the corresponding string in the national language, if available.
The TDELockFile class provides NFS safe lockfiles.
@ LockForce
Automatically remove a lock when a lock is detected that is stale for more than staleTime() seconds.
bool isLocked() const
Returns whether the lock is held or not.
void unlock()
Release the lock.
LockResult lock(int options=0)
Attempt to acquire the lock.
Child process invocation, monitoring and control.
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
@ Block
The application is suspended until the started process is finished.
TQString saveLocation(const char *type, const TQString &suffix=TQString::null, bool create=true) const
Finds a location to save files into for the given type in the user's home directory.
static TQString findExe(const TQString &appname, const TQString &pathstr=TQString::null, bool ignoreExecBit=false)
Finds the executable in the system path.
static bool makeDir(const TQString &dir, int mode=0755)
Recursively creates still-missing directories in the given path.
TQStringList findAllResources(const char *type, const TQString &filter=TQString::null, bool recursive=false, bool unique=false) const
Tries to find all resources with the specified type.
key structure holding both the actual key and the the group to which it belongs.
bool bDefault
Entry indicates if this is a default value.
bool bLocal
Entry is localised or not.
map/dict/list config node entry.
TQMap< KEntryKey, KEntry >::ConstIterator KEntryMapConstIterator
type for iterating over keys in a KEntryMap in sorted order.
bool bImmutable
Entry can not be modified.
bool bNLS
Entry should be written with locale tag.
bool bGlobal
Entry should be written to the global config file.
bool bExpand
Whether to apply dollar expansion or not.
bool bDirty
Must the entry be written back to disk?
TQMap< KEntryKey, KEntry > KEntryMap
type specifying a map of entries (key,value pairs).
bool bDeleted
Entry has been deleted.