• 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 <tdeprocess.h>
47#include <tdelocale.h>
48#include <tdestandarddirs.h>
49#include <ksavefile.h>
50#include <kurl.h>
51#include <kde_file.h>
52
53extern bool checkAccess(const TQString& pathname, int mode);
54/* translate escaped escape sequences to their actual values. */
55static 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
115static 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
166static 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
197static 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
214static 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
224static 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
234class TDEConfigBackEnd::TDEConfigBackEndPrivate
235{
236public:
237 TQDateTime localLastModified;
238 uint localLastSize;
239 TDELockFile::Ptr localLockFile;
240 TDELockFile::Ptr globalLockFile;
241};
242
243void 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
273TDELockFile::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
300TDEConfigBackEnd::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
310TDEConfigBackEnd::~TDEConfigBackEnd()
311{
312 delete d;
313}
314
315void TDEConfigBackEnd::setFileWriteMode(int mode)
316{
317 mFileMode = mode;
318}
319
320bool 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#ifdef HAVE_MMAP
435#ifdef SIGBUS
436static sigjmp_buf mmap_jmpbuf;
437struct sigaction mmap_old_sigact;
438
439extern "C" {
440 static void mmap_sigbus_handler(int)
441 {
442 siglongjmp (mmap_jmpbuf, 1);
443 }
444}
445#endif
446#endif
447
448extern bool kde_kiosk_exception;
449
450void 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 {
493tqWarning("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
775void 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
791void 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
892static 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
981bool 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 &" */
1035bool 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
1138void 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
1149void TDEConfigBackEnd::virtual_hook( int, void* )
1150{ /*BASE::virtual_hook( id, data );*/ }
1151
1152void TDEConfigINIBackEnd::virtual_hook( int id, void* data )
1153{ TDEConfigBackEnd::virtual_hook( id, data ); }
1154
1155bool 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 = tdeApp;
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}
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:1155
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:1138
TDEConfigINIBackEnd::sync
virtual void sync(bool bMerge=true)
Writes configuration data to file(s).
Definition: tdeconfigbackend.cpp:791
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:981
TDEConfigINIBackEnd::parseSingleConfigFile
void parseSingleConfigFile(TQFile &rFile, KEntryMap *pWriteBackMap=0L, bool bGlobal=false, bool bDefault=false)
Parses one configuration file.
Definition: tdeconfigbackend.cpp:450
TDEConfigINIBackEnd::writeConfigFile
bool writeConfigFile(TQString filename, bool bGlobal=false, bool bMerge=true)
Writes configuration file back.
Definition: tdeconfigbackend.cpp:1035
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: kinstance.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: tdeprocess.h:131
TDEProcess::start
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
Definition: tdeprocess.cpp:293
TDEProcess::Block
@ Block
The application is suspended until the started process is finished.
Definition: tdeprocess.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: tdestandarddirs.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: tdestandarddirs.cpp:932
TDEStandardDirs::makeDir
static bool makeDir(const TQString &dir, int mode=0755)
Recursively creates still-missing directories in the given path.
Definition: tdestandarddirs.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: tdestandarddirs.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::KEntryMapConstIterator
TQMap< KEntryKey, KEntry >::ConstIterator KEntryMapConstIterator
type for iterating over keys in a KEntryMap in sorted order.
Definition: tdeconfigdata.h:144
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::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.4
This website is maintained by Timothy Pearson.