• 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 Q_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 #ifdef HAVE_MMAP
435 #ifdef SIGBUS
436 static sigjmp_buf mmap_jmpbuf;
437 struct sigaction mmap_old_sigact;
438 
439 extern "C" {
440  static void mmap_sigbus_handler(int)
441  {
442  siglongjmp (mmap_jmpbuf, 1);
443  }
444 }
445 #endif
446 #endif
447 
448 extern bool kde_kiosk_exception;
449 
450 void TDEConfigINIBackEnd::parseSingleConfigFile(TQFile &rFile,
451  KEntryMap *pWriteBackMap,
452  bool bGlobal, bool bDefault)
453 {
454  const char *s; // May get clobbered by sigsetjump, but we don't use them afterwards.
455  const char *eof; // May get clobbered by sigsetjump, but we don't use them afterwards.
456  TQByteArray data;
457 
458  if (!rFile.isOpen()) // come back, if you have real work for us ;->
459  return;
460 
461  //using kdDebug() here leads to an infinite loop
462  //remove this for the release, aleXXX
463  //tqWarning("Parsing %s, global = %s default = %s",
464  // rFile.name().latin1(), bGlobal ? "true" : "false", bDefault ? "true" : "false");
465 
466  TQCString aCurrentGroup("<default>");
467 
468  unsigned int ll = localeString.length();
469 
470 #ifdef HAVE_MMAP
471  static volatile const char *map;
472  map = ( const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
473  rFile.handle(), 0);
474 
475  if ( map != MAP_FAILED )
476  {
477  s = (const char*) map;
478  eof = s + rFile.size();
479 
480 #ifdef SIGBUS
481  struct sigaction act;
482  act.sa_handler = mmap_sigbus_handler;
483  sigemptyset( &act.sa_mask );
484 #ifdef SA_ONESHOT
485  act.sa_flags = SA_ONESHOT;
486 #else
487  act.sa_flags = SA_RESETHAND;
488 #endif
489  sigaction( SIGBUS, &act, &mmap_old_sigact );
490 
491  if (sigsetjmp (mmap_jmpbuf, 1))
492  {
493 tqWarning("SIGBUS while reading %s", rFile.name().latin1());
494  munmap(( char* )map, rFile.size());
495  sigaction (SIGBUS, &mmap_old_sigact, 0);
496  return;
497  }
498 #endif
499  }
500  else
501 #endif
502  {
503  rFile.at(0);
504  data = rFile.readAll();
505  s = data.data();
506  eof = s + data.size();
507  }
508 
509  bool fileOptionImmutable = false;
510  bool groupOptionImmutable = false;
511  bool groupSkip = false;
512  bool foundGettextDomain = false;
513  TQCString gettextDomain;
514 
515  int line = 0;
516  for(; s < eof; s++)
517  {
518  line++;
519 
520  while((s < eof) && isspace(*s) && (*s != '\n'))
521  s++; //skip leading whitespace, shouldn't happen too often
522 
523  //skip empty lines, lines starting with #
524  if ((s < eof) && ((*s == '\n') || (*s == '#')))
525  {
526  sktoeol: //skip till end-of-line
527  while ((s < eof) && (*s != '\n'))
528  s++;
529  continue; // Empty or comment or no keyword
530  }
531  const char *startLine = s;
532 
533  if (*s == '[') //group
534  {
535  // In a group [[ and ]] have a special meaning
536  while ((s < eof) && (*s != '\n'))
537  {
538  if (*s == ']')
539  {
540  if ((s+1 < eof) && (*(s+1) == ']'))
541  s++; // Skip "]]"
542  else
543  break;
544  }
545 
546  s++; // Search till end of group
547  }
548  const char *e = s;
549  while ((s < eof) && (*s != '\n')) s++; // Search till end of line / end of file
550  if ((e >= eof) || (*e != ']'))
551  {
552  fprintf(stderr, "Invalid group header at %s:%d\n", rFile.name().latin1(), line);
553  continue;
554  }
555  // group found; get the group name by taking everything in
556  // between the brackets
557  if ((e-startLine == 3) &&
558  (startLine[1] == '$') &&
559  (startLine[2] == 'i'))
560  {
561  if (!kde_kiosk_exception)
562  fileOptionImmutable = true;
563  continue;
564  }
565 
566  aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
567  //cout<<"found group ["<<aCurrentGroup<<"]"<<endl;
568 
569  // Backwards compatibility
570  if (aCurrentGroup == "KDE Desktop Entry")
571  aCurrentGroup = "Desktop Entry";
572 
573  groupOptionImmutable = fileOptionImmutable;
574 
575  e++;
576  if ((e+2 < eof) && (*e++ == '[') && (*e++ == '$')) // Option follows
577  {
578  if ((*e == 'i') && !kde_kiosk_exception)
579  {
580  groupOptionImmutable = true;
581  }
582  }
583 
584  KEntryKey groupKey(aCurrentGroup, 0);
585  KEntry entry = pConfig->lookupData(groupKey);
586  groupSkip = entry.bImmutable;
587 
588  if (groupSkip && !bDefault)
589  continue;
590 
591  entry.bImmutable |= groupOptionImmutable;
592  pConfig->putData(groupKey, entry, false);
593 
594  if (pWriteBackMap)
595  {
596  // add the special group key indicator
597  (*pWriteBackMap)[groupKey] = entry;
598  }
599 
600  continue;
601  }
602  if (groupSkip && !bDefault)
603  goto sktoeol; // Skip entry
604 
605 
606  bool optionImmutable = groupOptionImmutable;
607  bool optionDeleted = false;
608  bool optionExpand = false;
609  const char *endOfKey = 0, *locale = 0, *elocale = 0;
610  for (; (s < eof) && (*s != '\n'); s++)
611  {
612  if (*s == '=') //find the equal sign
613  {
614  if (!endOfKey)
615  endOfKey = s;
616  goto haveeq;
617  }
618  if (*s == '[') //find the locale or options.
619  {
620  const char *option;
621  const char *eoption;
622  endOfKey = s;
623  option = ++s;
624  for (;; s++)
625  {
626  if ((s >= eof) || (*s == '\n') || (*s == '=')) {
627  fprintf(stderr, "Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
628  goto sktoeol;
629  }
630  if (*s == ']')
631  break;
632  }
633  eoption = s;
634  if (*option != '$')
635  {
636  // Locale
637  if (locale) {
638  fprintf(stderr, "Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
639  goto sktoeol;
640  }
641  locale = option;
642  elocale = eoption;
643  }
644  else
645  {
646  // Option
647  while (option < eoption)
648  {
649  option++;
650  if ((*option == 'i') && !kde_kiosk_exception)
651  optionImmutable = true;
652  else if (*option == 'e')
653  optionExpand = true;
654  else if (*option == 'd')
655  {
656  optionDeleted = true;
657  goto haveeq;
658  }
659  else if (*option == ']')
660  break;
661  }
662  }
663  }
664  }
665  fprintf(stderr, "Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
666  continue;
667 
668  haveeq:
669  for (endOfKey--; ; endOfKey--)
670  {
671  if (endOfKey < startLine)
672  {
673  fprintf(stderr, "Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
674  goto sktoeol;
675  }
676  if (!isspace(*endOfKey))
677  break;
678  }
679 
680  const char *st = ++s;
681  while ((s < eof) && (*s != '\n')) s++; // Search till end of line / end of file
682 
683  if (locale) {
684  unsigned int cl = static_cast<unsigned int>(elocale - locale);
685  if ((ll != cl) || memcmp(locale, localeString.data(), ll))
686  {
687  // backward compatibility. C == en_US
688  if ( cl != 1 || ll != 5 || *locale != 'C' || memcmp(localeString.data(), "en_US", 5)) {
689  //cout<<"mismatched locale '"<<TQCString(locale, elocale-locale +1)<<"'"<<endl;
690  // We can ignore this one
691  if (!pWriteBackMap)
692  continue; // We just ignore it
693  // We just store it as is to be able to write it back later.
694  endOfKey = elocale;
695  locale = 0;
696  }
697  }
698  }
699 
700  // insert the key/value line
701  TQCString key(startLine, endOfKey - startLine + 2);
702  TQCString val = printableToString(st, s - st);
703  //tqDebug("found key '%s' with value '%s'", key.data(), val.data());
704 
705  if (TQString(key.data()) == "X-Ubuntu-Gettext-Domain") {
706  gettextDomain = val.data();
707  foundGettextDomain = true;
708  }
709 
710  KEntryKey aEntryKey(aCurrentGroup, decodeKey(key));
711  aEntryKey.bLocal = (locale != 0);
712  aEntryKey.bDefault = bDefault;
713 
714  KEntry aEntry;
715  aEntry.mValue = val;
716  aEntry.bGlobal = bGlobal;
717  aEntry.bImmutable = optionImmutable;
718  aEntry.bDeleted = optionDeleted;
719  aEntry.bExpand = optionExpand;
720  aEntry.bNLS = (locale != 0);
721 
722  if (pWriteBackMap) {
723  // don't insert into the config object but into the temporary
724  // scratchpad map
725  pWriteBackMap->insert(aEntryKey, aEntry);
726  } else {
727  // directly insert value into config object
728  // no need to specify localization; if the key we just
729  // retrieved was localized already, no need to localize it again.
730  pConfig->putData(aEntryKey, aEntry, false);
731  }
732  }
733  // Look up translations using TDELocale
734  // https://launchpad.net/distros/ubuntu/+spec/langpacks-desktopfiles-kde
735  // This calls TDELocale up to 10 times for each config file (and each TDEConfig has up to 4 files)
736  // so I'll see how much of a performance hit it is
737  // it also only acts on the last group in a file
738  // Ideas: only translate most important fields, only translate "Desktop Entry" files,
739  // do translation per TDEConfig not per single file
740  if (!pWriteBackMap) {
741  TQFile file("file.txt");
742  if (foundGettextDomain) {
743 
744  TDELocale locale(gettextDomain);
745 
746  TQString language = locale.language();
747  translateKey(locale, aCurrentGroup, TQCString("Name"));
748  translateKey(locale, aCurrentGroup, TQCString("Comment"));
749  translateKey(locale, aCurrentGroup, TQCString("Language"));
750  translateKey(locale, aCurrentGroup, TQCString("Keywords"));
751  translateKey(locale, aCurrentGroup, TQCString("About"));
752  translateKey(locale, aCurrentGroup, TQCString("Description"));
753  translateKey(locale, aCurrentGroup, TQCString("GenericName"));
754  translateKey(locale, aCurrentGroup, TQCString("Query"));
755  translateKey(locale, aCurrentGroup, TQCString("ExtraNames"));
756  translateKey(locale, aCurrentGroup, TQCString("X-TDE-Submenu"));
757  }
758  }
759 
760 
761  if (fileOptionImmutable)
762  bFileImmutable = true;
763 
764 #ifdef HAVE_MMAP
765  if (map)
766  {
767  munmap(( char* )map, rFile.size());
768 #ifdef SIGBUS
769  sigaction (SIGBUS, &mmap_old_sigact, 0);
770 #endif
771  }
772 #endif
773 }
774 
775 void TDEConfigINIBackEnd::translateKey(TDELocale& locale, TQCString currentGroup, TQCString key) {
776  KEntryKey entryKey = KEntryKey(currentGroup, key);
777  KEntry entry = pConfig->lookupData(entryKey);
778  if (TQString(entry.mValue) != "") {
779  TQString orig = key + "=" + entry.mValue;
780  TQString translate = locale.translate(key + "=" + entry.mValue);
781  if (TQString::compare(orig, translate) != 0) {
782  translate = translate.mid(key.length() + 1);
783  entry.mValue = translate.utf8();
784  entryKey.bLocal = true;
785  entry.bNLS = true;
786  pConfig->putData(entryKey, entry, false);
787  }
788  }
789 }
790 
791 void TDEConfigINIBackEnd::sync(bool bMerge)
792 {
793  // write-sync is only necessary if there are dirty entries
794  if (!pConfig->isDirty())
795  return;
796 
797  bool bEntriesLeft = true;
798 
799  // find out the file to write to (most specific writable file)
800  // try local app-specific file first
801 
802  if (!mfileName.isEmpty()) {
803  // Create the containing dir if needed
804  if ((resType!="config") && !TQDir::isRelativePath(mLocalFileName))
805  {
806  KURL path;
807  path.setPath(mLocalFileName);
808  TQString dir=path.directory();
809  TDEStandardDirs::makeDir(dir);
810  }
811 
812  // Can we allow the write? We can, if the program
813  // doesn't run SUID. But if it runs SUID, we must
814  // check if the user would be allowed to write if
815  // it wasn't SUID.
816  if (checkAccess(mLocalFileName, W_OK)) {
817  // File is writable
818  TDELockFile::Ptr lf;
819 
820  bool mergeLocalFile = bMerge;
821  // Check if the file has been updated since.
822  if (mergeLocalFile)
823  {
824  lf = lockFile(false); // Lock file for local file
825  if (lf && lf->isLocked())
826  lf = 0; // Already locked, we don't need to lock/unlock again
827 
828  if (lf)
829  {
830  lf->lock( TDELockFile::LockForce );
831  // But what if the locking failed? Ignore it for now...
832  }
833 
834  TQFileInfo info(mLocalFileName);
835  if ((d->localLastSize == info.size()) &&
836  (d->localLastModified == info.lastModified()))
837  {
838  // Not changed, don't merge.
839  mergeLocalFile = false;
840  }
841  else
842  {
843  // Changed...
844  d->localLastModified = TQDateTime();
845  d->localLastSize = 0;
846  }
847  }
848 
849  bEntriesLeft = writeConfigFile( mLocalFileName, false, mergeLocalFile );
850 
851  // Only if we didn't have to merge anything can we use our in-memory state
852  // the next time around. Otherwise the config-file may contain entries
853  // that are different from our in-memory state which means we will have to
854  // do a merge from then on.
855  // We do not automatically update the in-memory state with the on-disk
856  // state when writing the config to disk. We only do so when
857  // KCOnfig::reparseConfiguration() is called.
858  // For KDE 4.0 we may wish to reconsider that.
859  if (!mergeLocalFile)
860  {
861  TQFileInfo info(mLocalFileName);
862  d->localLastModified = info.lastModified();
863  d->localLastSize = info.size();
864  }
865  if (lf) lf->unlock();
866  }
867  }
868 
869  // only write out entries to the kdeglobals file if there are any
870  // entries marked global (indicated by bEntriesLeft) and
871  // the useKDEGlobals flag is set.
872  if (bEntriesLeft && useKDEGlobals) {
873 
874  // can we allow the write? (see above)
875  if (checkAccess ( mGlobalFileName, W_OK )) {
876  TDELockFile::Ptr lf = lockFile(true); // Lock file for global file
877  if (lf && lf->isLocked())
878  lf = 0; // Already locked, we don't need to lock/unlock again
879 
880  if (lf)
881  {
882  lf->lock( TDELockFile::LockForce );
883  // But what if the locking failed? Ignore it for now...
884  }
885  writeConfigFile( mGlobalFileName, true, bMerge ); // Always merge
886  if (lf) lf->unlock();
887  }
888  }
889 
890 }
891 
892 static void writeEntries(FILE *pStream, const KEntryMap& entryMap, bool defaultGroup, bool &firstEntry, const TQCString &localeString)
893 {
894  // now write out all other groups.
895  TQCString currentGroup;
896  for (KEntryMapConstIterator aIt = entryMap.begin();
897  aIt != entryMap.end(); ++aIt)
898  {
899  const KEntryKey &key = aIt.key();
900 
901  // Either proces the default group or all others
902  if ((key.mGroup != "<default>") == defaultGroup)
903  continue; // Skip
904 
905  // Skip default values and group headers.
906  if ((key.bDefault) || key.mKey.isEmpty())
907  continue; // Skip
908 
909  const KEntry &currentEntry = *aIt;
910 
911  KEntryMapConstIterator aTestIt = aIt;
912  ++aTestIt;
913  bool hasDefault = (aTestIt != entryMap.end());
914  if (hasDefault)
915  {
916  const KEntryKey &defaultKey = aTestIt.key();
917  if ((!defaultKey.bDefault) ||
918  (defaultKey.mKey != key.mKey) ||
919  (defaultKey.mGroup != key.mGroup) ||
920  (defaultKey.bLocal != key.bLocal))
921  hasDefault = false;
922  }
923 
924 
925  if (hasDefault)
926  {
927  // Entry had a default value
928  if ((currentEntry.mValue == (*aTestIt).mValue) &&
929  (currentEntry.bDeleted == (*aTestIt).bDeleted))
930  continue; // Same as default, don't write.
931  }
932  else
933  {
934  // Entry had no default value.
935  if (currentEntry.bDeleted)
936  continue; // Don't write deleted entries if there is no default.
937  }
938 
939  if (!defaultGroup && (currentGroup != key.mGroup)) {
940  if (!firstEntry)
941  fprintf(pStream, "\n");
942  currentGroup = key.mGroup;
943  fprintf(pStream, "[%s]\n", encodeGroup(currentGroup).data());
944  }
945 
946  firstEntry = false;
947  // it is data for a group
948  fputs(encodeKey(key.mKey.data()), pStream); // Key
949 
950  if ( currentEntry.bNLS )
951  {
952  fputc('[', pStream);
953  fputs(localeString.data(), pStream);
954  fputc(']', pStream);
955  }
956 
957  if (currentEntry.bDeleted)
958  {
959  fputs("[$d]\n", pStream); // Deleted
960  }
961  else
962  {
963  if (currentEntry.bImmutable || currentEntry.bExpand)
964  {
965  fputc('[', pStream);
966  fputc('$', pStream);
967  if (currentEntry.bImmutable)
968  fputc('i', pStream);
969  if (currentEntry.bExpand)
970  fputc('e', pStream);
971 
972  fputc(']', pStream);
973  }
974  fputc('=', pStream);
975  fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
976  fputc('\n', pStream);
977  }
978  } // for loop
979 }
980 
981 bool TDEConfigINIBackEnd::getEntryMap(KEntryMap &aTempMap, bool bGlobal,
982  TQFile *mergeFile)
983 {
984  bool bEntriesLeft = false;
985  bFileImmutable = false;
986 
987  // Read entries from disk
988  if (mergeFile && mergeFile->open(IO_ReadOnly))
989  {
990  // fill the temporary structure with entries from the file
991  parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal, false );
992 
993  if (bFileImmutable) // File has become immutable on disk
994  return bEntriesLeft;
995  }
996 
997  KEntryMap aMap = pConfig->internalEntryMap();
998 
999  // augment this structure with the dirty entries from the config object
1000  for (KEntryMapIterator aIt = aMap.begin();
1001  aIt != aMap.end(); ++aIt)
1002  {
1003  const KEntry &currentEntry = *aIt;
1004  if(aIt.key().bDefault)
1005  {
1006  aTempMap.replace(aIt.key(), currentEntry);
1007  continue;
1008  }
1009 
1010  if (mergeFile && !currentEntry.bDirty)
1011  continue;
1012 
1013  // only write back entries that have the same
1014  // "globality" as the file
1015  if (currentEntry.bGlobal != bGlobal)
1016  {
1017  // wrong "globality" - might have to be saved later
1018  bEntriesLeft = true;
1019  continue;
1020  }
1021 
1022  // put this entry from the config object into the
1023  // temporary map, possibly replacing an existing entry
1024  KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
1025  if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
1026  continue; // Bail out if the on-disk entry is immutable
1027 
1028  aTempMap.insert(aIt.key(), currentEntry, true);
1029  } // loop
1030 
1031  return bEntriesLeft;
1032 }
1033 
1034 /* antlarr: KDE 4.0: make the first parameter "const TQString &" */
1035 bool TDEConfigINIBackEnd::writeConfigFile(TQString filename, bool bGlobal,
1036  bool bMerge)
1037 {
1038  // is the config object read-only?
1039  if (pConfig->isReadOnly())
1040  return true; // pretend we wrote it
1041 
1042  KEntryMap aTempMap;
1043  TQFile *mergeFile = (bMerge ? new TQFile(filename) : 0);
1044  bool bEntriesLeft = getEntryMap(aTempMap, bGlobal, mergeFile);
1045  delete mergeFile;
1046  if (bFileImmutable)
1047  return true; // pretend we wrote it
1048 
1049  // OK now the temporary map should be full of ALL entries.
1050  // write it out to disk.
1051 
1052  // Check if file exists:
1053  int fileMode = -1;
1054  bool createNew = true;
1055 
1056  KDE_struct_stat buf;
1057  if (KDE_stat(TQFile::encodeName(filename), &buf) == 0)
1058  {
1059  if (buf.st_uid == getuid())
1060  {
1061  // Preserve file mode if file exists and is owned by user.
1062  fileMode = buf.st_mode & 0777;
1063  }
1064  else
1065  {
1066  // File is not owned by user:
1067  // Don't create new file but write to existing file instead.
1068  createNew = false;
1069  }
1070  }
1071 
1072  KSaveFile *pConfigFile = 0;
1073  FILE *pStream = 0;
1074 
1075  if (createNew)
1076  {
1077  pConfigFile = new KSaveFile( filename, 0600 );
1078 
1079  if (pConfigFile->status() != 0)
1080  {
1081  delete pConfigFile;
1082  return bEntriesLeft;
1083  }
1084 
1085  if (!bGlobal && (fileMode == -1))
1086  fileMode = mFileMode;
1087 
1088  if (fileMode != -1)
1089  {
1090  fchmod(pConfigFile->handle(), fileMode);
1091  }
1092 
1093  pStream = pConfigFile->fstream();
1094  }
1095  else
1096  {
1097  // Open existing file.
1098  // We use open() to ensure that we call without O_CREAT.
1099  int fd = KDE_open( TQFile::encodeName(filename), O_WRONLY | O_TRUNC );
1100  if (fd < 0)
1101  {
1102  return bEntriesLeft;
1103  }
1104  pStream = KDE_fdopen( fd, "w");
1105  if (!pStream)
1106  {
1107  close(fd);
1108  return bEntriesLeft;
1109  }
1110  }
1111 
1112  writeEntries(pStream, aTempMap);
1113 
1114  if (pConfigFile)
1115  {
1116  bool bEmptyFile = (ftell(pStream) == 0);
1117  if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
1118  {
1119  // File is empty and doesn't have special permissions: delete it.
1120  ::unlink(TQFile::encodeName(filename));
1121  pConfigFile->abort();
1122  }
1123  else
1124  {
1125  // Normal case: Close the file
1126  pConfigFile->close();
1127  }
1128  delete pConfigFile;
1129  }
1130  else
1131  {
1132  fclose(pStream);
1133  }
1134 
1135  return bEntriesLeft;
1136 }
1137 
1138 void TDEConfigINIBackEnd::writeEntries(FILE *pStream, const KEntryMap &aTempMap)
1139 {
1140  bool firstEntry = true;
1141 
1142  // Write default group
1143  ::writeEntries(pStream, aTempMap, true, firstEntry, localeString);
1144 
1145  // Write all other groups
1146  ::writeEntries(pStream, aTempMap, false, firstEntry, localeString);
1147 }
1148 
1149 void TDEConfigBackEnd::virtual_hook( int, void* )
1150 { /*BASE::virtual_hook( id, data );*/ }
1151 
1152 void TDEConfigINIBackEnd::virtual_hook( int id, void* data )
1153 { TDEConfigBackEnd::virtual_hook( id, data ); }
1154 
1155 bool TDEConfigBackEnd::checkConfigFilesWritable(bool warnUser)
1156 {
1157  // WARNING: Do NOT use the event loop as it may not exist at this time.
1158  bool allWritable = true;
1159  TQString errorMsg;
1160  if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
1161  {
1162  errorMsg = i18n("Will not save configuration.\n");
1163  allWritable = false;
1164  errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
1165  }
1166  // We do not have an immutability flag for kdeglobals. However, making kdeglobals mutable while making
1167  // the local config file immutable is senseless.
1168  if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
1169  {
1170  if ( errorMsg.isEmpty() )
1171  errorMsg = i18n("Will not save configuration.\n");
1172  errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
1173  allWritable = false;
1174  }
1175 
1176  if (warnUser && !allWritable)
1177  {
1178  // Note: We don't ask the user if we should not ask this question again because we can't save the answer.
1179  errorMsg += i18n("Please contact your system administrator.");
1180  TQString cmdToExec = TDEStandardDirs::findExe(TQString("kdialog"));
1181  TDEApplication *app = kapp;
1182  if (!cmdToExec.isEmpty() && app)
1183  {
1184  TDEProcess lprocess;
1185  lprocess << cmdToExec << "--title" << app->instanceName() << "--msgbox" << TQCString(errorMsg.local8Bit());
1186  lprocess.start( TDEProcess::Block );
1187  }
1188  }
1189  return allWritable;
1190 }
KURL
Represents and parses a URL.
Definition: kurl.h:127
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...
KSaveFile::status
int status() const
Returns the status of the file based on errno.
Definition: ksavefile.h:68
KSaveFile::handle
int handle() const
An integer file descriptor open for writing to the file.
Definition: ksavefile.h:83
TDELocale::language
TQString language() const
Returns the language used by this object.
Definition: tdelocale.cpp:553
TDEConfigBackEnd::~TDEConfigBackEnd
virtual ~TDEConfigBackEnd()
Destructs the configuration backend.
Definition: tdeconfigbackend.cpp:310
KEntry::bDeleted
bool bDeleted
Entry has been deleted.
Definition: tdeconfigdata.h:57
KEntry
map/dict/list config node entry.
Definition: tdeconfigdata.h:32
TDEConfigINIBackEnd::writeConfigFile
bool writeConfigFile(TQString filename, bool bGlobal=false, bool bMerge=true)
Writes configuration file back.
Definition: tdeconfigbackend.cpp:1035
TDELockFile::isLocked
bool isLocked() const
Returns whether the lock is held or not.
Definition: klockfile.cpp:354
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
KEntryKey::bDefault
bool bDefault
Entry indicates if this is a default value.
Definition: tdeconfigdata.h:90
KSaveFile
The KSaveFile class has been made to write out changes to an existing file atomically.
Definition: ksavefile.h:41
TDEConfigINIBackEnd::parseConfigFiles
bool parseConfigFiles()
Parses all INI-style configuration files for a config object.
Definition: tdeconfigbackend.cpp:320
TDEProcess::start
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
Definition: kprocess.cpp:298
KSaveFile::abort
void abort()
Aborts the write operation and removes any intermediate files This implies a close.
Definition: ksavefile.cpp:100
TDELockFile::unlock
void unlock()
Release the lock.
Definition: klockfile.cpp:359
TDEApplication
Controls and provides information to all KDE applications.
Definition: tdeapplication.h:96
TDEProcess::Block
The application is suspended until the started process is finished.
Definition: kprocess.h:182
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
TDEConfigBackEnd::setFileWriteMode
void setFileWriteMode(int mode)
Set the file mode for newly created files.
Definition: tdeconfigbackend.cpp:315
KEntry::bImmutable
bool bImmutable
Entry can not be modified.
Definition: tdeconfigdata.h:53
TDEConfigBase
KDE Configuration Management abstract base class.
Definition: tdeconfigbase.h:70
KEntryKey
key structure holding both the actual key and the the group to which it belongs.
Definition: tdeconfigdata.h:69
TDEGlobal::dirs
static TDEStandardDirs * dirs()
Returns the application standard dirs object.
Definition: tdeglobal.cpp:58
tdelocale.h
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
KEntry::KEntryMapConstIterator
TQMap< KEntryKey, KEntry >::ConstIterator KEntryMapConstIterator
Definition: tdeconfigdata.h:144
TDELocale
TDELocale provides support for country specific stuff like the national language. ...
Definition: tdelocale.h:123
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
KURL::setPath
void setPath(const TQString &path)
Sets the decoded path of the URL.
Definition: kurl.cpp:2025
TDEGlobal::checkAccess
bool checkAccess(const TQString &pathname, int mode)
Definition: tdeapplication.cpp:3302
KEntryKey::bLocal
bool bLocal
Entry is localised or not.
Definition: tdeconfigdata.h:86
KEntry::KEntryMap
TQMap< KEntryKey, KEntry > KEntryMap
Definition: tdeconfigdata.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
TDEInstance::instanceName
TQCString instanceName() const
Returns the name of the instance.
Definition: kinstance.cpp:320
TDEConfigINIBackEnd::parseSingleConfigFile
void parseSingleConfigFile(TQFile &rFile, KEntryMap *pWriteBackMap=0L, bool bGlobal=false, bool bDefault=false)
Parses one configuration file.
Definition: tdeconfigbackend.cpp:450
TDEConfigINIBackEnd::getEntryMap
bool getEntryMap(KEntryMap &map, bool bGlobal, TQFile *mergeFile)
Get the entry map.
Definition: tdeconfigbackend.cpp:981
TDEConfigBackEnd::changeFileName
void changeFileName(const TQString &_fileName, const char *_resType, bool _useKDEGlobals)
Changes the filenames associated with this back end.
Definition: tdeconfigbackend.cpp:243
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
TDEConfigINIBackEnd::writeEntries
void writeEntries(FILE *pStream, const KEntryMap &aTempMap)
Write the entries in aTempMap to the file stream.
Definition: tdeconfigbackend.cpp:1138
KEntry::bGlobal
bool bGlobal
Entry should be written to the global config file.
Definition: tdeconfigdata.h:49
TDEConfigINIBackEnd::sync
virtual void sync(bool bMerge=true)
Writes configuration data to file(s).
Definition: tdeconfigbackend.cpp:791
TDELockFile
The TDELockFile class provides NFS safe lockfiles.
Definition: klockfile.h:33
TDEConfigBase::internalEntryMap
virtual KEntryMap internalEntryMap(const TQString &pGroup) const =0
Returns a map (tree) of the entries in the specified group.
TDEConfigBackEnd::checkConfigFilesWritable
bool checkConfigFilesWritable(bool warnUser)
Check whether the config files are writable.
Definition: tdeconfigbackend.cpp:1155
TDEConfigBase::isDirty
bool isDirty() const
Checks whether the config file has any dirty (modified) entries.
Definition: tdeconfigbase.h:1746
KEntry::bNLS
bool bNLS
Entry should be written with locale tag.
Definition: tdeconfigdata.h:45
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
TDEConfigBackEnd::lockFile
TDELockFile::Ptr lockFile(bool bGlobal=false)
Returns a lock file object for the configuration file.
Definition: tdeconfigbackend.cpp:273
TDEConfigBase::lookupData
virtual KEntry lookupData(const KEntryKey &_key) const =0
Looks up an entry in the config object's internal structure.
KEntryKey::mGroup
TQCString mGroup
The "group" to which this EntryKey belongs.
Definition: tdeconfigdata.h:78
TDEProcess
Child process invocation, monitoring and control.
Definition: kprocess.h:130
TDELockFile::lock
LockResult lock(int options=0)
Attempt to acquire the lock.
Definition: klockfile.cpp:240
TDELockFile::LockForce
Automatically remove a lock when a lock is detected that is stale for more than staleTime() seconds...
Definition: klockfile.h:80
TDESharedPtr< TDELockFile >
KEntry::bExpand
bool bExpand
Whether to apply dollar expansion or not.
Definition: tdeconfigdata.h:61
TDEConfigBase::isReadOnly
bool isReadOnly() const
Returns the read-only status of the config object.
Definition: tdeconfigbase.h:1762
KEntryKey::mKey
TQCString mKey
The actual key of the entry in question.
Definition: tdeconfigdata.h:82
KEntry::bDirty
bool bDirty
Must the entry be written back to disk?
Definition: tdeconfigdata.h:41
TDEStandardDirs::makeDir
static bool makeDir(const TQString &dir, int mode=0755)
Recursively creates still-missing directories in the given path.
Definition: kstandarddirs.cpp:1176

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.