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 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( QString::fromLocal8Bit( 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     if ( argType() == ArgType_None ) {
00451         bool ok = true;
00452         const QVariant v = str.isEmpty() ? 0U : str.toUInt( &ok ) ;
00453         if ( !ok )
00454             kdWarning(5150) << "list-of-none should have an unsigned int as value:" << str << endl;
00455         return v;
00456     }
00457     QValueList<QVariant> lst;
00458     QStringList items = QStringList::split( ',', str );
00459     for( QStringList::const_iterator valit = items.begin(); valit != items.end(); ++valit ) {
00460       QString val = *valit;
00461       if ( isString ) {
00462         if ( val.isEmpty() ) {
00463           lst << QString::null;
00464           continue;
00465         }
00466         else if ( unescape ) {
00467           if( val[0] != '"' ) // see README.gpgconf
00468             kdWarning(5150) << "String value should start with '\"' : " << val << endl;
00469           val = val.mid( 1 );
00470         }
00471       }
00472       lst << QVariant( unescape ? gpgconf_unescape( val ) : val );
00473     }
00474     return lst;
00475   } else { // not a list
00476     QString val( str );
00477     if ( isString ) {
00478       if ( val.isEmpty() )
00479         return QVariant( QString::null ); // not set  [ok with lists too?]
00480       else if ( unescape ) {
00481         Q_ASSERT( val[0] == '"' ); // see README.gpgconf
00482         val = val.mid( 1 );
00483       }
00484     }
00485     return QVariant( unescape ? gpgconf_unescape( val ) : val );
00486   }
00487 }
00488 
00489 QGpgMECryptoConfigEntry::~QGpgMECryptoConfigEntry()
00490 {
00491 #ifndef NDEBUG
00492   if ( !s_duringClear && mDirty )
00493     kdWarning(5150) << "Deleting a QGpgMECryptoConfigEntry that was modified (" << mDescription << ")\n"
00494                     << "You forgot to call sync() (to commit) or clear() (to discard)" << endl;
00495 #endif
00496 }
00497 
00498 bool QGpgMECryptoConfigEntry::isOptional() const
00499 {
00500   return mFlags & GPGCONF_FLAG_OPTIONAL;
00501 }
00502 
00503 bool QGpgMECryptoConfigEntry::isReadOnly() const
00504 {
00505   return mFlags & GPGCONF_FLAG_NO_CHANGE;
00506 }
00507 
00508 bool QGpgMECryptoConfigEntry::isList() const
00509 {
00510   return mFlags & GPGCONF_FLAG_LIST;
00511 }
00512 
00513 bool QGpgMECryptoConfigEntry::isRuntime() const
00514 {
00515   return mFlags & GPGCONF_FLAG_RUNTIME;
00516 }
00517 
00518 bool QGpgMECryptoConfigEntry::isSet() const
00519 {
00520   return mSet;
00521 }
00522 
00523 bool QGpgMECryptoConfigEntry::boolValue() const
00524 {
00525   Q_ASSERT( mArgType == ArgType_None );
00526   Q_ASSERT( !isList() );
00527   return mValue.toBool();
00528 }
00529 
00530 QString QGpgMECryptoConfigEntry::stringValue() const
00531 {
00532   return toString( false );
00533 }
00534 
00535 int QGpgMECryptoConfigEntry::intValue() const
00536 {
00537   Q_ASSERT( mArgType == ArgType_Int );
00538   Q_ASSERT( !isList() );
00539   return mValue.toInt();
00540 }
00541 
00542 unsigned int QGpgMECryptoConfigEntry::uintValue() const
00543 {
00544   Q_ASSERT( mArgType == ArgType_UInt );
00545   Q_ASSERT( !isList() );
00546   return mValue.toUInt();
00547 }
00548 
00549 static KURL parseURL( int mRealArgType, const QString& str )
00550 {
00551   if ( mRealArgType == 33 ) { // LDAP server
00552     // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
00553     QStringList items = QStringList::split( ':', str, true );
00554     if ( items.count() == 5 ) {
00555       QStringList::const_iterator it = items.begin();
00556       KURL url;
00557       url.setProtocol( "ldap" );
00558       url.setHost( urlpart_decode( *it++ ) );
00559       url.setPort( (*it++).toInt() );
00560       url.setPath( "/" ); // workaround KURL parsing bug
00561       url.setUser( urlpart_decode( *it++ ) );
00562       url.setPass( urlpart_decode( *it++ ) );
00563       url.setQuery( urlpart_decode( *it ) );
00564       return url;
00565     } else
00566       kdWarning(5150) << "parseURL: malformed LDAP server: " << str << endl;
00567   }
00568   // other URLs : assume wellformed URL syntax.
00569   return KURL( str );
00570 }
00571 
00572 // The opposite of parseURL
00573 static QString splitURL( int mRealArgType, const KURL& url )
00574 {
00575   if ( mRealArgType == 33 ) { // LDAP server
00576     // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
00577     Q_ASSERT( url.protocol() == "ldap" );
00578     return urlpart_encode( url.host() ) + ":" +
00579       QString::number( url.port() ) + ":" +
00580       urlpart_encode( url.user() ) + ":" +
00581       urlpart_encode( url.pass() ) + ":" +
00582       // KURL automatically encoded the query (e.g. for spaces inside it),
00583       // so decode it before writing it out to gpgconf (issue119)
00584       urlpart_encode( KURL::decode_string( url.query().mid(1) ) );
00585   }
00586   return url.path();
00587 }
00588 
00589 KURL QGpgMECryptoConfigEntry::urlValue() const
00590 {
00591   Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
00592   Q_ASSERT( !isList() );
00593   QString str = mValue.toString();
00594   if ( mArgType == ArgType_Path )
00595   {
00596     KURL url;
00597     url.setPath( str );
00598     return url;
00599   }
00600   return parseURL( mRealArgType, str );
00601 }
00602 
00603 unsigned int QGpgMECryptoConfigEntry::numberOfTimesSet() const
00604 {
00605   Q_ASSERT( mArgType == ArgType_None );
00606   Q_ASSERT( isList() );
00607   return mValue.toUInt();
00608 }
00609 
00610 QStringList QGpgMECryptoConfigEntry::stringValueList() const
00611 {
00612   Q_ASSERT( isStringType() );
00613   Q_ASSERT( isList() );
00614   return mValue.toStringList();
00615 }
00616 
00617 QValueList<int> QGpgMECryptoConfigEntry::intValueList() const
00618 {
00619   Q_ASSERT( mArgType == ArgType_Int );
00620   Q_ASSERT( isList() );
00621   QValueList<int> ret;
00622   QValueList<QVariant> lst = mValue.toList();
00623   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00624     ret.append( (*it).toInt() );
00625   }
00626   return ret;
00627 }
00628 
00629 QValueList<unsigned int> QGpgMECryptoConfigEntry::uintValueList() const
00630 {
00631   Q_ASSERT( mArgType == ArgType_UInt );
00632   Q_ASSERT( isList() );
00633   QValueList<unsigned int> ret;
00634   QValueList<QVariant> lst = mValue.toList();
00635   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00636     ret.append( (*it).toUInt() );
00637   }
00638   return ret;
00639 }
00640 
00641 KURL::List QGpgMECryptoConfigEntry::urlValueList() const
00642 {
00643   Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
00644   Q_ASSERT( isList() );
00645   QStringList lst = mValue.toStringList();
00646 
00647   KURL::List ret;
00648   for( QStringList::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00649     if ( mArgType == ArgType_Path ) {
00650       KURL url;
00651       url.setPath( *it );
00652       ret << url;
00653     } else {
00654       ret << parseURL( mRealArgType, *it );
00655     }
00656   }
00657   return ret;
00658 }
00659 
00660 void QGpgMECryptoConfigEntry::resetToDefault()
00661 {
00662   mSet = false;
00663   mDirty = true;
00664   if ( mFlags & GPGCONF_FLAG_DEFAULT )
00665     mValue = mDefaultValue;
00666   else if ( mArgType == ArgType_None )
00667     if ( isList() )
00668       mValue = 0U;
00669     else
00670       mValue = false;
00671 }
00672 
00673 void QGpgMECryptoConfigEntry::setBoolValue( bool b )
00674 {
00675   Q_ASSERT( mArgType == ArgType_None );
00676   Q_ASSERT( !isList() );
00677   // A "no arg" option is either set or not set.
00678   // Being set means mSet==true + mValue==true, being unset means resetToDefault(), i.e. both false
00679   mValue = b;
00680   mSet = b;
00681   mDirty = true;
00682 }
00683 
00684 void QGpgMECryptoConfigEntry::setStringValue( const QString& str )
00685 {
00686   mValue = stringToValue( str, false );
00687   // When setting a string to empty (and there's no default), we need to act like resetToDefault
00688   // Otherwise we try e.g. "ocsp-responder:0:" and gpgconf answers:
00689   // "gpgconf: argument required for option ocsp-responder"
00690   if ( str.isEmpty() && !isOptional() )
00691     mSet = false;
00692   else
00693     mSet = true;
00694   mDirty = true;
00695 }
00696 
00697 void QGpgMECryptoConfigEntry::setIntValue( int i )
00698 {
00699   Q_ASSERT( mArgType == ArgType_Int );
00700   Q_ASSERT( !isList() );
00701   mValue = i;
00702   mSet = true;
00703   mDirty = true;
00704 }
00705 
00706 void QGpgMECryptoConfigEntry::setUIntValue( unsigned int i )
00707 {
00708   mValue = i;
00709   mSet = true;
00710   mDirty = true;
00711 }
00712 
00713 void QGpgMECryptoConfigEntry::setURLValue( const KURL& url )
00714 {
00715   QString str = splitURL( mRealArgType, url );
00716   if ( str.isEmpty() && !isOptional() )
00717     mSet = false;
00718   else
00719     mSet = true;
00720   mValue = str;
00721   mDirty = true;
00722 }
00723 
00724 void QGpgMECryptoConfigEntry::setNumberOfTimesSet( unsigned int i )
00725 {
00726   Q_ASSERT( mArgType == ArgType_None );
00727   Q_ASSERT( isList() );
00728   mValue = i;
00729   mSet = i > 0;
00730   mDirty = true;
00731 }
00732 
00733 void QGpgMECryptoConfigEntry::setStringValueList( const QStringList& lst )
00734 {
00735   mValue = lst;
00736   if ( lst.isEmpty() && !isOptional() )
00737     mSet = false;
00738   else
00739     mSet = true;
00740   mDirty = true;
00741 }
00742 
00743 void QGpgMECryptoConfigEntry::setIntValueList( const QValueList<int>& lst )
00744 {
00745   QValueList<QVariant> ret;
00746   for( QValueList<int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00747     ret << QVariant( *it );
00748   }
00749   mValue = ret;
00750   if ( ret.isEmpty() && !isOptional() )
00751     mSet = false;
00752   else
00753     mSet = true;
00754   mDirty = true;
00755 }
00756 
00757 void QGpgMECryptoConfigEntry::setUIntValueList( const QValueList<unsigned int>& lst )
00758 {
00759   QValueList<QVariant> ret;
00760   for( QValueList<unsigned int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00761     ret << QVariant( *it );
00762   }
00763   if ( ret.isEmpty() && !isOptional() )
00764     mSet = false;
00765   else
00766     mSet = true;
00767   mValue = ret;
00768   mDirty = true;
00769 }
00770 
00771 void QGpgMECryptoConfigEntry::setURLValueList( const KURL::List& urls )
00772 {
00773   QStringList lst;
00774   for( KURL::List::const_iterator it = urls.begin(); it != urls.end(); ++it ) {
00775     lst << splitURL( mRealArgType, *it );
00776   }
00777   mValue = lst;
00778   if ( lst.isEmpty() && !isOptional() )
00779     mSet = false;
00780   else
00781     mSet = true;
00782   mDirty = true;
00783 }
00784 
00785 QString QGpgMECryptoConfigEntry::toString( bool escape ) const
00786 {
00787   // Basically the opposite of stringToValue
00788   if ( isStringType() ) {
00789     if ( mValue.isNull() )
00790       return QString::null;
00791     else if ( isList() ) { // string list
00792       QStringList lst = mValue.toStringList();
00793       if ( escape ) {
00794         for( QStringList::iterator it = lst.begin(); it != lst.end(); ++it ) {
00795           if ( !(*it).isNull() )
00796             *it = gpgconf_escape( *it ).prepend( "\"" );
00797         }
00798       }
00799       QString res = lst.join( "," );
00800       kdDebug(5150) << "toString: " << res << endl;
00801       return res;
00802     } else { // normal string
00803       QString res = mValue.toString();
00804       if ( escape )
00805         res = gpgconf_escape( res ).prepend( "\"" );
00806       return res;
00807     }
00808   }
00809   if ( !isList() ) // non-list non-string
00810   {
00811     if ( mArgType == ArgType_None ) {
00812       return mValue.toBool() ? QString::fromLatin1( "1" ) : QString::null;
00813     } else { // some int
00814       Q_ASSERT( mArgType == ArgType_Int || mArgType == ArgType_UInt );
00815       return mValue.toString(); // int to string conversion
00816     }
00817   }
00818 
00819   // Lists (of other types than strings)
00820   if ( mArgType == ArgType_None )
00821     return QString::number( numberOfTimesSet() );
00822   QStringList ret;
00823   QValueList<QVariant> lst = mValue.toList();
00824   for( QValueList<QVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00825       ret << (*it).toString(); // QVariant does the conversion
00826   }
00827   return ret.join( "," );
00828 }
00829 
00830 QString QGpgMECryptoConfigEntry::outputString() const
00831 {
00832   Q_ASSERT( mSet );
00833   return toString( true );
00834 }
00835 
00836 bool QGpgMECryptoConfigEntry::isStringType() const
00837 {
00838   return ( mArgType == Kleo::CryptoConfigEntry::ArgType_String
00839            || mArgType == Kleo::CryptoConfigEntry::ArgType_Path
00840            || mArgType == Kleo::CryptoConfigEntry::ArgType_URL
00841            || mArgType == Kleo::CryptoConfigEntry::ArgType_LDAPURL );
00842 }
00843 
00844 void QGpgMECryptoConfigEntry::setDirty( bool b )
00845 {
00846   mDirty = b;
00847 }
00848 
00849 #include "qgpgmecryptoconfig.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys