1 | /* |
2 | key.cpp - wraps a gpgme key |
3 | Copyright (C) 2003, 2005 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 <gpgme++/key.h> |
26 | |
27 | #include "util.h" |
28 | |
29 | #include <gpgme.h> |
30 | |
31 | #include <string.h> |
32 | |
33 | GpgME::Key::Null GpgME::Key::null; |
34 | |
35 | namespace GpgME { |
36 | |
37 | Key::Key() : key() {} |
38 | |
39 | Key::Key( const Null & ) : key() {} |
40 | |
41 | Key::Key( const shared_gpgme_key_t & k ) : key( k ) {} |
42 | |
43 | Key::Key( gpgme_key_t k, bool ref ) |
44 | : key( k |
45 | ? shared_gpgme_key_t( k, &gpgme_key_unref ) |
46 | : shared_gpgme_key_t() ) |
47 | { |
48 | if ( ref && impl() ) { |
49 | gpgme_key_ref( impl() ); |
50 | } |
51 | } |
52 | |
53 | UserID Key::userID( unsigned int index ) const { |
54 | return UserID( key, index ); |
55 | } |
56 | |
57 | Subkey Key::subkey( unsigned int index ) const { |
58 | return Subkey( key, index ); |
59 | } |
60 | |
61 | |
62 | unsigned int Key::numUserIDs() const { |
63 | if ( !key ) { |
64 | return 0; |
65 | } |
66 | unsigned int count = 0; |
67 | for ( gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next ) { |
68 | ++count; |
69 | } |
70 | return count; |
71 | } |
72 | |
73 | unsigned int Key::numSubkeys() const { |
74 | if ( !key ) { |
75 | return 0; |
76 | } |
77 | unsigned int count = 0; |
78 | for ( gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next ) { |
79 | ++count; |
80 | } |
81 | return count; |
82 | } |
83 | |
84 | std::vector<UserID> Key::userIDs() const { |
85 | if ( !key ) { |
86 | return std::vector<UserID>(); |
87 | } |
88 | |
89 | std::vector<UserID> v; |
90 | v.reserve( numUserIDs() ); |
91 | for ( gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next ) { |
92 | v.push_back( UserID( key, uid ) ); |
93 | } |
94 | return v; |
95 | } |
96 | |
97 | std::vector<Subkey> Key::subkeys() const { |
98 | if ( !key ) { |
99 | return std::vector<Subkey>(); |
100 | } |
101 | |
102 | std::vector<Subkey> v; |
103 | v.reserve( numSubkeys() ); |
104 | for ( gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next ) { |
105 | v.push_back( Subkey( key, subkey ) ); |
106 | } |
107 | return v; |
108 | } |
109 | |
110 | Key::OwnerTrust Key::ownerTrust() const { |
111 | if ( !key ) { |
112 | return Unknown; |
113 | } |
114 | switch ( key->owner_trust ) { |
115 | default: |
116 | case GPGME_VALIDITY_UNKNOWN: return Unknown; |
117 | case GPGME_VALIDITY_UNDEFINED: return Undefined; |
118 | case GPGME_VALIDITY_NEVER: return Never; |
119 | case GPGME_VALIDITY_MARGINAL: return Marginal; |
120 | case GPGME_VALIDITY_FULL: return Full; |
121 | case GPGME_VALIDITY_ULTIMATE: return Ultimate; |
122 | } |
123 | } |
124 | char Key::ownerTrustAsString() const { |
125 | if ( !key ) { |
126 | return '?'; |
127 | } |
128 | switch ( key->owner_trust ) { |
129 | default: |
130 | case GPGME_VALIDITY_UNKNOWN: return '?'; |
131 | case GPGME_VALIDITY_UNDEFINED: return 'q'; |
132 | case GPGME_VALIDITY_NEVER: return 'n'; |
133 | case GPGME_VALIDITY_MARGINAL: return 'm'; |
134 | case GPGME_VALIDITY_FULL: return 'f'; |
135 | case GPGME_VALIDITY_ULTIMATE: return 'u'; |
136 | } |
137 | } |
138 | |
139 | Protocol Key::protocol() const { |
140 | if ( !key ) { |
141 | return UnknownProtocol; |
142 | } |
143 | switch ( key->protocol ) { |
144 | case GPGME_PROTOCOL_CMS: return CMS; |
145 | case GPGME_PROTOCOL_OpenPGP: return OpenPGP; |
146 | default: return UnknownProtocol; |
147 | } |
148 | } |
149 | |
150 | const char * Key::protocolAsString() const { |
151 | return key ? gpgme_get_protocol_name( key->protocol ) : 0 ; |
152 | } |
153 | |
154 | bool Key::isRevoked() const { |
155 | return key && key->revoked; |
156 | } |
157 | |
158 | bool Key::isExpired() const { |
159 | return key && key->expired; |
160 | } |
161 | |
162 | bool Key::isDisabled() const { |
163 | return key && key->disabled; |
164 | } |
165 | |
166 | bool Key::isInvalid() const { |
167 | return key && key->invalid; |
168 | } |
169 | |
170 | bool Key::hasSecret() const { |
171 | return key && key->secret; |
172 | } |
173 | |
174 | bool Key::isRoot() const { |
175 | return key && key->subkeys && key->subkeys->fpr && key->chain_id && |
176 | strcasecmp( key->subkeys->fpr, key->chain_id ) == 0; |
177 | } |
178 | |
179 | bool Key::canEncrypt() const { |
180 | return key && key->can_encrypt; |
181 | } |
182 | |
183 | bool Key::canSign() const { |
184 | #ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN |
185 | if ( key && key->protocol == GPGME_PROTOCOL_OpenPGP ) { |
186 | return true; |
187 | } |
188 | #endif |
189 | return canReallySign(); |
190 | } |
191 | |
192 | bool Key::canReallySign() const { |
193 | return key && key->can_sign; |
194 | } |
195 | |
196 | bool Key::canCertify() const { |
197 | return key && key->can_certify; |
198 | } |
199 | |
200 | bool Key::canAuthenticate() const { |
201 | return key && key->can_authenticate; |
202 | } |
203 | |
204 | bool Key::isQualified() const { |
205 | #ifdef HAVE_GPGME_KEY_T_IS_QUALIFIED |
206 | return key && key->is_qualified; |
207 | #else |
208 | return false; |
209 | #endif |
210 | } |
211 | |
212 | const char * Key::issuerSerial() const { |
213 | return key ? key->issuer_serial : 0 ; |
214 | } |
215 | const char * Key::issuerName() const { |
216 | return key ? key->issuer_name : 0 ; |
217 | } |
218 | const char * Key::chainID() const { |
219 | return key ? key->chain_id : 0 ; |
220 | } |
221 | |
222 | const char * Key::keyID() const { |
223 | return key && key->subkeys ? key->subkeys->keyid : 0 ; |
224 | } |
225 | |
226 | const char * Key::shortKeyID() const { |
227 | if ( !key || !key->subkeys || !key->subkeys->keyid ) { |
228 | return 0; |
229 | } |
230 | const int len = strlen( key->subkeys->keyid ); |
231 | if ( len > 8 ) { |
232 | return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation) |
233 | } else { |
234 | return key->subkeys->keyid; |
235 | } |
236 | } |
237 | |
238 | const char * Key::primaryFingerprint() const { |
239 | const char * fpr = key && key->subkeys ? key->subkeys->fpr : 0 ; |
240 | if ( fpr ) { |
241 | return fpr; |
242 | } else { |
243 | return keyID(); |
244 | } |
245 | } |
246 | |
247 | unsigned int Key::keyListMode() const { |
248 | return key ? convert_from_gpgme_keylist_mode_t( key->keylist_mode ) : 0 ; |
249 | } |
250 | |
251 | const Key & Key::mergeWith( const Key & other ) { |
252 | // ### incomplete. Just merges has* and can*, nothing else atm |
253 | // ### detach also missing |
254 | |
255 | if ( !this->primaryFingerprint() || |
256 | !other.primaryFingerprint() || |
257 | strcasecmp( this->primaryFingerprint(), other.primaryFingerprint() ) != 0 ) { |
258 | return *this; // only merge the Key object which describe the same key |
259 | } |
260 | |
261 | const gpgme_key_t me = impl(); |
262 | const gpgme_key_t him = other.impl(); |
263 | |
264 | if ( !me || !him ) { |
265 | return *this; |
266 | } |
267 | |
268 | me->revoked |= him->revoked; |
269 | me->expired |= him->expired; |
270 | me->disabled |= him->disabled; |
271 | me->invalid |= him->invalid; |
272 | me->can_encrypt |= him->can_encrypt; |
273 | me->can_sign |= him->can_sign; |
274 | me->can_certify |= him->can_certify; |
275 | me->secret |= him->secret; |
276 | me->can_authenticate |= him->can_authenticate; |
277 | #ifdef HAVE_GPGME_KEY_T_IS_QUALIFIED |
278 | me->is_qualified |= him->is_qualified; |
279 | #endif |
280 | me->keylist_mode |= him->keylist_mode; |
281 | |
282 | #ifdef HAVE_GPGME_SUBKEY_T_IS_CARDKEY |
283 | // make sure the gpgme_sub_key_t::is_cardkey flag isn't lost: |
284 | for ( gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next ) { |
285 | for ( gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next ) { |
286 | if ( strcmp( mysk->fpr, hissk->fpr ) == 0 ) { |
287 | mysk->is_cardkey |= hissk->is_cardkey; |
288 | break; |
289 | } |
290 | } |
291 | } |
292 | #endif |
293 | |
294 | return *this; |
295 | } |
296 | |
297 | // |
298 | // |
299 | // class Subkey |
300 | // |
301 | // |
302 | |
303 | gpgme_sub_key_t find_subkey( const shared_gpgme_key_t & key, unsigned int idx ) { |
304 | if ( key ) { |
305 | for ( gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx ) { |
306 | if ( idx == 0 ) { |
307 | return s; |
308 | } |
309 | } |
310 | } |
311 | return 0; |
312 | } |
313 | |
314 | gpgme_sub_key_t verify_subkey( const shared_gpgme_key_t & key, gpgme_sub_key_t subkey ) { |
315 | if ( key ) { |
316 | for ( gpgme_sub_key_t s = key->subkeys ; s ; s = s->next ) { |
317 | if ( s == subkey ) { |
318 | return subkey; |
319 | } |
320 | } |
321 | } |
322 | return 0; |
323 | } |
324 | |
325 | Subkey::Subkey() : key(), subkey( 0 ) {} |
326 | |
327 | Subkey::Subkey( const shared_gpgme_key_t & k, unsigned int idx ) |
328 | : key( k ), subkey( find_subkey( k, idx ) ) |
329 | { |
330 | |
331 | } |
332 | |
333 | Subkey::Subkey( const shared_gpgme_key_t & k, gpgme_sub_key_t sk ) |
334 | : key( k ), subkey( verify_subkey( k, sk ) ) |
335 | { |
336 | |
337 | } |
338 | |
339 | Key Subkey::parent() const { |
340 | return Key( key ); |
341 | } |
342 | |
343 | const char * Subkey::keyID() const { |
344 | return subkey ? subkey->keyid : 0 ; |
345 | } |
346 | |
347 | const char * Subkey::fingerprint() const { |
348 | return subkey ? subkey->fpr : 0 ; |
349 | } |
350 | |
351 | unsigned int Subkey::publicKeyAlgorithm() const { |
352 | return subkey ? subkey->pubkey_algo : 0 ; |
353 | } |
354 | |
355 | const char * Subkey::publicKeyAlgorithmAsString() const { |
356 | return gpgme_pubkey_algo_name( subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0 ); |
357 | } |
358 | |
359 | bool Subkey::canEncrypt() const { |
360 | return subkey && subkey->can_encrypt; |
361 | } |
362 | |
363 | bool Subkey::canSign() const { |
364 | return subkey && subkey->can_sign; |
365 | } |
366 | |
367 | bool Subkey::canCertify() const { |
368 | return subkey && subkey->can_certify; |
369 | } |
370 | |
371 | bool Subkey::canAuthenticate() const { |
372 | return subkey && subkey->can_authenticate; |
373 | } |
374 | |
375 | bool Subkey::isQualified() const { |
376 | #ifdef HAVE_GPGME_SUBKEY_T_IS_QUALIFIED |
377 | return subkey && subkey->is_qualified; |
378 | #else |
379 | return false; |
380 | #endif |
381 | } |
382 | |
383 | bool Subkey::isCardKey() const { |
384 | #ifdef HAVE_GPGME_SUBKEY_T_IS_CARDKEY |
385 | return subkey && subkey->is_cardkey; |
386 | #else |
387 | return false; |
388 | #endif |
389 | } |
390 | |
391 | const char * Subkey::cardSerialNumber() const { |
392 | #ifdef HAVE_GPGME_SUBKEY_T_IS_CARDKEY |
393 | return subkey ? subkey->card_number : 0 ; |
394 | #else |
395 | return 0; |
396 | #endif |
397 | } |
398 | |
399 | bool Subkey::isSecret() const { |
400 | return subkey && subkey->secret; |
401 | } |
402 | |
403 | unsigned int Subkey::length() const { |
404 | return subkey ? subkey->length : 0 ; |
405 | } |
406 | |
407 | time_t Subkey::creationTime() const { |
408 | return static_cast<time_t>( subkey ? subkey->timestamp : 0 ); |
409 | } |
410 | |
411 | time_t Subkey::expirationTime() const { |
412 | return static_cast<time_t>( subkey ? subkey->expires : 0 ); |
413 | } |
414 | |
415 | bool Subkey::neverExpires() const { |
416 | return expirationTime() == time_t( 0 ); |
417 | } |
418 | |
419 | bool Subkey::isRevoked() const { |
420 | return subkey && subkey->revoked; |
421 | } |
422 | |
423 | bool Subkey::isInvalid() const { |
424 | return subkey && subkey->invalid; |
425 | } |
426 | |
427 | bool Subkey::isExpired() const { |
428 | return subkey && subkey->expired; |
429 | } |
430 | |
431 | bool Subkey::isDisabled() const { |
432 | return subkey && subkey->disabled; |
433 | } |
434 | |
435 | // |
436 | // |
437 | // class UserID |
438 | // |
439 | // |
440 | |
441 | gpgme_user_id_t find_uid( const shared_gpgme_key_t & key, unsigned int idx ) { |
442 | if ( key ) { |
443 | for ( gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx ) { |
444 | if ( idx == 0 ) { |
445 | return u; |
446 | } |
447 | } |
448 | } |
449 | return 0; |
450 | } |
451 | |
452 | gpgme_user_id_t verify_uid( const shared_gpgme_key_t & key, gpgme_user_id_t uid ) { |
453 | if ( key ) { |
454 | for ( gpgme_user_id_t u = key->uids ; u ; u = u->next ) { |
455 | if ( u == uid ) { |
456 | return uid; |
457 | } |
458 | } |
459 | } |
460 | return 0; |
461 | } |
462 | |
463 | UserID::UserID() : key(), uid( 0 ) {} |
464 | |
465 | UserID::UserID( const shared_gpgme_key_t & k, gpgme_user_id_t u ) |
466 | : key( k ), uid( verify_uid( k, u ) ) |
467 | { |
468 | |
469 | } |
470 | |
471 | UserID::UserID( const shared_gpgme_key_t & k, unsigned int idx ) |
472 | : key( k ), uid( find_uid( k, idx ) ) |
473 | { |
474 | |
475 | } |
476 | |
477 | Key UserID::parent() const { |
478 | return Key( key ); |
479 | } |
480 | |
481 | UserID::Signature UserID::signature( unsigned int index ) const { |
482 | return Signature( key, uid, index ); |
483 | } |
484 | |
485 | unsigned int UserID::numSignatures() const { |
486 | if ( !uid ) { |
487 | return 0; |
488 | } |
489 | unsigned int count = 0; |
490 | for ( gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next ) { |
491 | ++count; |
492 | } |
493 | return count; |
494 | } |
495 | |
496 | std::vector<UserID::Signature> UserID::signatures() const { |
497 | if ( !uid ) { |
498 | return std::vector<Signature>(); |
499 | } |
500 | |
501 | std::vector<Signature> v; |
502 | v.reserve( numSignatures() ); |
503 | for ( gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next ) { |
504 | v.push_back( Signature( key, uid, sig ) ); |
505 | } |
506 | return v; |
507 | } |
508 | |
509 | const char * UserID::id() const { |
510 | return uid ? uid->uid : 0 ; |
511 | } |
512 | |
513 | const char * UserID::name() const { |
514 | return uid ? uid->name : 0 ; |
515 | } |
516 | |
517 | const char * UserID::email() const { |
518 | return uid ? uid->email : 0 ; |
519 | } |
520 | |
521 | const char * UserID::() const { |
522 | return uid ? uid->comment : 0 ; |
523 | } |
524 | |
525 | UserID::Validity UserID::validity() const { |
526 | if ( !uid ) { |
527 | return Unknown; |
528 | } |
529 | switch ( uid->validity ) { |
530 | default: |
531 | case GPGME_VALIDITY_UNKNOWN: return Unknown; |
532 | case GPGME_VALIDITY_UNDEFINED: return Undefined; |
533 | case GPGME_VALIDITY_NEVER: return Never; |
534 | case GPGME_VALIDITY_MARGINAL: return Marginal; |
535 | case GPGME_VALIDITY_FULL: return Full; |
536 | case GPGME_VALIDITY_ULTIMATE: return Ultimate; |
537 | } |
538 | } |
539 | |
540 | char UserID::validityAsString() const { |
541 | if ( !uid ) { |
542 | return '?'; |
543 | } |
544 | switch ( uid->validity ) { |
545 | default: |
546 | case GPGME_VALIDITY_UNKNOWN: return '?'; |
547 | case GPGME_VALIDITY_UNDEFINED: return 'q'; |
548 | case GPGME_VALIDITY_NEVER: return 'n'; |
549 | case GPGME_VALIDITY_MARGINAL: return 'm'; |
550 | case GPGME_VALIDITY_FULL: return 'f'; |
551 | case GPGME_VALIDITY_ULTIMATE: return 'u'; |
552 | } |
553 | } |
554 | |
555 | bool UserID::isRevoked() const { |
556 | return uid && uid->revoked; |
557 | } |
558 | |
559 | bool UserID::isInvalid() const { |
560 | return uid && uid->invalid; |
561 | } |
562 | |
563 | // |
564 | // |
565 | // class Signature |
566 | // |
567 | // |
568 | |
569 | gpgme_key_sig_t find_signature( gpgme_user_id_t uid, unsigned int idx ) { |
570 | if ( uid ) { |
571 | for ( gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx ) { |
572 | if ( idx == 0 ) { |
573 | return s; |
574 | } |
575 | } |
576 | } |
577 | return 0; |
578 | } |
579 | |
580 | gpgme_key_sig_t verify_signature( gpgme_user_id_t uid, gpgme_key_sig_t sig ) { |
581 | if ( uid ) { |
582 | for ( gpgme_key_sig_t s = uid->signatures ; s ; s = s->next ) { |
583 | if ( s == sig ) { |
584 | return sig; |
585 | } |
586 | } |
587 | } |
588 | return 0; |
589 | } |
590 | |
591 | |
592 | UserID::Signature::Signature() : key(), uid( 0 ), sig( 0 ) {} |
593 | |
594 | UserID::Signature::Signature( const shared_gpgme_key_t & k, gpgme_user_id_t u, unsigned int idx ) |
595 | : key( k ), uid( verify_uid( k, u ) ), sig( find_signature( uid, idx ) ) |
596 | { |
597 | |
598 | } |
599 | |
600 | UserID::Signature::Signature( const shared_gpgme_key_t & k, gpgme_user_id_t u, gpgme_key_sig_t s ) |
601 | : key( k ), uid( verify_uid( k, u ) ), sig( verify_signature( uid, s ) ) |
602 | { |
603 | |
604 | } |
605 | |
606 | UserID UserID::Signature::parent() const { |
607 | return UserID( key, uid ); |
608 | } |
609 | |
610 | const char * UserID::Signature::signerKeyID() const { |
611 | return sig ? sig->keyid : 0 ; |
612 | } |
613 | |
614 | const char * UserID::Signature::algorithmAsString() const { |
615 | return gpgme_pubkey_algo_name( sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0 ); |
616 | } |
617 | |
618 | unsigned int UserID::Signature::algorithm() const { |
619 | return sig ? sig->pubkey_algo : 0 ; |
620 | } |
621 | |
622 | time_t UserID::Signature::creationTime() const { |
623 | return static_cast<time_t>( sig ? sig->timestamp : 0 ); |
624 | } |
625 | |
626 | time_t UserID::Signature::expirationTime() const { |
627 | return static_cast<time_t>( sig ? sig->expires : 0 ); |
628 | } |
629 | |
630 | bool UserID::Signature::neverExpires() const { |
631 | return expirationTime() == time_t( 0 ); |
632 | } |
633 | |
634 | bool UserID::Signature::isRevokation() const { |
635 | return sig && sig->revoked; |
636 | } |
637 | |
638 | bool UserID::Signature::isInvalid() const { |
639 | return sig && sig->invalid; |
640 | } |
641 | |
642 | bool UserID::Signature::isExpired() const { |
643 | return sig && sig->expired; |
644 | } |
645 | |
646 | bool UserID::Signature::isExportable() const { |
647 | return sig && sig->exportable; |
648 | } |
649 | |
650 | const char * UserID::Signature::signerUserID() const { |
651 | return sig ? sig->uid : 0 ; |
652 | } |
653 | |
654 | const char * UserID::Signature::signerName() const { |
655 | return sig ? sig->name : 0 ; |
656 | } |
657 | |
658 | const char * UserID::Signature::signerEmail() const { |
659 | return sig ? sig->email : 0 ; |
660 | } |
661 | |
662 | const char * UserID::Signature::() const { |
663 | return sig ? sig->comment : 0 ; |
664 | } |
665 | |
666 | unsigned int UserID::Signature::certClass() const { |
667 | return sig ? sig->sig_class : 0 ; |
668 | } |
669 | |
670 | UserID::Signature::Status UserID::Signature::status() const { |
671 | if ( !sig ) { |
672 | return GeneralError; |
673 | } |
674 | |
675 | switch ( gpgme_err_code( sig->status ) ) { |
676 | case GPG_ERR_NO_ERROR: return NoError; |
677 | case GPG_ERR_SIG_EXPIRED: return SigExpired; |
678 | case GPG_ERR_KEY_EXPIRED: return KeyExpired; |
679 | case GPG_ERR_BAD_SIGNATURE: return BadSignature; |
680 | case GPG_ERR_NO_PUBKEY: return NoPublicKey; |
681 | default: |
682 | case GPG_ERR_GENERAL: return GeneralError; |
683 | } |
684 | } |
685 | |
686 | std::string UserID::Signature::statusAsString() const { |
687 | if ( !sig ) { |
688 | return std::string(); |
689 | } |
690 | char buf[ 1024 ]; |
691 | gpgme_strerror_r( sig->status, buf, sizeof buf ); |
692 | buf[ sizeof buf - 1 ] = '\0'; |
693 | return std::string( buf ); |
694 | } |
695 | |
696 | GpgME::Notation UserID::Signature::notation( unsigned int idx ) const { |
697 | if ( !sig ) { |
698 | return GpgME::Notation(); |
699 | } |
700 | #ifdef HAVE_GPGME_KEY_SIG_NOTATIONS |
701 | for ( gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next ) { |
702 | if ( nota->name ) { |
703 | if ( idx-- == 0 ) { |
704 | return GpgME::Notation( nota ); |
705 | } |
706 | } |
707 | } |
708 | #endif |
709 | return GpgME::Notation(); |
710 | } |
711 | |
712 | unsigned int UserID::Signature::numNotations() const { |
713 | if ( !sig ) { |
714 | return 0; |
715 | } |
716 | unsigned int count = 0; |
717 | #ifdef HAVE_GPGME_KEY_SIG_NOTATIONS |
718 | for ( gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next ) { |
719 | if ( nota->name ) { |
720 | ++count; // others are policy URLs... |
721 | } |
722 | } |
723 | #endif |
724 | return count; |
725 | } |
726 | |
727 | std::vector<Notation> UserID::Signature::notations() const { |
728 | if ( !sig ) { |
729 | return std::vector<GpgME::Notation>(); |
730 | } |
731 | std::vector<GpgME::Notation> v; |
732 | #ifdef HAVE_GPGME_KEY_SIG_NOTATIONS |
733 | v.reserve( numNotations() ); |
734 | for ( gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next ) { |
735 | if ( nota->name ) { |
736 | v.push_back( GpgME::Notation( nota ) ); |
737 | } |
738 | } |
739 | #endif |
740 | return v; |
741 | } |
742 | |
743 | const char * UserID::Signature::policyURL() const { |
744 | #ifdef HAVE_GPGME_KEY_SIG_NOTATIONS |
745 | if ( !sig ) { |
746 | return 0; |
747 | } |
748 | for ( gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next ) { |
749 | if ( !nota->name ) { |
750 | return nota->value; |
751 | } |
752 | } |
753 | #endif |
754 | return 0; |
755 | } |
756 | |
757 | } // namespace GpgME |
758 | |