summaryrefslogtreecommitdiff
path: root/library/config.cpp
Unidiff
Diffstat (limited to 'library/config.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--library/config.cpp164
1 files changed, 163 insertions, 1 deletions
diff --git a/library/config.cpp b/library/config.cpp
index 664ca34..61ff089 100644
--- a/library/config.cpp
+++ b/library/config.cpp
@@ -1,580 +1,742 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000,2004 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qtopia Environment. 4** This file is part of Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21#include <qdir.h> 21#include <qdir.h>
22#include <qmessagebox.h> 22#include <qmessagebox.h>
23#if QT_VERSION <= 230 && defined(QT_NO_CODECS) 23#if QT_VERSION <= 230 && defined(QT_NO_CODECS)
24#include <qtextcodec.h> 24#include <qtextcodec.h>
25#endif 25#endif
26#include <qtextstream.h> 26#include <qtextstream.h>
27 27
28#include <sys/stat.h> 28#include <sys/stat.h>
29#include <sys/types.h> 29#include <sys/types.h>
30#include <fcntl.h> 30#include <fcntl.h>
31#include <stdlib.h> 31#include <stdlib.h>
32#include <unistd.h> 32#include <unistd.h>
33 33
34#define QTOPIA_INTERNAL_LANGLIST 34#define QTOPIA_INTERNAL_LANGLIST
35#include "config.h" 35#include "config.h"
36#include "global.h" 36#include "global.h"
37 37
38 38
39/*! 39/*!
40 \internal 40 \internal
41*/ 41*/
42QString Config::configFilename(const QString& name, Domain d) 42QString Config::configFilename(const QString& name, Domain d)
43{ 43{
44 switch (d) { 44 switch (d) {
45 case File: 45 case File:
46 return name; 46 return name;
47 case User: { 47 case User: {
48 QDir dir = (QString(getenv("HOME")) + "/Settings"); 48 QDir dir = (QString(getenv("HOME")) + "/Settings");
49 if ( !dir.exists() ) 49 if ( !dir.exists() )
50 mkdir(dir.path().local8Bit(),0700); 50 mkdir(dir.path().local8Bit(),0700);
51 return dir.path() + "/" + name + ".conf"; 51 return dir.path() + "/" + name + ".conf";
52 } 52 }
53 } 53 }
54 return name; 54 return name;
55} 55}
56 56
57/*! 57/*!
58 \class Config config.h 58 \class Config config.h
59 \brief The Config class provides for saving application cofniguration state. 59 \brief The Config class provides for saving application cofniguration state.
60 60
61 You should keep a Config in existence only while you do not want others 61 You should keep a Config in existence only while you do not want others
62 to be able to change the state. There is no locking currently, but there 62 to be able to change the state. There is no locking currently, but there
63 may be in the future. 63 may be in the future.
64*/ 64*/
65 65
66/*! 66/*!
67 \enum Config::ConfigGroup 67 \enum Config::ConfigGroup
68 \internal 68 \internal
69*/ 69*/
70 70
71/*! 71/*!
72 \enum Config::Domain 72 \enum Config::Domain
73 73
74 \value File 74 \value File
75 \value User 75 \value User
76 76
77 See Config for details. 77 See Config for details.
78*/ 78*/
79 79
80/*! 80/*!
81 Constructs a config that will load or create a configuration with the 81 Constructs a config that will load or create a configuration with the
82 given \a name in the given \a domain. 82 given \a name in the given \a domain.
83 83
84 You must call setGroup() before doing much else with the Config. 84 You must call setGroup() before doing much else with the Config.
85 85
86 In the default Domain, \e User, 86 In the default Domain, \e User,
87 the configuration is user-specific. \a name should not contain "/" in 87 the configuration is user-specific. \a name should not contain "/" in
88 this case, and in general should be the name of the C++ class that is 88 this case, and in general should be the name of the C++ class that is
89 primarily responsible for maintaining the configuration. 89 primarily responsible for maintaining the configuration.
90 90
91 In the File Domain, \a name is an absolute filename. 91 In the File Domain, \a name is an absolute filename.
92*/ 92*/
93Config::Config( const QString &name, Domain domain ) 93Config::Config( const QString &name, Domain domain )
94 : filename( configFilename(name,domain) ) 94 : filename( configFilename(name,domain) )
95{ 95{
96 git = groups.end(); 96 git = groups.end();
97 read(); 97 read();
98 QStringList l = Global::languageList(); 98 QStringList l = Global::languageList();
99 lang = l[0]; 99 lang = l[0];
100 glang = l[1]; 100 glang = l[1];
101} 101}
102 102
103 103
104// Sharp ROM compatibility 104// Sharp ROM compatibility
105Config::Config ( const QString &name, bool what ) 105Config::Config ( const QString &name, bool what )
106 : filename( configFilename(name,what ? User : File) ) 106 : filename( configFilename(name,what ? User : File) )
107{ 107{
108 git = groups.end(); 108 git = groups.end();
109 read(); 109 read();
110 QStringList l = Global::languageList(); 110 QStringList l = Global::languageList();
111 lang = l[0]; 111 lang = l[0];
112 glang = l[1]; 112 glang = l[1];
113} 113}
114 114
115/*! 115/*!
116 Writes any changes to disk and destroys the in-memory object. 116 Writes any changes to disk and destroys the in-memory object.
117*/ 117*/
118Config::~Config() 118Config::~Config()
119{ 119{
120 if ( changed ) 120 if ( changed )
121 write(); 121 write();
122} 122}
123 123
124/*! 124/*!
125 Returns whether the current group has an entry called \a key. 125 Returns whether the current group has an entry called \a key.
126*/ 126*/
127bool Config::hasKey( const QString &key ) const 127bool Config::hasKey( const QString &key ) const
128{ 128{
129 if ( groups.end() == git ) 129 if ( groups.end() == git )
130 return FALSE; 130 return FALSE;
131 ConfigGroup::ConstIterator it = ( *git ).find( key ); 131 ConfigGroup::ConstIterator it = ( *git ).find( key );
132 return it != ( *git ).end(); 132 return it != ( *git ).end();
133} 133}
134 134
135/*! 135/*!
136 Sets the current group for subsequent reading and writing of 136 Sets the current group for subsequent reading and writing of
137 entries to \a gname. Grouping allows the application to partition the namespace. 137 entries to \a gname. Grouping allows the application to partition the namespace.
138 138
139 This function must be called prior to any reading or writing 139 This function must be called prior to any reading or writing
140 of entries. 140 of entries.
141 141
142 The \a gname must not be empty. 142 The \a gname must not be empty.
143*/ 143*/
144void Config::setGroup( const QString &gname ) 144void Config::setGroup( const QString &gname )
145{ 145{
146 QMap< QString, ConfigGroup>::Iterator it = groups.find( gname ); 146 QMap< QString, ConfigGroup>::Iterator it = groups.find( gname );
147 if ( it == groups.end() ) { 147 if ( it == groups.end() ) {
148 git = groups.insert( gname, ConfigGroup() ); 148 git = groups.insert( gname, ConfigGroup() );
149 changed = TRUE; 149 changed = TRUE;
150 return; 150 return;
151 } 151 }
152 git = it; 152 git = it;
153} 153}
154 154
155/*! 155/*!
156 Writes a (\a key, \a value) entry to the current group. 156 Writes a (\a key, \a value) entry to the current group.
157 157
158 \sa readEntry() 158 \sa readEntry()
159*/ 159*/
160void Config::writeEntry( const QString &key, const char* value ) 160void Config::writeEntry( const QString &key, const char* value )
161{ 161{
162 writeEntry(key,QString(value)); 162 writeEntry(key,QString(value));
163} 163}
164 164
165/*! 165/*!
166 Writes a (\a key, \a value) entry to the current group. 166 Writes a (\a key, \a value) entry to the current group.
167 167
168 \sa readEntry() 168 \sa readEntry()
169*/ 169*/
170void Config::writeEntry( const QString &key, const QString &value ) 170void Config::writeEntry( const QString &key, const QString &value )
171{ 171{
172 if ( git == groups.end() ) { 172 if ( git == groups.end() ) {
173 qWarning( "no group set" ); 173 qWarning( "no group set" );
174 return; 174 return;
175 } 175 }
176 if ( (*git)[key] != value ) { 176 if ( (*git)[key] != value ) {
177 ( *git ).insert( key, value ); 177 ( *git ).insert( key, value );
178 changed = TRUE; 178 changed = TRUE;
179 } 179 }
180} 180}
181 181
182/* 182/*
183 Note that the degree of protection offered by the encryption here is 183 Note that the degree of protection offered by the encryption here is
184 only sufficient to avoid the most casual observation of the configuration 184 only sufficient to avoid the most casual observation of the configuration
185 files. People with access to the files can write down the contents and 185 files. People with access to the files can write down the contents and
186 decrypt it using this source code. 186 decrypt it using this source code.
187 187
188 Conceivably, and at some burden to the user, this encryption could 188 Conceivably, and at some burden to the user, this encryption could
189 be improved. 189 be improved.
190*/ 190*/
191static QString encipher(const QString& plain) 191static QString encipher(const QString& plain)
192{ 192{
193 // mainly, we make it long 193 // mainly, we make it long
194 QString cipher; 194 QString cipher;
195 int mix=28730492; 195 int mix=28730492;
196 for (int i=0; i<(int)plain.length(); i++) { 196 for (int i=0; i<(int)plain.length(); i++) {
197 int u = plain[i].unicode(); 197 int u = plain[i].unicode();
198 int c = u ^ mix; 198 int c = u ^ mix;
199 QString x = QString::number(c,36); 199 QString x = QString::number(c,36);
200 cipher.append(QChar('a'+x.length())); 200 cipher.append(QChar('a'+x.length()));
201 cipher.append(x); 201 cipher.append(x);
202 mix *= u; 202 mix *= u;
203 } 203 }
204 return cipher; 204 return cipher;
205} 205}
206 206
207static QString decipher(const QString& cipher) 207static QString decipher(const QString& cipher)
208{ 208{
209 QString plain; 209 QString plain;
210 int mix=28730492; 210 int mix=28730492;
211 for (int i=0; i<(int)cipher.length();) { 211 for (int i=0; i<(int)cipher.length();) {
212 int l = cipher[i].unicode()-'a'; 212 int l = cipher[i].unicode()-'a';
213 QString x = cipher.mid(i+1,l); i+=l+1; 213 QString x = cipher.mid(i+1,l); i+=l+1;
214 int u = x.toInt(0,36) ^ mix; 214 int u = x.toInt(0,36) ^ mix;
215 plain.append(QChar(u)); 215 plain.append(QChar(u));
216 mix *= u; 216 mix *= u;
217 } 217 }
218 return plain; 218 return plain;
219} 219}
220 220
221/*! 221/*!
222 Writes an encrypted (\a key, \a value) entry to the current group. 222 Writes an encrypted (\a key, \a value) entry to the current group.
223 223
224 Note that the degree of protection offered by the encryption is 224 Note that the degree of protection offered by the encryption is
225 only sufficient to avoid the most casual observation of the configuration 225 only sufficient to avoid the most casual observation of the configuration
226 files. 226 files.
227 227
228 \sa readEntry() 228 \sa readEntry()
229*/ 229*/
230void Config::writeEntryCrypt( const QString &key, const QString &value ) 230void Config::writeEntryCrypt( const QString &key, const QString &value )
231{ 231{
232 if ( git == groups.end() ) { 232 if ( git == groups.end() ) {
233 qWarning( "no group set" ); 233 qWarning( "no group set" );
234 return; 234 return;
235 } 235 }
236 QString evalue = encipher(value); 236 QString evalue = encipher(value);
237 if ( (*git)[key] != evalue ) { 237 if ( (*git)[key] != evalue ) {
238 ( *git ).insert( key, evalue ); 238 ( *git ).insert( key, evalue );
239 changed = TRUE; 239 changed = TRUE;
240 } 240 }
241} 241}
242 242
243/*! 243/*!
244 Writes a (\a key, \a num) entry to the current group. 244 Writes a (\a key, \a num) entry to the current group.
245 245
246 \sa readNumEntry() 246 \sa readNumEntry()
247*/ 247*/
248void Config::writeEntry( const QString &key, int num ) 248void Config::writeEntry( const QString &key, int num )
249{ 249{
250 QString s; 250 QString s;
251 s.setNum( num ); 251 s.setNum( num );
252 writeEntry( key, s ); 252 writeEntry( key, s );
253} 253}
254 254
255#ifdef Q_HAS_BOOL_TYPE 255#ifdef Q_HAS_BOOL_TYPE
256/*! 256/*!
257 Writes a (\a key, \a b) entry to the current group. This is equivalent 257 Writes a (\a key, \a b) entry to the current group. This is equivalent
258 to writing a 0 or 1 as an integer entry. 258 to writing a 0 or 1 as an integer entry.
259 259
260 \sa readBoolEntry() 260 \sa readBoolEntry()
261*/ 261*/
262void Config::writeEntry( const QString &key, bool b ) 262void Config::writeEntry( const QString &key, bool b )
263{ 263{
264 QString s; 264 QString s;
265 s.setNum( ( int )b ); 265 s.setNum( ( int )b );
266 writeEntry( key, s ); 266 writeEntry( key, s );
267} 267}
268#endif 268#endif
269 269
270/*! 270/*!
271 Writes a (\a key, \a lst) entry to the current group. The list 271 Writes a (\a key, \a lst) entry to the current group. The list
272 is separated by \a sep, so the strings must not contain that character. 272 is separated by \a sep, so the strings must not contain that character.
273 273
274 \sa readListEntry() 274 \sa readListEntry()
275*/ 275*/
276void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep ) 276void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep )
277{ 277{
278 QString s; 278 QString s;
279 QStringList::ConstIterator it = lst.begin(); 279 QStringList::ConstIterator it = lst.begin();
280 for ( ; it != lst.end(); ++it ) 280 for ( ; it != lst.end(); ++it )
281 s += *it + sep; 281 s += *it + sep;
282 writeEntry( key, s ); 282 writeEntry( key, s );
283} 283}
284 284
285/*! 285/*!
286 Removes the \a key entry from the current group. Does nothing if 286 Removes the \a key entry from the current group. Does nothing if
287 there is no such entry. 287 there is no such entry.
288*/ 288*/
289 289
290void Config::removeEntry( const QString &key ) 290void Config::removeEntry( const QString &key )
291{ 291{
292 if ( git == groups.end() ) { 292 if ( git == groups.end() ) {
293 qWarning( "no group set" ); 293 qWarning( "no group set" );
294 return; 294 return;
295 } 295 }
296 ( *git ).remove( key ); 296 ( *git ).remove( key );
297 changed = TRUE; 297 changed = TRUE;
298} 298}
299 299
300/*! 300/*!
301 \fn bool Config::operator == ( const Config & other ) const 301 \fn bool Config::operator == ( const Config & other ) const
302 302
303 Tests for equality with \a other. Config objects are equal if they refer to the same filename. 303 Tests for equality with \a other. Config objects are equal if they refer to the same filename.
304*/ 304*/
305 305
306/*! 306/*!
307 \fn bool Config::operator != ( const Config & other ) const 307 \fn bool Config::operator != ( const Config & other ) const
308 308
309 Tests for inequality with \a other. Config objects are equal if they refer to the same filename. 309 Tests for inequality with \a other. Config objects are equal if they refer to the same filename.
310*/ 310*/
311 311
312/*! 312/*!
313 \fn QString Config::readEntry( const QString &key, const QString &deflt ) const 313 \fn QString Config::readEntry( const QString &key, const QString &deflt ) const
314 314
315 Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry. 315 Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry.
316*/ 316*/
317 317
318/*! 318/*!
319 \internal 319 \internal
320 For compatibility, non-const version. 320 For compatibility, non-const version.
321*/ 321*/
322QString Config::readEntry( const QString &key, const QString &deflt ) 322QString Config::readEntry( const QString &key, const QString &deflt )
323{ 323{
324 QString res = readEntryDirect( key+"["+lang+"]" ); 324 QString res = readEntryDirect( key+"["+lang+"]" );
325 if ( !res.isNull() ) 325 if ( !res.isNull() )
326 return res; 326 return res;
327 if ( !glang.isEmpty() ) { 327 if ( !glang.isEmpty() ) {
328 res = readEntryDirect( key+"["+glang+"]" ); 328 res = readEntryDirect( key+"["+glang+"]" );
329 if ( !res.isNull() ) 329 if ( !res.isNull() )
330 return res; 330 return res;
331 } 331 }
332 return readEntryDirect( key, deflt ); 332 return readEntryDirect( key, deflt );
333} 333}
334 334
335/*! 335/*!
336 \fn QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const 336 \fn QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const
337 337
338 Reads an encrypted string entry stored with \a key, defaulting to \a deflt if there is no entry. 338 Reads an encrypted string entry stored with \a key, defaulting to \a deflt if there is no entry.
339*/ 339*/
340 340
341/*! 341/*!
342 \internal 342 \internal
343 For compatibility, non-const version. 343 For compatibility, non-const version.
344*/ 344*/
345QString Config::readEntryCrypt( const QString &key, const QString &deflt ) 345QString Config::readEntryCrypt( const QString &key, const QString &deflt )
346{ 346{
347 QString res = readEntryDirect( key+"["+lang+"]" ); 347 QString res = readEntryDirect( key+"["+lang+"]" );
348 if ( res.isNull() && glang.isEmpty() ) 348 if ( res.isNull() && glang.isEmpty() )
349 res = readEntryDirect( key+"["+glang+"]" ); 349 res = readEntryDirect( key+"["+glang+"]" );
350 if ( res.isNull() ) 350 if ( res.isNull() )
351 res = readEntryDirect( key, QString::null ); 351 res = readEntryDirect( key, QString::null );
352 if ( res.isNull() ) 352 if ( res.isNull() )
353 return deflt; 353 return deflt;
354 return decipher(res); 354 return decipher(res);
355} 355}
356 356
357/*! 357/*!
358 \fn QString Config::readEntryDirect( const QString &key, const QString &deflt ) const 358 \fn QString Config::readEntryDirect( const QString &key, const QString &deflt ) const
359 \internal 359 \internal
360*/ 360*/
361 361
362/*! 362/*!
363 \internal 363 \internal
364 For compatibility, non-const version. 364 For compatibility, non-const version.
365*/ 365*/
366QString Config::readEntryDirect( const QString &key, const QString &deflt ) 366QString Config::readEntryDirect( const QString &key, const QString &deflt )
367{ 367{
368 if ( git == groups.end() ) { 368 if ( git == groups.end() ) {
369 //qWarning( "no group set" ); 369 //qWarning( "no group set" );
370 return deflt; 370 return deflt;
371 } 371 }
372 ConfigGroup::ConstIterator it = ( *git ).find( key ); 372 ConfigGroup::ConstIterator it = ( *git ).find( key );
373 if ( it != ( *git ).end() ) 373 if ( it != ( *git ).end() )
374 return *it; 374 return *it;
375 else 375 else
376 return deflt; 376 return deflt;
377} 377}
378 378
379/*! 379/*!
380 \fn int Config::readNumEntry( const QString &key, int deflt ) const 380 \fn int Config::readNumEntry( const QString &key, int deflt ) const
381 Reads a numeric entry stored with \a key, defaulting to \a deflt if there is no entry. 381 Reads a numeric entry stored with \a key, defaulting to \a deflt if there is no entry.
382*/ 382*/
383 383
384/*! 384/*!
385 \internal 385 \internal
386 For compatibility, non-const version. 386 For compatibility, non-const version.
387*/ 387*/
388int Config::readNumEntry( const QString &key, int deflt ) 388int Config::readNumEntry( const QString &key, int deflt )
389{ 389{
390 QString s = readEntry( key ); 390 QString s = readEntry( key );
391 if ( s.isEmpty() ) 391 if ( s.isEmpty() )
392 return deflt; 392 return deflt;
393 else 393 else
394 return s.toInt(); 394 return s.toInt();
395} 395}
396 396
397/*! 397/*!
398 \fn bool Config::readBoolEntry( const QString &key, bool deflt ) const 398 \fn bool Config::readBoolEntry( const QString &key, bool deflt ) const
399 Reads a bool entry stored with \a key, defaulting to \a deflt if there is no entry. 399 Reads a bool entry stored with \a key, defaulting to \a deflt if there is no entry.
400*/ 400*/
401 401
402/*! 402/*!
403 \internal 403 \internal
404 For compatibility, non-const version. 404 For compatibility, non-const version.
405*/ 405*/
406bool Config::readBoolEntry( const QString &key, bool deflt ) 406bool Config::readBoolEntry( const QString &key, bool deflt )
407{ 407{
408 QString s = readEntry( key ); 408 QString s = readEntry( key );
409 if ( s.isEmpty() ) 409 if ( s.isEmpty() )
410 return deflt; 410 return deflt;
411 else 411 else
412 return (bool)s.toInt(); 412 return (bool)s.toInt();
413} 413}
414 414
415/*! 415/*!
416 \fn QStringList Config::readListEntry( const QString &key, const QChar &sep ) const 416 \fn QStringList Config::readListEntry( const QString &key, const QChar &sep ) const
417 Reads a string list entry stored with \a key, and with \a sep as the separator. 417 Reads a string list entry stored with \a key, and with \a sep as the separator.
418*/ 418*/
419 419
420/*! 420/*!
421 \internal 421 \internal
422 For compatibility, non-const version. 422 For compatibility, non-const version.
423*/ 423*/
424QStringList Config::readListEntry( const QString &key, const QChar &sep ) 424QStringList Config::readListEntry( const QString &key, const QChar &sep )
425{ 425{
426 QString s = readEntry( key ); 426 QString s = readEntry( key );
427 if ( s.isEmpty() ) 427 if ( s.isEmpty() )
428 return QStringList(); 428 return QStringList();
429 else 429 else
430 return QStringList::split( sep, s ); 430 return QStringList::split( sep, s );
431} 431}
432 432
433/*! 433/*!
434 Removes all entries from the current group. 434 Removes all entries from the current group.
435*/ 435*/
436void Config::clearGroup() 436void Config::clearGroup()
437{ 437{
438 if ( git == groups.end() ) { 438 if ( git == groups.end() ) {
439 qWarning( "no group set" ); 439 qWarning( "no group set" );
440 return; 440 return;
441 } 441 }
442 if ( !(*git).isEmpty() ) { 442 if ( !(*git).isEmpty() ) {
443 ( *git ).clear(); 443 ( *git ).clear();
444 changed = TRUE; 444 changed = TRUE;
445 } 445 }
446} 446}
447 447
448/*! 448/*!
449 \internal 449 \internal
450*/ 450*/
451void Config::write( const QString &fn ) 451void Config::write( const QString &fn )
452{ 452{
453 QString strNewFile; 453 QString strNewFile;
454 if ( !fn.isEmpty() ) 454 if ( !fn.isEmpty() )
455 filename = fn; 455 filename = fn;
456 strNewFile = filename + ".new"; 456 strNewFile = filename + ".new";
457 457
458 QFile f( strNewFile ); 458 QFile f( strNewFile );
459 if ( !f.open( IO_WriteOnly|IO_Raw ) ) { 459 if ( !f.open( IO_WriteOnly|IO_Raw ) ) {
460 qWarning( "could not open for writing `%s'", strNewFile.latin1() ); 460 qWarning( "could not open for writing `%s'", strNewFile.latin1() );
461 git = groups.end(); 461 git = groups.end();
462 return; 462 return;
463 } 463 }
464 464
465 QString str; 465 QString str;
466 QCString cstr; 466 QCString cstr;
467 QMap< QString, ConfigGroup >::Iterator g_it = groups.begin(); 467 QMap< QString, ConfigGroup >::Iterator g_it = groups.begin();
468 468
469 for ( ; g_it != groups.end(); ++g_it ) { 469 for ( ; g_it != groups.end(); ++g_it ) {
470 str += "[" + g_it.key() + "]\n"; 470 str += "[" + g_it.key() + "]\n";
471 ConfigGroup::Iterator e_it = ( *g_it ).begin(); 471 ConfigGroup::Iterator e_it = ( *g_it ).begin();
472 for ( ; e_it != ( *g_it ).end(); ++e_it ) 472 for ( ; e_it != ( *g_it ).end(); ++e_it )
473 str += e_it.key() + " = " + *e_it + "\n"; 473 str += e_it.key() + " = " + *e_it + "\n";
474 } 474 }
475 cstr = str.utf8(); 475 cstr = str.utf8();
476 476
477 int total_length; 477 int total_length;
478 total_length = f.writeBlock( cstr.data(), cstr.length() ); 478 total_length = f.writeBlock( cstr.data(), cstr.length() );
479 if ( total_length != int(cstr.length()) ) { 479 if ( total_length != int(cstr.length()) ) {
480 QMessageBox::critical( 0, QObject::tr("Out of Space"), 480 QMessageBox::critical( 0, QObject::tr("Out of Space"),
481 QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") ); 481 QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") );
482 f.close(); 482 f.close();
483 QFile::remove( strNewFile ); 483 QFile::remove( strNewFile );
484 return; 484 return;
485 } 485 }
486 486
487 f.close(); 487 f.close();
488 // now rename the file... 488 // now rename the file...
489 if ( rename( strNewFile, filename ) < 0 ) { 489 if ( rename( strNewFile, filename ) < 0 ) {
490 qWarning( "problem renaming the file %s to %s", strNewFile.latin1(), 490 qWarning( "problem renaming the file %s to %s", strNewFile.latin1(),
491 filename.latin1() ); 491 filename.latin1() );
492 QFile::remove( strNewFile ); 492 QFile::remove( strNewFile );
493 } 493 }
494} 494}
495 495
496/*! 496/*!
497 Returns whether the Config is in a valid state. 497 Returns whether the Config is in a valid state.
498*/ 498*/
499bool Config::isValid() const 499bool Config::isValid() const
500{ 500{
501 return groups.end() != git; 501 return groups.end() != git;
502} 502}
503 503
504/*! 504/*!
505 \internal 505 \internal
506*/ 506*/
507void Config::read() 507void Config::read()
508{ 508{
509 changed = FALSE; 509 changed = FALSE;
510 510
511 if ( !QFileInfo( filename ).exists() ) { 511 if ( !QFileInfo( filename ).exists() ) {
512 git = groups.end(); 512 git = groups.end();
513 return; 513 return;
514 } 514 }
515 515
516 QFile f( filename ); 516 QFile f( filename );
517 if ( !f.open( IO_ReadOnly ) ) { 517 if ( !f.open( IO_ReadOnly ) ) {
518 git = groups.end(); 518 git = groups.end();
519 return; 519 return;
520 } 520 }
521 521
522 522
523 // hack to avoid problems if big files are passed to test 523 // hack to avoid problems if big files are passed to test
524 // if they are valid configs ( like passing a mp3 ... ) 524 // if they are valid configs ( like passing a mp3 ... )
525 // I just hope that there are no conf files > 100000 byte 525 // I just hope that there are no conf files > 100000 byte
526 // not the best solution, find something else later 526 // not the best solution, find something else later
527 if ( f.getch()!='[' ||f.size() > 100000 ) { 527 if ( f.getch()!='[' ||f.size() > 100000 ) {
528 git = groups.end(); 528 git = groups.end();
529 return; 529 return;
530 } 530 }
531 f.ungetch('['); 531 f.ungetch('[');
532 532
533 533
534 QTextStream s( &f ); 534 QTextStream s( &f );
535#if QT_VERSION <= 230 && defined(QT_NO_CODECS) 535#if QT_VERSION <= 230 && defined(QT_NO_CODECS)
536 // The below should work, but doesn't in Qt 2.3.0 536 // The below should work, but doesn't in Qt 2.3.0
537 s.setCodec( QTextCodec::codecForMib( 106 ) ); 537 s.setCodec( QTextCodec::codecForMib( 106 ) );
538#else 538#else
539 s.setEncoding( QTextStream::UnicodeUTF8 ); 539 s.setEncoding( QTextStream::UnicodeUTF8 );
540#endif 540#endif
541 541
542 QStringList list = QStringList::split('\n', s.read() ); 542 QStringList list = QStringList::split('\n', s.read() );
543 f.close(); 543 f.close();
544 544
545 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { 545 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
546 if ( !parse( *it ) ) { 546 if ( !parse( *it ) ) {
547 git = groups.end(); 547 git = groups.end();
548 return; 548 return;
549 } 549 }
550 } 550 }
551} 551}
552 552
553/*! 553/*!
554 \internal 554 \internal
555*/ 555*/
556bool Config::parse( const QString &l ) 556bool Config::parse( const QString &l )
557{ 557{
558 QString line = l.stripWhiteSpace(); 558 QString line = l.stripWhiteSpace();
559 559
560 if ( line [0] == QChar ( '#' )) 560 if ( line [0] == QChar ( '#' ))
561 return true; // ignore comments 561 return true; // ignore comments
562 562
563 if ( line[ 0 ] == QChar( '[' ) ) { 563 if ( line[ 0 ] == QChar( '[' ) ) {
564 QString gname = line; 564 QString gname = line;
565 gname = gname.remove( 0, 1 ); 565 gname = gname.remove( 0, 1 );
566 if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) ) 566 if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) )
567 gname = gname.remove( gname.length() - 1, 1 ); 567 gname = gname.remove( gname.length() - 1, 1 );
568 git = groups.insert( gname, ConfigGroup() ); 568 git = groups.insert( gname, ConfigGroup() );
569 } else if ( !line.isEmpty() ) { 569 } else if ( !line.isEmpty() ) {
570 if ( git == groups.end() ) 570 if ( git == groups.end() )
571 return FALSE; 571 return FALSE;
572 int eq = line.find( '=' ); 572 int eq = line.find( '=' );
573 if ( eq == -1 ) 573 if ( eq == -1 )
574 return FALSE; 574 return FALSE;
575 QString key = line.left(eq).stripWhiteSpace(); 575 QString key = line.left(eq).stripWhiteSpace();
576 QString value = line.mid(eq+1).stripWhiteSpace(); 576 QString value = line.mid(eq+1).stripWhiteSpace();
577 ( *git ).insert( key, value ); 577 ( *git ).insert( key, value );
578 } 578 }
579 return TRUE; 579 return TRUE;
580} 580}
581
582
583
584bool Config::hasGroup( const QString& name )const {
585 return ( groups. find ( name ) != groups. end ( ));
586};
587
588QStringList Config::groupList()const {
589 QStringList sl;
590 for ( ConfigGroupMap::ConstIterator it = groups. begin ( ); it != groups. end ( ); ++it )
591 sl << it.key();
592
593 return sl;
594};
595
596/////////////
597// Qtopia 2.1 Functions
598//
599////////////
600
601QStringList Config::allGroups()const {
602 return groupList();
603}
604
605/*!
606 Returns the time stamp for the config identified by \a name. The
607 time stamp represents the time the config was last committed to storage.
608 Returns 0 if there is no time stamp available for the config.
609
610 A \a domain can optionally be specified and defaults to User.
611 See \l{Config()} for details.
612
613 First availability: Qtopia 2.0
614*/
615long Config::timeStamp(const QString& name, Domain domain)
616{
617#ifdef Q_WS_WIN
618 // Too slow (many conversions too and from time_t and QDataTime)
619 QDateTime epoch;
620 epoch.setTime_t(0);
621 return epoch.secsTo(QFileInfo(Config::configFilename(name,domain)).lastModified());
622#else
623 QString fn = Config::configFilename(name,domain);
624 struct stat b;
625 if (lstat( QFile::encodeName(fn).data(), &b ) == 0)
626 return b.st_mtime;
627 else
628 return 0;
629#endif
630}
631
632
633/*!
634 Removes the current group (and all its entries).
635
636 The current group becomes unset.
637
638 First availability: Qtopia 2.0
639*/
640void Config::removeGroup()
641{
642 if ( git == groups.end() ) {
643 qWarning( "no group set" );
644 return;
645 }
646
647 groups.remove(git.key());
648 git = groups.end();
649 changed = TRUE;
650}
651
652/*!
653 Removes the current group (and all its entries).
654
655 The current group becomes unset.
656
657 First availability: Qtopia 2.0
658*/
659void Config::removeGroup(const QString& g)
660{
661 groups.remove(g);
662 git = groups.end();
663}
664
665
666
667/*!
668 Writes a (\a key, \a lst) entry to the current group.
669
670 The list is
671 separated by the two characters "^e", and "^" withing the strings
672 is replaced by "^^", such that the strings may contain any character,
673 including "^".
674
675 Null strings are also allowed, and are recorded as "^0" in the string.
676
677 First availability: Qtopia 2.0
678
679 \sa readListEntry()
680*/
681void Config::writeEntry( const QString &key, const QStringList &lst )
682{
683 QString s;
684 for (QStringList::ConstIterator it=lst.begin(); it!=lst.end(); ++it) {
685 QString el = *it;
686 if ( el.isNull() ) {
687 el = "^0";
688 } else {
689 el.replace(QRegExp("\\^"), "^^");
690 }
691 s+=el;
692 s+="^e"; // end of element
693 }
694 writeEntry(key, s);
695}
696
697/*!
698 Returns the string list entry stored using \a key and with
699 the escaped seperator convention described in writeListEntry().
700
701 First availability: Qtopia 2.0
702*/
703QStringList Config::readListEntry( const QString &key ) const
704{
705 QString value = readEntry( key, QString::null );
706 QStringList l;
707 QString s;
708 bool esc=FALSE;
709 for (int i=0; i<(int)value.length(); i++) {
710 if ( esc ) {
711 if ( value[i] == 'e' ) { // end-of-string
712 l.append(s);
713 s="";
714 } else if ( value[i] == '0' ) { // null string
715 s=QString::null;
716 } else {
717 s.append(value[i]);
718 }
719 esc = FALSE;
720 } else if ( value[i] == '^' ) {
721 esc = TRUE;
722 } else {
723 s.append(value[i]);
724 if ( i == (int)value.length()-1 )
725 l.append(s);
726 }
727 }
728 return l;
729}
730
731QString Config::readEntry( const QString &key, const QString &deflt ) const
732{ return ((Config*)this)->readEntry(key,deflt); }
733QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const
734{ return ((Config*)this)->readEntryCrypt(key,deflt); }
735QString Config::readEntryDirect( const QString &key, const QString &deflt ) const
736{ return ((Config*)this)->readEntryDirect(key,deflt); }
737int Config::readNumEntry( const QString &key, int deflt ) const
738{ return ((Config*)this)->readNumEntry(key,deflt); }
739bool Config::readBoolEntry( const QString &key, bool deflt ) const
740{ return ((Config*)this)->readBoolEntry(key,deflt); }
741QStringList Config::readListEntry( const QString &key, const QChar &sep ) const
742{ return ((Config*)this)->readListEntry(key,sep); }