Qtopia library API Documentation

config.cpp

00001 /**********************************************************************
00002 ** Copyright (C) 2000 Trolltech AS.  All rights reserved.
00003 **
00004 ** This file is part of Qtopia Environment.
00005 **
00006 ** This file may be distributed and/or modified under the terms of the
00007 ** GNU General Public License version 2 as published by the Free Software
00008 ** Foundation and appearing in the file LICENSE.GPL included in the
00009 ** packaging of this file.
00010 **
00011 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013 **
00014 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015 **
00016 ** Contact info@trolltech.com if any conditions of this licensing are
00017 ** not clear to you.
00018 **
00019 **********************************************************************/
00020 
00021 #include <qdir.h>
00022 #include <qfile.h>
00023 #include <qfileinfo.h>
00024 #include <qmessagebox.h>
00025 #if QT_VERSION <= 230 && defined(QT_NO_CODECS)
00026 #include <qtextcodec.h>
00027 #endif
00028 #include <qtextstream.h>
00029 
00030 #include <sys/stat.h>
00031 #include <sys/types.h>
00032 #include <fcntl.h>
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035 
00036 #define QTOPIA_INTERNAL_LANGLIST
00037 #include "config.h"
00038 #include "global.h"
00039 
00040 
00044 QString Config::configFilename(const QString& name, Domain d)
00045 {
00046     switch (d) {
00047     case File:
00048         return name;
00049     case User: {
00050         QDir dir = (QString(getenv("HOME")) + "/Settings");
00051         if ( !dir.exists() )
00052         mkdir(dir.path().local8Bit(),0700);
00053         return dir.path() + "/" + name + ".conf";
00054     }
00055     }
00056     return name;
00057 }
00058 
00095 Config::Config( const QString &name, Domain domain )
00096     : filename( configFilename(name,domain) )
00097 {
00098     git = groups.end();
00099     read();
00100     QStringList l = Global::languageList();
00101     lang = l[0];
00102     glang = l[1];
00103 }
00104 
00105 
00106 // Sharp ROM compatibility
00107 Config::Config ( const QString &name, bool what )
00108     : filename( configFilename(name,what ? User : File) )
00109 {
00110     git = groups.end();
00111     read();
00112     QStringList l = Global::languageList();
00113     lang = l[0];
00114     glang = l[1];
00115 }
00116 
00120 Config::~Config()
00121 {
00122     if ( changed )
00123     write();
00124 }
00125 
00129 bool Config::hasKey( const QString &key ) const
00130 {
00131     if ( groups.end() == git )
00132     return FALSE;
00133     ConfigGroup::ConstIterator it = ( *git ).find( key );
00134     return it != ( *git ).end();
00135 }
00136 
00146 void Config::setGroup( const QString &gname )
00147 {
00148     QMap< QString, ConfigGroup>::Iterator it = groups.find( gname );
00149     if ( it == groups.end() ) {
00150     git = groups.insert( gname, ConfigGroup() );
00151     changed = TRUE;
00152     return;
00153     }
00154     git = it;
00155 }
00156 
00162 void Config::writeEntry( const QString &key, const char* value )
00163 {
00164     writeEntry(key,QString(value));
00165 }
00166 
00172 void Config::writeEntry( const QString &key, const QString &value )
00173 {
00174     if ( git == groups.end() ) {
00175     qWarning( "no group set" );
00176     return;
00177     }
00178     if ( (*git)[key] != value ) {
00179     ( *git ).insert( key, value );
00180     changed = TRUE;
00181     }
00182 }
00183 
00184 /*
00185   Note that the degree of protection offered by the encryption here is
00186   only sufficient to avoid the most casual observation of the configuration
00187   files. People with access to the files can write down the contents and
00188   decrypt it using this source code.
00189 
00190   Conceivably, and at some burden to the user, this encryption could
00191   be improved.
00192 */
00193 static QString encipher(const QString& plain)
00194 {
00195     // mainly, we make it long
00196     QString cipher;
00197     int mix=28730492;
00198     for (int i=0; i<(int)plain.length(); i++) {
00199     int u = plain[i].unicode();
00200     int c = u ^ mix;
00201     QString x = QString::number(c,36);
00202     cipher.append(QChar('a'+x.length()));
00203     cipher.append(x);
00204     mix *= u;
00205     }
00206     return cipher;
00207 }
00208 
00209 static QString decipher(const QString& cipher)
00210 {
00211     QString plain;
00212     int mix=28730492;
00213     for (int i=0; i<(int)cipher.length();) {
00214     int l = cipher[i].unicode()-'a';
00215     QString x = cipher.mid(i+1,l); i+=l+1;
00216     int u = x.toInt(0,36) ^ mix;
00217     plain.append(QChar(u));
00218     mix *= u;
00219     }
00220     return plain;
00221 }
00222 
00232 void Config::writeEntryCrypt( const QString &key, const QString &value )
00233 {
00234     if ( git == groups.end() ) {
00235     qWarning( "no group set" );
00236     return;
00237     }
00238     QString evalue = encipher(value);
00239     if ( (*git)[key] != evalue ) {
00240     ( *git ).insert( key, evalue );
00241     changed = TRUE;
00242     }
00243 }
00244 
00250 void Config::writeEntry( const QString &key, int num )
00251 {
00252     QString s;
00253     s.setNum( num );
00254     writeEntry( key, s );
00255 }
00256 
00257 #ifdef Q_HAS_BOOL_TYPE
00258 
00264 void Config::writeEntry( const QString &key, bool b )
00265 {
00266     QString s;
00267     s.setNum( ( int )b );
00268     writeEntry( key, s );
00269 }
00270 #endif
00271 
00278 void Config::writeEntry( const QString &key, const QStringList &lst, const QChar &sep )
00279 {
00280     QString s;
00281     QStringList::ConstIterator it = lst.begin();
00282     for ( ; it != lst.end(); ++it )
00283     s += *it + sep;
00284     writeEntry( key, s );
00285 }
00286 
00292 void Config::removeEntry( const QString &key )
00293 {
00294     if ( git == groups.end() ) {
00295     qWarning( "no group set" );
00296     return;
00297     }
00298     ( *git ).remove( key );
00299     changed = TRUE;
00300 }
00301 
00324 QString Config::readEntry( const QString &key, const QString &deflt )
00325 {
00326     QString res = readEntryDirect( key+"["+lang+"]" );
00327     if ( !res.isNull() )
00328     return res;
00329     if ( !glang.isEmpty() ) {
00330     res = readEntryDirect( key+"["+glang+"]" );
00331     if ( !res.isNull() )
00332         return res;
00333     }
00334     return readEntryDirect( key, deflt );
00335 }
00336 
00347 QString Config::readEntryCrypt( const QString &key, const QString &deflt )
00348 {
00349     QString res = readEntryDirect( key+"["+lang+"]" );
00350     if ( res.isNull() && glang.isEmpty() )
00351     res = readEntryDirect( key+"["+glang+"]" );
00352     if ( res.isNull() )
00353     res = readEntryDirect( key, QString::null );
00354     if ( res.isNull() )
00355     return deflt;
00356     return decipher(res);
00357 }
00358 
00368 QString Config::readEntryDirect( const QString &key, const QString &deflt )
00369 {
00370     if ( git == groups.end() ) {
00371     //qWarning( "no group set" );
00372     return deflt;
00373     }
00374     ConfigGroup::ConstIterator it = ( *git ).find( key );
00375     if ( it != ( *git ).end() )
00376     return *it;
00377     else
00378     return deflt;
00379 }
00380 
00390 int Config::readNumEntry( const QString &key, int deflt )
00391 {
00392     QString s = readEntry( key );
00393     if ( s.isEmpty() )
00394     return deflt;
00395     else
00396     return s.toInt();
00397 }
00398 
00408 bool Config::readBoolEntry( const QString &key, bool deflt )
00409 {
00410     QString s = readEntry( key );
00411     if ( s.isEmpty() )
00412     return deflt;
00413     else
00414     return (bool)s.toInt();
00415 }
00416 
00426 QStringList Config::readListEntry( const QString &key, const QChar &sep )
00427 {
00428     QString s = readEntry( key );
00429     if ( s.isEmpty() )
00430     return QStringList();
00431     else
00432     return QStringList::split( sep, s );
00433 }
00434 
00438 void Config::clearGroup()
00439 {
00440     if ( git == groups.end() ) {
00441     qWarning( "no group set" );
00442     return;
00443     }
00444     if ( !(*git).isEmpty() ) {
00445     ( *git ).clear();
00446     changed = TRUE;
00447     }
00448 }
00449 
00453 void Config::write( const QString &fn )
00454 {
00455     QString strNewFile;
00456     if ( !fn.isEmpty() )
00457     filename = fn;
00458     strNewFile = filename + ".new";
00459 
00460     QFile f( strNewFile );
00461     if ( !f.open( IO_WriteOnly|IO_Raw ) ) {
00462     qWarning( "could not open for writing `%s'", strNewFile.latin1() );
00463     git = groups.end();
00464     return;
00465     }
00466 
00467     QString str;
00468     QCString cstr;
00469     QMap< QString, ConfigGroup >::Iterator g_it = groups.begin();
00470 
00471     for ( ; g_it != groups.end(); ++g_it ) {
00472     str += "[" + g_it.key() + "]\n";
00473     ConfigGroup::Iterator e_it = ( *g_it ).begin();
00474     for ( ; e_it != ( *g_it ).end(); ++e_it )
00475         str += e_it.key() + " = " + *e_it + "\n";
00476     }
00477     cstr = str.utf8();
00478 
00479     int total_length;
00480     total_length = f.writeBlock( cstr.data(), cstr.length() );
00481     if ( total_length != int(cstr.length()) ) {
00482     QMessageBox::critical( 0, QObject::tr("Out of Space"),
00483                    QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") );
00484     f.close();
00485     QFile::remove( strNewFile );
00486     return;
00487     }
00488 
00489     f.close();
00490     // now rename the file...
00491     if ( rename( strNewFile, filename ) < 0 ) {
00492     qWarning( "problem renaming the file %s to %s", strNewFile.latin1(),
00493           filename.latin1() );
00494     QFile::remove( strNewFile );
00495     }
00496 }
00497 
00501 bool Config::isValid() const
00502 {
00503     return groups.end() != git;
00504 }
00505 
00509 void Config::read()
00510 {
00511     changed = FALSE;
00512 
00513     if ( !QFileInfo( filename ).exists() ) {
00514     git = groups.end();
00515     return;
00516     }
00517 
00518     QFile f( filename );
00519     if ( !f.open( IO_ReadOnly ) ) {
00520     git = groups.end();
00521     return;
00522     }
00523 
00524 
00525     // hack to avoid problems if big files are passed to test
00526     // if they are valid configs ( like passing a mp3 ... )
00527     // I just hope that there are no conf files > 100000 byte
00528     // not the best solution, find something else later
00529     if ( f.size() > 100000 )  {
00530         return;
00531     }
00532 
00533 
00534     QTextStream s( &f );
00535 #if QT_VERSION <= 230 && defined(QT_NO_CODECS)
00536     // The below should work, but doesn't in Qt 2.3.0
00537     s.setCodec( QTextCodec::codecForMib( 106 ) );
00538 #else
00539     s.setEncoding( QTextStream::UnicodeUTF8 );
00540 #endif
00541 
00542     QStringList list = QStringList::split('\n', s.read() );
00543     f.close();
00544 
00545     for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
00546         if ( !parse( *it ) ) {
00547             git = groups.end();
00548             return;
00549         }
00550     }
00551 }
00552 
00556 bool Config::parse( const QString &l )
00557 {
00558     QString line = l.stripWhiteSpace();
00559 
00560     if ( line [0] == QChar ( '#' ))
00561         return true; // ignore comments
00562 
00563     if ( line[ 0 ] == QChar( '[' ) ) {
00564     QString gname = line;
00565     gname = gname.remove( 0, 1 );
00566     if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) )
00567         gname = gname.remove( gname.length() - 1, 1 );
00568     git = groups.insert( gname, ConfigGroup() );
00569     } else if ( !line.isEmpty() ) {
00570     if ( git == groups.end() )
00571         return FALSE;
00572     int eq = line.find( '=' );
00573     if ( eq == -1 )
00574         return FALSE;
00575     QString key = line.left(eq).stripWhiteSpace();
00576     QString value = line.mid(eq+1).stripWhiteSpace();
00577     ( *git ).insert( key, value );
00578     }
00579     return TRUE;
00580 }
KDE Logo
This file is part of the documentation for OPIE Version 1.5.5.
Documentation copyright © 1997-2003 the KDE developers. 2003 OPIE developers
Generated on Tue Feb 10 20:24:03 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001