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