qgpgmecryptoconfig.cpp
1/*
2 qgpgmecryptoconfig.cpp
3
4 This file is part of libkleopatra, the KDE keymanagement library
5 Copyright (c) 2004 Klarälvdalens Datakonsult AB
6
7 Libkleopatra is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 Libkleopatra is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21 In addition, as a special exception, the copyright holders give
22 permission to link the code of this program with any edition of
23 the TQt library by Trolltech AS, Norway (or with modified versions
24 of TQt that use the same license as TQt), and distribute linked
25 combinations including the two. You must obey the GNU General
26 Public License in all respects for all of the code used other than
27 TQt. If you modify this file, you may extend this exception to
28 your version of the file, but you are not obligated to do so. If
29 you do not wish to do so, delete this exception statement from
30 your version.
31*/
32
33#include "qgpgmecryptoconfig.h"
34#include <kdebug.h>
35#include <tdeprocio.h>
36#include <errno.h>
37#include <tdemessagebox.h>
38#include <tdelocale.h>
39
40#include <assert.h>
41#include <tdetempfile.h>
42#include <tqfile.h>
43#include <stdlib.h>
44#include <tqtextcodec.h>
45
46// Just for the Q_ASSERT in the dtor. Not thread-safe, but who would
47// have 2 threads talking to gpgconf anyway? :)
48static bool s_duringClear = false;
49
50static const int GPGCONF_FLAG_GROUP = 1;
51static const int GPGCONF_FLAG_OPTIONAL = 2;
52static const int GPGCONF_FLAG_LIST = 4;
53static const int GPGCONF_FLAG_RUNTIME = 8;
54static const int GPGCONF_FLAG_DEFAULT = 16; // fixed default value available
55static const int GPGCONF_FLAG_DEFAULT_DESC = 32; // runtime default value available
56static const int GPGCONF_FLAG_NOARG_DESC = 64; // option with optional arg; special meaning if no arg set
57static const int GPGCONF_FLAG_NO_CHANGE = 128; // readonly
58// Change size of mFlags bitfield if adding new values here
59
61 : mComponents( 7 ), mParsed( false )
62{
63 mComponents.setAutoDelete( true );
64}
65
66QGpgMECryptoConfig::~QGpgMECryptoConfig()
67{
68}
69
70void QGpgMECryptoConfig::runGpgConf( bool showErrors )
71{
72 // Run gpgconf --list-components to make the list of components
73
74 TDEProcIO proc( TQTextCodec::codecForName( "utf8" ) );
75 proc << "gpgconf"; // must be in the PATH
76 proc << "--list-components";
77
78 TQObject::connect( &proc, TQ_SIGNAL( readReady(TDEProcIO*) ),
79 this, TQ_SLOT( slotCollectStdOut(TDEProcIO*) ) );
80
81 // run the process:
82 int rc = 0;
83 if ( !proc.start( TDEProcess::Block ) )
84 rc = -1;
85 else
86 rc = ( proc.normalExit() ) ? proc.exitStatus() : -2 ;
87
88 // handle errors, if any (and if requested)
89 if ( showErrors && rc != 0 ) {
90 TQString wmsg = i18n("<qt>Failed to execute gpgconf:<br>%1</qt>");
91 if ( rc == -1 )
92 wmsg = wmsg.arg( i18n( "program not found" ) );
93 else if ( rc == -2 )
94 wmsg = wmsg.arg( i18n( "program cannot be executed" ) );
95 else
96 wmsg = wmsg.arg( strerror(rc) );
97 kdWarning(5150) << wmsg << endl; // to see it from test_cryptoconfig.cpp
98 KMessageBox::error(0, wmsg);
99 }
100 mParsed = true;
101}
102
103void QGpgMECryptoConfig::slotCollectStdOut( TDEProcIO* proc )
104{
105 TQString line;
106 int result;
107 while( ( result = proc->readln(line) ) != -1 ) {
108 //kdDebug(5150) << "GOT LINE:" << line << endl;
109 // Format: NAME:DESCRIPTION
110 TQStringList lst = TQStringList::split( ':', line, true );
111 if ( lst.count() >= 2 ) {
112 mComponents.insert( lst[0], new QGpgMECryptoConfigComponent( this, lst[0], lst[1] ) );
113 } else {
114 kdWarning(5150) << "Parse error on gpgconf --list-components output: " << line << endl;
115 }
116 }
117}
118
120{
121 if ( !mParsed )
122 const_cast<QGpgMECryptoConfig*>( this )->runGpgConf( true );
123 TQDictIterator<QGpgMECryptoConfigComponent> it( mComponents );
124 TQStringList names;
125 for( ; it.current(); ++it )
126 names.push_back( it.currentKey() );
127 return names;
128}
129
131{
132 if ( !mParsed )
133 const_cast<QGpgMECryptoConfig*>( this )->runGpgConf( false );
134 return mComponents.find( name );
135}
136
137void QGpgMECryptoConfig::sync( bool runtime )
138{
139 TQDictIterator<QGpgMECryptoConfigComponent> it( mComponents );
140 for( ; it.current(); ++it )
141 it.current()->sync( runtime );
142}
143
145{
146 s_duringClear = true;
147 mComponents.clear();
148 s_duringClear = false;
149 mParsed = false; // next call to componentList/component will need to run gpgconf again
150}
151
153
154QGpgMECryptoConfigComponent::QGpgMECryptoConfigComponent( QGpgMECryptoConfig*, const TQString& name, const TQString& description )
155 : mGroups( 7 ), mName( name ), mDescription( description )
156{
157 mGroups.setAutoDelete( true );
158 runGpgConf();
159}
160
161QGpgMECryptoConfigComponent::~QGpgMECryptoConfigComponent()
162{
163}
164
165void QGpgMECryptoConfigComponent::runGpgConf()
166{
167 // Run gpgconf --list-options <component>, and create all groups and entries for that component
168
169 TDEProcIO proc( TQTextCodec::codecForName( "utf8" ) );
170 proc << "gpgconf"; // must be in the PATH
171 proc << "--list-options";
172 proc << mName;
173
174 //kdDebug(5150) << "Running gpgconf --list-options " << mName << endl;
175
176 TQObject::connect( &proc, TQ_SIGNAL( readReady(TDEProcIO*) ),
177 this, TQ_SLOT( slotCollectStdOut(TDEProcIO*) ) );
178 mCurrentGroup = 0;
179
180 // run the process:
181 int rc = 0;
182 if ( !proc.start( TDEProcess::Block ) )
183 rc = -1;
184 else
185 rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ;
186
187 if( rc != 0 ) // can happen when using the wrong version of gpg...
188 kdWarning(5150) << "Running 'gpgconf --list-options " << mName << "' failed. " << strerror( rc ) << ", but try that command to see the real output" << endl;
189 else {
190 if ( mCurrentGroup && !mCurrentGroup->mEntries.isEmpty() ) // only add non-empty groups
191 mGroups.insert( mCurrentGroupName, mCurrentGroup );
192 }
193}
194
195void QGpgMECryptoConfigComponent::slotCollectStdOut( TDEProcIO* proc )
196{
197 TQString line;
198 int result;
199 while( ( result = proc->readln(line) ) != -1 ) {
200 //kdDebug(5150) << "GOT LINE:" << line << endl;
201 // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
202 const TQStringList lst = TQStringList::split( ':', line, true );
203 if ( lst.count() >= 10 ) {
204 const int flags = lst[1].toInt();
205 const int level = lst[2].toInt();
206 if ( level > 2 ) // invisible or internal -> skip it;
207 continue;
208 if ( flags & GPGCONF_FLAG_GROUP ) {
209 if ( mCurrentGroup && !mCurrentGroup->mEntries.isEmpty() ) // only add non-empty groups
210 mGroups.insert( mCurrentGroupName, mCurrentGroup );
211 //else
212 // kdDebug(5150) << "Discarding empty group " << mCurrentGroupName << endl;
213 mCurrentGroup = new QGpgMECryptoConfigGroup( lst[0], lst[3], level );
214 mCurrentGroupName = lst[0];
215 } else {
216 // normal entry
217 if ( !mCurrentGroup ) { // first toplevel entry -> create toplevel group
218 mCurrentGroup = new QGpgMECryptoConfigGroup( "<nogroup>", TQString(), 0 );
219 mCurrentGroupName = "<nogroup>";
220 }
221 mCurrentGroup->mEntries.insert( lst[0], new QGpgMECryptoConfigEntry( lst ) );
222 }
223 } else {
224 // This happens on lines like
225 // dirmngr[31465]: error opening `/home/dfaure/.gnupg/dirmngr_ldapservers.conf': No such file or directory
226 // so let's not bother the user with it.
227 //kdWarning(5150) << "Parse error on gpgconf --list-options output: " << line << endl;
228 }
229 }
230}
231
233{
234 TQDictIterator<QGpgMECryptoConfigGroup> it( mGroups );
235 TQStringList names;
236 for( ; it.current(); ++it )
237 names.push_back( it.currentKey() );
238 return names;
239}
240
242{
243 return mGroups.find( name );
244}
245
246void QGpgMECryptoConfigComponent::sync( bool runtime )
247{
248 KTempFile tmpFile;
249 tmpFile.setAutoDelete( true );
250
251 TQValueList<QGpgMECryptoConfigEntry *> dirtyEntries;
252
253 // Collect all dirty entries
254 TQDictIterator<QGpgMECryptoConfigGroup> groupit( mGroups );
255 for( ; groupit.current(); ++groupit ) {
256 TQDictIterator<QGpgMECryptoConfigEntry> it( groupit.current()->mEntries );
257 for( ; it.current(); ++it ) {
258 if ( it.current()->isDirty() ) {
259 // OK, we can set it.currentKey() to it.current()->outputString()
260 TQString line = it.currentKey();
261 if ( it.current()->isSet() ) { // set option
262 line += ":0:";
263 line += it.current()->outputString();
264 } else { // unset option
265 line += ":16:";
266 }
267 line += '\n';
268 TQCString line8bit = line.utf8(); // encode with utf8, and TDEProcIO uses utf8 when reading.
269 tmpFile.file()->writeBlock( line8bit.data(), line8bit.size()-1 /*no 0*/ );
270 dirtyEntries.append( it.current() );
271 }
272 }
273 }
274 tmpFile.close();
275 if ( dirtyEntries.isEmpty() )
276 return;
277
278 // Call gpgconf --change-options <component>
279 TQString commandLine = "gpgconf";
280 if ( runtime )
281 commandLine += " --runtime";
282 commandLine += " --change-options ";
283 commandLine += TDEProcess::quote( mName );
284 commandLine += " < ";
285 commandLine += TDEProcess::quote( tmpFile.name() );
286
287 //kdDebug(5150) << commandLine << endl;
288 //system( TQCString( "cat " ) + tmpFile.name().latin1() ); // DEBUG
289
290 TDEProcess proc;
291 proc.setUseShell( true );
292 proc << commandLine;
293
294 // run the process:
295 int rc = 0;
296 if ( !proc.start( TDEProcess::Block ) )
297 rc = -1;
298 else
299 rc = ( proc.normalExit() ) ? proc.exitStatus() : -1 ;
300
301 if ( rc == -1 )
302 {
303 TQString wmsg = i18n( "Could not start gpgconf\nCheck that gpgconf is in the PATH and that it can be started" );
304 kdWarning(5150) << wmsg << endl;
305 KMessageBox::error(0, wmsg);
306 }
307 else if( rc != 0 ) // Happens due to bugs in gpgconf (e.g. issues 104/115)
308 {
309 TQString wmsg = i18n( "Error from gpgconf while saving configuration: %1" ).arg( TQString::fromLocal8Bit( strerror( rc ) ) );
310 kdWarning(5150) << k_funcinfo << ":" << strerror( rc ) << endl;
311 KMessageBox::error(0, wmsg);
312 }
313 else
314 {
315 TQValueList<QGpgMECryptoConfigEntry *>::Iterator it = dirtyEntries.begin();
316 for( ; it != dirtyEntries.end(); ++it ) {
317 (*it)->setDirty( false );
318 }
319 }
320}
321
323
324QGpgMECryptoConfigGroup::QGpgMECryptoConfigGroup( const TQString & name, const TQString& description, int level )
325 : mEntries( 29 ),
326 mName( name ),
327 mDescription( description ),
328 mLevel( static_cast<Kleo::CryptoConfigEntry::Level>( level ) )
329{
330 mEntries.setAutoDelete( true );
331}
332
333TQStringList QGpgMECryptoConfigGroup::entryList() const
334{
335 TQDictIterator<QGpgMECryptoConfigEntry> it( mEntries );
336 TQStringList names;
337 for( ; it.current(); ++it )
338 names.push_back( it.currentKey() );
339 return names;
340}
341
342Kleo::CryptoConfigEntry* QGpgMECryptoConfigGroup::entry( const TQString& name ) const
343{
344 return mEntries.find( name );
345}
346
348
349static TQString gpgconf_unescape( const TQString& str )
350{
351 // Looks like it's the same rules as KURL.
352 return KURL::decode_string( str, 106 );
353}
354
355static TQString gpgconf_escape( const TQString& str )
356{
357 // Escape special chars (including ':' and '%')
358 TQString enc = KURL::encode_string( str, 106 ); // and convert to utf8 first (to get %12%34 for one special char)
359 // Also encode commas, for lists.
360 enc.replace( ',', "%2c" );
361 return enc;
362}
363
364static TQString urlpart_encode( const TQString& str )
365{
366 TQString enc( str );
367 enc.replace( '%', "%25" ); // first!
368 enc.replace( ':', "%3a" );
369 //kdDebug() << " urlpart_encode: " << str << " -> " << enc << endl;
370 return enc;
371}
372
373static TQString urlpart_decode( const TQString& str )
374{
375 return KURL::decode_string( str );
376}
377
378// gpgconf arg type number -> CryptoConfigEntry arg type enum mapping
379static Kleo::CryptoConfigEntry::ArgType knownArgType( int argType, bool& ok ) {
380 ok = true;
381 switch( argType ) {
382 case 0: // none
383 return Kleo::CryptoConfigEntry::ArgType_None;
384 case 1: // string
385 return Kleo::CryptoConfigEntry::ArgType_String;
386 case 2: // int32
387 return Kleo::CryptoConfigEntry::ArgType_Int;
388 case 3: // uint32
389 return Kleo::CryptoConfigEntry::ArgType_UInt;
390 case 32: // pathname
391 return Kleo::CryptoConfigEntry::ArgType_Path;
392 case 33: // ldap server
393 return Kleo::CryptoConfigEntry::ArgType_LDAPURL;
394 default:
395 ok = false;
396 return Kleo::CryptoConfigEntry::ArgType_None;
397 }
398}
399
400QGpgMECryptoConfigEntry::QGpgMECryptoConfigEntry( const TQStringList& parsedLine )
401{
402 // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
403 assert( parsedLine.count() >= 10 ); // called checked for it already
404 TQStringList::const_iterator it = parsedLine.begin();
405 mName = *it++;
406 mFlags = (*it++).toInt();
407 mLevel = (*it++).toInt();
408 mDescription = *it++;
409 bool ok;
410 // we keep the real (int) arg type, since it influences the parsing (e.g. for ldap urls)
411 mRealArgType = (*it++).toInt();
412 mArgType = knownArgType( mRealArgType, ok );
413 if ( !ok && !(*it).isEmpty() ) {
414 // use ALT-TYPE
415 mRealArgType = (*it).toInt();
416 mArgType = knownArgType( mRealArgType, ok );
417 }
418 if ( !ok )
419 kdWarning(5150) << "Unsupported datatype: " << parsedLine[4] << " : " << *it << " for " << parsedLine[0] << endl;
420 ++it; // done with alt-type
421 ++it; // skip argname (not useful in GUIs)
422
423 mSet = false;
424 TQString value;
425 if ( mFlags & GPGCONF_FLAG_DEFAULT ) {
426 value = *it; // get default value
427 mDefaultValue = stringToValue( value, true );
428 }
429 ++it; // done with DEFAULT
430 ++it; // ### skip ARGDEF for now. It's only for options with an "optional arg"
431 //kdDebug(5150) << "Entry " << parsedLine[0] << " val=" << *it << endl;
432
433 if ( !(*it).isEmpty() ) { // a real value was set
434 mSet = true;
435 value = *it;
436 mValue = stringToValue( value, true );
437 }
438 else {
439 mValue = mDefaultValue;
440 }
441
442 mDirty = false;
443}
444
445TQVariant QGpgMECryptoConfigEntry::stringToValue( const TQString& str, bool unescape ) const
446{
447 bool isString = isStringType();
448
449 if ( isList() ) {
450 if ( argType() == ArgType_None ) {
451 bool ok = true;
452 const TQVariant v = str.isEmpty() ? 0U : str.toUInt( &ok ) ;
453 if ( !ok )
454 kdWarning(5150) << "list-of-none should have an unsigned int as value:" << str << endl;
455 return v;
456 }
457 TQValueList<TQVariant> lst;
458 TQStringList items = TQStringList::split( ',', str );
459 for( TQStringList::const_iterator valit = items.begin(); valit != items.end(); ++valit ) {
460 TQString val = *valit;
461 if ( isString ) {
462 if ( val.isEmpty() ) {
463 lst << TQString();
464 continue;
465 }
466 else if ( unescape ) {
467 if( val[0] != '"' ) // see README.gpgconf
468 kdWarning(5150) << "String value should start with '\"' : " << val << endl;
469 val = val.mid( 1 );
470 }
471 }
472 lst << TQVariant( unescape ? gpgconf_unescape( val ) : val );
473 }
474 return lst;
475 } else { // not a list
476 TQString val( str );
477 if ( isString ) {
478 if ( val.isEmpty() )
479 return TQVariant( TQString() ); // not set [ok with lists too?]
480 else if ( unescape ) {
481 Q_ASSERT( val[0] == '"' ); // see README.gpgconf
482 val = val.mid( 1 );
483 }
484 }
485 return TQVariant( unescape ? gpgconf_unescape( val ) : val );
486 }
487}
488
489QGpgMECryptoConfigEntry::~QGpgMECryptoConfigEntry()
490{
491#ifndef NDEBUG
492 if ( !s_duringClear && mDirty )
493 kdWarning(5150) << "Deleting a QGpgMECryptoConfigEntry that was modified (" << mDescription << ")\n"
494 << "You forgot to call sync() (to commit) or clear() (to discard)" << endl;
495#endif
496}
497
498bool QGpgMECryptoConfigEntry::isOptional() const
499{
500 return mFlags & GPGCONF_FLAG_OPTIONAL;
501}
502
503bool QGpgMECryptoConfigEntry::isReadOnly() const
504{
505 return mFlags & GPGCONF_FLAG_NO_CHANGE;
506}
507
508bool QGpgMECryptoConfigEntry::isList() const
509{
510 return mFlags & GPGCONF_FLAG_LIST;
511}
512
513bool QGpgMECryptoConfigEntry::isRuntime() const
514{
515 return mFlags & GPGCONF_FLAG_RUNTIME;
516}
517
518bool QGpgMECryptoConfigEntry::isSet() const
519{
520 return mSet;
521}
522
523bool QGpgMECryptoConfigEntry::boolValue() const
524{
525 Q_ASSERT( mArgType == ArgType_None );
526 Q_ASSERT( !isList() );
527 return mValue.toBool();
528}
529
530TQString QGpgMECryptoConfigEntry::stringValue() const
531{
532 return toString( false );
533}
534
535int QGpgMECryptoConfigEntry::intValue() const
536{
537 Q_ASSERT( mArgType == ArgType_Int );
538 Q_ASSERT( !isList() );
539 return mValue.toInt();
540}
541
542unsigned int QGpgMECryptoConfigEntry::uintValue() const
543{
544 Q_ASSERT( mArgType == ArgType_UInt );
545 Q_ASSERT( !isList() );
546 return mValue.toUInt();
547}
548
549static KURL parseURL( int mRealArgType, const TQString& str )
550{
551 if ( mRealArgType == 33 ) { // LDAP server
552 // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
553 TQStringList items = TQStringList::split( ':', str, true );
554 if ( items.count() == 5 ) {
555 TQStringList::const_iterator it = items.begin();
556 KURL url;
557 url.setProtocol( "ldap" );
558 url.setHost( urlpart_decode( *it++ ) );
559 url.setPort( (*it++).toInt() );
560 url.setPath( "/" ); // workaround KURL parsing bug
561 url.setUser( urlpart_decode( *it++ ) );
562 url.setPass( urlpart_decode( *it++ ) );
563 url.setQuery( urlpart_decode( *it ) );
564 return url;
565 } else
566 kdWarning(5150) << "parseURL: malformed LDAP server: " << str << endl;
567 }
568 // other URLs : assume wellformed URL syntax.
569 return KURL( str );
570}
571
572// The opposite of parseURL
573static TQString splitURL( int mRealArgType, const KURL& url )
574{
575 if ( mRealArgType == 33 ) { // LDAP server
576 // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
577 Q_ASSERT( url.protocol() == "ldap" );
578 return urlpart_encode( url.host() ) + ":" +
579 TQString::number( url.port() ) + ":" +
580 urlpart_encode( url.user() ) + ":" +
581 urlpart_encode( url.pass() ) + ":" +
582 // KURL automatically encoded the query (e.g. for spaces inside it),
583 // so decode it before writing it out to gpgconf (issue119)
584 urlpart_encode( KURL::decode_string( url.query().mid(1) ) );
585 }
586 return url.path();
587}
588
589KURL QGpgMECryptoConfigEntry::urlValue() const
590{
591 Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
592 Q_ASSERT( !isList() );
593 TQString str = mValue.toString();
594 if ( mArgType == ArgType_Path )
595 {
596 KURL url;
597 url.setPath( str );
598 return url;
599 }
600 return parseURL( mRealArgType, str );
601}
602
603unsigned int QGpgMECryptoConfigEntry::numberOfTimesSet() const
604{
605 Q_ASSERT( mArgType == ArgType_None );
606 Q_ASSERT( isList() );
607 return mValue.toUInt();
608}
609
610TQStringList QGpgMECryptoConfigEntry::stringValueList() const
611{
612 Q_ASSERT( isStringType() );
613 Q_ASSERT( isList() );
614 return mValue.toStringList();
615}
616
617TQValueList<int> QGpgMECryptoConfigEntry::intValueList() const
618{
619 Q_ASSERT( mArgType == ArgType_Int );
620 Q_ASSERT( isList() );
621 TQValueList<int> ret;
622 TQValueList<TQVariant> lst = mValue.toList();
623 for( TQValueList<TQVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
624 ret.append( (*it).toInt() );
625 }
626 return ret;
627}
628
629TQValueList<unsigned int> QGpgMECryptoConfigEntry::uintValueList() const
630{
631 Q_ASSERT( mArgType == ArgType_UInt );
632 Q_ASSERT( isList() );
633 TQValueList<unsigned int> ret;
634 TQValueList<TQVariant> lst = mValue.toList();
635 for( TQValueList<TQVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
636 ret.append( (*it).toUInt() );
637 }
638 return ret;
639}
640
641KURL::List QGpgMECryptoConfigEntry::urlValueList() const
642{
643 Q_ASSERT( mArgType == ArgType_Path || mArgType == ArgType_URL || mArgType == ArgType_LDAPURL );
644 Q_ASSERT( isList() );
645 TQStringList lst = mValue.toStringList();
646
647 KURL::List ret;
648 for( TQStringList::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
649 if ( mArgType == ArgType_Path ) {
650 KURL url;
651 url.setPath( *it );
652 ret << url;
653 } else {
654 ret << parseURL( mRealArgType, *it );
655 }
656 }
657 return ret;
658}
659
660void QGpgMECryptoConfigEntry::resetToDefault()
661{
662 mSet = false;
663 mDirty = true;
664 if ( mFlags & GPGCONF_FLAG_DEFAULT ) {
665 mValue = mDefaultValue;
666 }
667 else if ( mArgType == ArgType_None ) {
668 if ( isList() ) {
669 mValue = 0U;
670 }
671 else {
672 mValue = false;
673 }
674 }
675}
676
677void QGpgMECryptoConfigEntry::setBoolValue( bool b )
678{
679 Q_ASSERT( mArgType == ArgType_None );
680 Q_ASSERT( !isList() );
681 // A "no arg" option is either set or not set.
682 // Being set means mSet==true + mValue==true, being unset means resetToDefault(), i.e. both false
683 mValue = b;
684 mSet = b;
685 mDirty = true;
686}
687
688void QGpgMECryptoConfigEntry::setStringValue( const TQString& str )
689{
690 mValue = stringToValue( str, false );
691 // When setting a string to empty (and there's no default), we need to act like resetToDefault
692 // Otherwise we try e.g. "ocsp-responder:0:" and gpgconf answers:
693 // "gpgconf: argument required for option ocsp-responder"
694 if ( str.isEmpty() && !isOptional() )
695 mSet = false;
696 else
697 mSet = true;
698 mDirty = true;
699}
700
701void QGpgMECryptoConfigEntry::setIntValue( int i )
702{
703 Q_ASSERT( mArgType == ArgType_Int );
704 Q_ASSERT( !isList() );
705 mValue = i;
706 mSet = true;
707 mDirty = true;
708}
709
710void QGpgMECryptoConfigEntry::setUIntValue( unsigned int i )
711{
712 mValue = i;
713 mSet = true;
714 mDirty = true;
715}
716
717void QGpgMECryptoConfigEntry::setURLValue( const KURL& url )
718{
719 TQString str = splitURL( mRealArgType, url );
720 if ( str.isEmpty() && !isOptional() )
721 mSet = false;
722 else
723 mSet = true;
724 mValue = str;
725 mDirty = true;
726}
727
728void QGpgMECryptoConfigEntry::setNumberOfTimesSet( unsigned int i )
729{
730 Q_ASSERT( mArgType == ArgType_None );
731 Q_ASSERT( isList() );
732 mValue = i;
733 mSet = i > 0;
734 mDirty = true;
735}
736
737void QGpgMECryptoConfigEntry::setStringValueList( const TQStringList& lst )
738{
739 mValue = lst;
740 if ( lst.isEmpty() && !isOptional() )
741 mSet = false;
742 else
743 mSet = true;
744 mDirty = true;
745}
746
747void QGpgMECryptoConfigEntry::setIntValueList( const TQValueList<int>& lst )
748{
749 TQValueList<TQVariant> ret;
750 for( TQValueList<int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
751 ret << TQVariant( *it );
752 }
753 mValue = ret;
754 if ( ret.isEmpty() && !isOptional() )
755 mSet = false;
756 else
757 mSet = true;
758 mDirty = true;
759}
760
761void QGpgMECryptoConfigEntry::setUIntValueList( const TQValueList<unsigned int>& lst )
762{
763 TQValueList<TQVariant> ret;
764 for( TQValueList<unsigned int>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
765 ret << TQVariant( *it );
766 }
767 if ( ret.isEmpty() && !isOptional() )
768 mSet = false;
769 else
770 mSet = true;
771 mValue = ret;
772 mDirty = true;
773}
774
775void QGpgMECryptoConfigEntry::setURLValueList( const KURL::List& urls )
776{
777 TQStringList lst;
778 for( KURL::List::const_iterator it = urls.begin(); it != urls.end(); ++it ) {
779 lst << splitURL( mRealArgType, *it );
780 }
781 mValue = lst;
782 if ( lst.isEmpty() && !isOptional() )
783 mSet = false;
784 else
785 mSet = true;
786 mDirty = true;
787}
788
789TQString QGpgMECryptoConfigEntry::toString( bool escape ) const
790{
791 // Basically the opposite of stringToValue
792 if ( isStringType() ) {
793 if ( mValue.isNull() )
794 return TQString();
795 else if ( isList() ) { // string list
796 TQStringList lst = mValue.toStringList();
797 if ( escape ) {
798 for( TQStringList::iterator it = lst.begin(); it != lst.end(); ++it ) {
799 if ( !(*it).isNull() )
800 *it = gpgconf_escape( *it ).prepend( "\"" );
801 }
802 }
803 TQString res = lst.join( "," );
804 kdDebug(5150) << "toString: " << res << endl;
805 return res;
806 } else { // normal string
807 TQString res = mValue.toString();
808 if ( escape )
809 res = gpgconf_escape( res ).prepend( "\"" );
810 return res;
811 }
812 }
813 if ( !isList() ) // non-list non-string
814 {
815 if ( mArgType == ArgType_None ) {
816 return mValue.toBool() ? TQString::fromLatin1( "1" ) : TQString();
817 } else { // some int
818 Q_ASSERT( mArgType == ArgType_Int || mArgType == ArgType_UInt );
819 return mValue.toString(); // int to string conversion
820 }
821 }
822
823 // Lists (of other types than strings)
824 if ( mArgType == ArgType_None )
825 return TQString::number( numberOfTimesSet() );
826 TQStringList ret;
827 TQValueList<TQVariant> lst = mValue.toList();
828 for( TQValueList<TQVariant>::const_iterator it = lst.begin(); it != lst.end(); ++it ) {
829 ret << (*it).toString(); // TQVariant does the conversion
830 }
831 return ret.join( "," );
832}
833
834TQString QGpgMECryptoConfigEntry::outputString() const
835{
836 Q_ASSERT( mSet );
837 return toString( true );
838}
839
840bool QGpgMECryptoConfigEntry::isStringType() const
841{
842 return ( mArgType == Kleo::CryptoConfigEntry::ArgType_String
843 || mArgType == Kleo::CryptoConfigEntry::ArgType_Path
844 || mArgType == Kleo::CryptoConfigEntry::ArgType_URL
845 || mArgType == Kleo::CryptoConfigEntry::ArgType_LDAPURL );
846}
847
848void QGpgMECryptoConfigEntry::setDirty( bool b )
849{
850 mDirty = b;
851}
852
853#include "qgpgmecryptoconfig.moc"
Crypto config for one component (e.g.
Definition: cryptoconfig.h:295
Description of a single option.
Definition: cryptoconfig.h:49
ArgType
Type of the argument.
Definition: cryptoconfig.h:79
Group containing a set of config options.
Definition: cryptoconfig.h:252
For docu, see kleo/cryptoconfig.h.
TQStringList groupList() const
Returns the list of groups that are known about.
TQString name() const
Return the internal name of this component.
Kleo::CryptoConfigGroup * group(const TQString &name) const
CryptoConfig implementation around the gpgconf command-line tool For method docu, see kleo/cryptoconf...
virtual TQStringList componentList() const
Returns the list of known components (e.g.
virtual void sync(bool runtime)
Write back changes.
virtual Kleo::CryptoConfigComponent * component(const TQString &name) const
virtual void clear()
Tells the CryptoConfig to discard any cached information, including all components,...
QGpgMECryptoConfig()
Constructor.