1/*
2 configuration.cpp - wraps gpgme configuration components
3 Copyright (C) 2010 Klarälvdalens Datakonsult AB
4
5 This file is part of GPGME++.
6
7 GPGME++ is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 GPGME++ 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
15 GNU Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with GPGME++; see the file COPYING.LIB. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23#include <config-gpgme++.h>
24
25#include "configuration.h"
26#include "error.h"
27#include "util.h"
28
29#include <gpgme.h>
30
31#include <boost/foreach.hpp>
32
33#include <iterator>
34#include <algorithm>
35#include <ostream>
36#include <cstring>
37
38using namespace GpgME;
39using namespace GpgME::Configuration;
40
41typedef boost::shared_ptr< boost::remove_pointer<gpgme_conf_opt_t>::type > shared_gpgme_conf_opt_t;
42typedef boost::weak_ptr< boost::remove_pointer<gpgme_conf_opt_t>::type > weak_gpgme_conf_opt_t;
43
44typedef boost::shared_ptr< boost::remove_pointer<gpgme_conf_arg_t>::type > shared_gpgme_conf_arg_t;
45typedef boost::weak_ptr< boost::remove_pointer<gpgme_conf_arg_t>::type > weak_gpgme_conf_arg_t;
46
47typedef boost::shared_ptr< boost::remove_pointer<gpgme_ctx_t>::type > shared_gpgme_ctx_t;
48typedef boost::weak_ptr< boost::remove_pointer<gpgme_ctx_t>::type > weak_gpgme_ctx_t;
49
50namespace {
51 struct nodelete { template <typename T> void operator()( T * ) {} };
52}
53
54// static
55std::vector<Component> Component::load( Error & returnedError ) {
56
57#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
58 //
59 // 1. get a context:
60 //
61 gpgme_ctx_t ctx_native = 0;
62 if ( const gpgme_error_t err = gpgme_new( &ctx_native ) ) {
63 returnedError = Error( err );
64 return std::vector<Component>();
65 }
66 const shared_gpgme_ctx_t ctx( ctx_native, &gpgme_release );
67
68 //
69 // 2. load the config:
70 //
71 gpgme_conf_comp_t conf_list_native = 0;
72 if ( const gpgme_error_t err = gpgme_op_conf_load( ctx_native, &conf_list_native ) ) {
73 returnedError = Error( err );
74 return std::vector<Component>();
75 }
76 shared_gpgme_conf_comp_t head( conf_list_native, &gpgme_conf_release );
77
78 //
79 // 3. convert to vector<Component>:
80 //
81 std::vector<Component> result;
82
83 while ( head ) {
84 // secure 'head->next' (if any) against memleaks:
85 shared_gpgme_conf_comp_t next;
86 if ( head->next ) {
87 next.reset( head->next, &gpgme_conf_release );
88 }
89
90 // now prevent double-free of next.get() and following:
91 head->next = 0;
92
93 // now add a new Component to 'result' (may throw):
94 result.resize( result.size() + 1 );
95 result.back().comp.swap( head ); // .comp = std::move( head );
96 head.swap( next ); // head = std::move( next );
97 }
98
99 return result;
100#else
101 returnedError = Error( make_error( GPG_ERR_NOT_SUPPORTED ) );
102 return std::vector<Component>();
103#endif
104}
105
106Error Component::save() const {
107
108#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
109 if ( isNull() ) {
110 return Error( make_error( GPG_ERR_INV_ARG ) );
111 }
112
113 //
114 // 1. get a context:
115 //
116 gpgme_ctx_t ctx_native = 0;
117 if ( const gpgme_error_t err = gpgme_new( &ctx_native ) ) {
118 return Error( err );
119 }
120 const shared_gpgme_ctx_t ctx( ctx_native, &gpgme_release );
121
122 //
123 // 2. save the config:
124 //
125 return Error( gpgme_op_conf_save( ctx.get(), comp.get() ) );
126#else
127 return Error( make_error( GPG_ERR_NOT_SUPPORTED ) );
128#endif
129}
130
131const char * Component::name() const {
132#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
133 return comp ? comp->name : 0 ;
134#else
135 return 0;
136#endif
137}
138
139const char * Component::description() const {
140#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
141 return comp ? comp->description : 0 ;
142#else
143 return 0;
144#endif
145}
146
147const char * Component::programName() const {
148#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
149 return comp ? comp->program_name : 0 ;
150#else
151 return 0;
152#endif
153}
154
155Option Component::option( unsigned int idx ) const {
156#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
157 gpgme_conf_opt_t opt = 0;
158 if ( comp ) {
159 opt = comp->options;
160 }
161 while ( opt && idx ) {
162 opt = opt->next;
163 --idx;
164 }
165 if ( opt ) {
166 return Option( comp, opt );
167 } else {
168#endif
169 return Option();
170#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
171 }
172#endif
173}
174
175Option Component::option( const char * name ) const {
176#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
177 gpgme_conf_opt_t opt = 0;
178 if ( comp ) {
179 opt = comp->options;
180 }
181 using namespace std; // for strcmp
182 while ( opt && strcmp( name, opt->name ) != 0 ) {
183 opt = opt->next;
184 }
185 if ( opt ) {
186 return Option( comp, opt );
187 } else {
188#endif
189 return Option();
190#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
191 }
192#endif
193}
194
195unsigned int Component::numOptions() const {
196 unsigned int result = 0;
197#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
198 for ( gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next ) {
199 ++result;
200 }
201#endif
202 return result;
203}
204
205std::vector<Option> Component::options() const {
206 std::vector<Option> result;
207#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
208 for ( gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next ) {
209 result.push_back( Option( comp, opt ) );
210 }
211#endif
212 return result;
213}
214
215#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
216static gpgme_conf_arg_t mygpgme_conf_arg_copy( gpgme_conf_arg_t other, gpgme_conf_type_t type ) {
217 gpgme_conf_arg_t result = 0, last = 0;
218 for ( gpgme_conf_arg_t a = other ; a ; a = a->next ) {
219 gpgme_conf_arg_t arg = 0;
220 const gpgme_error_t err
221 = gpgme_conf_arg_new( &arg, type,
222 a->no_arg ? 0 :
223 type == GPGME_CONF_STRING ? a->value.string :
224 /* else */ static_cast<void*>(&a->value) );
225 if ( err ) {
226 gpgme_conf_arg_release( result, type );
227 return 0;
228 }
229 assert( arg );
230 if ( result ) {
231 last->next = arg;
232 } else {
233 result = arg;
234 }
235 last = arg;
236 }
237 return result;
238}
239#endif
240
241Component Option::parent() const {
242 return Component( comp.lock() );
243}
244
245unsigned int Option::flags() const {
246#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
247 return isNull() ? 0 : opt->flags;
248#else
249 return 0;
250#endif
251}
252
253Level Option::level() const {
254#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
255 return isNull() ? Internal : static_cast<Level>( opt->level ) ;
256#else
257 return Internal;
258#endif
259}
260
261const char * Option::name() const {
262#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
263 return isNull() ? 0 : opt->name ;
264#else
265 return 0;
266#endif
267}
268
269const char * Option::description() const {
270#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
271 return isNull() ? 0 : opt->description ;
272#else
273 return 0;
274#endif
275}
276
277const char * Option::argumentName() const {
278#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
279 return isNull() ? 0 : opt->argname ;
280#else
281 return 0;
282#endif
283}
284
285Type Option::type() const {
286#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
287 return isNull() ? NoType : static_cast<Type>( opt->type ) ;
288#else
289 return NoType;
290#endif
291}
292
293Type Option::alternateType() const {
294#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
295 return isNull() ? NoType : static_cast<Type>( opt->alt_type ) ;
296#else
297 return NoType;
298#endif
299}
300
301#if 0
302static Option::Variant argument_to_variant( gpgme_conf_type_t type, bool list, gpgme_conf_arg_t arg ) {
303 assert( arg );
304 switch ( type ) {
305 case GPGME_CONF_NONE:
306 if ( list ) {
307 // return the count (number of times set):
308 return arg->value.count;
309 } else {
310 return none;
311 }
312 case GPGME_CONF_INT32:
313 if ( list ) {
314 std::vector<int> result;
315 for ( gpgme_conf_arg_t a = arg ; a ; a = a->next ) {
316 result.push_back( a->value.int32 );
317 }
318 return result;
319 } else {
320 return arg->value.int32;
321 }
322 case GPGME_CONF_UINT32:
323 if ( list ) {
324 std::vector<unsigned int> result;
325 for ( gpgme_conf_arg_t a = arg ; a ; a = a->next ) {
326 result.push_back( a->value.uint32 );
327 }
328 return result;
329 } else {
330 return arg->value.uint32;
331 }
332 case GPGME_CONF_FILENAME:
333 case GPGME_CONF_LDAP_SERVER:
334 case GPGME_CONF_KEY_FPR:
335 case GPGME_CONF_PUB_KEY:
336 case GPGME_CONF_SEC_KEY:
337 case GPGME_CONF_ALIAS_LIST:
338 // these should not happen in alt_type, but fall through
339 case GPGME_CONF_STRING:
340 if ( list ) {
341 std::vector<const char*> result;
342 for ( gpgme_conf_arg_t a = arg ; a ; a = a->next ) {
343 result.push_back( a->value.string );
344 }
345 return result;
346 } else {
347 return arg->value.string;
348 }
349 }
350 assert( !"Option: unknown alt_type!" );
351 return Option::Variant();
352}
353
354
355namespace {
356 inline const void * to_void_star( const char * s ) { return s; }
357 inline const void * to_void_star( const std::string & s ) { return s.c_str(); }
358 inline const void * to_void_star( const int & i ) { return &i; } // const-&: sic!
359 inline const void * to_void_star( const unsigned int & i ) { return &i; } // const-&: sic!
360
361 struct VariantToArgumentVisitor : boost::static_visitor<gpgme_conf_arg_t> {
362 static gpgme_conf_arg_t make_argument( gpgme_conf_type_t type, const void * value ) {
363 gpgme_conf_arg_t arg = 0;
364#ifdef HAVE_GPGME_CONF_ARG_NEW_WITH_CONST_VALUE
365 if ( const gpgme_error_t err = gpgme_conf_arg_new( &arg, type, value ) ) {
366 return 0;
367 }
368#else
369 if ( const gpgme_error_t err = gpgme_conf_arg_new( &arg, type, const_cast<void*>( value ) ) ) {
370 return 0;
371 }
372#endif
373 else {
374 return arg;
375 }
376 }
377
378 gpgme_conf_arg_t operator()( bool v ) const {
379 return v ? make_argument( 0 ) : 0 ;
380 }
381
382 gpgme_conf_arg_t operator()( const char * s ) const {
383 return make_argument( s ? s : "" );
384 }
385
386 gpgme_conf_arg_t operator()( const std::string & s ) const {
387 return operator()( s.c_str() );
388 }
389
390 gpgme_conf_arg_t operator()( int i ) const {
391 return make_argument( &i );
392 }
393
394 gpgme_conf_arg_t operator()( unsigned int i ) const {
395 return make_argument( &i );
396 }
397
398 template <typename T>
399 gpgme_conf_arg_t operator()( const std::vector<T> & value ) const {
400 gpgme_conf_arg_t result = 0;
401 gpgme_conf_arg_t last = 0;
402 for ( typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it ) {
403 if ( gpgme_conf_arg_t arg = make_argument( to_void_star( *it ) ) ) {
404 if ( last ) {
405 last = last->next = arg;
406 } else {
407 result = last = arg;
408 }
409 }
410 }
411 return result;
412 }
413
414 };
415}
416
417static gpgme_conf_arg_t variant_to_argument( const Option::Variant & value ) {
418 VariantToArgumentVisitor v;
419 return apply_visitor( v, value );
420}
421
422optional<Option::Variant> Option::defaultValue() const {
423 if ( isNull() ) {
424 return optional<Variant>();
425 } else {
426 return argument_to_variant( opt->alt_type, opt->flags & GPGME_CONF_LIST, opt->default_value );
427 }
428}
429#endif
430
431Argument Option::defaultValue() const {
432#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
433 if ( isNull() ) {
434 return Argument();
435 } else {
436 return Argument( comp.lock(), opt, opt->default_value, false );
437 }
438#else
439 return Argument();
440#endif
441}
442
443const char * Option::defaultDescription() const {
444#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
445 return isNull() ? 0 : opt->default_description ;
446#else
447 return 0;
448#endif
449}
450
451Argument Option::noArgumentValue() const {
452#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
453 if ( isNull() ) {
454 return Argument();
455 } else {
456 return Argument( comp.lock(), opt, opt->no_arg_value, false );
457 }
458#else
459 return Argument();
460#endif
461}
462
463const char * Option::noArgumentDescription() const {
464#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
465 return isNull() ? 0 : opt->no_arg_description ;
466#else
467 return 0;
468#endif
469}
470
471Argument Option::activeValue() const {
472#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
473 if ( isNull() ) {
474 return Argument();
475 } else {
476 return Argument( comp.lock(), opt, opt->value, false );
477 }
478#else
479 return Argument();
480#endif
481}
482
483Argument Option::currentValue() const {
484#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
485 if ( isNull() ) {
486 return Argument();
487 }
488 const gpgme_conf_arg_t arg =
489 opt->change_value ? opt->new_value ? opt->new_value : opt->default_value :
490 opt->value ? opt->value :
491 /* else */ opt->default_value ;
492 return Argument( comp.lock(), opt, arg, false );
493#else
494 return Argument();
495#endif
496}
497
498Argument Option::newValue() const {
499#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
500 if ( isNull() ) {
501 return Argument();
502 } else {
503 return Argument( comp.lock(), opt, opt->new_value, false );
504 }
505#else
506 return Argument();
507#endif
508}
509
510bool Option::set() const {
511#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
512 if ( isNull() ) {
513 return false;
514 } else if ( opt->change_value ) {
515 return opt->new_value;
516 } else {
517 return opt->value;
518 }
519#else
520 return false;
521#endif
522}
523
524bool Option::dirty() const {
525#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
526 return !isNull() && opt->change_value ;
527#else
528 return false;
529#endif
530}
531
532Error Option::setNewValue( const Argument & argument ) {
533#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
534 if ( isNull() ) {
535 return Error( make_error( GPG_ERR_INV_ARG ) );
536 } else if ( argument.isNull() ) {
537 return resetToDefaultValue();
538 } else if ( const gpgme_conf_arg_t arg = mygpgme_conf_arg_copy( argument.arg, opt->alt_type ) ) {
539 return Error( gpgme_conf_opt_change( opt, 0, arg ) );
540 } else {
541 return Error( make_error( GPG_ERR_ENOMEM ) );
542 }
543#else
544 return Error( make_error( GPG_ERR_NOT_SUPPORTED ) );
545#endif
546}
547
548Error Option::resetToActiveValue() {
549#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
550 if ( isNull() ) {
551 return Error( make_error( GPG_ERR_INV_ARG ) );
552 } else {
553 return Error( gpgme_conf_opt_change( opt, 1, 0 ) );
554 }
555#else
556 return Error( make_error( GPG_ERR_NOT_SUPPORTED ) );
557#endif
558}
559
560Error Option::resetToDefaultValue() {
561#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
562 if ( isNull() ) {
563 return Error( make_error( GPG_ERR_INV_ARG ) );
564 } else {
565 return Error( gpgme_conf_opt_change( opt, 0, 0 ) );
566 }
567#else
568 return Error( make_error( GPG_ERR_NOT_SUPPORTED ) );
569#endif
570}
571
572#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
573static gpgme_conf_arg_t make_argument( gpgme_conf_type_t type, const void * value ) {
574 gpgme_conf_arg_t arg = 0;
575#ifdef HAVE_GPGME_CONF_ARG_NEW_WITH_CONST_VALUE
576 if ( const gpgme_error_t err = gpgme_conf_arg_new( &arg, type, value ) ) {
577 return 0;
578 }
579#else
580 if ( const gpgme_error_t err = gpgme_conf_arg_new( &arg, type, const_cast<void*>( value ) ) ) {
581 return 0;
582 }
583#endif
584 else {
585 return arg;
586 }
587}
588#endif
589
590Argument Option::createNoneArgument( bool set ) const {
591#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
592 if ( isNull() || alternateType() != NoType ) {
593 return Argument();
594 } else {
595 if ( set ) {
596 return createNoneListArgument( 1 );
597 } else {
598#endif
599 return Argument();
600#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
601 }
602 }
603#endif
604}
605
606Argument Option::createStringArgument( const char * value ) const {
607#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
608 if ( isNull() || alternateType() != StringType ) {
609 return Argument();
610 } else {
611 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_STRING, value ), true );
612 }
613#else
614 return Argument();
615#endif
616}
617
618Argument Option::createStringArgument( const std::string & value ) const {
619#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
620 if ( isNull() || alternateType() != StringType ) {
621 return Argument();
622 } else {
623 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_STRING, value.c_str() ), true );
624 }
625#else
626 return Argument();
627#endif
628}
629
630Argument Option::createIntArgument( int value ) const {
631#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
632 if ( isNull() || alternateType() != IntegerType ) {
633 return Argument();
634 } else {
635 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_INT32, &value ), true );
636 }
637#else
638 return Argument();
639#endif
640}
641
642Argument Option::createUIntArgument( unsigned int value ) const {
643#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
644 if ( isNull() || alternateType() != UnsignedIntegerType ) {
645 return Argument();
646 } else {
647 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_UINT32, &value ), true );
648 }
649#else
650 return Argument();
651#endif
652}
653
654#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
655namespace {
656 const void * to_void_star( const char * s ) { return s; }
657 const void * to_void_star( const std::string & s ) { return s.c_str(); }
658 const void * to_void_star( const int & i ) { return &i; } // const-&: sic!
659 const void * to_void_star( const unsigned int & i ) { return &i; } // const-&: sic!
660
661 template <typename T>
662 gpgme_conf_arg_t make_argument( gpgme_conf_type_t type, const std::vector<T> & value ) {
663 gpgme_conf_arg_t result = 0;
664 gpgme_conf_arg_t last = 0;
665 for ( typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it ) {
666 if ( gpgme_conf_arg_t arg = make_argument( type, to_void_star( *it ) ) ) {
667 if ( last ) {
668 last = last->next = arg;
669 } else {
670 result = last = arg;
671 }
672 }
673 }
674 return result;
675 }
676}
677#endif
678
679Argument Option::createNoneListArgument( unsigned int value ) const {
680#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
681 if ( value ) {
682 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_NONE, &value ), true );
683 } else {
684#endif
685 return Argument();
686#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
687 }
688#endif
689}
690
691Argument Option::createStringListArgument( const std::vector<const char*> & value ) const {
692#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
693 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_STRING, value ), true );
694#else
695 return Argument();
696#endif
697}
698
699Argument Option::createStringListArgument( const std::vector<std::string> & value ) const {
700#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
701 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_STRING, value ), true );
702#else
703 return Argument();
704#endif
705}
706
707Argument Option::createIntListArgument( const std::vector<int> & value ) const {
708#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
709 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_INT32, value ), true );
710#else
711 return Argument();
712#endif
713}
714
715Argument Option::createUIntListArgument( const std::vector<unsigned int> & value ) const {
716#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
717 return Argument( comp.lock(), opt, make_argument( GPGME_CONF_UINT32, value ), true );
718#else
719 return Argument();
720#endif
721}
722
723
724
725
726Argument::Argument( const shared_gpgme_conf_comp_t & comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg, bool owns )
727 : comp( comp ),
728 opt( opt ),
729#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
730 arg( owns ? arg : mygpgme_conf_arg_copy( arg, opt ? opt->alt_type : GPGME_CONF_NONE ) )
731#else
732 arg( 0 )
733#endif
734{
735
736}
737
738#if 0
739Argument::Argument( const shared_gpgme_conf_comp_t & comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg )
740 : comp( comp ),
741 opt( opt ),
742 arg( mygpgme_conf_arg_copy( arg, opt ? opt->alt_type : GPGME_CONF_NONE ) )
743{
744
745}
746#endif
747
748Argument::Argument( const Argument & other )
749 : comp( other.comp ),
750 opt( other.opt ),
751#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
752 arg( mygpgme_conf_arg_copy( other.arg, opt ? opt->alt_type : GPGME_CONF_NONE ) )
753#else
754 arg( 0 )
755#endif
756{
757
758}
759
760Argument::~Argument() {
761#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
762 gpgme_conf_arg_release( arg, opt ? opt->alt_type : GPGME_CONF_NONE );
763#endif
764}
765
766Option Argument::parent() const {
767 return Option( comp.lock(), opt );
768}
769
770bool Argument::boolValue() const {
771 return numberOfTimesSet();
772}
773
774unsigned int Argument::numElements() const {
775 if ( isNull() ) {
776 return 0;
777 }
778 unsigned int result = 0;
779#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
780 for ( gpgme_conf_arg_t a = arg ; a ; a = a->next ) {
781 ++result;
782 }
783#endif
784 return result;
785}
786
787const char * Argument::stringValue( unsigned int idx ) const {
788#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
789 if ( isNull() || opt->alt_type != GPGME_CONF_STRING ) {
790 return 0;
791 }
792 gpgme_conf_arg_t a = arg;
793 while ( a && idx ) {
794 a = a->next;
795 --idx;
796 }
797 return a ? a->value.string : 0 ;
798#else
799 return 0;
800#endif
801}
802
803int Argument::intValue( unsigned int idx ) const {
804#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
805 if ( isNull() || opt->alt_type != GPGME_CONF_INT32 ) {
806 return 0;
807 }
808 gpgme_conf_arg_t a = arg;
809 while ( a && idx ) {
810 a = a->next;
811 --idx;
812 }
813 return a ? a->value.int32 : 0 ;
814#else
815 return 0;
816#endif
817}
818
819unsigned int Argument::uintValue( unsigned int idx ) const {
820#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
821 if ( isNull() || opt->alt_type != GPGME_CONF_UINT32 ) {
822 return 0;
823 }
824 gpgme_conf_arg_t a = arg;
825 while ( a && idx ) {
826 a = a->next;
827 --idx;
828 }
829 return a ? a->value.uint32 : 0 ;
830#else
831 return 0;
832#endif
833}
834
835unsigned int Argument::numberOfTimesSet() const {
836#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
837 if ( isNull() || opt->alt_type != GPGME_CONF_NONE ) {
838 return 0;
839 }
840 return arg->value.count;
841#else
842 return 0;
843#endif
844}
845
846std::vector<const char *> Argument::stringValues() const {
847 if ( isNull() || opt->alt_type != GPGME_CONF_STRING ) {
848 return std::vector<const char *>();
849 }
850 std::vector<const char *> result;
851 for ( gpgme_conf_arg_t a = arg ; a ; a = a->next ) {
852 result.push_back( a->value.string );
853 }
854 return result;
855}
856
857std::vector<int> Argument::intValues() const {
858#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
859 if ( isNull() || opt->alt_type != GPGME_CONF_INT32 ) {
860 return std::vector<int>();
861 }
862#endif
863 std::vector<int> result;
864#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
865 for ( gpgme_conf_arg_t a = arg ; a ; a = a->next ) {
866 result.push_back( a->value.int32 );
867 }
868#endif
869 return result;
870}
871
872std::vector<unsigned int> Argument::uintValues() const {
873#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
874 if ( isNull() || opt->alt_type != GPGME_CONF_UINT32 ) {
875 return std::vector<unsigned int>();
876 }
877#endif
878 std::vector<unsigned int> result;
879#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
880 for ( gpgme_conf_arg_t a = arg ; a ; a = a->next ) {
881 result.push_back( a->value.uint32 );
882 }
883#endif
884 return result;
885}
886
887std::ostream & Configuration::operator<<( std::ostream & os, Level level ) {
888 switch ( level ) {
889 case Basic: return os << "Basic";
890 case Advanced: return os << "Advanced";
891 case Expert: return os << "Expert";
892 case Invisible: return os << "Invisible";
893 case Internal: return os << "Internal";
894 case NumLevels: ;
895 }
896 return os << "<unknown>";
897}
898
899std::ostream & Configuration::operator<<( std::ostream & os, Type type ) {
900 switch ( type ) {
901 case NoType: return os << "None";
902 case StringType: return os << "String";
903 case IntegerType: return os << "Integer";
904 case UnsignedIntegerType: return os << "UnsignedInteger";
905 case FilenameType: return os << "Filename";
906 case LdapServerType: return os << "LdapServer";
907 case KeyFingerprintType: return os << "KeyFingerprint";
908 case PublicKeyType: return os << "PublicKey";
909 case SecretKeyType: return os << "SecretKey";
910 case AliasListType: return os << "AliasList";
911 case MaxType: ;
912 }
913 return os << "<unknown>";
914}
915
916std::ostream & Configuration::operator<<( std::ostream & os, Flag f ) {
917 unsigned int flags = f;
918 std::vector<const char *> s;
919 if ( flags & Group ) {
920 s.push_back( "Group" );
921 }
922 if ( flags & Optional ) {
923 s.push_back( "Optional" );
924 }
925 if ( flags & List ) {
926 s.push_back( "List" );
927 }
928 if ( flags & Runtime ) {
929 s.push_back( "Runtime" );
930 }
931 if ( flags & Default ) {
932 s.push_back( "Default" );
933 }
934 if ( flags & DefaultDescription ) {
935 s.push_back( "DefaultDescription" );
936 }
937 if ( flags & NoArgumentDescription ) {
938 s.push_back( "NoArgumentDescription" );
939 }
940 if ( flags & NoChange ) {
941 s.push_back( "NoChange" );
942 }
943 flags &= ~( Group|Optional|List|Runtime|Default|DefaultDescription|NoArgumentDescription|NoChange );
944 if ( flags ) {
945 s.push_back( "other flags(" );
946 }
947 std::copy( s.begin(), s.end(),
948 std::ostream_iterator<const char*>( os, "|" ) );
949 if ( flags ) {
950 os << flags << ')';
951 }
952 return os;
953}
954
955std::ostream & Configuration::operator<<( std::ostream & os, const Component & c ) {
956 os << "Component["
957 << "\n name : " << protect( c.name() )
958 << "\n description: " << protect( c.description() )
959 << "\n programName: " << protect( c.programName() )
960 << "\n options : \n";
961 const std::vector<Option> options = c.options();
962 std::copy( options.begin(), options.end(),
963 std::ostream_iterator<Option>( os, "\n" ) );
964 os << "\n]";
965 return os;
966}
967
968std::ostream & Configuration::operator<<( std::ostream & os, const Option & o ) {
969 return os << "Option["
970 << "\n name: : " << protect( o.name() )
971 << "\n description : " << protect( o.description() )
972 << "\n argName : " << protect( o.argumentName() )
973 << "\n flags : " << static_cast<Flag>( o.flags() )
974 << "\n level : " << o.level()
975 << "\n type : " << o.type()
976 << "\n alt_type : " << o.alternateType()
977 << "\n default_val : " << o.defaultValue()
978 << "\n default_desc: " << protect( o.defaultDescription() )
979 << "\n no_arg_value: " << o.noArgumentValue()
980 << "\n no_arg_desc : " << protect( o.noArgumentDescription() )
981 << "\n active_value: " << o.activeValue()
982 << "\n new_value : " << o.newValue()
983 << "\n --> cur_val : " << o.currentValue()
984 << "\n set : " << o.set()
985 << "\n dirty : " << o.dirty()
986 << "\n]"
987 ;
988}
989
990std::ostream & Configuration::operator<<( std::ostream & os, const Argument & a ) {
991 const Option o = a.parent();
992 const bool list = o.flags() & List;
993 os << "Argument[";
994 if ( a ) {
995 switch ( o.alternateType() ) {
996 case NoType:
997 if ( list ) {
998 os << a.numberOfTimesSet() << 'x';
999 } else {
1000 os << a.boolValue();
1001 }
1002 break;
1003 default:
1004 case StringType:
1005 if ( list ) {
1006 const std::vector<const char*> v = a.stringValues();
1007 os << v.size() << ':';
1008 // can't use std::copy + ostream_iterator here, since we need the protect() call
1009 bool first = true;
1010 BOOST_FOREACH ( const char * s, v ) {
1011 if ( first ) {
1012 first = false;
1013 } else {
1014 os << ',';
1015 }
1016 os << protect( s );
1017 }
1018 } else {
1019 os << protect( a.stringValue() );
1020 }
1021 break;
1022 case IntegerType:
1023 if ( list ) {
1024 const std::vector<int> v = a.intValues();
1025 os << v.size() << ':';
1026 std::copy( v.begin(), v.end(),
1027 std::ostream_iterator<int>( os, "," ) );
1028 } else {
1029 os << a.intValue();
1030 }
1031 break;
1032 case UnsignedIntegerType:
1033 if ( list ) {
1034 const std::vector<unsigned int> v = a.uintValues();
1035 os << v.size() << ':';
1036 std::copy( v.begin(), v.end(),
1037 std::ostream_iterator<unsigned int>( os, "," ) );
1038 } else {
1039 os << a.intValue();
1040 }
1041 break;
1042 }
1043 }
1044 return os << ']';
1045}
1046