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 TQt library by Trolltech AS, Norway (or with modified versions
00024     of TQt that use the same license as TQt), 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     TQt.  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 <tdemessagebox.h>
00038 #include <tdelocale.h>
00039 
00040 #include <assert.h>
00041 #include <tdetempfile.h>
00042 #include <tqfile.h>
00043 #include <stdlib.h>
00044 #include <tqtextcodec.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( TQTextCodec::codecForName( "utf8" ) );
00075   proc << "gpgconf"; // must be in the PATH
00076   proc << "--list-components";
00077 
00078   TQObject::connect( &proc, TQT_SIGNAL( readReady(KProcIO*) ),
00079                     this, TQT_SLOT( slotCollectStdOut(KProcIO*) ) );
00080 
00081   // run the process:
00082   int rc = 0;
00083   if ( !proc.start( TDEProcess::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     TQString 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   TQString line;
00106   int result;
00107   while( ( result = proc->readln(line) ) != -1 ) {
00108     //kdDebug(5150) << "GOT LINE:" << line << endl;
00109     // Format: NAME:DESCRIPTION
00110     TQStringList lst = TQStringList::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 TQStringList QGpgMECryptoConfig::componentList() const
00120 {
00121   if ( !mParsed )
00122     const_cast<QGpgMECryptoConfig*>( this )->runGpgConf( true );
00123   TQDictIterator<QGpgMECryptoConfigComponent> it( mComponents );
00124   TQStringList names;
00125   for( ; it.current(); ++it )
00126     names.push_back( it.currentKey() );
00127   return names;
00128 }
00129 
00130 Kleo::CryptoConfigComponent* QGpgMECryptoConfig::component( const TQString& 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   TQDictIterator<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 TQString& name, const TQString& 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( TQTextCodec::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   TQObject::connect( &proc, TQT_SIGNAL( readReady(KProcIO*) ),
00177                     this, TQT_SLOT( slotCollectStdOut(KProcIO*) ) );
00178   mCurrentGroup = 0;
00179 
00180   // run the process:
00181   int rc = 0;
00182   if ( !proc.start( TDEProcess::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   TQString 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 TQStringList lst = TQStringList::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>", TQString(), 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 TQStringList QGpgMECryptoConfigComponent::groupList() const
00233 {
00234   TQDictIterator<QGpgMECryptoConfigGroup> it( mGroups );
00235   TQStringList names;
00236   for( ; it.current(); ++it )
00237     names.push_back( it.currentKey() );
00238   return names;
00239 }
00240 
00241 Kleo::CryptoConfigGroup* QGpgMECryptoConfigComponent::group(const TQString& 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   TQValueList<QGpgMECryptoConfigEntry *> dirtyEntries;
00252 
00253   // Collect all dirty entries
00254   TQDictIterator<QGpgMECryptoConfigGroup> groupit( mGroups );
00255   for( ; groupit.current(); ++groupit ) {
00256     TQDictIterator<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         TQString 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         TQCString 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   TQString commandLine = "gpgconf";
00280   if ( runtime )
00281     commandLine += " --runtime";
00282   commandLine += " --change-options ";
00283   commandLine += TDEProcess::quote( mName );
00284   commandLine += " < ";
00285   commandLine += TDEProcess::quote( tmpFile.name() );
00286 
00287   //kdDebug(5150) << commandLine << endl;
00288   //system( TQCString( "cat " ) + tmpFile.name().latin1() ); // DEBUG
00289 
00290   TDEProcess proc;
00291   proc.setUseShell( true );
00292   proc << commandLine;
00293 
00294   // run the process:
00295   int rc = 0;
00296   if ( !proc.start( TDEProcess::Block ) )
00297     rc = -1;
00298   else
00299     rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ;
00300 
00301   if ( rc == -1 )
00302   {
00303     TQString 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     TQString wmsg = i18n( "Error from gpgconf while saving configuration: %1" ).arg( TQString::fromLocal8Bit( strerror( rc ) ) );
00310     kdWarning(5150) << k_funcinfo << ":" << strerror( rc ) << endl;
00311     KMessageBox::error(0, wmsg);
00312   }
00313   else
00314   {
00315     TQValueList<QGpgMECryptoConfigEntry *>::Iterator it = dirtyEntries.begin();
00316     for( ; it != dirtyEntries.end(); ++it ) {
00317       (*it)->setDirty( false );
00318     }
00319   }
00320 }
00321 
00323 
00324 QGpgMECryptoConfigGroup::QGpgMECryptoConfigGroup( const TQString & name, const TQString& 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 TQStringList QGpgMECryptoConfigGroup::entryList() const
00334 {
00335   TQDictIterator<QGpgMECryptoConfigEntry> it( mEntries );
00336   TQStringList names;
00337   for( ; it.current(); ++it )
00338     names.push_back( it.currentKey() );
00339   return names;
00340 }
00341 
00342 Kleo::CryptoConfigEntry* QGpgMECryptoConfigGroup::entry( const TQString& name ) const
00343 {
00344   return mEntries.find( name );
00345 }
00346 
00348 
00349 static TQString gpgconf_unescape( const TQString& str )
00350 {
00351   // Looks like it's the same rules as KURL.
00352   return KURL::decode_string( str, 106 );
00353 }
00354 
00355 static TQString gpgconf_escape( const TQString& str )
00356 {
00357   // Escape special chars (including ':' and '%')
00358   TQString 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 TQString urlpart_encode( const TQString& str )
00365 {
00366   TQString 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 TQString urlpart_decode( const TQString& 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 TQStringList& 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   TQStringList::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   TQString 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 TQVariant QGpgMECryptoConfigEntry::stringToValue( const TQString& str, bool unescape ) const
00446 {
00447   bool isString = isStringType();
00448 
00449   if ( isList() ) {
00450     if ( argType() == ArgType_None ) {
00451         bool ok = true;
00452         const TQVariant 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     TQValueList<TQVariant> lst;
00458     TQStringList items = TQStringList::split( ',', str );
00459     for( TQStringList::const_iterator valit = items.begin(); valit != items.end(); ++valit ) {
00460       TQString val = *valit;
00461       if ( isString ) {
00462         if ( val.isEmpty() ) {
00463           lst << TQString();
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 << TQVariant( unescape ? gpgconf_unescape( val ) : val );
00473     }
00474     return lst;
00475   } else { // not a list
00476     TQString val( str );
00477     if ( isString ) {
00478       if ( val.isEmpty() )
00479         return TQVariant( TQString() ); // 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 TQVariant( 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 TQString 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 TQString& str )
00550 {
00551   if ( mRealArgType == 33 ) { // LDAP server
00552     // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
00553     TQStringList items = TQStringList::split( ':', str, true );
00554     if ( items.count() == 5 ) {
00555       TQStringList::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 TQString 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       TQString::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   TQString 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 TQStringList QGpgMECryptoConfigEntry::stringValueList() const
00611 {
00612   Q_ASSERT( isStringType() );
00613   Q_ASSERT( isList() );
00614   return mValue.toStringList();
00615 }
00616 
00617 TQValueList<int> QGpgMECryptoConfigEntry::intValueList() const
00618 {
00619   Q_ASSERT( mArgType == ArgType_Int );
00620   Q_ASSERT( isList() );
00621   TQValueList<int> ret;
00622   TQValueList<TQVariant> lst = mValue.toList();
00623   for( TQValueList<TQVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00624     ret.append( (*it).toInt() );
00625   }
00626   return ret;
00627 }
00628 
00629 TQValueList<unsigned int> QGpgMECryptoConfigEntry::uintValueList() const
00630 {
00631   Q_ASSERT( mArgType == ArgType_UInt );
00632   Q_ASSERT( isList() );
00633   TQValueList<unsigned int> ret;
00634   TQValueList<TQVariant> lst = mValue.toList();
00635   for( TQValueList<TQVariant>::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   TQStringList lst = mValue.toStringList();
00646 
00647   KURL::List ret;
00648   for( TQStringList::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   }
00667   else if ( mArgType == ArgType_None ) {
00668     if ( isList() ) {
00669       mValue = 0U;
00670     }
00671     else {
00672       mValue = false;
00673     }
00674   }
00675 }
00676 
00677 void QGpgMECryptoConfigEntry::setBoolValue( bool b )
00678 {
00679   Q_ASSERT( mArgType == ArgType_None );
00680   Q_ASSERT( !isList() );
00681   // A "no arg" option is either set or not set.
00682   // Being set means mSet==true + mValue==true, being unset means resetToDefault(), i.e. both false
00683   mValue = b;
00684   mSet = b;
00685   mDirty = true;
00686 }
00687 
00688 void QGpgMECryptoConfigEntry::setStringValue( const TQString& str )
00689 {
00690   mValue = stringToValue( str, false );
00691   // When setting a string to empty (and there's no default), we need to act like resetToDefault
00692   // Otherwise we try e.g. "ocsp-responder:0:" and gpgconf answers:
00693   // "gpgconf: argument required for option ocsp-responder"
00694   if ( str.isEmpty() && !isOptional() )
00695     mSet = false;
00696   else
00697     mSet = true;
00698   mDirty = true;
00699 }
00700 
00701 void QGpgMECryptoConfigEntry::setIntValue( int i )
00702 {
00703   Q_ASSERT( mArgType == ArgType_Int );
00704   Q_ASSERT( !isList() );
00705   mValue = i;
00706   mSet = true;
00707   mDirty = true;
00708 }
00709 
00710 void QGpgMECryptoConfigEntry::setUIntValue( unsigned int i )
00711 {
00712   mValue = i;
00713   mSet = true;
00714   mDirty = true;
00715 }
00716 
00717 void QGpgMECryptoConfigEntry::setURLValue( const KURL& url )
00718 {
00719   TQString str = splitURL( mRealArgType, url );
00720   if ( str.isEmpty() && !isOptional() )
00721     mSet = false;
00722   else
00723     mSet = true;
00724   mValue = str;
00725   mDirty = true;
00726 }
00727 
00728 void QGpgMECryptoConfigEntry::setNumberOfTimesSet( unsigned int i )
00729 {
00730   Q_ASSERT( mArgType == ArgType_None );
00731   Q_ASSERT( isList() );
00732   mValue = i;
00733   mSet = i > 0;
00734   mDirty = true;
00735 }
00736 
00737 void QGpgMECryptoConfigEntry::setStringValueList( const TQStringList& lst )
00738 {
00739   mValue = lst;
00740   if ( lst.isEmpty() && !isOptional() )
00741     mSet = false;
00742   else
00743     mSet = true;
00744   mDirty = true;
00745 }
00746 
00747 void QGpgMECryptoConfigEntry::setIntValueList( const TQValueList<int>& lst )
00748 {
00749   TQValueList<TQVariant> ret;
00750   for( TQValueList<int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00751     ret << TQVariant( *it );
00752   }
00753   mValue = ret;
00754   if ( ret.isEmpty() && !isOptional() )
00755     mSet = false;
00756   else
00757     mSet = true;
00758   mDirty = true;
00759 }
00760 
00761 void QGpgMECryptoConfigEntry::setUIntValueList( const TQValueList<unsigned int>& lst )
00762 {
00763   TQValueList<TQVariant> ret;
00764   for( TQValueList<unsigned int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00765     ret << TQVariant( *it );
00766   }
00767   if ( ret.isEmpty() && !isOptional() )
00768     mSet = false;
00769   else
00770     mSet = true;
00771   mValue = ret;
00772   mDirty = true;
00773 }
00774 
00775 void QGpgMECryptoConfigEntry::setURLValueList( const KURL::List& urls )
00776 {
00777   TQStringList lst;
00778   for( KURL::List::const_iterator it = urls.begin(); it != urls.end(); ++it ) {
00779     lst << splitURL( mRealArgType, *it );
00780   }
00781   mValue = lst;
00782   if ( lst.isEmpty() && !isOptional() )
00783     mSet = false;
00784   else
00785     mSet = true;
00786   mDirty = true;
00787 }
00788 
00789 TQString QGpgMECryptoConfigEntry::toString( bool escape ) const
00790 {
00791   // Basically the opposite of stringToValue
00792   if ( isStringType() ) {
00793     if ( mValue.isNull() )
00794       return TQString();
00795     else if ( isList() ) { // string list
00796       TQStringList lst = mValue.toStringList();
00797       if ( escape ) {
00798         for( TQStringList::iterator it = lst.begin(); it != lst.end(); ++it ) {
00799           if ( !(*it).isNull() )
00800             *it = gpgconf_escape( *it ).prepend( "\"" );
00801         }
00802       }
00803       TQString res = lst.join( "," );
00804       kdDebug(5150) << "toString: " << res << endl;
00805       return res;
00806     } else { // normal string
00807       TQString res = mValue.toString();
00808       if ( escape )
00809         res = gpgconf_escape( res ).prepend( "\"" );
00810       return res;
00811     }
00812   }
00813   if ( !isList() ) // non-list non-string
00814   {
00815     if ( mArgType == ArgType_None ) {
00816       return mValue.toBool() ? TQString::fromLatin1( "1" ) : TQString();
00817     } else { // some int
00818       Q_ASSERT( mArgType == ArgType_Int || mArgType == ArgType_UInt );
00819       return mValue.toString(); // int to string conversion
00820     }
00821   }
00822 
00823   // Lists (of other types than strings)
00824   if ( mArgType == ArgType_None )
00825     return TQString::number( numberOfTimesSet() );
00826   TQStringList ret;
00827   TQValueList<TQVariant> lst = mValue.toList();
00828   for( TQValueList<TQVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
00829       ret << (*it).toString(); // TQVariant does the conversion
00830   }
00831   return ret.join( "," );
00832 }
00833 
00834 TQString QGpgMECryptoConfigEntry::outputString() const
00835 {
00836   Q_ASSERT( mSet );
00837   return toString( true );
00838 }
00839 
00840 bool QGpgMECryptoConfigEntry::isStringType() const
00841 {
00842   return ( mArgType == Kleo::CryptoConfigEntry::ArgType_String
00843            || mArgType == Kleo::CryptoConfigEntry::ArgType_Path
00844            || mArgType == Kleo::CryptoConfigEntry::ArgType_URL
00845            || mArgType == Kleo::CryptoConfigEntry::ArgType_LDAPURL );
00846 }
00847 
00848 void QGpgMECryptoConfigEntry::setDirty( bool b )
00849 {
00850   mDirty = b;
00851 }
00852 
00853 #include "qgpgmecryptoconfig.moc"