certmanager/lib

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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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     const QStringList lst = QStringList::split( ':', line, true );
00202     if ( lst.count() >= 10 ) {
00203       const int flags = lst[1].toInt();
00204       const 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[0], 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( "<nogroup>", 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 & name, const QString& description, int level )
00324   : mEntries( 29 ),
00325     mName( name ),
00326     mDescription( description ),
00327     mLevel( static_cast<Kleo::CryptoConfigEntry::Level>( level ) )
00328 {
00329   mEntries.setAutoDelete( true );
00330 }
00331 
00332 QStringList QGpgMECryptoConfigGroup::entryList() const
00333 {
00334   QDictIterator<QGpgMECryptoConfigEntry> it( mEntries );
00335   QStringList names;
00336   for( ; it.current(); ++it )
00337     names.push_back( it.currentKey() );
00338   return names;
00339 }
00340 
00341 Kleo::CryptoConfigEntry* QGpgMECryptoConfigGroup::entry( const QString& name ) const
00342 {
00343   return mEntries.find( name );
00344 }
00345 
00347 
00348 static QString gpgconf_unescape( const QString& str )
00349 {
00350   // Looks like it's the same rules as KURL.
00351   return KURL::decode_string( str, 106 );
00352 }
00353 
00354 static QString gpgconf_escape( const QString& str )
00355 {
00356   // Escape special chars (including ':' and '%')
00357   QString enc = KURL::encode_string( str, 106 ); // and convert to utf8 first (to get %12%34 for one special char)
00358   // Also encode commas, for lists.
00359   enc.replace( ',', "%2c" );
00360   return enc;
00361 }
00362 
00363 static QString urlpart_encode( const QString& str )
00364 {
00365   QString enc( str );
00366   enc.replace( '%', "%25" ); // first!
00367   enc.replace( ':', "%3a" );
00368   //kdDebug() << "  urlpart_encode: " << str << " -> " << enc << endl;
00369   return enc;
00370 }
00371 
00372 static QString urlpart_decode( const QString& str )
00373 {
00374   return KURL::decode_string( str );
00375 }
00376 
00377 // gpgconf arg type number -> CryptoConfigEntry arg type enum mapping
00378 static Kleo::CryptoConfigEntry::ArgType knownArgType( int argType, bool& ok ) {
00379   ok = true;
00380   switch( argType ) {
00381   case 0: // none
00382     return Kleo::CryptoConfigEntry::ArgType_None;
00383   case 1: // string
00384     return Kleo::CryptoConfigEntry::ArgType_String;
00385   case 2: // int32
00386     return Kleo::CryptoConfigEntry::ArgType_Int;
00387   case 3: // uint32
00388     return Kleo::CryptoConfigEntry::ArgType_UInt;
00389   case 32: // pathname
00390     return Kleo::CryptoConfigEntry::ArgType_Path;
00391   case 33: // ldap server
00392     return Kleo::CryptoConfigEntry::ArgType_LDAPURL;
00393   default:
00394     ok = false;
00395     return Kleo::CryptoConfigEntry::ArgType_None;
00396   }
00397 }
00398 
00399 QGpgMECryptoConfigEntry::QGpgMECryptoConfigEntry( const QStringList& parsedLine )
00400 {
00401   // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
00402   assert( parsedLine.count() >= 10 ); // called checked for it already
00403   QStringList::const_iterator it = parsedLine.begin();
00404   mName = *it++;
00405   mFlags = (*it++).toInt();
00406   mLevel = (*it++).toInt();
00407   mDescription = *it++;
00408   bool ok;
00409   // we keep the real (int) arg type, since it influences the parsing (e.g. for ldap urls)
00410   mRealArgType = (*it++).toInt();
00411   mArgType = knownArgType( mRealArgType, ok );
00412   if ( !ok && !(*it).isEmpty() ) {
00413     // use ALT-TYPE
00414     mRealArgType = (*it).toInt();
00415     mArgType = knownArgType( mRealArgType, ok );
00416   }
00417   if ( !ok )
00418     kdWarning(5150) << "Unsupported datatype: " << parsedLine[4] << " : " << *it << " for " << parsedLine[0] << endl;
00419   ++it; // done with alt-type
00420   ++it; // skip argname (not useful in GUIs)
00421 
00422   mSet = false;
00423   QString value;
00424   if ( mFlags & GPGCONF_FLAG_DEFAULT ) {
00425     value = *it; // get default value
00426     mDefaultValue = stringToValue( value, true );
00427   }
00428   ++it; // done with DEFAULT
00429   ++it; // ### skip ARGDEF for now. It's only for options with an "optional arg"
00430   //kdDebug(5150) << "Entry " << parsedLine[0] << " val=" << *it << endl;
00431 
00432   if ( !(*it).isEmpty() ) {  // a real value was set
00433     mSet = true;
00434     value = *it;
00435     mValue = stringToValue( value, true );
00436   }
00437   else {
00438     mValue = mDefaultValue;
00439   }
00440 
00441   mDirty = false;
00442 }
00443 
00444 QVariant QGpgMECryptoConfigEntry::stringToValue( const QString& str, bool unescape ) const
00445 {
00446   bool isString = isStringType();
00447 
00448   if ( isList() ) {
00449     QValueList<QVariant> lst;
00450     QStringList items = QStringList::split( ',', str );
00451     for( QStringList::const_iterator valit = items.begin(); valit != items.end(); ++valit ) {
00452       QString val = *valit;
00453       if ( isString ) {
00454         if ( val.isEmpty() ) {
00455           lst << QString::null;
00456           continue;
00457         }
00458         else if ( unescape ) {
00459           if( val[0] != '"' ) // see README.gpgconf
00460             kdWarning(5150) << "String value should start with '\"' : " << val << endl;
00461           val = val.mid( 1 );
00462         }
00463       }
00464       lst << QVariant( unescape ? gpgconf_unescape( val ) : val );
00465     }
00466     return lst;
00467   } else { // not a list
00468     QString val( str );
00469     if ( isString ) {
00470       if ( val.isEmpty() )
00471         return QVariant( QString::null ); // not set  [ok with lists too?]
00472       else if ( unescape ) {
00473         Q_ASSERT( val[0] == '"' ); // see README.gpgconf
00474         val = val.mid( 1 );
00475       }
00476     }
00477     return QVariant( unescape ? gpgconf_unescape( val ) : val );
00478   }
00479 }
00480 
00481 QGpgMECryptoConfigEntry::~QGpgMECryptoConfigEntry()
00482 {
00483 #ifndef NDEBUG
00484   if ( !s_duringClear && mDirty )
00485     kdWarning(5150) << "Deleting a QGpgMECryptoConfigEntry that was modified (" << mDescription << ")\n"
00486                     << "You forgot to call sync() (to commit) or clear() (to discard)" << endl;
00487 #endif
00488 }
00489 
00490 bool QGpgMECryptoConfigEntry::isOptional() const
00491 {
00492   return mFlags & GPGCONF_FLAG_OPTIONAL;
00493 }
00494 
00495 bool QGpgMECryptoConfigEntry::isList() const
00496 {
00497   return mFlags & GPGCONF_FLAG_LIST;
00498 }
00499 
00500 bool QGpgMECryptoConfigEntry::isRuntime() const
00501 {
00502   return mFlags & GPGCONF_FLAG_RUNTIME;
00503 }
00504 
00505 bool QGpgMECryptoConfigEntry::isSet() const
00506 {
00507   return mSet;
00508 }
00509 
00510 bool QGpgMECryptoConfigEntry::boolValue() const
00511 {
00512   Q_ASSERT( mArgType == ArgType_None );
00513   Q_ASSERT( !isList() );
00514   return mValue.toBool();
00515 }
00516 
00517 QString QGpgMECryptoConfigEntry::stringValue() const
00518 {
00519   return toString( false );
00520 }
00521 
00522 int QGpgMECryptoConfigEntry::intValue() const
00523 {
00524   Q_ASSERT( mArgType == ArgType_Int );
00525   Q_ASSERT( !isList() );
00526   return mValue.toInt();
00527 }
00528 
00529 unsigned int QGpgMECryptoConfigEntry::uintValue() const
00530 {
00531   Q_ASSERT( mArgType == ArgType_UInt );
00532   Q_ASSERT( !isList() );
00533   return mValue.toUInt();
00534 }
00535 
00536 static KURL parseURL( int mRealArgType, const QString& str )
00537 {
00538   if ( mRealArgType == 33 ) { // LDAP server
00539     // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
00540     QStringList items = QStringList::split( ':', str, true );
00541     if ( items.count() == 5 ) {
00542       QStringList::const_iterator it = items.begin();
00543       KURL url;
00544       url.setProtocol( "ldap" );
00545       url.setHost( urlpart_decode( *it++ ) );
00546       url.setPort( (*it++).toInt() );
00547       url.setPath( "/" ); // workaround KURL parsing bug
00548       url.setUser( urlpart_decode( *it++ ) );
00549       url.setPass( urlpart_decode( *it++ ) );
00550       url.setQuery( urlpart_decode( *it ) );
00551       return url;
00552     } else
00553       kdWarning(5150) << "parseURL: malformed LDAP server: " << str << endl;
00554   }
00555   // other URLs : assume wellformed URL syntax.
00556   return KURL( str );
00557 }
00558 
00559 // The opposite of parseURL
00560 static QString splitURL( int mRealArgType, const KURL& url )
00561 {
00562   if ( mRealArgType == 33 ) { // LDAP server
00563     // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
00564     Q_ASSERT( url.protocol() == "ldap" );
00565     return urlpart_encode( url.host() ) + ":" +
00566       QString::number( url.port() ) + ":" +
00567       urlpart_encode( url.user() ) + ":" +
00568       urlpart_encode( url.pass() ) + ":" +
00569       // KURL automatically encoded the query (e.g. for spaces inside it),
00570       // so decode it before writing it out to gpgconf (issue119)
00571       urlpart_encode( KURL::decode_string( url.query().mid(1) ) );
00572   }
00573   return url.path();
00574 }
00575 
00576 KURL QGpgMECryptoConfigEntry::urlValue() const
00577 {
00578   Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
00579   Q_ASSERT( !isList() );
00580   QString str = mValue.toString();
00581   if ( mArgType == ArgType_Path )
00582   {
00583     KURL url;
00584     url.setPath( str );
00585     return url;
00586   }
00587   return parseURL( mRealArgType, str );
00588 }
00589 
00590 unsigned int QGpgMECryptoConfigEntry::numberOfTimesSet() const
00591 {
00592   Q_ASSERT( mArgType == ArgType_None );
00593   Q_ASSERT( isList() );
00594   return mValue.toUInt();
00595 }
00596 
00597 QStringList QGpgMECryptoConfigEntry::stringValueList() const
00598 {
00599   Q_ASSERT( isStringType() );
00600   Q_ASSERT( isList() );
00601   return mValue.toStringList();
00602 }
00603 
00604 QValueList<int> QGpgMECryptoConfigEntry::intValueList() const
00605 {
00606   Q_ASSERT( mArgType == ArgType_Int );
00607   Q_ASSERT( isList() );
00608   QValueList<int> ret;
00609   QValueList<QVariant> lst = mValue.toList();
00610   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00611     ret.append( (*it).toInt() );
00612   }
00613   return ret;
00614 }
00615 
00616 QValueList<unsigned int> QGpgMECryptoConfigEntry::uintValueList() const
00617 {
00618   Q_ASSERT( mArgType == ArgType_UInt );
00619   Q_ASSERT( isList() );
00620   QValueList<unsigned int> ret;
00621   QValueList<QVariant> lst = mValue.toList();
00622   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00623     ret.append( (*it).toUInt() );
00624   }
00625   return ret;
00626 }
00627 
00628 KURL::List QGpgMECryptoConfigEntry::urlValueList() const
00629 {
00630   Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
00631   Q_ASSERT( isList() );
00632   QStringList lst = mValue.toStringList();
00633 
00634   KURL::List ret;
00635   for( QStringList::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00636     if ( mArgType == ArgType_Path ) {
00637       KURL url;
00638       url.setPath( *it );
00639       ret << url;
00640     } else {
00641       ret << parseURL( mRealArgType, *it );
00642     }
00643   }
00644   return ret;
00645 }
00646 
00647 void QGpgMECryptoConfigEntry::resetToDefault()
00648 {
00649   mSet = false;
00650   mDirty = true;
00651   if ( mFlags & GPGCONF_FLAG_DEFAULT )
00652     mValue = mDefaultValue;
00653   else if ( mArgType == ArgType_None )
00654     mValue = false;
00655 }
00656 
00657 void QGpgMECryptoConfigEntry::setBoolValue( bool b )
00658 {
00659   Q_ASSERT( mArgType == ArgType_None );
00660   Q_ASSERT( !isList() );
00661   // A "no arg" option is either set or not set.
00662   // Being set means mSet==true + mValue==true, being unset means resetToDefault(), i.e. both false
00663   mValue = b;
00664   mSet = b;
00665   mDirty = true;
00666 }
00667 
00668 void QGpgMECryptoConfigEntry::setStringValue( const QString& str )
00669 {
00670   mValue = stringToValue( str, false );
00671   // When setting a string to empty (and there's no default), we need to act like resetToDefault
00672   // Otherwise we try e.g. "ocsp-responder:0:" and gpgconf answers:
00673   // "gpgconf: argument required for option ocsp-responder"
00674   if ( str.isEmpty() && !isOptional() )
00675     mSet = false;
00676   else
00677     mSet = true;
00678   mDirty = true;
00679 }
00680 
00681 void QGpgMECryptoConfigEntry::setIntValue( int i )
00682 {
00683   Q_ASSERT( mArgType == ArgType_Int );
00684   Q_ASSERT( !isList() );
00685   mValue = i;
00686   mSet = true;
00687   mDirty = true;
00688 }
00689 
00690 void QGpgMECryptoConfigEntry::setUIntValue( unsigned int i )
00691 {
00692   mValue = i;
00693   mSet = true;
00694   mDirty = true;
00695 }
00696 
00697 void QGpgMECryptoConfigEntry::setURLValue( const KURL& url )
00698 {
00699   QString str = splitURL( mRealArgType, url );
00700   if ( str.isEmpty() && !isOptional() )
00701     mSet = false;
00702   else
00703     mSet = true;
00704   mValue = str;
00705   mDirty = true;
00706 }
00707 
00708 void QGpgMECryptoConfigEntry::setNumberOfTimesSet( unsigned int i )
00709 {
00710   Q_ASSERT( mArgType == ArgType_None );
00711   Q_ASSERT( isList() );
00712   setUIntValue( i );
00713 }
00714 
00715 void QGpgMECryptoConfigEntry::setStringValueList( const QStringList& lst )
00716 {
00717   mValue = lst;
00718   if ( lst.isEmpty() && !isOptional() )
00719     mSet = false;
00720   else
00721     mSet = true;
00722   mDirty = true;
00723 }
00724 
00725 void QGpgMECryptoConfigEntry::setIntValueList( const QValueList<int>& lst )
00726 {
00727   QValueList<QVariant> ret;
00728   for( QValueList<int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00729     ret << QVariant( *it );
00730   }
00731   mValue = ret;
00732   if ( ret.isEmpty() && !isOptional() )
00733     mSet = false;
00734   else
00735     mSet = true;
00736   mDirty = true;
00737 }
00738 
00739 void QGpgMECryptoConfigEntry::setUIntValueList( const QValueList<unsigned int>& lst )
00740 {
00741   QValueList<QVariant> ret;
00742   for( QValueList<unsigned int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00743     ret << QVariant( *it );
00744   }
00745   if ( ret.isEmpty() && !isOptional() )
00746     mSet = false;
00747   else
00748     mSet = true;
00749   mValue = ret;
00750   mDirty = true;
00751 }
00752 
00753 void QGpgMECryptoConfigEntry::setURLValueList( const KURL::List& urls )
00754 {
00755   QStringList lst;
00756   for( KURL::List::const_iterator it = urls.begin(); it != urls.end(); ++it ) {
00757     lst << splitURL( mRealArgType, *it );
00758   }
00759   mValue = lst;
00760   if ( lst.isEmpty() && !isOptional() )
00761     mSet = false;
00762   else
00763     mSet = true;
00764   mDirty = true;
00765 }
00766 
00767 QString QGpgMECryptoConfigEntry::toString( bool escape ) const
00768 {
00769   // Basically the opposite of stringToValue
00770   if ( isStringType() ) {
00771     if ( mValue.isNull() )
00772       return QString::null;
00773     else if ( isList() ) { // string list
00774       QStringList lst = mValue.toStringList();
00775       if ( escape ) {
00776         for( QStringList::iterator it = lst.begin(); it != lst.end(); ++it ) {
00777           if ( !(*it).isNull() )
00778             *it = gpgconf_escape( *it ).prepend( "\"" );
00779         }
00780       }
00781       QString res = lst.join( "," );
00782       kdDebug(5150) << "toString: " << res << endl;
00783       return res;
00784     } else { // normal string
00785       QString res = mValue.toString();
00786       if ( escape )
00787         res = gpgconf_escape( res ).prepend( "\"" );
00788       return res;
00789     }
00790   }
00791   if ( !isList() ) // non-list non-string
00792   {
00793     if ( mArgType == ArgType_None ) {
00794       return mValue.toBool() ? QString::fromLatin1( "1" ) : QString::null;
00795     } else { // some int
00796       Q_ASSERT( mArgType == ArgType_Int || mArgType == ArgType_UInt );
00797       return mValue.toString(); // int to string conversion
00798     }
00799   }
00800 
00801   // Lists (of other types than strings)
00802   if ( mArgType == ArgType_None )
00803     return QString::number( numberOfTimesSet() );
00804   QStringList ret;
00805   QValueList<QVariant> lst = mValue.toList();
00806   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00807       ret << (*it).toString(); // QVariant does the conversion
00808   }
00809   return ret.join( "," );
00810 }
00811 
00812 QString QGpgMECryptoConfigEntry::outputString() const
00813 {
00814   Q_ASSERT( mSet );
00815   return toString( true );
00816 }
00817 
00818 bool QGpgMECryptoConfigEntry::isStringType() const
00819 {
00820   return ( mArgType == Kleo::CryptoConfigEntry::ArgType_String
00821            || mArgType == Kleo::CryptoConfigEntry::ArgType_Path
00822            || mArgType == Kleo::CryptoConfigEntry::ArgType_URL
00823            || mArgType == Kleo::CryptoConfigEntry::ArgType_LDAPURL );
00824 }
00825 
00826 void QGpgMECryptoConfigEntry::setDirty( bool b )
00827 {
00828   mDirty = b;
00829 }
00830 
00831 #include "qgpgmecryptoconfig.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys