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 | |
38 | using namespace GpgME; |
39 | using namespace GpgME::Configuration; |
40 | |
41 | typedef boost::shared_ptr< boost::remove_pointer<gpgme_conf_opt_t>::type > shared_gpgme_conf_opt_t; |
42 | typedef boost::weak_ptr< boost::remove_pointer<gpgme_conf_opt_t>::type > weak_gpgme_conf_opt_t; |
43 | |
44 | typedef boost::shared_ptr< boost::remove_pointer<gpgme_conf_arg_t>::type > shared_gpgme_conf_arg_t; |
45 | typedef boost::weak_ptr< boost::remove_pointer<gpgme_conf_arg_t>::type > weak_gpgme_conf_arg_t; |
46 | |
47 | typedef boost::shared_ptr< boost::remove_pointer<gpgme_ctx_t>::type > shared_gpgme_ctx_t; |
48 | typedef boost::weak_ptr< boost::remove_pointer<gpgme_ctx_t>::type > weak_gpgme_ctx_t; |
49 | |
50 | namespace { |
51 | struct nodelete { template <typename T> void operator()( T * ) {} }; |
52 | } |
53 | |
54 | // static |
55 | std::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 | |
106 | Error 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 | |
131 | const 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 | |
139 | const 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 | |
147 | const 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 | |
155 | Option 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 | |
175 | Option 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 | |
195 | unsigned 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 | |
205 | std::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 |
216 | static 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 | |
241 | Component Option::parent() const { |
242 | return Component( comp.lock() ); |
243 | } |
244 | |
245 | unsigned 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 | |
253 | Level 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 | |
261 | const 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 | |
269 | const 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 | |
277 | const 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 | |
285 | Type 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 | |
293 | Type 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 |
302 | static 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 | |
355 | namespace { |
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 | |
417 | static gpgme_conf_arg_t variant_to_argument( const Option::Variant & value ) { |
418 | VariantToArgumentVisitor v; |
419 | return apply_visitor( v, value ); |
420 | } |
421 | |
422 | optional<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 | |
431 | Argument 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 | |
443 | const 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 | |
451 | Argument 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 | |
463 | const 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 | |
471 | Argument 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 | |
483 | Argument 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 | |
498 | Argument 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 | |
510 | bool 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 | |
524 | bool Option::dirty() const { |
525 | #ifdef HAVE_GPGME_PROTOCOL_GPGCONF |
526 | return !isNull() && opt->change_value ; |
527 | #else |
528 | return false; |
529 | #endif |
530 | } |
531 | |
532 | Error 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 | |
548 | Error 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 | |
560 | Error 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 |
573 | static 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 | |
590 | Argument 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 | |
606 | Argument 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 | |
618 | Argument 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 | |
630 | Argument 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 | |
642 | Argument 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 |
655 | namespace { |
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 | |
679 | Argument 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 | |
691 | Argument 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 | |
699 | Argument 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 | |
707 | Argument 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 | |
715 | Argument 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 | |
726 | Argument::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 |
739 | Argument::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 | |
748 | Argument::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 | |
760 | Argument::~Argument() { |
761 | #ifdef HAVE_GPGME_PROTOCOL_GPGCONF |
762 | gpgme_conf_arg_release( arg, opt ? opt->alt_type : GPGME_CONF_NONE ); |
763 | #endif |
764 | } |
765 | |
766 | Option Argument::parent() const { |
767 | return Option( comp.lock(), opt ); |
768 | } |
769 | |
770 | bool Argument::boolValue() const { |
771 | return numberOfTimesSet(); |
772 | } |
773 | |
774 | unsigned 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 | |
787 | const 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 | |
803 | int 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 | |
819 | unsigned 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 | |
835 | unsigned 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 | |
846 | std::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 | |
857 | std::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 | |
872 | std::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 | |
887 | std::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 | |
899 | std::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 | |
916 | std::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 | |
955 | std::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 | |
968 | std::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 | |
990 | std::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 | |