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 <kmessagebox.h> 00038 #include <klocale.h> 00039 00040 #include <assert.h> 00041 #include <ktempfile.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( 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 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( 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 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 += KProcess::quote( mName ); 00284 commandLine += " < "; 00285 commandLine += KProcess::quote( tmpFile.name() ); 00286 00287 //kdDebug(5150) << commandLine << endl; 00288 //system( TQCString( "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 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"