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 <kprocio.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? :)
48 static bool s_duringClear = false;
49 
50 static const int GPGCONF_FLAG_GROUP = 1;
51 static const int GPGCONF_FLAG_OPTIONAL = 2;
52 static const int GPGCONF_FLAG_LIST = 4;
53 static const int GPGCONF_FLAG_RUNTIME = 8;
54 static const int GPGCONF_FLAG_DEFAULT = 16; // fixed default value available
55 static const int GPGCONF_FLAG_DEFAULT_DESC = 32; // runtime default value available
56 static const int GPGCONF_FLAG_NOARG_DESC = 64; // option with optional arg; special meaning if no arg set
57 static 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 
66 QGpgMECryptoConfig::~QGpgMECryptoConfig()
67 {
68 }
69 
70 void QGpgMECryptoConfig::runGpgConf( bool showErrors )
71 {
72  // Run gpgconf --list-components to make the list of components
73 
74  KProcIO proc( TQTextCodec::codecForName( "utf8" ) );
75  proc << "gpgconf"; // must be in the PATH
76  proc << "--list-components";
77 
78  TQObject::connect( &proc, TQ_SIGNAL( readReady(KProcIO*) ),
79  this, TQ_SLOT( slotCollectStdOut(KProcIO*) ) );
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 
103 void QGpgMECryptoConfig::slotCollectStdOut( KProcIO* 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 
137 void 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 
154 QGpgMECryptoConfigComponent::QGpgMECryptoConfigComponent( QGpgMECryptoConfig*, const TQString& name, const TQString& description )
155  : mGroups( 7 ), mName( name ), mDescription( description )
156 {
157  mGroups.setAutoDelete( true );
158  runGpgConf();
159 }
160 
161 QGpgMECryptoConfigComponent::~QGpgMECryptoConfigComponent()
162 {
163 }
164 
165 void QGpgMECryptoConfigComponent::runGpgConf()
166 {
167  // Run gpgconf --list-options <component>, and create all groups and entries for that component
168 
169  KProcIO 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(KProcIO*) ),
177  this, TQ_SLOT( slotCollectStdOut(KProcIO*) ) );
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 
195 void QGpgMECryptoConfigComponent::slotCollectStdOut( KProcIO* 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 
246 void 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 KProcIO 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 
324 QGpgMECryptoConfigGroup::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 
333 TQStringList 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 
342 Kleo::CryptoConfigEntry* QGpgMECryptoConfigGroup::entry( const TQString& name ) const
343 {
344  return mEntries.find( name );
345 }
346 
348 
349 static 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 
355 static 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 
364 static 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 
373 static 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
379 static 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 
400 QGpgMECryptoConfigEntry::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 
445 TQVariant 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 
489 QGpgMECryptoConfigEntry::~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 
498 bool QGpgMECryptoConfigEntry::isOptional() const
499 {
500  return mFlags & GPGCONF_FLAG_OPTIONAL;
501 }
502 
503 bool QGpgMECryptoConfigEntry::isReadOnly() const
504 {
505  return mFlags & GPGCONF_FLAG_NO_CHANGE;
506 }
507 
508 bool QGpgMECryptoConfigEntry::isList() const
509 {
510  return mFlags & GPGCONF_FLAG_LIST;
511 }
512 
513 bool QGpgMECryptoConfigEntry::isRuntime() const
514 {
515  return mFlags & GPGCONF_FLAG_RUNTIME;
516 }
517 
518 bool QGpgMECryptoConfigEntry::isSet() const
519 {
520  return mSet;
521 }
522 
523 bool QGpgMECryptoConfigEntry::boolValue() const
524 {
525  Q_ASSERT( mArgType == ArgType_None );
526  Q_ASSERT( !isList() );
527  return mValue.toBool();
528 }
529 
530 TQString QGpgMECryptoConfigEntry::stringValue() const
531 {
532  return toString( false );
533 }
534 
535 int QGpgMECryptoConfigEntry::intValue() const
536 {
537  Q_ASSERT( mArgType == ArgType_Int );
538  Q_ASSERT( !isList() );
539  return mValue.toInt();
540 }
541 
542 unsigned int QGpgMECryptoConfigEntry::uintValue() const
543 {
544  Q_ASSERT( mArgType == ArgType_UInt );
545  Q_ASSERT( !isList() );
546  return mValue.toUInt();
547 }
548 
549 static 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
573 static 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 
589 KURL 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 
603 unsigned int QGpgMECryptoConfigEntry::numberOfTimesSet() const
604 {
605  Q_ASSERT( mArgType == ArgType_None );
606  Q_ASSERT( isList() );
607  return mValue.toUInt();
608 }
609 
610 TQStringList QGpgMECryptoConfigEntry::stringValueList() const
611 {
612  Q_ASSERT( isStringType() );
613  Q_ASSERT( isList() );
614  return mValue.toStringList();
615 }
616 
617 TQValueList<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 
629 TQValueList<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 
641 KURL::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 
660 void 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 
677 void 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 
688 void 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 
701 void 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 
710 void QGpgMECryptoConfigEntry::setUIntValue( unsigned int i )
711 {
712  mValue = i;
713  mSet = true;
714  mDirty = true;
715 }
716 
717 void 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 
728 void 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 
737 void 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 
747 void 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 
761 void 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 
775 void 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 
789 TQString 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 
834 TQString QGpgMECryptoConfigEntry::outputString() const
835 {
836  Q_ASSERT( mSet );
837  return toString( true );
838 }
839 
840 bool 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 
848 void 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.