certmanager/lib Library API Documentation

qgpgmecryptoconfig.cpp

00001 /*
00002     qgpgmecryptoconfig.cpp
00003 
00004     This file is part of libkleopatra, the KDE keymanagement library
00005     Copyright (c) 2004 Klarälvdalens Datakonsult AB
00006 
00007     Libkleopatra is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU General Public License as
00009     published by the Free Software Foundation; either version 2 of the
00010     License, or (at your option) any later version.
00011 
00012     Libkleopatra is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 
00021     In addition, as a special exception, the copyright holders give
00022     permission to link the code of this program with any edition of
00023     the Qt library by Trolltech AS, Norway (or with modified versions
00024     of Qt that use the same license as Qt), and distribute linked
00025     combinations including the two.  You must obey the GNU General
00026     Public License in all respects for all of the code used other than
00027     Qt.  If you modify this file, you may extend this exception to
00028     your version of the file, but you are not obligated to do so.  If
00029     you do not wish to do so, delete this exception statement from
00030     your version.
00031 */
00032 
00033 #include "qgpgmecryptoconfig.h"
00034 #include <kdebug.h>
00035 #include <kprocio.h>
00036 #include <errno.h>
00037 #include <kmessagebox.h>
00038 #include <klocale.h>
00039 
00040 #include <assert.h>
00041 #include <ktempfile.h>
00042 #include <qfile.h>
00043 #include <stdlib.h>
00044 #include <qtextcodec.h>
00045 
00046 // Just for the Q_ASSERT in the dtor. Not thread-safe, but who would
00047 // have 2 threads talking to gpgconf anyway? :)
00048 static bool s_duringClear = false;
00049 
00050 static const int GPGCONF_FLAG_GROUP = 1;
00051 static const int GPGCONF_FLAG_OPTIONAL = 2;
00052 static const int GPGCONF_FLAG_LIST = 4;
00053 static const int GPGCONF_FLAG_RUNTIME = 8;
00054 static const int GPGCONF_FLAG_DEFAULT = 16; // fixed default value available
00055 static const int GPGCONF_FLAG_DEFAULT_DESC = 32; // runtime default value available
00056 static const int GPGCONF_FLAG_NOARG_DESC = 64; // option with optional arg; special meaning if no arg set
00057 static const int GPGCONF_FLAG_NO_CHANGE = 128; // readonly
00058 // Change size of mFlags bitfield if adding new values here
00059 
00060 QGpgMECryptoConfig::QGpgMECryptoConfig()
00061  : mComponents( 7 ), mParsed( false )
00062 {
00063     mComponents.setAutoDelete( true );
00064 }
00065 
00066 QGpgMECryptoConfig::~QGpgMECryptoConfig()
00067 {
00068 }
00069 
00070 void QGpgMECryptoConfig::runGpgConf( bool showErrors )
00071 {
00072   // Run gpgconf --list-components to make the list of components
00073 
00074   KProcIO proc( QTextCodec::codecForName( "utf8" ) );
00075   proc << "gpgconf"; // must be in the PATH
00076   proc << "--list-components";
00077 
00078   QObject::connect( &proc, SIGNAL( readReady(KProcIO*) ),
00079                     this, SLOT( slotCollectStdOut(KProcIO*) ) );
00080 
00081   // run the process:
00082   int rc = 0;
00083   if ( !proc.start( KProcess::Block ) )
00084     rc = -1;
00085   else
00086     rc = ( proc.normalExit() ) ? proc.exitStatus() : -2 ;
00087 
00088   // handle errors, if any (and if requested)
00089   if ( showErrors && rc != 0 ) {
00090     QString wmsg = i18n("<qt>Failed to execute gpgconf:<br>%1</qt>");
00091     if ( rc == -1 )
00092         wmsg = wmsg.arg( i18n( "program not found" ) );
00093     else if ( rc == -2 )
00094         wmsg = wmsg.arg( i18n( "program cannot be executed" ) );
00095     else
00096         wmsg = wmsg.arg( strerror(rc) );
00097     kdWarning(5150) << wmsg << endl; // to see it from test_cryptoconfig.cpp
00098     KMessageBox::error(0, wmsg);
00099   }
00100   mParsed = true;
00101 }
00102 
00103 void QGpgMECryptoConfig::slotCollectStdOut( KProcIO* proc )
00104 {
00105   QString line;
00106   int result;
00107   while( ( result = proc->readln(line) ) != -1 ) {
00108     //kdDebug(5150) << "GOT LINE:" << line << endl;
00109     // Format: NAME:DESCRIPTION
00110     QStringList lst = QStringList::split( ':', line, true );
00111     if ( lst.count() >= 2 ) {
00112       mComponents.insert( lst[0], new QGpgMECryptoConfigComponent( this, lst[0], lst[1] ) );
00113     } else {
00114       kdWarning(5150) << "Parse error on gpgconf --list-components output: " << line << endl;
00115     }
00116   }
00117 }
00118 
00119 QStringList QGpgMECryptoConfig::componentList() const
00120 {
00121   if ( !mParsed )
00122     const_cast<QGpgMECryptoConfig*>( this )->runGpgConf( true );
00123   QDictIterator<QGpgMECryptoConfigComponent> it( mComponents );
00124   QStringList names;
00125   for( ; it.current(); ++it )
00126     names.push_back( it.currentKey() );
00127   return names;
00128 }
00129 
00130 Kleo::CryptoConfigComponent* QGpgMECryptoConfig::component( const QString& name ) const
00131 {
00132   if ( !mParsed )
00133     const_cast<QGpgMECryptoConfig*>( this )->runGpgConf( false );
00134   return mComponents.find( name );
00135 }
00136 
00137 void QGpgMECryptoConfig::sync( bool runtime )
00138 {
00139   QDictIterator<QGpgMECryptoConfigComponent> it( mComponents );
00140   for( ; it.current(); ++it )
00141     it.current()->sync( runtime );
00142 }
00143 
00144 void QGpgMECryptoConfig::clear()
00145 {
00146   s_duringClear = true;
00147   mComponents.clear();
00148   s_duringClear = false;
00149   mParsed = false; // next call to componentList/component will need to run gpgconf again
00150 }
00151 
00153 
00154 QGpgMECryptoConfigComponent::QGpgMECryptoConfigComponent( QGpgMECryptoConfig*, const QString& name, const QString& description )
00155   : mGroups( 7 ), mName( name ), mDescription( description )
00156 {
00157   mGroups.setAutoDelete( true );
00158   runGpgConf();
00159 }
00160 
00161 QGpgMECryptoConfigComponent::~QGpgMECryptoConfigComponent()
00162 {
00163 }
00164 
00165 void QGpgMECryptoConfigComponent::runGpgConf()
00166 {
00167   // Run gpgconf --list-options <component>, and create all groups and entries for that component
00168 
00169   KProcIO proc( QTextCodec::codecForName( "utf8" ) );
00170   proc << "gpgconf"; // must be in the PATH
00171   proc << "--list-options";
00172   proc << mName;
00173 
00174   //kdDebug(5150) << "Running gpgconf --list-options " << mName << endl;
00175 
00176   QObject::connect( &proc, SIGNAL( readReady(KProcIO*) ),
00177                     this, SLOT( slotCollectStdOut(KProcIO*) ) );
00178   mCurrentGroup = 0;
00179 
00180   // run the process:
00181   int rc = 0;
00182   if ( !proc.start( KProcess::Block ) )
00183     rc = -1;
00184   else
00185     rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ;
00186 
00187   if( rc != 0 ) // can happen when using the wrong version of gpg...
00188     kdWarning(5150) << "Running 'gpgconf --list-options " << mName << "' failed. " << strerror( rc ) << ", but try that command to see the real output" << endl;
00189   else {
00190     if ( mCurrentGroup && !mCurrentGroup->mEntries.isEmpty() ) // only add non-empty groups
00191       mGroups.insert( mCurrentGroupName, mCurrentGroup );
00192   }
00193 }
00194 
00195 void QGpgMECryptoConfigComponent::slotCollectStdOut( KProcIO* proc )
00196 {
00197   QString line;
00198   int result;
00199   while( ( result = proc->readln(line) ) != -1 ) {
00200     //kdDebug(5150) << "GOT LINE:" << line << endl;
00201     // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
00202     const QStringList lst = QStringList::split( ':', line, true );
00203     if ( lst.count() >= 10 ) {
00204       const int flags = lst[1].toInt();
00205       const int level = lst[2].toInt();
00206       if ( level > 2 ) // invisible or internal -> skip it;
00207         continue;
00208       if ( flags & GPGCONF_FLAG_GROUP ) {
00209         if ( mCurrentGroup && !mCurrentGroup->mEntries.isEmpty() ) // only add non-empty groups
00210           mGroups.insert( mCurrentGroupName, mCurrentGroup );
00211         //else
00212         //  kdDebug(5150) << "Discarding empty group " << mCurrentGroupName << endl;
00213         mCurrentGroup = new QGpgMECryptoConfigGroup( lst[0], lst[3], level );
00214         mCurrentGroupName = lst[0];
00215       } else {
00216         // normal entry
00217         if ( !mCurrentGroup ) {  // first toplevel entry -> create toplevel group
00218           mCurrentGroup = new QGpgMECryptoConfigGroup( "<nogroup>", QString::null, 0 );
00219           mCurrentGroupName = "<nogroup>";
00220         }
00221         mCurrentGroup->mEntries.insert( lst[0], new QGpgMECryptoConfigEntry( lst ) );
00222       }
00223     } else {
00224       // This happens on lines like
00225       // dirmngr[31465]: error opening `/home/dfaure/.gnupg/dirmngr_ldapservers.conf': No such file or directory
00226       // so let's not bother the user with it.
00227       //kdWarning(5150) << "Parse error on gpgconf --list-options output: " << line << endl;
00228     }
00229   }
00230 }
00231 
00232 QStringList QGpgMECryptoConfigComponent::groupList() const
00233 {
00234   QDictIterator<QGpgMECryptoConfigGroup> it( mGroups );
00235   QStringList names;
00236   for( ; it.current(); ++it )
00237     names.push_back( it.currentKey() );
00238   return names;
00239 }
00240 
00241 Kleo::CryptoConfigGroup* QGpgMECryptoConfigComponent::group(const QString& name ) const
00242 {
00243   return mGroups.find( name );
00244 }
00245 
00246 void QGpgMECryptoConfigComponent::sync( bool runtime )
00247 {
00248   KTempFile tmpFile;
00249   tmpFile.setAutoDelete( true );
00250 
00251   QValueList<QGpgMECryptoConfigEntry *> dirtyEntries;
00252 
00253   // Collect all dirty entries
00254   QDictIterator<QGpgMECryptoConfigGroup> groupit( mGroups );
00255   for( ; groupit.current(); ++groupit ) {
00256     QDictIterator<QGpgMECryptoConfigEntry> it( groupit.current()->mEntries );
00257     for( ; it.current(); ++it ) {
00258       if ( it.current()->isDirty() ) {
00259         // OK, we can set it.currentKey() to it.current()->outputString()
00260         QString line = it.currentKey();
00261         if ( it.current()->isSet() ) { // set option
00262           line += ":0:";
00263           line += it.current()->outputString();
00264         } else {                       // unset option
00265           line += ":16:";
00266         }
00267         line += '\n';
00268         QCString line8bit = line.utf8(); // encode with utf8, and KProcIO uses utf8 when reading.
00269         tmpFile.file()->writeBlock( line8bit.data(), line8bit.size()-1 /*no 0*/ );
00270         dirtyEntries.append( it.current() );
00271       }
00272     }
00273   }
00274   tmpFile.close();
00275   if ( dirtyEntries.isEmpty() )
00276     return;
00277 
00278   // Call gpgconf --change-options <component>
00279   QString commandLine = "gpgconf";
00280   if ( runtime )
00281     commandLine += " --runtime";
00282   commandLine += " --change-options ";
00283   commandLine += KProcess::quote( mName );
00284   commandLine += " < ";
00285   commandLine += KProcess::quote( tmpFile.name() );
00286 
00287   //kdDebug(5150) << commandLine << endl;
00288   //system( QCString( "cat " ) + tmpFile.name().latin1() ); // DEBUG
00289 
00290   KProcess proc;
00291   proc.setUseShell( true );
00292   proc << commandLine;
00293 
00294   // run the process:
00295   int rc = 0;
00296   if ( !proc.start( KProcess::Block ) )
00297     rc = -1;
00298   else
00299     rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ;
00300 
00301   if ( rc == -1 )
00302   {
00303     QString wmsg = i18n( "Could not start gpgconf\nCheck that gpgconf is in the PATH and that it can be started" );
00304     kdWarning(5150) << wmsg << endl;
00305     KMessageBox::error(0, wmsg);
00306   }
00307   else if( rc != 0 ) // Happens due to bugs in gpgconf (e.g. issues 104/115)
00308   {
00309     QString wmsg = i18n( "Error from gpgconf while saving configuration: %1" ).arg( strerror( rc ) );
00310     kdWarning(5150) << k_funcinfo << ":" << strerror( rc ) << endl;
00311     KMessageBox::error(0, wmsg);
00312   }
00313   else
00314   {
00315     QValueList<QGpgMECryptoConfigEntry *>::Iterator it = dirtyEntries.begin();
00316     for( ; it != dirtyEntries.end(); ++it ) {
00317       (*it)->setDirty( false );
00318     }
00319   }
00320 }
00321 
00323 
00324 QGpgMECryptoConfigGroup::QGpgMECryptoConfigGroup( const QString & name, const QString& description, int level )
00325   : mEntries( 29 ),
00326     mName( name ),
00327     mDescription( description ),
00328     mLevel( static_cast<Kleo::CryptoConfigEntry::Level>( level ) )
00329 {
00330   mEntries.setAutoDelete( true );
00331 }
00332 
00333 QStringList QGpgMECryptoConfigGroup::entryList() const
00334 {
00335   QDictIterator<QGpgMECryptoConfigEntry> it( mEntries );
00336   QStringList names;
00337   for( ; it.current(); ++it )
00338     names.push_back( it.currentKey() );
00339   return names;
00340 }
00341 
00342 Kleo::CryptoConfigEntry* QGpgMECryptoConfigGroup::entry( const QString& name ) const
00343 {
00344   return mEntries.find( name );
00345 }
00346 
00348 
00349 static QString gpgconf_unescape( const QString& str )
00350 {
00351   // Looks like it's the same rules as KURL.
00352   return KURL::decode_string( str, 106 );
00353 }
00354 
00355 static QString gpgconf_escape( const QString& str )
00356 {
00357   // Escape special chars (including ':' and '%')
00358   QString enc = KURL::encode_string( str, 106 ); // and convert to utf8 first (to get %12%34 for one special char)
00359   // Also encode commas, for lists.
00360   enc.replace( ',', "%2c" );
00361   return enc;
00362 }
00363 
00364 static QString urlpart_encode( const QString& str )
00365 {
00366   QString enc( str );
00367   enc.replace( '%', "%25" ); // first!
00368   enc.replace( ':', "%3a" );
00369   //kdDebug() << "  urlpart_encode: " << str << " -> " << enc << endl;
00370   return enc;
00371 }
00372 
00373 static QString urlpart_decode( const QString& str )
00374 {
00375   return KURL::decode_string( str );
00376 }
00377 
00378 // gpgconf arg type number -> CryptoConfigEntry arg type enum mapping
00379 static Kleo::CryptoConfigEntry::ArgType knownArgType( int argType, bool& ok ) {
00380   ok = true;
00381   switch( argType ) {
00382   case 0: // none
00383     return Kleo::CryptoConfigEntry::ArgType_None;
00384   case 1: // string
00385     return Kleo::CryptoConfigEntry::ArgType_String;
00386   case 2: // int32
00387     return Kleo::CryptoConfigEntry::ArgType_Int;
00388   case 3: // uint32
00389     return Kleo::CryptoConfigEntry::ArgType_UInt;
00390   case 32: // pathname
00391     return Kleo::CryptoConfigEntry::ArgType_Path;
00392   case 33: // ldap server
00393     return Kleo::CryptoConfigEntry::ArgType_LDAPURL;
00394   default:
00395     ok = false;
00396     return Kleo::CryptoConfigEntry::ArgType_None;
00397   }
00398 }
00399 
00400 QGpgMECryptoConfigEntry::QGpgMECryptoConfigEntry( const QStringList& parsedLine )
00401 {
00402   // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
00403   assert( parsedLine.count() >= 10 ); // called checked for it already
00404   QStringList::const_iterator it = parsedLine.begin();
00405   mName = *it++;
00406   mFlags = (*it++).toInt();
00407   mLevel = (*it++).toInt();
00408   mDescription = *it++;
00409   bool ok;
00410   // we keep the real (int) arg type, since it influences the parsing (e.g. for ldap urls)
00411   mRealArgType = (*it++).toInt();
00412   mArgType = knownArgType( mRealArgType, ok );
00413   if ( !ok && !(*it).isEmpty() ) {
00414     // use ALT-TYPE
00415     mRealArgType = (*it).toInt();
00416     mArgType = knownArgType( mRealArgType, ok );
00417   }
00418   if ( !ok )
00419     kdWarning(5150) << "Unsupported datatype: " << parsedLine[4] << " : " << *it << " for " << parsedLine[0] << endl;
00420   ++it; // done with alt-type
00421   ++it; // skip argname (not useful in GUIs)
00422 
00423   mSet = false;
00424   QString value;
00425   if ( mFlags & GPGCONF_FLAG_DEFAULT ) {
00426     value = *it; // get default value
00427     mDefaultValue = stringToValue( value, true );
00428   }
00429   ++it; // done with DEFAULT
00430   ++it; // ### skip ARGDEF for now. It's only for options with an "optional arg"
00431   //kdDebug(5150) << "Entry " << parsedLine[0] << " val=" << *it << endl;
00432 
00433   if ( !(*it).isEmpty() ) {  // a real value was set
00434     mSet = true;
00435     value = *it;
00436     mValue = stringToValue( value, true );
00437   }
00438   else {
00439     mValue = mDefaultValue;
00440   }
00441 
00442   mDirty = false;
00443 }
00444 
00445 QVariant QGpgMECryptoConfigEntry::stringToValue( const QString& str, bool unescape ) const
00446 {
00447   bool isString = isStringType();
00448 
00449   if ( isList() ) {
00450     QValueList<QVariant> lst;
00451     QStringList items = QStringList::split( ',', str );
00452     for( QStringList::const_iterator valit = items.begin(); valit != items.end(); ++valit ) {
00453       QString val = *valit;
00454       if ( isString ) {
00455         if ( val.isEmpty() ) {
00456           lst << QString::null;
00457           continue;
00458         }
00459         else if ( unescape ) {
00460           if( val[0] != '"' ) // see README.gpgconf
00461             kdWarning(5150) << "String value should start with '\"' : " << val << endl;
00462           val = val.mid( 1 );
00463         }
00464       }
00465       lst << QVariant( unescape ? gpgconf_unescape( val ) : val );
00466     }
00467     return lst;
00468   } else { // not a list
00469     QString val( str );
00470     if ( isString ) {
00471       if ( val.isEmpty() )
00472         return QVariant( QString::null ); // not set  [ok with lists too?]
00473       else if ( unescape ) {
00474         Q_ASSERT( val[0] == '"' ); // see README.gpgconf
00475         val = val.mid( 1 );
00476       }
00477     }
00478     return QVariant( unescape ? gpgconf_unescape( val ) : val );
00479   }
00480 }
00481 
00482 QGpgMECryptoConfigEntry::~QGpgMECryptoConfigEntry()
00483 {
00484 #ifndef NDEBUG
00485   if ( !s_duringClear && mDirty )
00486     kdWarning(5150) << "Deleting a QGpgMECryptoConfigEntry that was modified (" << mDescription << ")\n"
00487                     << "You forgot to call sync() (to commit) or clear() (to discard)" << endl;
00488 #endif
00489 }
00490 
00491 bool QGpgMECryptoConfigEntry::isOptional() const
00492 {
00493   return mFlags & GPGCONF_FLAG_OPTIONAL;
00494 }
00495 
00496 bool QGpgMECryptoConfigEntry::isReadOnly() const
00497 {
00498   return mFlags & GPGCONF_FLAG_NO_CHANGE;
00499 }
00500 
00501 bool QGpgMECryptoConfigEntry::isList() const
00502 {
00503   return mFlags & GPGCONF_FLAG_LIST;
00504 }
00505 
00506 bool QGpgMECryptoConfigEntry::isRuntime() const
00507 {
00508   return mFlags & GPGCONF_FLAG_RUNTIME;
00509 }
00510 
00511 bool QGpgMECryptoConfigEntry::isSet() const
00512 {
00513   return mSet;
00514 }
00515 
00516 bool QGpgMECryptoConfigEntry::boolValue() const
00517 {
00518   Q_ASSERT( mArgType == ArgType_None );
00519   Q_ASSERT( !isList() );
00520   return mValue.toBool();
00521 }
00522 
00523 QString QGpgMECryptoConfigEntry::stringValue() const
00524 {
00525   return toString( false );
00526 }
00527 
00528 int QGpgMECryptoConfigEntry::intValue() const
00529 {
00530   Q_ASSERT( mArgType == ArgType_Int );
00531   Q_ASSERT( !isList() );
00532   return mValue.toInt();
00533 }
00534 
00535 unsigned int QGpgMECryptoConfigEntry::uintValue() const
00536 {
00537   Q_ASSERT( mArgType == ArgType_UInt );
00538   Q_ASSERT( !isList() );
00539   return mValue.toUInt();
00540 }
00541 
00542 static KURL parseURL( int mRealArgType, const QString& str )
00543 {
00544   if ( mRealArgType == 33 ) { // LDAP server
00545     // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
00546     QStringList items = QStringList::split( ':', str, true );
00547     if ( items.count() == 5 ) {
00548       QStringList::const_iterator it = items.begin();
00549       KURL url;
00550       url.setProtocol( "ldap" );
00551       url.setHost( urlpart_decode( *it++ ) );
00552       url.setPort( (*it++).toInt() );
00553       url.setPath( "/" ); // workaround KURL parsing bug
00554       url.setUser( urlpart_decode( *it++ ) );
00555       url.setPass( urlpart_decode( *it++ ) );
00556       url.setQuery( urlpart_decode( *it ) );
00557       return url;
00558     } else
00559       kdWarning(5150) << "parseURL: malformed LDAP server: " << str << endl;
00560   }
00561   // other URLs : assume wellformed URL syntax.
00562   return KURL( str );
00563 }
00564 
00565 // The opposite of parseURL
00566 static QString splitURL( int mRealArgType, const KURL& url )
00567 {
00568   if ( mRealArgType == 33 ) { // LDAP server
00569     // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
00570     Q_ASSERT( url.protocol() == "ldap" );
00571     return urlpart_encode( url.host() ) + ":" +
00572       QString::number( url.port() ) + ":" +
00573       urlpart_encode( url.user() ) + ":" +
00574       urlpart_encode( url.pass() ) + ":" +
00575       // KURL automatically encoded the query (e.g. for spaces inside it),
00576       // so decode it before writing it out to gpgconf (issue119)
00577       urlpart_encode( KURL::decode_string( url.query().mid(1) ) );
00578   }
00579   return url.path();
00580 }
00581 
00582 KURL QGpgMECryptoConfigEntry::urlValue() const
00583 {
00584   Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
00585   Q_ASSERT( !isList() );
00586   QString str = mValue.toString();
00587   if ( mArgType == ArgType_Path )
00588   {
00589     KURL url;
00590     url.setPath( str );
00591     return url;
00592   }
00593   return parseURL( mRealArgType, str );
00594 }
00595 
00596 unsigned int QGpgMECryptoConfigEntry::numberOfTimesSet() const
00597 {
00598   Q_ASSERT( mArgType == ArgType_None );
00599   Q_ASSERT( isList() );
00600   return mValue.toUInt();
00601 }
00602 
00603 QStringList QGpgMECryptoConfigEntry::stringValueList() const
00604 {
00605   Q_ASSERT( isStringType() );
00606   Q_ASSERT( isList() );
00607   return mValue.toStringList();
00608 }
00609 
00610 QValueList<int> QGpgMECryptoConfigEntry::intValueList() const
00611 {
00612   Q_ASSERT( mArgType == ArgType_Int );
00613   Q_ASSERT( isList() );
00614   QValueList<int> ret;
00615   QValueList<QVariant> lst = mValue.toList();
00616   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00617     ret.append( (*it).toInt() );
00618   }
00619   return ret;
00620 }
00621 
00622 QValueList<unsigned int> QGpgMECryptoConfigEntry::uintValueList() const
00623 {
00624   Q_ASSERT( mArgType == ArgType_UInt );
00625   Q_ASSERT( isList() );
00626   QValueList<unsigned int> ret;
00627   QValueList<QVariant> lst = mValue.toList();
00628   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00629     ret.append( (*it).toUInt() );
00630   }
00631   return ret;
00632 }
00633 
00634 KURL::List QGpgMECryptoConfigEntry::urlValueList() const
00635 {
00636   Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
00637   Q_ASSERT( isList() );
00638   QStringList lst = mValue.toStringList();
00639 
00640   KURL::List ret;
00641   for( QStringList::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00642     if ( mArgType == ArgType_Path ) {
00643       KURL url;
00644       url.setPath( *it );
00645       ret << url;
00646     } else {
00647       ret << parseURL( mRealArgType, *it );
00648     }
00649   }
00650   return ret;
00651 }
00652 
00653 void QGpgMECryptoConfigEntry::resetToDefault()
00654 {
00655   mSet = false;
00656   mDirty = true;
00657   if ( mFlags & GPGCONF_FLAG_DEFAULT )
00658     mValue = mDefaultValue;
00659   else if ( mArgType == ArgType_None )
00660     mValue = false;
00661 }
00662 
00663 void QGpgMECryptoConfigEntry::setBoolValue( bool b )
00664 {
00665   Q_ASSERT( mArgType == ArgType_None );
00666   Q_ASSERT( !isList() );
00667   // A "no arg" option is either set or not set.
00668   // Being set means mSet==true + mValue==true, being unset means resetToDefault(), i.e. both false
00669   mValue = b;
00670   mSet = b;
00671   mDirty = true;
00672 }
00673 
00674 void QGpgMECryptoConfigEntry::setStringValue( const QString& str )
00675 {
00676   mValue = stringToValue( str, false );
00677   // When setting a string to empty (and there's no default), we need to act like resetToDefault
00678   // Otherwise we try e.g. "ocsp-responder:0:" and gpgconf answers:
00679   // "gpgconf: argument required for option ocsp-responder"
00680   if ( str.isEmpty() && !isOptional() )
00681     mSet = false;
00682   else
00683     mSet = true;
00684   mDirty = true;
00685 }
00686 
00687 void QGpgMECryptoConfigEntry::setIntValue( int i )
00688 {
00689   Q_ASSERT( mArgType == ArgType_Int );
00690   Q_ASSERT( !isList() );
00691   mValue = i;
00692   mSet = true;
00693   mDirty = true;
00694 }
00695 
00696 void QGpgMECryptoConfigEntry::setUIntValue( unsigned int i )
00697 {
00698   mValue = i;
00699   mSet = true;
00700   mDirty = true;
00701 }
00702 
00703 void QGpgMECryptoConfigEntry::setURLValue( const KURL& url )
00704 {
00705   QString str = splitURL( mRealArgType, url );
00706   if ( str.isEmpty() && !isOptional() )
00707     mSet = false;
00708   else
00709     mSet = true;
00710   mValue = str;
00711   mDirty = true;
00712 }
00713 
00714 void QGpgMECryptoConfigEntry::setNumberOfTimesSet( unsigned int i )
00715 {
00716   Q_ASSERT( mArgType == ArgType_None );
00717   Q_ASSERT( isList() );
00718   setUIntValue( i );
00719 }
00720 
00721 void QGpgMECryptoConfigEntry::setStringValueList( const QStringList& lst )
00722 {
00723   mValue = lst;
00724   if ( lst.isEmpty() && !isOptional() )
00725     mSet = false;
00726   else
00727     mSet = true;
00728   mDirty = true;
00729 }
00730 
00731 void QGpgMECryptoConfigEntry::setIntValueList( const QValueList<int>& lst )
00732 {
00733   QValueList<QVariant> ret;
00734   for( QValueList<int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00735     ret << QVariant( *it );
00736   }
00737   mValue = ret;
00738   if ( ret.isEmpty() && !isOptional() )
00739     mSet = false;
00740   else
00741     mSet = true;
00742   mDirty = true;
00743 }
00744 
00745 void QGpgMECryptoConfigEntry::setUIntValueList( const QValueList<unsigned int>& lst )
00746 {
00747   QValueList<QVariant> ret;
00748   for( QValueList<unsigned int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00749     ret << QVariant( *it );
00750   }
00751   if ( ret.isEmpty() && !isOptional() )
00752     mSet = false;
00753   else
00754     mSet = true;
00755   mValue = ret;
00756   mDirty = true;
00757 }
00758 
00759 void QGpgMECryptoConfigEntry::setURLValueList( const KURL::List& urls )
00760 {
00761   QStringList lst;
00762   for( KURL::List::const_iterator it = urls.begin(); it != urls.end(); ++it ) {
00763     lst << splitURL( mRealArgType, *it );
00764   }
00765   mValue = lst;
00766   if ( lst.isEmpty() && !isOptional() )
00767     mSet = false;
00768   else
00769     mSet = true;
00770   mDirty = true;
00771 }
00772 
00773 QString QGpgMECryptoConfigEntry::toString( bool escape ) const
00774 {
00775   // Basically the opposite of stringToValue
00776   if ( isStringType() ) {
00777     if ( mValue.isNull() )
00778       return QString::null;
00779     else if ( isList() ) { // string list
00780       QStringList lst = mValue.toStringList();
00781       if ( escape ) {
00782         for( QStringList::iterator it = lst.begin(); it != lst.end(); ++it ) {
00783           if ( !(*it).isNull() )
00784             *it = gpgconf_escape( *it ).prepend( "\"" );
00785         }
00786       }
00787       QString res = lst.join( "," );
00788       kdDebug(5150) << "toString: " << res << endl;
00789       return res;
00790     } else { // normal string
00791       QString res = mValue.toString();
00792       if ( escape )
00793         res = gpgconf_escape( res ).prepend( "\"" );
00794       return res;
00795     }
00796   }
00797   if ( !isList() ) // non-list non-string
00798   {
00799     if ( mArgType == ArgType_None ) {
00800       return mValue.toBool() ? QString::fromLatin1( "1" ) : QString::null;
00801     } else { // some int
00802       Q_ASSERT( mArgType == ArgType_Int || mArgType == ArgType_UInt );
00803       return mValue.toString(); // int to string conversion
00804     }
00805   }
00806 
00807   // Lists (of other types than strings)
00808   if ( mArgType == ArgType_None )
00809     return QString::number( numberOfTimesSet() );
00810   QStringList ret;
00811   QValueList<QVariant> lst = mValue.toList();
00812   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00813       ret << (*it).toString(); // QVariant does the conversion
00814   }
00815   return ret.join( "," );
00816 }
00817 
00818 QString QGpgMECryptoConfigEntry::outputString() const
00819 {
00820   Q_ASSERT( mSet );
00821   return toString( true );
00822 }
00823 
00824 bool QGpgMECryptoConfigEntry::isStringType() const
00825 {
00826   return ( mArgType == Kleo::CryptoConfigEntry::ArgType_String
00827            || mArgType == Kleo::CryptoConfigEntry::ArgType_Path
00828            || mArgType == Kleo::CryptoConfigEntry::ArgType_URL
00829            || mArgType == Kleo::CryptoConfigEntry::ArgType_LDAPURL );
00830 }
00831 
00832 void QGpgMECryptoConfigEntry::setDirty( bool b )
00833 {
00834   mDirty = b;
00835 }
00836 
00837 #include "qgpgmecryptoconfig.moc"
KDE Logo
This file is part of the documentation for certmanager/lib Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Dec 21 14:23:04 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003