• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
tdeconfigbackend.cpp
1 /*
2  This file is part of the KDE libraries
3  Copyright (c) 1999 Preston Brown <pbrown@kde.org>
4  Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include <config.h>
23 
24 #include <unistd.h>
25 #include <ctype.h>
26 #ifdef HAVE_SYS_MMAN_H
27 #include <sys/mman.h>
28 #endif
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_STAT_H
31 #include <sys/stat.h>
32 #endif
33 #include <fcntl.h>
34 #include <signal.h>
35 #include <setjmp.h>
36 
37 #include <tqdir.h>
38 #include <tqfileinfo.h>
39 #include <tqtextcodec.h>
40 #include <tqtextstream.h>
41 
42 #include "tdeconfigbackend.h"
43 #include "tdeconfigbase.h"
44 #include <tdeapplication.h>
45 #include <tdeglobal.h>
46 #include <kprocess.h>
47 #include <tdelocale.h>
48 #include <kstandarddirs.h>
49 #include <ksavefile.h>
50 #include <kurl.h>
51 #include <kde_file.h>
52 
53 extern bool checkAccess(const TQString& pathname, int mode);
54 /* translate escaped escape sequences to their actual values. */
55 static TQCString printableToString(const char *str, int l)
56 {
57  // Strip leading white-space.
58  while((l>0) &&
59  ((*str == ' ') || (*str == '\t') || (*str == '\r')))
60  {
61  str++; l--;
62  }
63 
64  // Strip trailing white-space.
65  while((l>0) &&
66  ((str[l-1] == ' ') || (str[l-1] == '\t') || (str[l-1] == '\r')))
67  {
68  l--;
69  }
70 
71  TQCString result(l + 1);
72  char *r = result.data();
73 
74  for(int i = 0; i < l;i++, str++)
75  {
76  if (*str == '\\')
77  {
78  i++, str++;
79  if (i >= l) // End of line. (Line ends with single slash)
80  {
81  *r++ = '\\';
82  break;
83  }
84  switch(*str)
85  {
86  case 's':
87  *r++ = ' ';
88  break;
89  case 't':
90  *r++ = '\t';
91  break;
92  case 'n':
93  *r++ = '\n';
94  break;
95  case 'r':
96  *r++ = '\r';
97  break;
98  case '\\':
99  *r++ = '\\';
100  break;
101  default:
102  *r++ = '\\';
103  *r++ = *str;
104  }
105  }
106  else
107  {
108  *r++ = *str;
109  }
110  }
111  result.truncate(r-result.data());
112  return result;
113 }
114 
115 static TQCString stringToPrintable(const TQCString& str){
116  TQCString result(str.length()*2); // Maximum 2x as long as source string
117  char *r = const_cast<TQCString&>(result).data();
118  char *s = const_cast<TQCString&>(str).data();
119 
120  if (!s) return TQCString("");
121 
122  // Escape leading space
123  if (*s == ' ')
124  {
125  *r++ = '\\'; *r++ = 's';
126  s++;
127  }
128 
129  if (*s)
130  {
131  while(*s)
132  {
133  if (*s == '\n')
134  {
135  *r++ = '\\'; *r++ = 'n';
136  }
137  else if (*s == '\t')
138  {
139  *r++ = '\\'; *r++ = 't';
140  }
141  else if (*s == '\r')
142  {
143  *r++ = '\\'; *r++ = 'r';
144  }
145  else if (*s == '\\')
146  {
147  *r++ = '\\'; *r++ = '\\';
148  }
149  else
150  {
151  *r++ = *s;
152  }
153  s++;
154  }
155  // Escape trailing space
156  if (*(r-1) == ' ')
157  {
158  *(r-1) = '\\'; *r++ = 's';
159  }
160  }
161 
162  result.truncate(r - result.data());
163  return result;
164 }
165 
166 static TQCString decodeGroup(const char*s, int l)
167 {
168  TQCString result(l);
169  char *r = result.data();
170 
171  l--; // Correct for trailing \0
172  while(l)
173  {
174  if ((*s == '[') && (l > 1))
175  {
176  if ((*(s+1) == '['))
177  {
178  l--;
179  s++;
180  }
181  }
182  if ((*s == ']') && (l > 1))
183  {
184  if ((*(s+1) == ']'))
185  {
186  l--;
187  s++;
188  }
189  }
190  *r++ = *s++;
191  l--;
192  }
193  result.truncate(r - result.data());
194  return result;
195 }
196 
197 static TQCString encodeGroup(const TQCString &str)
198 {
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();
203  while(l)
204  {
205  if ((*s == '[') || (*s == ']'))
206  *r++ = *s;
207  *r++ = *s++;
208  l--;
209  }
210  result.truncate(r - result.data());
211  return result;
212 }
213 
214 static TQCString encodeKey(const char* key)
215 {
216  TQCString newKey(key);
217 
218  newKey.replace('[', "%5b");
219  newKey.replace(']', "%5d");
220 
221  return newKey;
222 }
223 
224 static TQCString decodeKey(const char* key)
225 {
226  TQCString newKey(key);
227 
228  newKey.replace("%5b", "[");
229  newKey.replace("%5d", "]");
230 
231  return newKey;
232 }
233 
234 class TDEConfigBackEnd::TDEConfigBackEndPrivate
235 {
236 public:
237  TQDateTime localLastModified;
238  uint localLastSize;
239  TDELockFile::Ptr localLockFile;
240  TDELockFile::Ptr globalLockFile;
241 };
242 
243 void TDEConfigBackEnd::changeFileName(const TQString &_fileName,
244  const char * _resType,
245  bool _useKDEGlobals)
246 {
247  mfileName = _fileName;
248  resType = _resType;
249  useKDEGlobals = _useKDEGlobals;
250  if (mfileName.isEmpty()) {
251  mLocalFileName = TQString::null;
252  }
253  else if (!TQDir::isRelativePath(mfileName)) {
254  mLocalFileName = mfileName;
255  }
256  else {
257  mLocalFileName = TDEGlobal::dirs()->saveLocation(resType, TQString(), false) + mfileName;
258  }
259 
260  if (useKDEGlobals) {
261  mGlobalFileName = TDEGlobal::dirs()->saveLocation("config", TQString(), false) + TQString::fromLatin1("kdeglobals");
262  }
263  else {
264  mGlobalFileName = TQString::null;
265  }
266 
267  d->localLastModified = TQDateTime();
268  d->localLastSize = 0;
269  d->localLockFile = 0;
270  d->globalLockFile = 0;
271 }
272 
273 TDELockFile::Ptr TDEConfigBackEnd::lockFile(bool bGlobal)
274 {
275  if (bGlobal)
276  {
277  if (d->globalLockFile)
278  return d->globalLockFile;
279 
280  if (!mGlobalFileName.isEmpty())
281  {
282  d->globalLockFile = new TDELockFile(mGlobalFileName+".lock");
283  return d->globalLockFile;
284  }
285  }
286  else
287  {
288  if (d->localLockFile)
289  return d->localLockFile;
290 
291  if (!mLocalFileName.isEmpty())
292  {
293  d->localLockFile = new TDELockFile(mLocalFileName+".lock");
294  return d->localLockFile;
295  }
296  }
297  return 0;
298 }
299 
300 TDEConfigBackEnd::TDEConfigBackEnd(TDEConfigBase *_config,
301  const TQString &_fileName,
302  const char * _resType,
303  bool _useKDEGlobals)
304  : pConfig(_config), bFileImmutable(false), mConfigState(TDEConfigBase::NoAccess), mFileMode(-1)
305 {
306  d = new TDEConfigBackEndPrivate;
307  changeFileName(_fileName, _resType, _useKDEGlobals);
308 }
309 
310 TDEConfigBackEnd::~TDEConfigBackEnd()
311 {
312  delete d;
313 }
314 
315 void TDEConfigBackEnd::setFileWriteMode(int mode)
316 {
317  mFileMode = mode;
318 }
319 
320 bool TDEConfigINIBackEnd::parseConfigFiles()
321 {
322  // Check if we can write to the local file.
323  mConfigState = TDEConfigBase::ReadOnly;
324  if (!mLocalFileName.isEmpty() && !pConfig->isReadOnly())
325  {
326  if (checkAccess(mLocalFileName, W_OK))
327  {
328  mConfigState = TDEConfigBase::ReadWrite;
329  }
330  else
331  {
332  // Create the containing dir, maybe it wasn't there
333  KURL path;
334  path.setPath(mLocalFileName);
335  TQString dir=path.directory();
336  TDEStandardDirs::makeDir(dir);
337 
338  if (checkAccess(mLocalFileName, W_OK))
339  {
340  mConfigState = TDEConfigBase::ReadWrite;
341  }
342  }
343  TQFileInfo info(mLocalFileName);
344  d->localLastModified = info.lastModified();
345  d->localLastSize = info.size();
346  }
347 
348  // Parse all desired files from the least to the most specific.
349  bFileImmutable = false;
350 
351  // Parse the general config files
352  if (useKDEGlobals) {
353  TQStringList tdercs = TDEGlobal::dirs()->
354  findAllResources("config", TQString::fromLatin1("kdeglobals"));
355 
356 #ifdef TQ_WS_WIN
357  TQString etc_tderc = TQFile::decodeName( TQCString(getenv("WINDIR")) + "\\tderc" );
358 #else
359  TQString etc_tderc = TQString::fromLatin1("/etc/tderc");
360 #endif
361 
362  if (checkAccess(etc_tderc, R_OK))
363  tdercs += etc_tderc;
364 
365  tdercs += TDEGlobal::dirs()->
366  findAllResources("config", TQString::fromLatin1("system.kdeglobals"));
367 
368  TQStringList::ConstIterator it;
369 
370  for (it = tdercs.fromLast(); it != tdercs.end(); --it) {
371 
372  TQFile aConfigFile( *it );
373  if (!aConfigFile.open( IO_ReadOnly ))
374  continue;
375  parseSingleConfigFile( aConfigFile, 0L, true, (*it != mGlobalFileName) );
376  aConfigFile.close();
377  if (bFileImmutable)
378  break;
379  }
380  }
381 
382  bool bReadFile = !mfileName.isEmpty();
383  while(bReadFile) {
384  bReadFile = false;
385  TQString bootLanguage;
386  if (useKDEGlobals && localeString.isEmpty() && !TDEGlobal::_locale) {
387  // Boot strap language
388  bootLanguage = TDELocale::_initLanguage(pConfig);
389  setLocaleString(bootLanguage.utf8());
390  }
391 
392  bFileImmutable = false;
393  TQStringList list;
394  if ( !TQDir::isRelativePath(mfileName) )
395  list << mfileName;
396  else
397  list = TDEGlobal::dirs()->findAllResources(resType, mfileName);
398 
399  TQStringList::ConstIterator it;
400 
401  for (it = list.fromLast(); it != list.end(); --it) {
402 
403  TQFile aConfigFile( *it );
404  // we can already be sure that this file exists
405  bool bIsLocal = (*it == mLocalFileName);
406  if (aConfigFile.open( IO_ReadOnly )) {
407  parseSingleConfigFile( aConfigFile, 0L, false, !bIsLocal );
408  aConfigFile.close();
409  if (bFileImmutable)
410  break;
411  }
412  }
413  if (TDEGlobal::dirs()->isRestrictedResource(resType, mfileName))
414  bFileImmutable = true;
415  TQString currentLanguage;
416  if (!bootLanguage.isEmpty())
417  {
418  currentLanguage = TDELocale::_initLanguage(pConfig);
419  // If the file changed the language, we need to read the file again
420  // with the new language setting.
421  if (bootLanguage != currentLanguage)
422  {
423  bReadFile = true;
424  setLocaleString(currentLanguage.utf8());
425  }
426  }
427  }
428  if (bFileImmutable)
429  mConfigState = TDEConfigBase::ReadOnly;
430 
431  return true;
432 }
433 
434 extern bool kde_kiosk_exception;
435 
436 void TDEConfigINIBackEnd::parseSingleConfigFile(TQFile &rFile,
437  KEntryMap *pWriteBackMap,
438  bool bGlobal, bool bDefault)
439 {
440  if (!rFile.isOpen()) // come back, if you have real work for us ;->
441  return;
442 
443  TQCString aCurrentGroup("<default>");
444 
445  unsigned int ll = localeString.length();
446 
447  rFile.at(0);
448  TQByteArray data = rFile.readAll();
449  const char *s = data.data();
450  const char *eof = s + data.size();
451 
452  bool fileOptionImmutable = false;
453  bool groupOptionImmutable = false;
454  bool groupSkip = false;
455  bool foundGettextDomain = false;
456  TQCString gettextDomain;
457 
458  int line = 0;
459  for(; s < eof; s++)
460  {
461  line++;
462 
463  while((s < eof) && isspace(*s) && (*s != '\n'))
464  s++; //skip leading whitespace, shouldn't happen too often
465 
466  //skip empty lines, lines starting with #
467  if ((s < eof) && ((*s == '\n') || (*s == '#')))
468  {
469  sktoeol: //skip till end-of-line
470  while ((s < eof) && (*s != '\n'))
471  s++;
472  continue; // Empty or comment or no keyword
473  }
474  const char *startLine = s;
475 
476  if (*s == '[') //group
477  {
478  // In a group [[ and ]] have a special meaning
479  while ((s < eof) && (*s != '\n'))
480  {
481  if (*s == ']')
482  {
483  if ((s+1 < eof) && (*(s+1) == ']'))
484  s++; // Skip "]]"
485  else
486  break;
487  }
488 
489  s++; // Search till end of group
490  }
491  const char *e = s;
492  while ((s < eof) && (*s != '\n')) s++; // Search till end of line / end of file
493  if ((e >= eof) || (*e != ']'))
494  {
495  fprintf(stderr, "Invalid group header at %s:%d\n", rFile.name().latin1(), line);
496  continue;
497  }
498  // group found; get the group name by taking everything in
499  // between the brackets
500  if ((e-startLine == 3) &&
501  (startLine[1] == '$') &&
502  (startLine[2] == 'i'))
503  {
504  if (!kde_kiosk_exception)
505  fileOptionImmutable = true;
506  continue;
507  }
508 
509  aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
510  //cout<<"found group ["<<aCurrentGroup<<"]"<<endl;
511 
512  // Backwards compatibility
513  if (aCurrentGroup == "KDE Desktop Entry")
514  aCurrentGroup = "Desktop Entry";
515 
516  groupOptionImmutable = fileOptionImmutable;
517 
518  e++;
519  if ((e+2 < eof) && (*e++ == '[') && (*e++ == '$')) // Option follows
520  {
521  if ((*e == 'i') && !kde_kiosk_exception)
522  {
523  groupOptionImmutable = true;
524  }
525  }
526 
527  KEntryKey groupKey(aCurrentGroup, 0);
528  KEntry entry = pConfig->lookupData(groupKey);
529  groupSkip = entry.bImmutable;
530 
531  if (groupSkip && !bDefault)
532  continue;
533 
534  entry.bImmutable |= groupOptionImmutable;
535  pConfig->putData(groupKey, entry, false);
536 
537  if (pWriteBackMap)
538  {
539  // add the special group key indicator
540  (*pWriteBackMap)[groupKey] = entry;
541  }
542 
543  continue;
544  }
545  if (groupSkip && !bDefault)
546  goto sktoeol; // Skip entry
547 
548 
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++)
554  {
555  if (*s == '=') //find the equal sign
556  {
557  if (!endOfKey)
558  endOfKey = s;
559  goto haveeq;
560  }
561  if (*s == '[') //find the locale or options.
562  {
563  const char *option;
564  const char *eoption;
565  endOfKey = s;
566  option = ++s;
567  for (;; s++)
568  {
569  if ((s >= eof) || (*s == '\n') || (*s == '=')) {
570  fprintf(stderr, "Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
571  goto sktoeol;
572  }
573  if (*s == ']')
574  break;
575  }
576  eoption = s;
577  if (*option != '$')
578  {
579  // Locale
580  if (locale) {
581  fprintf(stderr, "Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
582  goto sktoeol;
583  }
584  locale = option;
585  elocale = eoption;
586  }
587  else
588  {
589  // Option
590  while (option < eoption)
591  {
592  option++;
593  if ((*option == 'i') && !kde_kiosk_exception)
594  optionImmutable = true;
595  else if (*option == 'e')
596  optionExpand = true;
597  else if (*option == 'd')
598  {
599  optionDeleted = true;
600  goto haveeq;
601  }
602  else if (*option == ']')
603  break;
604  }
605  }
606  }
607  }
608  fprintf(stderr, "Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
609  continue;
610 
611  haveeq:
612  for (endOfKey--; ; endOfKey--)
613  {
614  if (endOfKey < startLine)
615  {
616  fprintf(stderr, "Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
617  goto sktoeol;
618  }
619  if (!isspace(*endOfKey))
620  break;
621  }
622 
623  const char *st = ++s;
624  while ((s < eof) && (*s != '\n')) s++; // Search till end of line / end of file
625 
626  if (locale) {
627  unsigned int cl = static_cast<unsigned int>(elocale - locale);
628  if ((ll != cl) || memcmp(locale, localeString.data(), ll))
629  {
630  // backward compatibility. C == en_US
631  if ( cl != 1 || ll != 5 || *locale != 'C' || memcmp(localeString.data(), "en_US", 5)) {
632  //cout<<"mismatched locale '"<<TQCString(locale, elocale-locale +1)<<"'"<<endl;
633  // We can ignore this one
634  if (!pWriteBackMap)
635  continue; // We just ignore it
636  // We just store it as is to be able to write it back later.
637  endOfKey = elocale;
638  locale = 0;
639  }
640  }
641  }
642 
643  // insert the key/value line
644  TQCString key(startLine, endOfKey - startLine + 2);
645  TQCString val = printableToString(st, s - st);
646  //tqDebug("found key '%s' with value '%s'", key.data(), val.data());
647 
648  if (TQString(key.data()) == "X-Ubuntu-Gettext-Domain") {
649  gettextDomain = val.data();
650  foundGettextDomain = true;
651  }
652 
653  KEntryKey aEntryKey(aCurrentGroup, decodeKey(key));
654  aEntryKey.bLocal = (locale != 0);
655  aEntryKey.bDefault = bDefault;
656 
657  KEntry aEntry;
658  aEntry.mValue = val;
659  aEntry.bGlobal = bGlobal;
660  aEntry.bImmutable = optionImmutable;
661  aEntry.bDeleted = optionDeleted;
662  aEntry.bExpand = optionExpand;
663  aEntry.bNLS = (locale != 0);
664 
665  if (pWriteBackMap) {
666  // don't insert into the config object but into the temporary
667  // scratchpad map
668  pWriteBackMap->insert(aEntryKey, aEntry);
669  } else {
670  // directly insert value into config object
671  // no need to specify localization; if the key we just
672  // retrieved was localized already, no need to localize it again.
673  pConfig->putData(aEntryKey, aEntry, false);
674  }
675  }
676  // Look up translations using TDELocale
677  // https://launchpad.net/distros/ubuntu/+spec/langpacks-desktopfiles-kde
678  // This calls TDELocale up to 10 times for each config file (and each TDEConfig has up to 4 files)
679  // so I'll see how much of a performance hit it is
680  // it also only acts on the last group in a file
681  // Ideas: only translate most important fields, only translate "Desktop Entry" files,
682  // do translation per TDEConfig not per single file
683  if (!pWriteBackMap) {
684  TQFile file("file.txt");
685  if (foundGettextDomain) {
686 
687  TDELocale locale(gettextDomain);
688 
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"));
700  }
701  }
702 
703  if (fileOptionImmutable)
704  bFileImmutable = true;
705 }
706 
707 void TDEConfigINIBackEnd::translateKey(TDELocale& locale, TQCString currentGroup, TQCString key) {
708  KEntryKey entryKey = KEntryKey(currentGroup, key);
709  KEntry entry = pConfig->lookupData(entryKey);
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();
716  entryKey.bLocal = true;
717  entry.bNLS = true;
718  pConfig->putData(entryKey, entry, false);
719  }
720  }
721 }
722 
723 void TDEConfigINIBackEnd::sync(bool bMerge)
724 {
725  // write-sync is only necessary if there are dirty entries
726  if (!pConfig->isDirty())
727  return;
728 
729  bool bEntriesLeft = true;
730 
731  // find out the file to write to (most specific writable file)
732  // try local app-specific file first
733 
734  if (!mfileName.isEmpty()) {
735  // Create the containing dir if needed
736  if ((resType!="config") && !TQDir::isRelativePath(mLocalFileName))
737  {
738  KURL path;
739  path.setPath(mLocalFileName);
740  TQString dir=path.directory();
741  TDEStandardDirs::makeDir(dir);
742  }
743 
744  // Can we allow the write? We can, if the program
745  // doesn't run SUID. But if it runs SUID, we must
746  // check if the user would be allowed to write if
747  // it wasn't SUID.
748  if (checkAccess(mLocalFileName, W_OK)) {
749  // File is writable
750  TDELockFile::Ptr lf;
751 
752  bool mergeLocalFile = bMerge;
753  // Check if the file has been updated since.
754  if (mergeLocalFile)
755  {
756  lf = lockFile(false); // Lock file for local file
757  if (lf && lf->isLocked())
758  lf = 0; // Already locked, we don't need to lock/unlock again
759 
760  if (lf)
761  {
762  lf->lock( TDELockFile::LockForce );
763  // But what if the locking failed? Ignore it for now...
764  }
765 
766  TQFileInfo info(mLocalFileName);
767  if ((d->localLastSize == info.size()) &&
768  (d->localLastModified == info.lastModified()))
769  {
770  // Not changed, don't merge.
771  mergeLocalFile = false;
772  }
773  else
774  {
775  // Changed...
776  d->localLastModified = TQDateTime();
777  d->localLastSize = 0;
778  }
779  }
780 
781  bEntriesLeft = writeConfigFile( mLocalFileName, false, mergeLocalFile );
782 
783  // Only if we didn't have to merge anything can we use our in-memory state
784  // the next time around. Otherwise the config-file may contain entries
785  // that are different from our in-memory state which means we will have to
786  // do a merge from then on.
787  // We do not automatically update the in-memory state with the on-disk
788  // state when writing the config to disk. We only do so when
789  // KCOnfig::reparseConfiguration() is called.
790  // For KDE 4.0 we may wish to reconsider that.
791  if (!mergeLocalFile)
792  {
793  TQFileInfo info(mLocalFileName);
794  d->localLastModified = info.lastModified();
795  d->localLastSize = info.size();
796  }
797  if (lf) lf->unlock();
798  }
799  }
800 
801  // only write out entries to the kdeglobals file if there are any
802  // entries marked global (indicated by bEntriesLeft) and
803  // the useKDEGlobals flag is set.
804  if (bEntriesLeft && useKDEGlobals) {
805 
806  // can we allow the write? (see above)
807  if (checkAccess ( mGlobalFileName, W_OK )) {
808  TDELockFile::Ptr lf = lockFile(true); // Lock file for global file
809  if (lf && lf->isLocked())
810  lf = 0; // Already locked, we don't need to lock/unlock again
811 
812  if (lf)
813  {
814  lf->lock( TDELockFile::LockForce );
815  // But what if the locking failed? Ignore it for now...
816  }
817  writeConfigFile( mGlobalFileName, true, bMerge ); // Always merge
818  if (lf) lf->unlock();
819  }
820  }
821 
822 }
823 
824 static void writeEntries(FILE *pStream, const KEntryMap& entryMap, bool defaultGroup, bool &firstEntry, const TQCString &localeString)
825 {
826  // now write out all other groups.
827  TQCString currentGroup;
828  for (KEntryMapConstIterator aIt = entryMap.begin();
829  aIt != entryMap.end(); ++aIt)
830  {
831  const KEntryKey &key = aIt.key();
832 
833  // Either proces the default group or all others
834  if ((key.mGroup != "<default>") == defaultGroup)
835  continue; // Skip
836 
837  // Skip default values and group headers.
838  if ((key.bDefault) || key.mKey.isEmpty())
839  continue; // Skip
840 
841  const KEntry &currentEntry = *aIt;
842 
843  KEntryMapConstIterator aTestIt = aIt;
844  ++aTestIt;
845  bool hasDefault = (aTestIt != entryMap.end());
846  if (hasDefault)
847  {
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))
853  hasDefault = false;
854  }
855 
856 
857  if (hasDefault)
858  {
859  // Entry had a default value
860  if ((currentEntry.mValue == (*aTestIt).mValue) &&
861  (currentEntry.bDeleted == (*aTestIt).bDeleted))
862  continue; // Same as default, don't write.
863  }
864  else
865  {
866  // Entry had no default value.
867  if (currentEntry.bDeleted)
868  continue; // Don't write deleted entries if there is no default.
869  }
870 
871  if (!defaultGroup && (currentGroup != key.mGroup)) {
872  if (!firstEntry)
873  fprintf(pStream, "\n");
874  currentGroup = key.mGroup;
875  fprintf(pStream, "[%s]\n", encodeGroup(currentGroup).data());
876  }
877 
878  firstEntry = false;
879  // it is data for a group
880  fputs(encodeKey(key.mKey.data()), pStream); // Key
881 
882  if ( currentEntry.bNLS )
883  {
884  fputc('[', pStream);
885  fputs(localeString.data(), pStream);
886  fputc(']', pStream);
887  }
888 
889  if (currentEntry.bDeleted)
890  {
891  fputs("[$d]\n", pStream); // Deleted
892  }
893  else
894  {
895  if (currentEntry.bImmutable || currentEntry.bExpand)
896  {
897  fputc('[', pStream);
898  fputc('$', pStream);
899  if (currentEntry.bImmutable)
900  fputc('i', pStream);
901  if (currentEntry.bExpand)
902  fputc('e', pStream);
903 
904  fputc(']', pStream);
905  }
906  fputc('=', pStream);
907  fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
908  fputc('\n', pStream);
909  }
910  } // for loop
911 }
912 
913 bool TDEConfigINIBackEnd::getEntryMap(KEntryMap &aTempMap, bool bGlobal,
914  TQFile *mergeFile)
915 {
916  bool bEntriesLeft = false;
917  bFileImmutable = false;
918 
919  // Read entries from disk
920  if (mergeFile && mergeFile->open(IO_ReadOnly))
921  {
922  // fill the temporary structure with entries from the file
923  parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal, false );
924 
925  if (bFileImmutable) // File has become immutable on disk
926  return bEntriesLeft;
927  }
928 
929  KEntryMap aMap = pConfig->internalEntryMap();
930 
931  // augment this structure with the dirty entries from the config object
932  for (KEntryMapIterator aIt = aMap.begin();
933  aIt != aMap.end(); ++aIt)
934  {
935  const KEntry &currentEntry = *aIt;
936  if(aIt.key().bDefault)
937  {
938  aTempMap.replace(aIt.key(), currentEntry);
939  continue;
940  }
941 
942  if (mergeFile && !currentEntry.bDirty)
943  continue;
944 
945  // only write back entries that have the same
946  // "globality" as the file
947  if (currentEntry.bGlobal != bGlobal)
948  {
949  // wrong "globality" - might have to be saved later
950  bEntriesLeft = true;
951  continue;
952  }
953 
954  // put this entry from the config object into the
955  // temporary map, possibly replacing an existing entry
956  KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
957  if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
958  continue; // Bail out if the on-disk entry is immutable
959 
960  aTempMap.insert(aIt.key(), currentEntry, true);
961  } // loop
962 
963  return bEntriesLeft;
964 }
965 
966 /* antlarr: KDE 4.0: make the first parameter "const TQString &" */
967 bool TDEConfigINIBackEnd::writeConfigFile(TQString filename, bool bGlobal,
968  bool bMerge)
969 {
970  // is the config object read-only?
971  if (pConfig->isReadOnly())
972  return true; // pretend we wrote it
973 
974  KEntryMap aTempMap;
975  TQFile *mergeFile = (bMerge ? new TQFile(filename) : 0);
976  bool bEntriesLeft = getEntryMap(aTempMap, bGlobal, mergeFile);
977  delete mergeFile;
978  if (bFileImmutable)
979  return true; // pretend we wrote it
980 
981  // OK now the temporary map should be full of ALL entries.
982  // write it out to disk.
983 
984  // Check if file exists:
985  int fileMode = -1;
986  bool createNew = true;
987 
988  KDE_struct_stat buf;
989  if (KDE_stat(TQFile::encodeName(filename), &buf) == 0)
990  {
991  if (buf.st_uid == getuid())
992  {
993  // Preserve file mode if file exists and is owned by user.
994  fileMode = buf.st_mode & 0777;
995  }
996  else
997  {
998  // File is not owned by user:
999  // Don't create new file but write to existing file instead.
1000  createNew = false;
1001  }
1002  }
1003 
1004  KSaveFile *pConfigFile = 0;
1005  FILE *pStream = 0;
1006 
1007  if (createNew)
1008  {
1009  pConfigFile = new KSaveFile( filename, 0600 );
1010 
1011  if (pConfigFile->status() != 0)
1012  {
1013  delete pConfigFile;
1014  return bEntriesLeft;
1015  }
1016 
1017  if (!bGlobal && (fileMode == -1))
1018  fileMode = mFileMode;
1019 
1020  if (fileMode != -1)
1021  {
1022  fchmod(pConfigFile->handle(), fileMode);
1023  }
1024 
1025  pStream = pConfigFile->fstream();
1026  }
1027  else
1028  {
1029  // Open existing file.
1030  // We use open() to ensure that we call without O_CREAT.
1031  int fd = KDE_open( TQFile::encodeName(filename), O_WRONLY | O_TRUNC );
1032  if (fd < 0)
1033  {
1034  return bEntriesLeft;
1035  }
1036  pStream = KDE_fdopen( fd, "w");
1037  if (!pStream)
1038  {
1039  close(fd);
1040  return bEntriesLeft;
1041  }
1042  }
1043 
1044  writeEntries(pStream, aTempMap);
1045 
1046  if (pConfigFile)
1047  {
1048  bool bEmptyFile = (ftell(pStream) == 0);
1049  if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
1050  {
1051  // File is empty and doesn't have special permissions: delete it.
1052  ::unlink(TQFile::encodeName(filename));
1053  pConfigFile->abort();
1054  }
1055  else
1056  {
1057  // Normal case: Close the file
1058  pConfigFile->close();
1059  }
1060  delete pConfigFile;
1061  }
1062  else
1063  {
1064  fclose(pStream);
1065  }
1066 
1067  return bEntriesLeft;
1068 }
1069 
1070 void TDEConfigINIBackEnd::writeEntries(FILE *pStream, const KEntryMap &aTempMap)
1071 {
1072  bool firstEntry = true;
1073 
1074  // Write default group
1075  ::writeEntries(pStream, aTempMap, true, firstEntry, localeString);
1076 
1077  // Write all other groups
1078  ::writeEntries(pStream, aTempMap, false, firstEntry, localeString);
1079 }
1080 
1081 void TDEConfigBackEnd::virtual_hook( int, void* )
1082 { /*BASE::virtual_hook( id, data );*/ }
1083 
1084 void TDEConfigINIBackEnd::virtual_hook( int id, void* data )
1085 { TDEConfigBackEnd::virtual_hook( id, data ); }
1086 
1087 bool TDEConfigBackEnd::checkConfigFilesWritable(bool warnUser)
1088 {
1089  // WARNING: Do NOT use the event loop as it may not exist at this time.
1090  bool allWritable = true;
1091  TQString errorMsg;
1092  if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
1093  {
1094  errorMsg = i18n("Will not save configuration.\n");
1095  allWritable = false;
1096  errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
1097  }
1098  // We do not have an immutability flag for kdeglobals. However, making kdeglobals mutable while making
1099  // the local config file immutable is senseless.
1100  if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
1101  {
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;
1106  }
1107 
1108  if (warnUser && !allWritable)
1109  {
1110  // Note: We don't ask the user if we should not ask this question again because we can't save the answer.
1111  errorMsg += i18n("Please contact your system administrator.");
1112  TQString cmdToExec = TDEStandardDirs::findExe(TQString("kdialog"));
1113  TDEApplication *app = kapp;
1114  if (!cmdToExec.isEmpty() && app)
1115  {
1116  TDEProcess lprocess;
1117  lprocess << cmdToExec << "--title" << app->instanceName() << "--msgbox" << TQCString(errorMsg.local8Bit());
1118  lprocess.start( TDEProcess::Block );
1119  }
1120  }
1121  return allWritable;
1122 }
KSaveFile
The KSaveFile class has been made to write out changes to an existing file atomically.
Definition: ksavefile.h:42
KSaveFile::status
int status() const
Returns the status of the file based on errno.
Definition: ksavefile.h:68
KSaveFile::fstream
FILE * fstream()
A FILE* stream open for writing to the file.
Definition: ksavefile.h:91
KSaveFile::close
bool close()
Closes the file and makes the changes definitive.
Definition: ksavefile.cpp:107
KSaveFile::abort
void abort()
Aborts the write operation and removes any intermediate files This implies a close.
Definition: ksavefile.cpp:100
KSaveFile::handle
int handle() const
An integer file descriptor open for writing to the file.
Definition: ksavefile.h:83
KURL
Represents and parses a URL.
Definition: kurl.h:128
KURL::directory
TQString directory(bool _strip_trailing_slash_from_result=true, bool _ignore_trailing_slash_in_path=true) const
Returns the directory of the path.
Definition: kurl.cpp:1801
KURL::setPath
void setPath(const TQString &path)
Sets the decoded path of the URL.
Definition: kurl.cpp:2025
TDEApplication
Controls and provides information to all KDE applications.
Definition: tdeapplication.h:95
TDEConfigBackEnd::lockFile
TDELockFile::Ptr lockFile(bool bGlobal=false)
Returns a lock file object for the configuration file.
Definition: tdeconfigbackend.cpp:273
TDEConfigBackEnd::setLocaleString
void setLocaleString(const TQCString &_localeString)
Set the locale string that defines the current language.
Definition: tdeconfigbackend.h:133
TDEConfigBackEnd::TDEConfigBackEnd
TDEConfigBackEnd(TDEConfigBase *_config, const TQString &_fileName, const char *_resType, bool _useKDEGlobals)
Constructs a configuration back end.
Definition: tdeconfigbackend.cpp:300
TDEConfigBackEnd::checkConfigFilesWritable
bool checkConfigFilesWritable(bool warnUser)
Check whether the config files are writable.
Definition: tdeconfigbackend.cpp:1087
TDEConfigBackEnd::~TDEConfigBackEnd
virtual ~TDEConfigBackEnd()
Destructs the configuration backend.
Definition: tdeconfigbackend.cpp:310
TDEConfigBackEnd::filename
TDE_DEPRECATED TQString filename() const
Definition: tdeconfigbackend.h:162
TDEConfigBackEnd::setFileWriteMode
void setFileWriteMode(int mode)
Set the file mode for newly created files.
Definition: tdeconfigbackend.cpp:315
TDEConfigBackEnd::changeFileName
void changeFileName(const TQString &_fileName, const char *_resType, bool _useKDEGlobals)
Changes the filenames associated with this back end.
Definition: tdeconfigbackend.cpp:243
TDEConfigBase
KDE Configuration Management abstract base class.
Definition: tdeconfigbase.h:71
TDEConfigBase::lookupData
virtual KEntry lookupData(const KEntryKey &_key) const =0
Looks up an entry in the config object's internal structure.
TDEConfigBase::isReadOnly
bool isReadOnly() const
Returns the read-only status of the config object.
Definition: tdeconfigbase.h:1762
TDEConfigBase::putData
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.
TDEConfigBase::isDirty
bool isDirty() const
Checks whether the config file has any dirty (modified) entries.
Definition: tdeconfigbase.h:1746
TDEConfigBase::internalEntryMap
virtual KEntryMap internalEntryMap(const TQString &pGroup) const =0
Returns a map (tree) of the entries in the specified group.
TDEConfigINIBackEnd::writeEntries
void writeEntries(FILE *pStream, const KEntryMap &aTempMap)
Write the entries in aTempMap to the file stream.
Definition: tdeconfigbackend.cpp:1070
TDEConfigINIBackEnd::sync
virtual void sync(bool bMerge=true)
Writes configuration data to file(s).
Definition: tdeconfigbackend.cpp:723
TDEConfigINIBackEnd::parseConfigFiles
bool parseConfigFiles()
Parses all INI-style configuration files for a config object.
Definition: tdeconfigbackend.cpp:320
TDEConfigINIBackEnd::getEntryMap
bool getEntryMap(KEntryMap &map, bool bGlobal, TQFile *mergeFile)
Get the entry map.
Definition: tdeconfigbackend.cpp:913
TDEConfigINIBackEnd::parseSingleConfigFile
void parseSingleConfigFile(TQFile &rFile, KEntryMap *pWriteBackMap=0L, bool bGlobal=false, bool bDefault=false)
Parses one configuration file.
Definition: tdeconfigbackend.cpp:436
TDEConfigINIBackEnd::writeConfigFile
bool writeConfigFile(TQString filename, bool bGlobal=false, bool bMerge=true)
Writes configuration file back.
Definition: tdeconfigbackend.cpp:967
TDEGlobal::dirs
static TDEStandardDirs * dirs()
Returns the application standard dirs object.
Definition: tdeglobal.cpp:58
TDEGlobal::checkAccess
bool checkAccess(const TQString &pathname, int mode)
Check, if a file may be accessed in a given mode.
Definition: tdeapplication.cpp:3300
TDEInstance::instanceName
TQCString instanceName() const
Returns the name of the instance.
Definition: tdeinstance.cpp:342
TDELocale
TDELocale provides support for country specific stuff like the national language.
Definition: tdelocale.h:124
TDELocale::language
TQString language() const
Returns the language used by this object.
Definition: tdelocale.cpp:553
TDELocale::translate
TQString translate(const char *index) const
Translates the string into the corresponding string in the national language, if available.
Definition: tdelocale.cpp:768
TDELockFile
The TDELockFile class provides NFS safe lockfiles.
Definition: klockfile.h:34
TDELockFile::LockForce
@ LockForce
Automatically remove a lock when a lock is detected that is stale for more than staleTime() seconds.
Definition: klockfile.h:80
TDELockFile::isLocked
bool isLocked() const
Returns whether the lock is held or not.
Definition: klockfile.cpp:354
TDELockFile::unlock
void unlock()
Release the lock.
Definition: klockfile.cpp:359
TDELockFile::lock
LockResult lock(int options=0)
Attempt to acquire the lock.
Definition: klockfile.cpp:240
TDEProcess
Child process invocation, monitoring and control.
Definition: kprocess.h:131
TDEProcess::start
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
Definition: kprocess.cpp:289
TDEProcess::Block
@ Block
The application is suspended until the started process is finished.
Definition: kprocess.h:182
TDESharedPtr< TDELockFile >
TDEStandardDirs::saveLocation
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.
Definition: kstandarddirs.cpp:1099
TDEStandardDirs::findExe
static TQString findExe(const TQString &appname, const TQString &pathstr=TQString::null, bool ignoreExecBit=false)
Finds the executable in the system path.
Definition: kstandarddirs.cpp:932
TDEStandardDirs::makeDir
static bool makeDir(const TQString &dir, int mode=0755)
Recursively creates still-missing directories in the given path.
Definition: kstandarddirs.cpp:1176
TDEStandardDirs::findAllResources
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.
Definition: kstandarddirs.cpp:679
TDEStdAccel::key
int key(StdAccel id)
Definition: tdestdaccel.cpp:383
KEntryKey
key structure holding both the actual key and the the group to which it belongs.
Definition: tdeconfigdata.h:70
KEntryKey::bDefault
bool bDefault
Entry indicates if this is a default value.
Definition: tdeconfigdata.h:90
KEntryKey::bLocal
bool bLocal
Entry is localised or not.
Definition: tdeconfigdata.h:86
KEntry
map/dict/list config node entry.
Definition: tdeconfigdata.h:33
KEntry::bImmutable
bool bImmutable
Entry can not be modified.
Definition: tdeconfigdata.h:53
KEntry::bNLS
bool bNLS
Entry should be written with locale tag.
Definition: tdeconfigdata.h:45
KEntry::KEntryMapConstIterator
TQMap< KEntryKey, KEntry >::ConstIterator KEntryMapConstIterator
type for iterating over keys in a KEntryMap in sorted order.
Definition: tdeconfigdata.h:144
KEntry::bGlobal
bool bGlobal
Entry should be written to the global config file.
Definition: tdeconfigdata.h:49
KEntry::bExpand
bool bExpand
Whether to apply dollar expansion or not.
Definition: tdeconfigdata.h:61
KEntry::bDirty
bool bDirty
Must the entry be written back to disk?
Definition: tdeconfigdata.h:41
KEntry::KEntryMap
TQMap< KEntryKey, KEntry > KEntryMap
type specifying a map of entries (key,value pairs).
Definition: tdeconfigdata.h:128
KEntry::bDeleted
bool bDeleted
Entry has been deleted.
Definition: tdeconfigdata.h:57
tdelocale.h

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.1
This website is maintained by Timothy Pearson.